4 void print(const char *s
);
6 #define PAGE_SIZE 4096ul
7 #define LARGE_PAGE_SIZE (512 * PAGE_SIZE)
10 static void *vfree_top
= 0;
12 static unsigned long virt_to_phys(const void *virt
)
14 return (unsigned long)virt
;
17 static void *phys_to_virt(unsigned long phys
)
22 void *memset(void *data
, int c
, unsigned long len
)
32 static void free_memory(void *mem
, unsigned long size
)
34 while (size
>= PAGE_SIZE
) {
50 free
= *(void **)free
;
55 void free_page(void *page
)
57 *(void **)page
= free
;
62 static unsigned long end_of_memory
;
64 #define PTE_PRESENT (1ull << 0)
65 #define PTE_PSE (1ull << 7)
66 #define PTE_WRITE (1ull << 1)
67 #define PTE_ADDR (0xffffffffff000ull)
69 static void install_pte(unsigned long *cr3
,
75 unsigned long *pt
= cr3
;
78 for (level
= 4; level
> pte_level
; --level
) {
79 offset
= ((unsigned long)virt
>> ((level
-1) * 9 + 12)) & 511;
80 if (!(pt
[offset
] & PTE_PRESENT
)) {
81 unsigned long *new_pt
= alloc_page();
82 memset(new_pt
, 0, PAGE_SIZE
);
83 pt
[offset
] = virt_to_phys(new_pt
) | PTE_PRESENT
| PTE_WRITE
;
85 pt
= phys_to_virt(pt
[offset
] & 0xffffffffff000ull
);
87 offset
= ((unsigned long)virt
>> (((level
-1) * 9) + 12)) & 511;
91 static unsigned long get_pte(unsigned long *cr3
, void *virt
)
94 unsigned long *pt
= cr3
, pte
;
97 for (level
= 4; level
> 1; --level
) {
98 offset
= ((unsigned long)virt
>> (((level
-1) * 9) + 12)) & 511;
100 if (!(pte
& PTE_PRESENT
))
102 if (level
== 2 && (pte
& PTE_PSE
))
104 pt
= phys_to_virt(pte
& 0xffffffffff000ull
);
106 offset
= ((unsigned long)virt
>> (((level
-1) * 9) + 12)) & 511;
111 static void install_large_page(unsigned long *cr3
,
115 install_pte(cr3
, 2, virt
, phys
| PTE_PRESENT
| PTE_WRITE
| PTE_PSE
);
118 static void install_page(unsigned long *cr3
,
122 install_pte(cr3
, 1, virt
, phys
| PTE_PRESENT
| PTE_WRITE
);
125 static inline void load_cr3(unsigned long cr3
)
127 asm ( "mov %0, %%cr3" : : "r"(cr3
) );
130 static inline unsigned long read_cr3()
134 asm volatile ( "mov %%cr3, %0" : "=r"(cr3
) );
138 static inline void load_cr0(unsigned long cr0
)
140 asm volatile ( "mov %0, %%cr0" : : "r"(cr0
) );
143 static inline unsigned long read_cr0()
147 asm volatile ( "mov %%cr0, %0" : "=r"(cr0
) );
151 static inline void load_cr4(unsigned long cr4
)
153 asm volatile ( "mov %0, %%cr4" : : "r"(cr4
) );
156 static inline unsigned long read_cr4()
160 asm volatile ( "mov %%cr4, %0" : "=r"(cr4
) );
164 struct gdt_table_descr
167 unsigned long *table
;
168 } __attribute__((packed
));
170 static inline void load_gdt(unsigned long *table
, int nent
)
172 struct gdt_table_descr descr
;
174 descr
.len
= nent
* 8 - 1;
176 asm volatile ( "lgdt %0" : : "m"(descr
) );
187 static void setup_mmu(unsigned long len
)
189 unsigned long *cr3
= alloc_page();
190 unsigned long phys
= 0;
192 if (len
< (1ul << 32))
193 len
= 1ul << 32; /* map mmio 1:1 */
195 memset(cr3
, 0, PAGE_SIZE
);
196 while (phys
+ LARGE_PAGE_SIZE
<= len
) {
197 install_large_page(cr3
, phys
, (void *)phys
);
198 phys
+= LARGE_PAGE_SIZE
;
200 while (phys
+ PAGE_SIZE
<= len
) {
201 install_page(cr3
, phys
, (void *)phys
);
205 load_cr3(virt_to_phys(cr3
));
206 print("paging enabled\n");
209 static unsigned int inl(unsigned short port
)
212 asm volatile("inl %w1, %0" : "=a"(val
) : "Nd"(port
));
218 end_of_memory
= inl(0xd1);
219 free_memory(&edata
, end_of_memory
- (unsigned long)&edata
);
220 setup_mmu(end_of_memory
);
223 void *vmalloc(unsigned long size
)
228 size
+= sizeof(unsigned long);
230 size
= (size
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1);
233 pages
= size
/ PAGE_SIZE
;
235 install_page(phys_to_virt(read_cr3()), virt_to_phys(alloc_page()), p
);
238 *(unsigned long *)mem
= size
;
239 mem
+= sizeof(unsigned long);
243 void vfree(void *mem
)
245 unsigned long size
= ((unsigned long *)mem
)[-1];
248 free_page(phys_to_virt(get_pte(phys_to_virt(read_cr3()), mem
) & PTE_ADDR
));
254 void *vmap(unsigned long long phys
, unsigned long size
)
259 size
= (size
+ PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1);
261 phys
&= ~(unsigned long long)(PAGE_SIZE
- 1);
264 pages
= size
/ PAGE_SIZE
;
266 install_page(phys_to_virt(read_cr3()), phys
, p
);