Loading [MathJax]/extensions/tex2jax.js
CS350 COS
COS
All Data Structures Files Functions Variables Typedefs Macros
pmap.h File Reference
#include <machine/amd64.h>
Include dependency graph for pmap.h:

Go to the source code of this file.

Data Structures

struct  AS
 

Macros

#define MEM_USERSPACE_BASE   0x0000000000000000ULL
 
#define MEM_USERSPACE_LEN   0x0000800000000000ULL
 
#define MEM_USERSPACE_TOP   (MEM_USERSPACE_BASE + MEM_USERSPACE_LEN)
 
#define MEM_USERSPACE_STKBASE   0x0000000070000000ULL
 
#define MEM_USERSPACE_STKLEN   0x0000000000010000ULL
 
#define MEM_USERSPACE_STKTOP   (MEM_USERSPACE_STKBASE + MEM_USERSPACE_STKLEN)
 
#define MEM_DIRECTMAP_BASE   0xFFFF800000000000ULL
 
#define MEM_DIRECTMAP_LEN   0x0000010000000000ULL
 
#define MEM_XMAP_BASE   0xFFFF810000000000ULL
 
#define MEM_XMAP_LEN   0x0000002000000000ULL
 
#define PPN2DMVA(ppn)   (((ppn) << PGSIZE) + MEM_DIRECTMAP_BASE)
 
#define DMVA2PPN(dmva)   (((dmva) - MEM_DIRECTMAP_BASE) >> PGSIZE)
 
#define DMVA2PA(dmva)   ((dmva) - MEM_DIRECTMAP_BASE)
 
#define DMPA2VA(pa)   ((pa) + MEM_DIRECTMAP_BASE)
 
#define VA2PA(va)   PMap_Translate(PMap_CurrentAS(), va)
 

Typedefs

typedef struct AS AS
 

Functions

void PMap_Init ()
 
void PMap_InitAP ()
 
ASPMap_NewAS ()
 
void PMap_DestroyAS (AS *space)
 
ASPMap_CurrentAS ()
 
void PMap_LoadAS (AS *space)
 
void PMap_Dump (AS *space)
 
uintptr_t PMap_Translate (AS *space, uintptr_t va)
 
bool PMap_Map (AS *as, uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
 
bool PMap_AllocMap (AS *as, uint64_t virt, uint64_t len, uint64_t flags)
 
bool PMap_Unmap (AS *as, uint64_t virt, uint64_t pages)
 
void PMap_SystemLookup (uint64_t va, PageEntry **entry, int size)
 
bool PMap_SystemLMap (uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags)
 
bool PMap_SystemMap (uint64_t phys, uint64_t virt, uint64_t pages, uint64_t flags)
 
bool PMap_SystemUnmap (uint64_t virt, uint64_t pages)
 

Data Structure Documentation

◆ AS

struct AS

Definition at line 51 of file pmap.h.

Collaboration diagram for AS:
[legend]
Data Fields
uint64_t mappings
PageTable * root
uint64_t tables

Macro Definition Documentation

◆ DMPA2VA

#define DMPA2VA (   pa)    ((pa) + MEM_DIRECTMAP_BASE)

Definition at line 48 of file pmap.h.

◆ DMVA2PA

#define DMVA2PA (   dmva)    ((dmva) - MEM_DIRECTMAP_BASE)

Definition at line 47 of file pmap.h.

◆ DMVA2PPN

#define DMVA2PPN (   dmva)    (((dmva) - MEM_DIRECTMAP_BASE) >> PGSIZE)

Definition at line 46 of file pmap.h.

◆ MEM_DIRECTMAP_BASE

#define MEM_DIRECTMAP_BASE   0xFFFF800000000000ULL

Definition at line 40 of file pmap.h.

◆ MEM_DIRECTMAP_LEN

#define MEM_DIRECTMAP_LEN   0x0000010000000000ULL

Definition at line 41 of file pmap.h.

◆ MEM_USERSPACE_BASE

#define MEM_USERSPACE_BASE   0x0000000000000000ULL

Definition at line 32 of file pmap.h.

◆ MEM_USERSPACE_LEN

#define MEM_USERSPACE_LEN   0x0000800000000000ULL

Definition at line 33 of file pmap.h.

◆ MEM_USERSPACE_STKBASE

#define MEM_USERSPACE_STKBASE   0x0000000070000000ULL

Definition at line 36 of file pmap.h.

◆ MEM_USERSPACE_STKLEN

#define MEM_USERSPACE_STKLEN   0x0000000000010000ULL

Definition at line 37 of file pmap.h.

◆ MEM_USERSPACE_STKTOP

#define MEM_USERSPACE_STKTOP   (MEM_USERSPACE_STKBASE + MEM_USERSPACE_STKLEN)

Definition at line 38 of file pmap.h.

◆ MEM_USERSPACE_TOP

#define MEM_USERSPACE_TOP   (MEM_USERSPACE_BASE + MEM_USERSPACE_LEN)

Definition at line 34 of file pmap.h.

◆ MEM_XMAP_BASE

#define MEM_XMAP_BASE   0xFFFF810000000000ULL

Definition at line 42 of file pmap.h.

◆ MEM_XMAP_LEN

#define MEM_XMAP_LEN   0x0000002000000000ULL

Definition at line 43 of file pmap.h.

◆ PPN2DMVA

#define PPN2DMVA (   ppn)    (((ppn) << PGSIZE) + MEM_DIRECTMAP_BASE)

Definition at line 45 of file pmap.h.

◆ VA2PA

#define VA2PA (   va)    PMap_Translate(PMap_CurrentAS(), va)

Definition at line 49 of file pmap.h.

Typedef Documentation

◆ AS

typedef struct AS AS

Function Documentation

◆ PMap_AllocMap()

bool PMap_AllocMap ( AS as,
uint64_t  virt,
uint64_t  len,
uint64_t  flags 
)

PMap_AllocMap –

Map a virtual mapping in an address space and back it by newly allocated memory.

Parameters
[in]asAddress space.
[in]virtVirtual address.
[in]pagesPages to map in.
[in]flagsFlags to apply to the mapping.
Return values
trueOn success
falseOn failure

Definition at line 423 of file pmap.c.

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}
#define PTE_P
Definition: amd64.h:35
#define PTE_U
Definition: amd64.h:37
uint64_t PageEntry
Definition: amd64.h:52
#define PGMASK
Definition: amd64.h:22
#define ASSERT(_x)
Definition: kassert.h:8
int kprintf(const char *fmt,...)
Definition: printf.c:210
void * PAlloc_AllocPage()
Definition: palloc.c:188
#define PGSIZE
Definition: malloc.c:21
uint64_t len
Definition: multiboot.h:2
static void PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
Definition: pmap.c:278
#define DMVA2PA(dmva)
Definition: pmap.h:47
unsigned long uint64_t
Definition: types.h:13
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_CurrentAS()

