From 8cb0803605864ce4188358e591debe94ce1e68db Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 22 Apr 2018 13:37:44 -0700 Subject: [PATCH] Make page_manager::unmap_pages() handle multiple blocks --- src/kernel/memory_pages.cpp | 87 +++++++++++++++++++++++++++---------- src/kernel/memory_pages.h | 10 ++++- 2 files changed, 72 insertions(+), 25 deletions(-) diff --git a/src/kernel/memory_pages.cpp b/src/kernel/memory_pages.cpp index b3b4731..25749df 100644 --- a/src/kernel/memory_pages.cpp +++ b/src/kernel/memory_pages.cpp @@ -28,7 +28,7 @@ page_block::list_append(page_block *list) } page_block * -page_block::list_insert(page_block *block) +page_block::list_insert_physical(page_block *block) { page_block *cur = this; page_block **prev = nullptr; @@ -45,6 +45,24 @@ page_block::list_insert(page_block *block) return block; } +page_block * +page_block::list_insert_virtual(page_block *block) +{ + page_block *cur = this; + page_block **prev = nullptr; + while (cur->virtual_address < block->virtual_address) { + prev = &cur->next; + cur = cur->next; + } + + block->next = cur; + if (prev) { + *prev = block; + return this; + } + return block; +} + page_block * page_block::list_consolidate() { @@ -219,30 +237,53 @@ page_manager::unmap_pages(uint64_t address, unsigned count) kassert(cur, "Couldn't find existing mapped pages to unmap"); - uint64_t leading = address - cur->virtual_address; - uint64_t trailing = cur->virtual_end() - (address + page_size*count); + uint64_t end = address + page_size * count; - if (leading) { - page_block *lead_block = get_block(); - lead_block->copy(cur); - lead_block->next = cur; - lead_block->count = leading / page_size; - *prev = lead_block; - prev = &lead_block->next; + while (cur && cur->contains(address)) { + uint64_t leading = address - cur->virtual_address; + uint64_t trailing = + end > cur->virtual_end() ? + 0 : (cur->virtual_end() - end); + + if (leading) { + uint64_t pages = leading / page_size; + + page_block *lead_block = get_block(); + lead_block->copy(cur); + lead_block->next = cur; + lead_block->count = pages; + + cur->count -= pages; + cur->physical_address += leading; + cur->virtual_address += leading; + + *prev = lead_block; + prev = &lead_block->next; + } + + if (trailing) { + uint64_t pages = trailing / page_size; + + page_block *trail_block = get_block(); + trail_block->copy(cur); + trail_block->next = cur->next; + trail_block->count = pages; + + cur->count -= pages; + + cur->next = trail_block; + } + + address += cur->count * page_size; + page_block *next = cur->next; + + *prev = cur->next; + cur->next = nullptr; + cur->flags = cur->flags & ~(page_block_flags::used | page_block_flags::mapped); + m_free->list_insert_physical(cur); + + cur = next; } - - if (trailing) { - page_block *trail_block = get_block(); - trail_block->copy(cur); - trail_block->next = cur->next; - trail_block->count = trailing / page_size; - cur->next = trail_block; - } - - *prev = cur->next; - cur->next = nullptr; - cur->flags = cur->flags & ~(page_block_flags::used | page_block_flags::mapped); - m_free->list_insert(cur); } void diff --git a/src/kernel/memory_pages.h b/src/kernel/memory_pages.h index e6114d0..5d7511b 100644 --- a/src/kernel/memory_pages.h +++ b/src/kernel/memory_pages.h @@ -93,6 +93,7 @@ struct page_block inline bool has_flag(page_block_flags f) const { return bitfield_contains(flags, f); } inline uint64_t physical_end() const { return physical_address + (count * page_manager::page_size); } inline uint64_t virtual_end() const { return virtual_address + (count * page_manager::page_size); } + inline bool contains(uint64_t vaddr) const { return vaddr >= virtual_address && vaddr < virtual_end(); } /// Helper to zero out a block and optionally set the next pointer. @@ -115,10 +116,15 @@ struct page_block /// \arg list The list to append to the current list void list_append(page_block *list); - /// Sorted-insert of a block into the list. + /// Sorted-insert of a block into the list by physical address. /// \arg block The single block to insert /// \returns The new list head - page_block * list_insert(page_block *block); + page_block * list_insert_physical(page_block *block); + + /// Sorted-insert of a block into the list by virtual address. + /// \arg block The single block to insert + /// \returns The new list head + page_block * list_insert_virtual(page_block *block); /// Traverse the list, joining adjacent blocks where possible. /// \returns A linked list of freed page_block structures.