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; }
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; }
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); }
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; }
extern "C" inline void printPageFaultInfo(size_t address, size_t error) { //--------Start "just for Debugging"----------- const bool present = error & FLAG_PF_PRESENT; const bool userspace = error & FLAG_PF_USER; const bool writing = error & FLAG_PF_RDWR; const bool reserved = error & FLAG_PF_RSVD; const bool caused_by = error & FLAG_PF_INSTR_FETCH; debug(PAGEFAULT, "Address: %x, Present: %d, Writing: %d, Userspace: %d, Rsvc: %d, caused by: %s fetch" " - currentThread: %p %d"":%s, switch_to_userspace_: %d\n", address, present, writing, userspace, reserved, caused_by ? "instruction" : "operand", currentThread, currentThread->getTID(), currentThread->getName(), currentThread->switch_to_userspace_); const Stabs2DebugInfo* deb = kernel_debug_info; assert(currentThread->kernel_registers_ && "every thread needs kernel registers"); ArchThreadRegisters* registers_ = currentThread->kernel_registers_; if (error & FLAG_PF_USER) { assert(currentThread->loader_ && "User Threads need to have a Loader"); assert(currentThread->user_registers_ && (currentThread->user_registers_->cr3 == currentThread->kernel_registers_->cr3 && "User and Kernel CR3 register values differ, this most likely is a bug!")); deb = currentThread->loader_->getDebugInfos(); registers_ = currentThread->user_registers_; } if(deb && registers_->eip) { debug(PAGEFAULT, "This pagefault was probably caused by:"); deb->printCallInformation(registers_->eip); } if(!address) { debug(PAGEFAULT, "Maybe you're dereferencing a null-pointer!\n"); } if (error) { if (present) { debug(PAGEFAULT, "We got a pagefault even though the page mapping is present\n"); debug(PAGEFAULT, "%s tried to %s address %x\n", userspace ? "A userprogram" : "Some kernel code", writing ? "write to" : "read from", address); RESOLVEMAPPING(currentThread->loader_->arch_memory_.getRootOfPagingStructure(), address / PAGE_SIZE); if (page_directory[pde_vpn].pt.present) { if (page_directory[pde_vpn].page.size) { debug(PAGEFAULT, "Page 0x%zx is a 4MiB Page\n", address / PAGE_SIZE); debug(PAGEFAULT, "Page 0x%zx Flags are: writeable:%d, userspace_accessible:%d,\n", address / PAGE_SIZE, page_directory[pde_vpn].page.writeable, page_directory[pde_vpn].page.user_access); } else { PageTableEntry *pte_base = (PageTableEntry *) ArchMemory::getIdentAddressOfPPN(page_directory[pde_vpn].pt.page_table_ppn); debug(PAGEFAULT, "Page 0x%zx is a 4KiB Page\n", address / PAGE_SIZE); debug(PAGEFAULT, "Page 0x%zx Flags are: present:%zu, writeable:%zu, userspace_accessible:%zu,\n", address / PAGE_SIZE, pte_base[pte_vpn].present, pte_base[pte_vpn].writeable, pte_base[pte_vpn].user_access); } } else debug(PAGEFAULT, "WTF? PDE non-present but Exception present flag was set\n"); } else { if (address >= 2U*1024U*1024U*1024U) { debug(PAGEFAULT, "The virtual page we accessed was not mapped to a physical page\n"); if (userspace) { debug(PAGEFAULT, "WARNING: Your Userspace Programm tried to read from an unmapped address >2GiB\n"); debug(PAGEFAULT, "WARNING: Most likey there is an pointer error somewhere\n"); } else { // remove this error check if your implementation swaps out kernel pages debug(PAGEFAULT, "WARNING: This is unusual for addresses above 2Gb, unless you are swapping kernel pages\n"); debug(PAGEFAULT, "WARNING: Most likey there is an pointer error somewhere\n"); } } else { //debug(PAGEFAULT, "The virtual page we accessed was not mapped to a physical page\n"); //debug(PAGEFAULT, "this is normal and the Loader will propably take care of it now\n"); } } } ArchThreads::printThreadRegisters(currentThread, false); }