AS * PMap_CurrentAS ( )

PMap_CurrentAS –

Get the current address space on this CPU.

Returns
Current address space.

Definition at line 168 of file pmap.c.

169{
170 return currentAS[THISCPU()];
171}
#define THISCPU
Definition: mp.h:21
AS * currentAS[MAX_CPUS]
Definition: pmap.c:16

◆ PMap_DestroyAS()

void PMap_DestroyAS ( AS space)

PMap_DestroyAS –

Destroys an address space and releases the physical pages.

Parameters
[in]spaceAddress space to destroy.

Definition at line 116 of file pmap.c.

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}
PageEntry entries[PAGETABLE_ENTRIES]
Definition: amd64.h:55
#define PGNUMMASK
Definition: amd64.h:15
#define PTE_PS
Definition: amd64.h:42
#define PAGETABLE_ENTRIES
Definition: amd64.h:50
void PAlloc_Release(void *pg)
Definition: palloc.c:265
PageTable * root
Definition: pmap.h:53
#define DMPA2VA(pa)
Definition: pmap.h:48
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_Dump()

void PMap_Dump ( AS space)

Definition at line 616 of file pmap.c.

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}
#define PTE_W
Definition: amd64.h:36
#define PTE_NX
Definition: amd64.h:48
#define PTE_D
Definition: amd64.h:41
#define PTE_A
Definition: amd64.h:40
static uint64_t AddrFromIJKL(uint64_t i, uint64_t j, uint64_t k, uint64_t l)
Definition: pmap.c:546
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_Init()

void PMap_Init ( )

Definition at line 19 of file pmap.c.

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}
#define PTE_PCD
Definition: amd64.h:39
#define PANIC
Definition: kassert.h:18
#define MAX_CPUS
Definition: kconfig.h:8
bool PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags)
Definition: pmap.c:480
AS systemAS
Definition: pmap.c:15
void PMap_LoadAS(AS *space)
Definition: pmap.c:182
uint64_t mappings
Definition: pmap.h:55
uint64_t tables
Definition: pmap.h:54
#define MEM_DIRECTMAP_BASE
Definition: pmap.h:40
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_InitAP()

void PMap_InitAP ( )

Definition at line 67 of file pmap.c.

