Make page_manager::unmap_pages() handle multiple blocks

This commit is contained in:
Justin C. Miller
2018-04-22 13:37:44 -07:00
parent 95d52b87f4
commit 8cb0803605
2 changed files with 72 additions and 25 deletions

View File

@@ -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