CS350 COS
COS
Loading...
Searching...
No Matches
pmap.c
Go to the documentation of this file.
1
2#include <stdbool.h>
3#include <stdint.h>
4
5#include <sys/kconfig.h>
6#include <sys/kassert.h>
7#include <sys/kdebug.h>
8#include <sys/kmem.h>
9
10#include <machine/amd64.h>
11#include <machine/amd64op.h>
12#include <machine/mp.h>
13#include <machine/pmap.h>
14
17
18void
20{
21 int i, j;
22
23 kprintf("Initializing PMAP ... ");
24
25 // Setup global state
26 for (i = 0; i < MAX_CPUS; i++) {
27 currentAS[i] = 0;
28 }
29
30 // Allocate system page table
34 if (!systemAS.root)
35 PANIC("Cannot allocate system page table");
36
37 for (i = 0; i < PAGETABLE_ENTRIES / 2; i++)
38 systemAS.root->entries[i] = 0;
39
40 for (i = PAGETABLE_ENTRIES / 2; i < PAGETABLE_ENTRIES; i++) {
41 PageTable *pgtbl = PAlloc_AllocPage();
42 PageEntry pte = DMVA2PA((uint64_t)pgtbl) | PTE_W | PTE_P;
43 if (!pgtbl)
44 PANIC("Not enough memory!");
45
46 systemAS.root->entries[i] = pte;
47
48 for (j = 0; j < PAGETABLE_ENTRIES; j++) {
49 pgtbl->entries[j] = 0;
50 }
51 }
52
53 // Setup system mappings
55 3*512, 0); // 3GB RWX
56 PMap_SystemLMap(0xC0000000, MEM_DIRECTMAP_BASE + 0xC0000000,
57 512, PTE_NX|PTE_PCD); // 1GB RW + PCD
58 PMap_SystemLMap(0x100000000, MEM_DIRECTMAP_BASE + 0x100000000,
59 60*512, 0); // 60GB RWX
60
62
63 kprintf("Done!\n");
64}
65
66void
68{
70}
71
79AS*
81{
82 int i;
83 AS *as = PAlloc_AllocPage();
84
85 if (!as)
86 return NULL;
87
88 as->root = PAlloc_AllocPage();
89 as->tables = 1;
90 as->mappings = 0;
91
92 if (!as->root) {
94 return NULL;
95 }
96
97 for (i = 0; i < PAGETABLE_ENTRIES / 2; i++)
98 {
99 as->root->entries[i] = 0;
100 }
101 for (i = PAGETABLE_ENTRIES / 2; i < PAGETABLE_ENTRIES; i++) {
102 as->root->entries[i] = systemAS.root->entries[i];
103 }
104
105 return as;
106}
107
115void
117{
118 // Only free the userspace portion (bottom half)
119 for (int i = 0; i < PAGETABLE_ENTRIES / 2; i++)
120 {
121 PageEntry pte = space->root->entries[i];
122 if (pte & PTE_P) {
123 // Remove sub-pages
124 PageTable *tbl2 = (PageTable *)DMPA2VA(pte & PGNUMMASK);
125 for (int j = 0; j < PAGETABLE_ENTRIES; j++) {
126 PageEntry pte2 = tbl2->entries[j];
127 if (pte2 & PTE_P) {
128 PageTable *tbl3 = (PageTable *)DMPA2VA(pte2 & PGNUMMASK);
129 for (int k = 0; k < PAGETABLE_ENTRIES; k++) {
130 PageEntry pte3 = tbl3->entries[k];
131 if (pte3 & PTE_P) {
132 ASSERT((pte3 & PTE_PS) == 0); // XXX: Large pages not supported
133 PageTable *tbl4 = (PageTable *)DMPA2VA(pte3 & PGNUMMASK);
134 for (int l = 0; l < PAGETABLE_ENTRIES; l++) {
135 PageEntry pte4 = tbl4->entries[l];
136 if (pte4 & PTE_P) {
137 // Free userspace page
138 PAlloc_Release((void *)DMPA2VA(pte4 & PGNUMMASK));
139 }
140 }
141
142 // Free 3rd level page table page
143 PAlloc_Release((void *)DMPA2VA(pte3 & PGNUMMASK));
144 }
145 }
146
147 // Free 2nd level page table page
148 PAlloc_Release((void *)DMPA2VA(pte2 & PGNUMMASK));
149 }
150 }
151
152 // Free page table page
153 PAlloc_Release((void *)DMPA2VA(pte & PGNUMMASK));
154 }
155 }
156
157 PAlloc_Release(space);
158}
159
167AS *
169{
170 return currentAS[THISCPU()];
171}
172
181void
183{
184 write_cr3(DMVA2PA((uint64_t)space->root));
185 currentAS[THISCPU()] = space;
186}
187
195static PageTable *
197{
198 int i;
199 PageTable *pgtbl = PAlloc_AllocPage();
200
201 if (!pgtbl)
202 return 0;
203
204 for (i = 0; i < PAGETABLE_ENTRIES; i++) {
205 pgtbl->entries[i] = 0;
206 }
207
208 return pgtbl;
209}
210
221{
222 int i,j,k,l;
223 PageTable *table = space->root;
224 PageEntry pte;
225 PageEntry *entry;
226
227 i = (va >> (HUGE_PGSHIFT + PGIDXSHIFT)) & PGIDXMASK;
228 j = (va >> HUGE_PGSHIFT) & PGIDXMASK;
229 k = (va >> LARGE_PGSHIFT) & PGIDXMASK;
230 l = (va >> PGSHIFT) & PGIDXMASK;
231
232 pte = table->entries[i];
233 if (pte == 0) {
234 ASSERT(pte);
235 return 0;
236 }
237 table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
238
239 pte = table->entries[j];
240 // XXX: Support 1GB pages
241 if (pte == 0) {
242 ASSERT(pte);
243 return 0;
244 }
245 table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
246
247 pte = table->entries[k];
248 if ((pte & PTE_PS) == PTE_PS) {
249 // Handle 2MB pages
250 entry = &table->entries[k];
251 return (*entry & ~(LARGE_PGMASK | PTE_NX)) + (va & LARGE_PGMASK);
252 }
253 if (pte == 0) {
254 ASSERT(pte);
255 return 0;
256 }
257 table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
258
259 // Handle 4KB pages
260 entry = &table->entries[l];
261
262 return (*entry & ~(PGMASK | PTE_NX)) + (va & PGMASK);
263}
264
277static void
278PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
279{
280 int i,j,k,l;
281 PageTable *table = space->root;
282 PageEntry pte;
283
284 i = (va >> (HUGE_PGSHIFT + PGIDXSHIFT)) & PGIDXMASK;
285 j = (va >> HUGE_PGSHIFT) & PGIDXMASK;
286 k = (va >> LARGE_PGSHIFT) & PGIDXMASK;
287 l = (va >> PGSHIFT) & PGIDXMASK;
288
289 *entry = NULL;
290
291 pte = table->entries[i];
292 if (pte == 0) {
293 PageTable *newtable = PMapAllocPageTable();
294 if (!newtable)
295 return;
296
297 pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U;
298 table->entries[i] = pte;
299 }
300 table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
301
302 pte = table->entries[j];
303 if (size == HUGE_PGSIZE) {
304 // Handle 1GB pages
305 *entry = &table->entries[j];
306 return;
307 }
308 if (pte == 0) {
309 PageTable *newtable = PMapAllocPageTable();
310 if (!newtable)
311 return;
312
313 pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U;
314 table->entries[j] = pte;
315 }
316 table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
317
318 pte = table->entries[k];
319 if (size == LARGE_PGSIZE) {
320 // Handle 2MB pages
321 *entry = &table->entries[k];
322 return;
323 }
324 if (pte == 0) {
325 PageTable *newtable = PMapAllocPageTable();
326 if (!newtable)
327 return;
328
329 pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U;
330 table->entries[k] = pte;
331 }
332 table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
333
334 // Handle 4KB pages
335 ASSERT(size == PGSIZE);
336 *entry = &table->entries[l];
337 return;
338}
339
354bool
355PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
356{
357 int i;
358 PageEntry *entry;
359
360 for (i = 0; i < pages; i++) {
361 uint64_t va = virt + PGSIZE * i;
362 PMapLookupEntry(as, va, &entry, PGSIZE);
363 if (!entry) {
364 kprintf("Map failed to allocate memory!\n");
365 return false;
366 }
367
368 *entry = (phys + PGSIZE * i) | PTE_P | PTE_W | PTE_U | flags;
369 }
370
371 return true;
372}
373
386bool
388{
389 int i;
390 PageEntry *entry;
391
392 for (i = 0; i < pages; i++) {
393 uint64_t vai = va + PGSIZE * i;
394 PMapLookupEntry(as, vai, &entry, PGSIZE);
395 if (!entry) {
396 kprintf("Unmap tried to allocate memory!\n");
397 return false;
398 }
399
401
402 *entry = 0;
403 }
404
405 return true;
406}
407
422bool
424{
425 int i;
426 uint64_t pages = (len + PGSIZE - 1) / PGSIZE;
427 PageEntry *entry;
428
429 ASSERT((virt & PGMASK) == 0);
430
431 for (i = 0; i < pages; i++) {
432 uint64_t va = virt + PGSIZE * i;
433 PMapLookupEntry(as, va, &entry, PGSIZE);
434 if (!entry) {
435 kprintf("Map failed to allocate memory!\n");
436 return false;
437 }
438
439 if ((*entry & PTE_P) != PTE_P) {
440 void *pg = PAlloc_AllocPage();
441 *entry = (uint64_t)DMVA2PA(pg) | PTE_P | PTE_U | flags;
442 }
443 }
444
445 return true;
446}
447
459void
461{
462 PMapLookupEntry(&systemAS, va, entry, size);
463}
464
479bool
481{
482 int i;
483 PageEntry *entry;
484
485 for (i = 0; i < lpages; i++) {
486 uint64_t va = virt + LARGE_PGSIZE * i;
488 if (!entry) {
489 kprintf("SystemLMap failed to allocate memory!\n");
490 return false;
491 }
492
493 *entry = (phys + LARGE_PGSIZE * i) | PTE_P | PTE_W | PTE_PS | flags;
494 }
495
496 return true;
497}
498
513bool
515{
516 int i;
517 PageEntry *entry;
518
519 for (i = 0; i < pages; i++) {
520 uint64_t va = virt + PGSIZE * i;
521 PMapLookupEntry(&systemAS, va, &entry, PGSIZE);
522 if (!entry) {
523 kprintf("SystemMap failed to allocate memory!\n");
524 return false;
525 }
526
527 *entry = (phys + PGSIZE * i) | PTE_P | PTE_W | flags;
528 }
529
530 return true;
531}
532
538bool
540{
542 return false;
543}
544
545static uint64_t
547{
548 return (i << 39) | (j << HUGE_PGSHIFT) | (k << LARGE_PGSHIFT) | (l << PGSHIFT);
549}
550
551void
553{
554 int i = 0;
555 int j = 0;
556 int k = 0;
557 int l = 0;
558 PageTable *root = space->root;
559
560 kprintf("Root: %016llx\n", (uint64_t)space->root);
561
562 for (i = 0; i < PAGETABLE_ENTRIES; i++) {
563 PageEntry pte = root->entries[i];
564 PageTable *l1 = (PageTable *)DMPA2VA(pte & PGNUMMASK);
565
566 if (!(pte & PTE_P))
567 continue;
568
569 kprintf("Level 1: %016llx\n", (uint64_t)pte);
570
571 for (j = 0; j < PAGETABLE_ENTRIES; j++) {
572 PageEntry pte2 = l1->entries[j];
573 PageTable *l2 = (PageTable *)DMPA2VA(pte2 & PGNUMMASK);
574
575 if (!(pte2 & PTE_P))
576 continue;
577
578 kprintf("Level 2: %016llx\n", (uint64_t)pte2);
579
580 for (k = 0; k < PAGETABLE_ENTRIES; k++) {
581 PageEntry pte3 = l2->entries[k];
582 PageTable *l3 = (PageTable *)DMPA2VA(pte3 & PGNUMMASK);
583
584 if (!(pte3 & PTE_P))
585 continue;
586
587 kprintf("Level 3: %016llx:%016llx\n",
588 AddrFromIJKL(i, j, k, 0),
589 (uint64_t)pte3);
590
591 if ((pte3 & PTE_PS) == 0) {
592 for (l = 0; l < PAGETABLE_ENTRIES; l++) {
593 PageEntry pte4 = l3->entries[l];
594
595 kprintf("Level 4: %016llx:%016llx\n",
596 AddrFromIJKL(i, j, k, l),
597 (uint64_t)pte4);
598 }
599 }
600 }
601 }
602 }
603
604 return;
605}
606
607static void
608Debug_PMapDumpFull(int argc, const char *argv[])
609{
611}
612
613REGISTER_DBGCMD(pmapdumpfull, "Dump memory mappings", Debug_PMapDumpFull);
614
615void
617{
618 int i = 0;
619 int j = 0;
620 int k = 0;
621 int l = 0;
622 PageTable *root = space->root;
623
624 kprintf("%-18s %-18s %-5s\n", "Virtual", "Physical PTE", "Flags");
625 for (i = 0; i < PAGETABLE_ENTRIES/2; i++) {
626 PageEntry pte = root->entries[i];
627 PageTable *l1 = (PageTable *)DMPA2VA(pte & PGNUMMASK);
628
629 if (!(pte & PTE_P))
630 continue;
631
632 for (j = 0; j < PAGETABLE_ENTRIES; j++) {
633 PageEntry pte2 = l1->entries[j];
634 PageTable *l2 = (PageTable *)DMPA2VA(pte2 & PGNUMMASK);
635
636 if (!(pte2 & PTE_P))
637 continue;
638
639 for (k = 0; k < PAGETABLE_ENTRIES; k++) {
640 PageEntry pte3 = l2->entries[k];
641 PageTable *l3 = (PageTable *)DMPA2VA(pte3 & PGNUMMASK);
642
643 if (!(pte3 & PTE_P))
644 continue;
645
646 if ((pte3 & PTE_PS) == 0) {
647 for (l = 0; l < PAGETABLE_ENTRIES; l++) {
648 PageEntry pte4 = l3->entries[l];
649
650 if (pte4 & PTE_P)
651 kprintf("0x%016llx: 0x%016llx P%c%c%c%c%c\n",
652 AddrFromIJKL(i, j, k, l),
653 (uint64_t)pte4,
654 (pte4 & PTE_W) ? 'W' : ' ',
655 (pte4 & PTE_NX) ? ' ' : 'X',
656 (pte4 & PTE_U) ? 'U' : ' ',
657 (pte4 & PTE_A) ? 'A' : ' ',
658 (pte4 & PTE_D) ? 'D' : ' ');
659 }
660 }
661 }
662 }
663 }
664
665 return;
666}
667
668static void
669Debug_PMapDump(int argc, const char *argv[])
670{
672}
673
674REGISTER_DBGCMD(pmapdump, "Dump memory mappings", Debug_PMapDump);
675
676
#define THISCPU
Definition: mp.h:21
#define PTE_W
Definition: amd64.h:36
#define PTE_PCD
Definition: amd64.h:39
PageEntry entries[PAGETABLE_ENTRIES]
Definition: amd64.h:55
#define PGSHIFT
Definition: amd64.h:20
#define HUGE_PGSHIFT
Definition: amd64.h:28
#define LARGE_PGSHIFT
Definition: amd64.h:24
#define PGNUMMASK
Definition: amd64.h:15
#define PGIDXSHIFT
Definition: amd64.h:17
#define PTE_NX
Definition: amd64.h:48
#define PTE_P
Definition: amd64.h:35
#define LARGE_PGMASK
Definition: amd64.h:26
#define PTE_PS
Definition: amd64.h:42
#define PGIDXMASK
Definition: amd64.h:18
#define PTE_U
Definition: amd64.h:37
uint64_t PageEntry
Definition: amd64.h:52
#define HUGE_PGSIZE
Definition: amd64.h:29
#define PTE_D
Definition: amd64.h:41
#define PTE_A
Definition: amd64.h:40
#define LARGE_PGSIZE
Definition: amd64.h:25
#define PAGETABLE_ENTRIES
Definition: amd64.h:50
#define PGMASK
Definition: amd64.h:22
static INLINE void write_cr3(uint64_t val)
Definition: amd64op.h:166
#define NOT_IMPLEMENTED()
Definition: kassert.h:13
#define PANIC
Definition: kassert.h:18
#define ASSERT(_x)
Definition: kassert.h:8
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define MAX_CPUS
Definition: kconfig.h:8
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
void PAlloc_Release(void *pg)
Definition: palloc.c:265
void * PAlloc_AllocPage()
Definition: palloc.c:188
#define PGSIZE
Definition: malloc.c:21
uint32_t size
Definition: multiboot.h:0
uint64_t len
Definition: multiboot.h:2
static uint64_t AddrFromIJKL(uint64_t i, uint64_t j, uint64_t k, uint64_t l)
Definition: pmap.c:546
AS * PMap_CurrentAS()
Definition: pmap.c:168
static void PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
Definition: pmap.c:278
bool PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags)
Definition: pmap.c:480
void PMap_Init()
Definition: pmap.c:19
AS * PMap_NewAS()
Definition: pmap.c:80
bool PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
Definition: pmap.c:514
void PMap_DumpFull(AS *space)
Definition: pmap.c:552
static PageTable * PMapAllocPageTable()
Definition: pmap.c:196
AS systemAS
Definition: pmap.c:15
bool PMap_Map(AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
Definition: pmap.c:355
static void Debug_PMapDump(int argc, const char *argv[])
Definition: pmap.c:669
AS * currentAS[MAX_CPUS]
Definition: pmap.c:16
static void Debug_PMapDumpFull(int argc, const char *argv[])
Definition: pmap.c:608
void PMap_LoadAS(AS *space)
Definition: pmap.c:182
uintptr_t PMap_Translate(AS *space, uintptr_t va)
Definition: pmap.c:220
bool PMap_SystemUnmap(uint64_t virt, uint64_t pages)
Definition: pmap.c:539
bool PMap_Unmap(AS *as, uint64_t va, uint64_t pages)
Definition: pmap.c:387
void PMap_Dump(AS *space)
Definition: pmap.c:616
bool PMap_AllocMap(AS *as, uint64_t virt, uint64_t len, uint64_t flags)
Definition: pmap.c:423
void PMap_InitAP()
Definition: pmap.c:67
void PMap_DestroyAS(AS *space)
Definition: pmap.c:116
void PMap_SystemLookup(uint64_t va, PageEntry **entry, int size)
Definition: pmap.c:460
uint64_t mappings
Definition: pmap.h:55
#define DMVA2PA(dmva)
Definition: pmap.h:47
uint64_t tables
Definition: pmap.h:54
#define MEM_DIRECTMAP_BASE
Definition: pmap.h:40
PageTable * root
Definition: pmap.h:53
#define DMPA2VA(pa)
Definition: pmap.h:48
Definition: pmap.h:52
#define NULL
Definition: stddef.h:6
uint64_t uintptr_t
Definition: types.h:16
unsigned long uint64_t
Definition: types.h:13