]> git.dujemihanovic.xyz Git - nameless-os.git/blob - boot/x86/stage3/paging.c
Separate generic and arch-specific headers
[nameless-os.git] / boot / x86 / stage3 / paging.c
1 /* Code for enabling paging */
2
3 #include <stdint.h>
4
5 #define ADDRESS_NOT_ALIGNED 1
6 #define INVL_ADDRESS 2
7 #define ADDRESS_ALREADY_MAPPED 3
8 #define ADDRESS_RANGE_MISMATCHED 4
9
10 static uint32_t page_directory[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
11 static uint32_t page_table_firstmb[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
12 static uint32_t page_table_kernel[1024] __attribute__((aligned(4096))) __attribute__((section(".data")));
13
14 void enable_paging()
15 {
16 int cr3;
17 asm ("mov %0, %%cr3": : "a" (page_directory));
18 asm ("mov %%cr0, %0": "=a" (cr3));
19 cr3 |= 0x80000000;
20 asm ("mov %0, %%cr0": : "a" (cr3));
21 }
22
23 int map_address(void *physical, void *virtual, int flags)
24 {
25 if ((uint32_t) physical & 0xfff || (uint32_t) virtual & 0xfff)
26 return ADDRESS_NOT_ALIGNED;
27
28 uint32_t pdir_index = (uint32_t) virtual >> 22;
29 if (pdir_index != 0 && pdir_index != 0x300)
30 return INVL_ADDRESS;
31
32 uint32_t ptbl_index = ((uint32_t) virtual >> 12) & 0x3ff;
33 switch (pdir_index) {
34 case 0:
35 if (page_table_firstmb[ptbl_index] & 1 == 1)
36 return ADDRESS_ALREADY_MAPPED;
37 page_table_firstmb[ptbl_index] = ((uint32_t) physical & ~0xfff) | (flags & 0xfff) | 1;
38 break;
39 case 0x300:
40 if (page_table_kernel[ptbl_index] & 1 == 1)
41 return ADDRESS_ALREADY_MAPPED;
42 page_table_kernel[ptbl_index] = ((uint32_t) physical & ~0xfff) | (flags & 0xfff) | 1;
43 }
44
45 return 0;
46 }
47
48 int map_range(void *phys_start, void *phys_end, void *virt_start, void *virt_end, int flags)
49 {
50 if ((uint32_t) phys_start & 0xfff || (uint32_t) phys_end & 0xfff ||
51 (uint32_t) virt_start & 0xfff || (uint32_t) virt_end & 0xfff)
52 return ADDRESS_NOT_ALIGNED;
53
54 if ((uint32_t) phys_end - (uint32_t) phys_start != (uint32_t) virt_end - (uint32_t) virt_start)
55 return ADDRESS_RANGE_MISMATCHED;
56
57 int loops = ((uint32_t) phys_end - (uint32_t) phys_start) / 4096;
58 for (int i=0; i<loops; i++) {
59 int ret = map_address(phys_start + i*4096, virt_start + i*4096, flags);
60 if (ret)
61 return ret;
62 }
63 return 0;
64 }
65
66 void set_up_page_directory()
67 {
68 page_directory[0] = (uint32_t) page_table_firstmb | 3;
69 page_directory[0x300] = (uint32_t) page_table_kernel | 3;
70 }