Free pages in PMap_Destroy and add extra assertions to catch errors in PAlloc.

This commit is contained in:
Ali Mashtizadeh 2023-09-04 16:03:34 -04:00
parent 3e5eeacf09
commit e991129de9
3 changed files with 119 additions and 17 deletions

View File

@ -12,6 +12,8 @@
* Page Tables * Page Tables
*/ */
#define PGNUMMASK 0xFFFFFFFFFFFFF000ULL
#define PGIDXSHIFT 9 #define PGIDXSHIFT 9
#define PGIDXMASK (512 - 1) #define PGIDXMASK (512 - 1)

View File

@ -76,7 +76,7 @@ PMap_NewAS()
AS *as = PAlloc_AllocPage(); AS *as = PAlloc_AllocPage();
if (!as) if (!as)
return 0; return NULL;
as->root = PAlloc_AllocPage(); as->root = PAlloc_AllocPage();
as->tables = 1; as->tables = 1;
@ -84,7 +84,7 @@ PMap_NewAS()
if (!as->root) { if (!as->root) {
PAlloc_Release(as); PAlloc_Release(as);
return 0; return NULL;
} }
for (i = 0; i < PAGETABLE_ENTRIES / 2; i++) for (i = 0; i < PAGETABLE_ENTRIES / 2; i++)
@ -101,15 +101,46 @@ PMap_NewAS()
void void
PMap_DestroyAS(AS *space) PMap_DestroyAS(AS *space)
{ {
int i; // Only free the userspace portion (bottom half)
for (int i = 0; i < PAGETABLE_ENTRIES / 2; i++)
for (i = 0; i < PAGETABLE_ENTRIES / 2; i++)
{ {
if (space->root->entries[i] != 0) { PageEntry pte = space->root->entries[i];
// Remove subpages if (pte & PTE_P) {
PAlloc_Release((void *)DMPA2VA(space->root->entries[i])); // Remove sub-pages
PageTable *tbl2 = (PageTable *)DMPA2VA(pte & PGNUMMASK);
for (int j = 0; j < PAGETABLE_ENTRIES; j++) {
PageEntry pte2 = tbl2->entries[j];
if (pte2 & PTE_P) {
PageTable *tbl3 = (PageTable *)DMPA2VA(pte2 & PGNUMMASK);
for (int k = 0; k < PAGETABLE_ENTRIES; k++) {
PageEntry pte3 = tbl3->entries[k];
if (pte3 & PTE_P) {
ASSERT((pte3 & PTE_PS) == 0); // XXX: Large pages not supported
PageTable *tbl4 = (PageTable *)DMPA2VA(pte3 & PGNUMMASK);
for (int l = 0; l < PAGETABLE_ENTRIES; l++) {
PageEntry pte4 = tbl4->entries[l];
if (pte4 & PTE_P) {
// Free userspace page
PAlloc_Release((void *)DMPA2VA(pte4 & PGNUMMASK));
}
}
// Free 3rd level page table page
PAlloc_Release((void *)DMPA2VA(pte3 & PGNUMMASK));
}
}
// Free 2nd level page table page
PAlloc_Release((void *)DMPA2VA(pte2 & PGNUMMASK));
}
}
// Free page table page
PAlloc_Release((void *)DMPA2VA(pte & PGNUMMASK));
} }
} }
PAlloc_Release(space);
} }
AS * AS *
@ -159,7 +190,7 @@ PMap_Translate(AS *space, uintptr_t va)
ASSERT(pte); ASSERT(pte);
return 0; return 0;
} }
table = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
pte = table->entries[j]; pte = table->entries[j];
// XXX: Support 1GB pages // XXX: Support 1GB pages
@ -167,7 +198,7 @@ PMap_Translate(AS *space, uintptr_t va)
ASSERT(pte); ASSERT(pte);
return 0; return 0;
} }
table = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
pte = table->entries[k]; pte = table->entries[k];
if ((pte & PTE_PS) == PTE_PS) { if ((pte & PTE_PS) == PTE_PS) {
@ -179,7 +210,7 @@ PMap_Translate(AS *space, uintptr_t va)
ASSERT(pte); ASSERT(pte);
return 0; return 0;
} }
table = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
// Handle 4KB pages // Handle 4KB pages
entry = &table->entries[l]; entry = &table->entries[l];
@ -210,7 +241,7 @@ PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U; pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U;
table->entries[i] = pte; table->entries[i] = pte;
} }
table = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
pte = table->entries[j]; pte = table->entries[j];
if (size == HUGE_PGSIZE) { if (size == HUGE_PGSIZE) {
@ -226,7 +257,7 @@ PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U; pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U;
table->entries[j] = pte; table->entries[j] = pte;
} }
table = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
pte = table->entries[k]; pte = table->entries[k];
if (size == LARGE_PGSIZE) { if (size == LARGE_PGSIZE) {
@ -242,7 +273,7 @@ PMapLookupEntry(AS *space, uint64_t va, PageEntry **entry, int size)
pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U; pte = DMVA2PA((uint64_t)newtable) | PTE_P | PTE_W | PTE_U;
table->entries[k] = pte; table->entries[k] = pte;
} }
table = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); table = (PageTable *)DMPA2VA(pte & PGNUMMASK);
// Handle 4KB pages // Handle 4KB pages
ASSERT(size == PGSIZE); ASSERT(size == PGSIZE);
@ -284,6 +315,8 @@ PMap_Unmap(AS *as, uint64_t va, uint64_t pages)
return false; return false;
} }
NOT_IMPLEMENTED();
*entry = 0; *entry = 0;
} }
@ -388,7 +421,7 @@ PMap_Dump(AS *space)
for (i = 0; i < PAGETABLE_ENTRIES; i++) { for (i = 0; i < PAGETABLE_ENTRIES; i++) {
PageEntry pte = root->entries[i]; PageEntry pte = root->entries[i];
PageTable *l1 = (PageTable *)DMPA2VA(pte & 0xFFFFFFFFFFFFF000); PageTable *l1 = (PageTable *)DMPA2VA(pte & PGNUMMASK);
if (!(pte & PTE_P)) if (!(pte & PTE_P))
continue; continue;
@ -397,7 +430,7 @@ PMap_Dump(AS *space)
for (j = 0; j < PAGETABLE_ENTRIES; j++) { for (j = 0; j < PAGETABLE_ENTRIES; j++) {
PageEntry pte2 = l1->entries[j]; PageEntry pte2 = l1->entries[j];
PageTable *l2 = (PageTable *)DMPA2VA(pte2 & 0xFFFFFFFFFFFFF000); PageTable *l2 = (PageTable *)DMPA2VA(pte2 & PGNUMMASK);
if (!(pte2 & PTE_P)) if (!(pte2 & PTE_P))
continue; continue;
@ -406,7 +439,7 @@ PMap_Dump(AS *space)
for (k = 0; k < PAGETABLE_ENTRIES; k++) { for (k = 0; k < PAGETABLE_ENTRIES; k++) {
PageEntry pte3 = l2->entries[k]; PageEntry pte3 = l2->entries[k];
PageTable *l3 = (PageTable *)DMPA2VA(pte3 & 0xFFFFFFFFFFFFF000); PageTable *l3 = (PageTable *)DMPA2VA(pte3 & PGNUMMASK);
if (!(pte3 & PTE_P)) if (!(pte3 & PTE_P))
continue; continue;
@ -439,3 +472,64 @@ Debug_PMapDump(int argc, const char *argv[])
REGISTER_DBGCMD(pmapdump, "Dump memory mappings", Debug_PMapDump); REGISTER_DBGCMD(pmapdump, "Dump memory mappings", Debug_PMapDump);
void
PMap_DumpConcise(AS *space)
{
int i = 0;
int j = 0;
int k = 0;
int l = 0;
PageTable *root = space->root;
for (i = 0; i < PAGETABLE_ENTRIES/2; i++) {
PageEntry pte = root->entries[i];
PageTable *l1 = (PageTable *)DMPA2VA(pte & PGNUMMASK);
if (!(pte & PTE_P))
continue;
for (j = 0; j < PAGETABLE_ENTRIES; j++) {
PageEntry pte2 = l1->entries[j];
PageTable *l2 = (PageTable *)DMPA2VA(pte2 & PGNUMMASK);
if (!(pte2 & PTE_P))
continue;
for (k = 0; k < PAGETABLE_ENTRIES; k++) {
PageEntry pte3 = l2->entries[k];
PageTable *l3 = (PageTable *)DMPA2VA(pte3 & PGNUMMASK);
if (!(pte3 & PTE_P))
continue;
if ((pte3 & PTE_PS) == 0) {
for (l = 0; l < PAGETABLE_ENTRIES; l++) {
PageEntry pte4 = l3->entries[l];
if (pte4 & PTE_P)
kprintf("%016llx: %016llx P%c%c%c%c%c\n",
AddrFromIJKL(i, j, k, l),
(uint64_t)pte4,
(pte4 & PTE_W) ? 'W' : ' ',
(pte4 & PTE_NX) ? ' ' : 'X',
(pte4 & PTE_U) ? 'U' : ' ',
(pte4 & PTE_A) ? 'A' : ' ',
(pte4 & PTE_D) ? 'D' : ' ');
}
}
}
}
}
return;
}
static void
Debug_PMapDumpConcise(int argc, const char *argv[])
{
PMap_DumpConcise(currentAS[THISCPU()]);
}
REGISTER_DBGCMD(pmapdumpconcise, "Dump concise memory mappings", Debug_PMapDumpConcise);

View File

@ -186,6 +186,8 @@ PAlloc_AllocPage()
freePages--; freePages--;
Spinlock_Unlock(&pallocLock); Spinlock_Unlock(&pallocLock);
memset(pg, 0, PGSIZE);
return (void *)pg; return (void *)pg;
} }
@ -194,6 +196,8 @@ PAllocFreePage(void *region)
{ {
FreePage *pg = (FreePage *)region; FreePage *pg = (FreePage *)region;
ASSERT(((uintptr_t)region % PGSIZE) == 0);
LIST_INSERT_HEAD(&freeList, pg, entries); LIST_INSERT_HEAD(&freeList, pg, entries);
#ifndef NDEBUG #ifndef NDEBUG
@ -204,6 +208,7 @@ PAllocFreePage(void *region)
PageInfo *info = PAllocGetInfo(pg); PageInfo *info = PAllocGetInfo(pg);
ASSERT(info->refCount == 0); ASSERT(info->refCount == 0);
#endif #endif
pg->magic = FREEPAGE_MAGIC_FREE; pg->magic = FREEPAGE_MAGIC_FREE;
freePages++; freePages++;
} }
@ -225,6 +230,7 @@ PAlloc_Release(void *pg)
PageInfo *info = PAllocGetInfo(pg); PageInfo *info = PAllocGetInfo(pg);
Spinlock_Lock(&pallocLock); Spinlock_Lock(&pallocLock);
ASSERT(info->refCount != 0);
info->refCount--; info->refCount--;
if (info->refCount == 0) if (info->refCount == 0)
PAllocFreePage(pg); PAllocFreePage(pg);