diff --git a/kernel/amd64/mm.c b/kernel/amd64/mm.c index 30ef6d5..6ac2b9a 100644 --- a/kernel/amd64/mm.c +++ b/kernel/amd64/mm.c @@ -77,6 +77,14 @@ static uint64_t* amd64_mm_next_table (uint64_t* table, uint64_t entry_idx, bool return (uint64_t*)((uintptr_t)hhdm->offset + (uintptr_t)paddr); } +static bool amd64_mm_is_table_empty (uint64_t* table) { + for (size_t i = 0; i < 512; i++) { + if (table[i] & AMD64_PG_PRESENT) + return false; + } + return true; +} + /// Convert generic memory management subsystem flags into AMD64-specific flags static uint64_t amd64_mm_resolve_flags (uint32_t generic) { uint64_t flags = 0; @@ -171,8 +179,28 @@ void mm_unmap_page (struct pd* pd, uintptr_t vaddr, uint32_t flags) { uint64_t* pte = &pml1[pg_index.pml1]; - *pte &= ~AMD64_PG_PRESENT; - do_reload = true; + if ((*pte) & AMD64_PG_PRESENT) { + *pte = 0; + do_reload = true; + } + + if (amd64_mm_is_table_empty (pml1)) { + uintptr_t pml1_phys = pml2[pg_index.pml2] & ~0xFFFULL; + pmm_free (pml1_phys, 1); + pml2[pg_index.pml2] = 0; + + if (amd64_mm_is_table_empty (pml2)) { + uintptr_t pml2_phys = pml3[pg_index.pml3] & ~0xFFFULL; + pmm_free (pml2_phys, 1); + pml3[pg_index.pml3] = 0; + + if (amd64_mm_is_table_empty (pml3)) { + uintptr_t pml3_phys = pml4[pg_index.pml4] & ~0xFFFULL; + pmm_free (pml3_phys, 1); + pml4[pg_index.pml4] = 0; + } + } + } done: if (do_reload && (flags & MM_PD_RELOAD))