1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
#include "paging.h"
#include "arch/x86_64/x86_64.h"
#include "jove.h"
#include "init.h"
#include "config.h"
#include "smp.h"
#include "hal/obj.h"
#include "lib/string.h"
#include "lib/printf.h"
#include "lib/panic.h"
#include "idt.h"
PAGEALIGN page_t _kernel_pml4[512];
PAGEALIGN page_t _kernel_pml3[512];
PAGEALIGN page_t _kernel_pml2[512];
PAGEALIGN page_t _kernel_pml1[512];
#define IDENT_GIANTPAGES ((PHYS_HUGEPAGES_MAX + 511) / 512)
#define IDENT_MASSIVEPAGES ((IDENT_GIANTPAGES + 511) / 512)
PAGEALIGN static page_t ident_pml3[IDENT_MASSIVEPAGES][512];
PAGEALIGN static page_t ident_pml2[IDENT_GIANTPAGES][512];
void*
phys_tovirt(uintptr_t phys)
{
return (void*)(phys | IDENT_VIRT_BASE);
}
uintptr_t
paging_get_pml4(void)
{
uintptr_t ret = 0;
__asm__ volatile("movq %%cr3, %0": "=r"(ret));
return ret;
}
void
paging_pml4_switch(uintptr_t pml4)
{
__asm__ volatile("movq %0, %%cr3":: "r"(pml4));
}
static struct int_stackframe*
s_int_handle_pf_early(struct int_stackframe *frame)
{
extern int _kernel_panic_unlock;
_kernel_panic_unlock = 1;
union {
struct {
uint8_t p : 1;
uint8_t wr : 1;
uint8_t us : 1;
uint8_t rsvd : 1;
uint8_t id : 1;
uint8_t pk : 1;
};
uint64_t value;
} pf_error = { .value = frame->int_err };
kprintf("Kernel has encountered a page fault exception early in initializaiton\n");
kprintf("%s %s during %s\n",
pf_error.wr ? "Wrote to" : "Read from",
pf_error.p ? "Present" : "Non-present",
pf_error.id ? "Instruction fetch" : "Data access");
uintptr_t cr2 = 0;
__asm__ volatile("movq %%cr2, %0": "=r"(cr2));
kprintf("Faulting address: %p\n", cr2);
kprintf("RIP: %p | RSP: %p\n", frame->int_rip, frame->int_rsp);
print_state(&frame->state);
hcf();
}
void
paging_pml4_init(void)
{
//Setup kernel pages
memset(_kernel_pml4, 0, 0x1000);
memset(_kernel_pml3, 0, 0x1000);
memset(_kernel_pml2, 0, 0x1000);
memset(_kernel_pml1, 0, 0x1000);
memset(ident_pml3, 0, 0x1000 * IDENT_MASSIVEPAGES);
memset(ident_pml2, 0, 0x1000 * IDENT_GIANTPAGES);
/*Paging entries depend on physical addresses to properly map.
* Since the virtual kernel address differs from the physical memory address,
* we need to convert the pointers using the physical memory pointer passed
* to us by the bootloader.*/
uintptr_t kernel_pml4_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml4);
uintptr_t kernel_pml3_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml3);
uintptr_t kernel_pml2_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml2);
uintptr_t kernel_pml1_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml1);
/*Maps pml4-2 as global writeable pages.*/
_kernel_pml4[511].value = kernel_pml3_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL;
_kernel_pml3[510].value = kernel_pml2_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL;
_kernel_pml2[0].value = kernel_pml1_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL;
/*text*/
extern void *_kernel_text_start;
extern void *_kernel_text_end;
uintptr_t kernel_text_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_text_start);
uintptr_t kernel_text_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_text_end);
size_t kernel_text_pages = ((kernel_text_end_pptr - kernel_text_start_pptr) / 0x1000) + 1;
uintptr_t kernel_text_off = (((uintptr_t)&_kernel_text_start) - KERNEL_VIRT_BASE) >> 12;
for(size_t i = 0; i < kernel_text_pages; i++) {
size_t off = i + kernel_text_off;
uintptr_t page_off = kernel_text_start_pptr + (i << 12);
_kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_GLOBAL;
}
/*rodata*/
extern void *_kernel_rodata_start;
extern void *_kernel_rodata_end;
uintptr_t kernel_rodata_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_rodata_start);
uintptr_t kernel_rodata_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_rodata_end);
size_t kernel_rodata_pages = ((kernel_rodata_end_pptr - kernel_rodata_start_pptr) / 0x1000) + 1;
uintptr_t kernel_rodata_off = kernel_text_off + kernel_text_pages;
for(size_t i = 0; i < kernel_rodata_pages; i++) {
size_t off = i + kernel_rodata_off;
uintptr_t page_off = kernel_text_start_pptr + (off << 12);
_kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_GLOBAL | PAGE_XD;
}
/*data/bss*/
extern void *_kernel_data_start;
extern void *_kernel_bss_end;
uintptr_t kernel_data_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_data_start);
uintptr_t kernel_data_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_bss_end);
size_t kernel_data_pages = ((kernel_data_end_pptr - kernel_data_start_pptr) / 0x1000) + 1;
uintptr_t kernel_data_off = kernel_rodata_off + kernel_rodata_pages;
for(size_t i = 0; i < kernel_data_pages; i++) {
size_t off = i + kernel_data_off;
uintptr_t page_off = kernel_text_start_pptr + (off << 12);
_kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL | PAGE_XD;
}
/*Identity pages are mapped as huge pages starting at the 256'th PML3 entry.
*We want to support any range of physical memory up to several TiB, so
*the mapper has to consider multiple heirarchies of huge pages.*/
for(size_t l3 = 0; l3 < IDENT_MASSIVEPAGES; l3++) {
uintptr_t ident_pml3_pptr = KPTR_TOPHYS(&ident_pml3[l3]);
_kernel_pml4[256 + l3].value = ident_pml3_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL;
}
for(size_t l2 = 0; l2 < IDENT_GIANTPAGES; l2++) {
size_t l3 = l2 / 512;
size_t l2_mod = l2 % 512;
uintptr_t ident_pml2_pptr = KPTR_TOPHYS(&ident_pml2[l2]);
ident_pml3[l3][l2_mod].value = ident_pml2_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL;
}
for(size_t l1 = 0; l1 < PHYS_HUGEPAGES_MAX; l1++) {
size_t l2 = l1 / 512;
size_t l1_mod = l1 % 512;
ident_pml2[l2][l1_mod].value = (l1 << 21) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_PS | PAGE_GLOBAL | PAGE_XD;
ident_pml2[l2][l1_mod].xd = 1;
}
paging_pml4_switch(kernel_pml4_pptr);
{
jove_owned_obj_t *pgdir_o = objdir_getlocal(_rootdir_obj, ROOTDIR_PAGEDIR_I);
obj_settype(pgdir_o, JOVE_OBJ_PAGEDIR);
obj_setvalue(pgdir_o, kernel_pml4_pptr);
obj_release(pgdir_o);
}
/*Before tasking, if the kernel has a bug and crashes we need some
* information about what happened.*/
extern struct int_stackframe *(*__int_handles[])(struct int_stackframe*);
__int_handles[IDT_EXCEPT_PF] = s_int_handle_pf_early;
}
|