void ArchMemory::freePageDirectory(uint32 physical_page_directory_page) { PageDirEntry *page_directory = (PageDirEntry *) getIdentAddressOfPPN(physical_page_directory_page); for (uint32 pde_vpn=0; pde_vpn < PAGE_DIRECTORY_ENTRIES; ++pde_vpn) { if (page_directory[pde_vpn].pt.present) { if (page_directory[pde_vpn].page.size) { page_directory[pde_vpn].page.present=0; for (uint32 p=0;p<1024;++p) PageManager::instance()->freePPN(page_directory[pde_vpn].page.page_ppn*1024 + p); } else { PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); for (uint32 pte_vpn=0; pte_vpn < PAGE_TABLE_ENTRIES; ++pte_vpn) { if (pte_base[pte_vpn].present) { pte_base[pte_vpn].present = 0; PageManager::instance()->freePPN(pte_base[pte_vpn].page_ppn); } } page_directory[pde_vpn].pt.present=0; PageManager::instance()->freePPN(page_directory[pde_vpn].pt.page_table_ppn); } } } PageManager::instance()->freePPN(physical_page_directory_page); }
bool ArchMemory::mapPage(uint32 virtual_page, uint32 physical_page, uint32 user_access) { RESOLVEMAPPING(page_dir_pointer_table_,virtual_page); if (page_dir_pointer_table_[pdpte_vpn].present == 0) { uint32 pd_ppn = PageManager::instance()->allocPPN(); page_directory = (PageDirEntry*) getIdentAddressOfPPN(pd_ppn); insertPD(pdpte_vpn, pd_ppn); } if (page_directory[pde_vpn].pt.present == 0) { insertPT(page_directory, pde_vpn, PageManager::instance()->allocPPN()); } assert(page_directory[pde_vpn].page.size == 0); PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); if(pte_base[pte_vpn].present == 0) { pte_base[pte_vpn].writeable = 1; pte_base[pte_vpn].user_access = user_access; pte_base[pte_vpn].page_ppn = physical_page; pte_base[pte_vpn].present = 1; return true; } assert(false); return false; }
bool ArchMemory::mapPage(uint64 virtual_page, uint64 physical_page, uint64 user_access) { debug(A_MEMORY, "%zx %zx %zx %zx\n", page_map_level_4_, virtual_page, physical_page, user_access); ArchMemoryMapping m = resolveMapping(page_map_level_4_, virtual_page); assert((m.page_size == 0) || (m.page_size == PAGE_SIZE)); if (m.pdpt_ppn == 0) { m.pdpt_ppn = PageManager::instance()->allocPPN(); insert<PageMapLevel4Entry>((pointer) m.pml4, m.pml4i, m.pdpt_ppn, 1, 0, 1, 1); } if (m.pd_ppn == 0) { m.pd_ppn = PageManager::instance()->allocPPN(); insert<PageDirPointerTablePageDirEntry>(getIdentAddressOfPPN(m.pdpt_ppn), m.pdpti, m.pd_ppn, 1, 0, 1, 1); } if (m.pt_ppn == 0) { m.pt_ppn = PageManager::instance()->allocPPN(); insert<PageDirPageTableEntry>(getIdentAddressOfPPN(m.pd_ppn), m.pdi, m.pt_ppn, 1, 0, 1, 1); } if (m.page_ppn == 0) { return insert<PageTableEntry>(getIdentAddressOfPPN(m.pt_ppn), m.pti, physical_page, 0, 0, user_access, 1); } assert(false); // you should never get here return false; }
bool ArchMemory::unmapPage(uint64 virtual_page) { ArchMemoryMapping m = resolveMapping(page_map_level_4_, virtual_page); assert(m.page_ppn != 0 && m.page_size == PAGE_SIZE && m.pt[m.pti].present); m.pt[m.pti].present = 0; PageManager::instance()->freePPN(m.page_ppn, PAGE_SIZE); ((uint64*)m.pt)[m.pti] = 0; // for easier debugging bool empty = checkAndRemove<PageTableEntry>(getIdentAddressOfPPN(m.pt_ppn), m.pti); if (empty) { PageManager::instance()->freePPN(m.pt_ppn, PAGE_SIZE); empty = checkAndRemove<PageDirPageTableEntry>(getIdentAddressOfPPN(m.pd_ppn), m.pdi); } if (empty) { PageManager::instance()->freePPN(m.pd_ppn, PAGE_SIZE); empty = checkAndRemove<PageDirPointerTablePageDirEntry>(getIdentAddressOfPPN(m.pdpt_ppn), m.pdpti); } if (empty) { PageManager::instance()->freePPN(m.pdpt_ppn, PAGE_SIZE); empty = checkAndRemove<PageMapLevel4Entry>(getIdentAddressOfPPN(m.pml4_ppn), m.pml4i); } return true; }
bool ArchMemory::unmapPage(uint64 virtual_page) { ArchMemoryMapping m = resolveMapping(page_map_level_4_, virtual_page); assert(m.page_ppn != 0 && m.page_size == PAGE_SIZE); bool empty = checkAndRemove<PageTableEntry>(getIdentAddressOfPPN(m.pt_ppn), m.pti); if (empty) empty = checkAndRemove<PageDirPageEntry>(getIdentAddressOfPPN(m.pd_ppn), m.pdi); if (empty) empty = checkAndRemove<PageDirPointerTablePageDirEntry>(getIdentAddressOfPPN(m.pdpt_ppn), m.pdpti); if (empty) empty = checkAndRemove<PageMapLevel4Entry>(getIdentAddressOfPPN(m.pml4_ppn), m.pml4i); return true; }
uint32 ArchMemory::get_PPN_Of_VPN_In_KernelMapping(uint32 virtual_page, size_t *physical_page, uint32 *physical_pte_page) { PageDirPointerTableEntry *pdpt = kernel_page_directory_pointer_table; RESOLVEMAPPING(pdpt, virtual_page); if (pdpt[pdpte_vpn].present) { if (page_directory[pde_vpn].pt.present) { if (page_directory[pde_vpn].page.size) { if (physical_page) *physical_page = page_directory[pde_vpn].page.page_ppn; return (PAGE_SIZE*PAGE_TABLE_ENTRIES); } else { if (physical_pte_page) *physical_pte_page = page_directory[pde_vpn].pt.page_table_ppn; PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); if (pte_base[pte_vpn].present) { if (physical_page) *physical_page = pte_base[pte_vpn].page_ppn; return PAGE_SIZE; } } } } return 0; }
ArchMemory::ArchMemory() { page_map_level_4_ = PageManager::instance()->getFreePhysicalPage(); PageMapLevel4Entry* new_pml4 = (PageMapLevel4Entry*) getIdentAddressOfPPN(page_map_level_4_); ArchCommon::memcpy((pointer) new_pml4,(pointer)kernel_page_map_level_4, PAGE_SIZE); bzero(new_pml4,PAGE_SIZE / 2); // should be zero, this is just for safety }
ArchMemory::ArchMemory() { page_map_level_4_ = PageManager::instance()->allocPPN(); PageMapLevel4Entry* new_pml4 = (PageMapLevel4Entry*) getIdentAddressOfPPN(page_map_level_4_); memcpy((void*) new_pml4, (void*) kernel_page_map_level_4, PAGE_SIZE); memset(new_pml4, 0, PAGE_SIZE / 2); // should be zero, this is just for safety }
void ArchMemory::unmapKernelPage(size_t virtual_page) { ArchMemoryMapping mapping = resolveMapping(((uint64) VIRTUAL_TO_PHYSICAL_BOOT(kernel_page_map_level_4) / PAGE_SIZE), virtual_page); PageMapLevel4Entry* pml4 = kernel_page_map_level_4; assert(pml4[mapping.pml4i].present); PageDirPointerTableEntry *pdpt = (PageDirPointerTableEntry*) getIdentAddressOfPPN(pml4[mapping.pml4i].page_ppn); assert(pdpt[mapping.pdpti].pd.present); PageDirEntry *pd = (PageDirEntry*) getIdentAddressOfPPN(pdpt[mapping.pdpti].pd.page_ppn); assert(pd[mapping.pdi].pt.present); PageTableEntry *pt = (PageTableEntry*) getIdentAddressOfPPN(pd[mapping.pdi].pt.page_ppn); assert(pt[mapping.pti].present); pt[mapping.pti].present = 0; pt[mapping.pti].writeable = 0; PageManager::instance()->freePPN(pt[mapping.pti].page_ppn); asm volatile ("movq %%cr3, %%rax; movq %%rax, %%cr3;" ::: "%rax"); }
void ArchMemory::insertPD(uint32 pdpt_vpn, uint32 physical_page_directory_page) { kprintfd("insertPD: pdpt %p pdpt_vpn %x physical_page_table_page %x\n",page_dir_pointer_table_,pdpt_vpn,physical_page_directory_page); memset((void*)getIdentAddressOfPPN(physical_page_directory_page), 0,PAGE_SIZE); memset((void*)(page_dir_pointer_table_ + pdpt_vpn), 0, sizeof(PageDirPointerTableEntry)); page_dir_pointer_table_[pdpt_vpn].page_directory_ppn = physical_page_directory_page; page_dir_pointer_table_[pdpt_vpn].present = 1; }
pointer ArchMemory::checkAddressValid(uint32 vaddress_to_check) { RESOLVEMAPPING(page_dir_pointer_table_, vaddress_to_check / PAGE_SIZE); if (page_dir_pointer_table_[pdpte_vpn].present) { if (page_directory[pde_vpn].pt.present) { if (page_directory[pde_vpn].page.size) return getIdentAddressOfPPN(page_directory[pde_vpn].page.page_ppn,PAGE_SIZE * PAGE_TABLE_ENTRIES) | (vaddress_to_check % (PAGE_SIZE * PAGE_TABLE_ENTRIES)); PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); if (pte_base[pte_vpn].present) return getIdentAddressOfPPN(pte_base[pte_vpn].page_ppn) | (vaddress_to_check % PAGE_SIZE); } } return 0; }
void ArchMemory::checkAndRemovePT(uint32 physical_page_directory_page, uint32 pde_vpn) { PageDirEntry *page_directory = (PageDirEntry *) getIdentAddressOfPPN(physical_page_directory_page); PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); assert(page_directory[pde_vpn].page.size == 0); if (!page_directory[pde_vpn].pt.present) return; // PT not present -> do nothing. for (uint32 pte_vpn=0; pte_vpn < PAGE_TABLE_ENTRIES; ++pte_vpn) if (pte_base[pte_vpn].present > 0) return; //not empty -> do nothing //else: page_directory[pde_vpn].pt.present = 0; PageManager::instance()->freePPN(page_directory[pde_vpn].pt.page_table_ppn); ((uint64*)page_directory)[pde_vpn] = 0; // for easier debugging }
ArchMemory::~ArchMemory() { PageMapLevel4Entry* pml4 = (PageMapLevel4Entry*) getIdentAddressOfPPN(page_map_level_4_); for (uint64 pml4i = 0; pml4i < PAGE_MAP_LEVEL_4_ENTRIES / 2; pml4i++) // free only lower half { if (pml4[pml4i].present) { PageDirPointerTableEntry* pdpt = (PageDirPointerTableEntry*) getIdentAddressOfPPN(pml4[pml4i].page_ppn); for (uint64 pdpti = 0; pdpti < PAGE_DIR_POINTER_TABLE_ENTRIES; pdpti++) { if (pdpt[pdpti].pd.present) { assert(pdpt[pdpti].pd.size == 0); PageDirEntry* pd = (PageDirEntry*) getIdentAddressOfPPN(pdpt[pdpti].pd.page_ppn); for (uint64 pdi = 0; pdi < PAGE_DIR_ENTRIES; pdi++) { if (pd[pdi].pt.present) { assert(pd[pdi].pt.size == 0); PageTableEntry* pt = (PageTableEntry*) getIdentAddressOfPPN(pd[pdi].pt.page_ppn); for (uint64 pti = 0; pti < PAGE_TABLE_ENTRIES; pti++) { if (pt[pti].present) { pt[pti].present = 0; PageManager::instance()->freePPN(pt[pti].page_ppn); } } pd[pdi].pt.present = 0; PageManager::instance()->freePPN(pd[pdi].pt.page_ppn); } } pdpt[pdpti].pd.present = 0; PageManager::instance()->freePPN(pdpt[pdpti].pd.page_ppn); } } pml4[pml4i].present = 0; PageManager::instance()->freePPN(pml4[pml4i].page_ppn); } } PageManager::instance()->freePPN(page_map_level_4_); }
void ArchMemory::insertPT(PageDirEntry* page_directory, uint32 pde_vpn, uint32 physical_page_table_page) { kprintfd("insertPT: page_directory %p pde_vpn %x physical_page_table_page %x\n",page_directory,pde_vpn,physical_page_table_page); memset((void*)getIdentAddressOfPPN(physical_page_table_page), 0, PAGE_SIZE); memset((void*)(page_directory + pde_vpn), 0, sizeof(PageDirPointerTableEntry)); page_directory[pde_vpn].pt.writeable = 1; page_directory[pde_vpn].pt.size = 0; page_directory[pde_vpn].pt.page_table_ppn = physical_page_table_page; page_directory[pde_vpn].pt.user_access = 1; page_directory[pde_vpn].pt.present = 1; }
void ArchMemory::unmapKernelPage(uint32 virtual_page) { PageDirPointerTableEntry *pdpt = kernel_page_directory_pointer_table; RESOLVEMAPPING(pdpt, virtual_page); assert(pdpt[pdpte_vpn].present); assert(page_directory[pde_vpn].pt.present && page_directory[pde_vpn].pt.size == 0); PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); assert(pte_base[pte_vpn].present); pte_base[pte_vpn].present = 0; pte_base[pte_vpn].writeable = 0; PageManager::instance()->freePPN(pte_base[pte_vpn].page_ppn); asm volatile ("movl %%cr3, %%eax; movl %%eax, %%cr3;" ::: "%eax"); }
void ArchMemory::unmapPage(uint32 virtual_page) { RESOLVEMAPPING(page_dir_pointer_table_,virtual_page); assert(page_dir_pointer_table_[pdpte_vpn].present); assert(!page_directory[pde_vpn].page.size); PageTableEntry *pte_base = (PageTableEntry *) getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); assert(pte_base[pte_vpn].present); pte_base[pte_vpn].present = 0; PageManager::instance()->freePPN(pte_base[pte_vpn].page_ppn); ((uint64*)pte_base)[pte_vpn] = 0; // for easier debugging checkAndRemovePT(page_dir_pointer_table_[pdpte_vpn].page_directory_ppn, pde_vpn); }
bool ArchMemory::insert(pointer map_ptr, uint64 index, uint64 ppn, uint64 bzero, uint64 size, uint64 user_access, uint64 writeable) { assert(map_ptr & ~0xFFFFF00000000000ULL); T* map = (T*) map_ptr; debug(A_MEMORY,"%s: page %x index %x ppn %x user_access %x size %x\n", __PRETTY_FUNCTION__, map, index, ppn, user_access, size); if (bzero) { ArchCommon::bzero(getIdentAddressOfPPN(ppn), PAGE_SIZE); assert(((uint64*)map)[index] == 0); } map[index].size = size; map[index].writeable = writeable; map[index].page_ppn = ppn; map[index].user_access = user_access; map[index].present = 1; return true; }
bool ArchMemory::mapPage(uint64 virtual_page, uint64 physical_page, uint64 user_access, uint64 page_size) { debug(A_MEMORY,"%x %x %x %x %x\n",page_map_level_4_, virtual_page, physical_page, user_access, page_size); PageMapLevel4Entry* pml4p = (PageMapLevel4Entry*) getIdentAddressOfPPN(page_map_level_4_); ArchMemoryMapping m = resolveMapping(page_map_level_4_, virtual_page); if (m.pdpt_ppn == 0) { m.pdpt_ppn = PageManager::instance()->getFreePhysicalPage(); insert<PageMapLevel4Entry>((pointer) m.pml4, m.pml4i, m.pdpt_ppn, 1, 0, 1, 1); } if (m.pd_ppn == 0) { if (page_size == PAGE_SIZE * PAGE_TABLE_ENTRIES * PAGE_DIR_ENTRIES) { return insert<PageDirPointerTablePageEntry>(getIdentAddressOfPPN(m.pdpt_ppn), m.pdi, physical_page, 0, 1, user_access, 1); } else { m.pd_ppn = PageManager::instance()->getFreePhysicalPage(); insert<PageDirPointerTablePageDirEntry>(getIdentAddressOfPPN(m.pdpt_ppn), m.pdpti, m.pd_ppn, 1, 0, 1, 1); } } if (m.pt_ppn == 0) { if (page_size == PAGE_SIZE * PAGE_TABLE_ENTRIES) { return insert<PageDirPageEntry>(getIdentAddressOfPPN(m.pd_ppn), m.pdi, physical_page, 0, 1, user_access, 1); } else// if (m.pd == 0) { m.pt_ppn = PageManager::instance()->getFreePhysicalPage(); insert<PageDirPageTableEntry>(getIdentAddressOfPPN(m.pd_ppn), m.pdi, m.pt_ppn, 1, 0, 1, 1); } } if (m.page_ppn == 0 && page_size == PAGE_SIZE) { return insert<PageTableEntry>(getIdentAddressOfPPN(m.pt_ppn), m.pti, physical_page, 0, 0, user_access, 1); } assert(false); // you should never get here return false; }
ArchMemoryMapping ArchMemory::resolveMapping(uint64 pml4, uint64 vpage) { ArchMemoryMapping m; m.pti = vpage; m.pdi = m.pti / PAGE_TABLE_ENTRIES; m.pdpti = m.pdi / PAGE_DIR_ENTRIES; m.pml4i = m.pdpti / PAGE_DIR_POINTER_TABLE_ENTRIES; m.pti %= PAGE_TABLE_ENTRIES; m.pdi %= PAGE_DIR_ENTRIES; m.pdpti %= PAGE_DIR_POINTER_TABLE_ENTRIES; m.pml4i %= PAGE_MAP_LEVEL_4_ENTRIES; assert(pml4 <= 2048); m.pml4 = (PageMapLevel4Entry*) getIdentAddressOfPPN(pml4); m.pdpt = 0; m.pd = 0; m.pt = 0; m.page = 0; m.pml4_ppn = pml4; m.pdpt_ppn = 0; m.pd_ppn = 0; m.pt_ppn = 0; m.page_ppn = 0; m.page_size = 0; if (m.pml4[m.pml4i].present) { m.pdpt_ppn = m.pml4[m.pml4i].page_ppn; m.pdpt = (PageDirPointerTableEntry*) getIdentAddressOfPPN(m.pml4[m.pml4i].page_ppn); if (m.pdpt[m.pdpti].pd.present && !m.pdpt[m.pdpti].pd.size) // 1gb page ? { m.pd_ppn = m.pdpt[m.pdpti].pd.page_ppn; if (m.pd_ppn > 2048) { debug(A_MEMORY, "%zx\n", m.pd_ppn); } assert(m.pd_ppn <= 2048); m.pd = (PageDirEntry*) getIdentAddressOfPPN(m.pdpt[m.pdpti].pd.page_ppn); if (m.pd[m.pdi].pt.present && !m.pd[m.pdi].pt.size) // 2mb page ? { m.pt_ppn = m.pd[m.pdi].pt.page_ppn; assert(m.pt_ppn <= 2048); m.pt = (PageTableEntry*) getIdentAddressOfPPN(m.pd[m.pdi].pt.page_ppn); if (m.pt[m.pti].present) { m.page = getIdentAddressOfPPN(m.pt[m.pti].page_ppn); m.page_ppn = m.pt[m.pti].page_ppn; assert(m.page_ppn <= 2048); m.page_size = PAGE_SIZE; } } else if (m.pd[m.pdi].page.present) { m.page_size = PAGE_SIZE * PAGE_TABLE_ENTRIES; m.page_ppn = m.pd[m.pdi].page.page_ppn; assert(m.page_ppn <= 2048); m.page = getIdentAddressOfPPN(m.pd[m.pdi].page.page_ppn); } } else if (m.pdpt[m.pdpti].page.present) { m.page_size = PAGE_SIZE * PAGE_TABLE_ENTRIES * PAGE_DIR_ENTRIES; m.page_ppn = m.pdpt[m.pdpti].page.page_ppn; assert(m.page_ppn <= 2048); m.page = getIdentAddressOfPPN(m.pdpt[m.pdpti].page.page_ppn); } } return m; }