68{
70}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_LoadAS()

void PMap_LoadAS ( AS space)

PMap_LoadAS –

Load an address space into the CPU. Reloads the CR3 register in x86-64 that points the physical page tables and flushes the TLB entries.

Parameters
[in]spaceAddress space to load.

Definition at line 182 of file pmap.c.

183{
184 write_cr3(DMVA2PA((uint64_t)space->root));
185 currentAS[THISCPU()] = space;
186}
static INLINE void write_cr3(uint64_t val)
Definition: amd64op.h:166
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_Map()

bool PMap_Map ( AS as,
uint64_t  phys,
uint64_t  virt,
uint64_t  pages,
uint64_t  flags 
)

PMap_Map –

Map a physical to virtual mapping in an address space.

Parameters
[in]asAddress space.
[in]physPhysical address.
[in]virtVirtual address.
[in]pagesPages to map in.
[in]flagsFlags to apply to the mapping.
Return values
trueOn success
falseOn failure

Definition at line 355 of file pmap.c.

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}
Here is the call graph for this function:

◆ PMap_NewAS()

AS * PMap_NewAS ( )

PMap_NewAS –

Create a new address space.

Returns
Newly created address space.

Definition at line 80 of file pmap.c.

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}
Definition: pmap.h:52
#define NULL
Definition: stddef.h:6
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_SystemLMap()

bool PMap_SystemLMap ( uint64_t  phys,
uint64_t  virt,
uint64_t  lpages,
uint64_t  flags 
)

PMap_SystemLMap –

Map a range of large (2MB) physical pages to virtual pages in the kernel address space that is shared by all processes.

Parameters
[in]physPhysical address.
[in]virtVirtual address.
[in]lpagesLarge pages to map in.
[in]flagsFlags to apply to the mapping.
Return values
trueOn success
falseOn failure

Definition at line 480 of file pmap.c.

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}
#define LARGE_PGSIZE
Definition: amd64.h:25
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_SystemLookup()

void PMap_SystemLookup ( uint64_t  va,
PageEntry **  entry,
int  size 
)

PMap_SystemLookup –

Lookup a kernel virtual address in a page table and return a pointer to the page entry. This function allocates page tables as necessary to fill in the 4-level heirarchy.

Parameters
[in]vaVirtual address to lookup.
[out]entryPointer will point to the PageEntry.
[in]sizePage size we want to use.

Definition at line 460 of file pmap.c.

461{
462 PMapLookupEntry(&systemAS, va, entry, size);
463}
uint32_t size
Definition: multiboot.h:0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_SystemMap()

bool PMap_SystemMap ( uint64_t  phys,
uint64_t  virt,
uint64_t  pages,
uint64_t  flags 
)

PMap_SystemLMap –

Map a range of physical pages to virtual pages in the kernel address space that is shared by all processes.

Parameters
[in]physPhysical address.
[in]virtVirtual address.
[in]pagesPages to map in.
[in]flagsFlags to apply to the mapping.
Return values
trueOn success
falseOn failure

Definition at line 514 of file pmap.c.

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}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ PMap_SystemUnmap()

bool PMap_SystemUnmap ( uint64_t  virt,
uint64_t  pages 
)

PMap_SystemUnmap –

We do not currently use this!

Definition at line 539 of file pmap.c.

540{
542 return false;
543}
#define NOT_IMPLEMENTED()
Definition: kassert.h:13

◆ PMap_Translate()

uintptr_t PMap_Translate ( AS space,
uintptr_t  va 
)

PMap_Translate –

Translates a virtual address to physical address for a given address space.

Parameters
[in]spaceAddress space we wish to lookup a mapping in.
[in]vaVirtual address we wish to translate.

Definition at line 220 of file pmap.c.

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}
#define PGSHIFT
Definition: amd64.h:20
#define HUGE_PGSHIFT
Definition: amd64.h:28
#define LARGE_PGSHIFT
Definition: amd64.h:24
#define PGIDXSHIFT
Definition: amd64.h:17
#define LARGE_PGMASK
Definition: amd64.h:26
#define PGIDXMASK
Definition: amd64.h:18
Here is the caller graph for this function:

◆ PMap_Unmap()

bool PMap_Unmap ( AS as,
uint64_t  va,
uint64_t  pages 
)

PMap_Unmap –

Unmap a range of addresses.

Parameters
[in]asAddress space.
[in]vaVirtual address.
[in]pagesPages to map in.
Return values
trueOn success
falseOn failure

Definition at line 387 of file pmap.c.

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}
Here is the call graph for this function:
Here is the caller graph for this function: