/* * Paging (virtual memory) support * Copyright (c) 2003, Jeffrey K. Hollingsworth * Copyright (c) 2003,2004 David H. Hovemeyer * $Revision: 1.1 $ * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "COPYING". */ #include #include #include #include #include #include #include #include #include #include //#include //#include #include #include #include #include /* ---------------------------------------------------------------------- * Public data * ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- * Private functions/data * ---------------------------------------------------------------------- */ #define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE) /* * flag to indicate if debugging paging code */ int debugFaults = 0; #define Debug(args...) if (debugFaults) Print(args) void SerialPrintPD(pde_t *pde) { int i; SerialPrint("Page Directory at %p:\n",pde); for (i=0;i %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n", virtual_address, (void*) (pde->pageTableBaseAddr << PAGE_POWER), pde->present, pde->flags, pde->accessed, pde->reserved, pde->largePages, pde->globalPage, pde->kernelInfo); } void SerialPrintPTE(void *virtual_address, pte_t *pte) { SerialPrint("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n", virtual_address, (void*)(pte->pageBaseAddr << PAGE_POWER), pte->present, pte->flags, pte->accessed, pte->dirty, pte->pteAttribute, pte->globalPage, pte->kernelInfo); } void SerialDumpPageTables(pde_t *pde) { int i; SerialPrint("Dumping the pages starting with the pde page at %p\n",pde); for (i=0;ipid, address, g_freePageCount); if (faultCode.protectionViolation) SerialPrintLevel(100," Protection Violation, "); else SerialPrintLevel(100," Non-present page, "); if (faultCode.writeFault) SerialPrintLevel(100,"Write Fault, "); else SerialPrintLevel(100,"Read Fault, "); if (faultCode.userModeFault) SerialPrintLevel(100,"in User Mode\n"); else SerialPrintLevel(100,"in Supervisor Mode\n"); } /* * Handler for page faults. * You should call the Install_Interrupt_Handler() function to * register this function as the handler for interrupt 14. */ /*static*/ void Page_Fault_Handler(struct Interrupt_State* state) { ulong_t address; faultcode_t faultCode; KASSERT(!Interrupts_Enabled()); /* Get the address that caused the page fault */ address = Get_Page_Fault_Address(); Debug("Page fault @%lx\n", address); /* Get the fault code */ faultCode = *((faultcode_t *) &(state->errorCode)); /* rest of your handling code here */ SerialPrintLevel(100,"Unexpected Page Fault received\n"); Print_Fault_Info(address, faultCode); Dump_Interrupt_State(state); SerialPrint_VMCS_ALL(); /* user faults just kill the process */ if (!faultCode.userModeFault) KASSERT(0); /* For now, just kill the thread/process. */ Exit(-1); } /* ---------------------------------------------------------------------- * Public functions * ---------------------------------------------------------------------- */ /* * Initialize virtual memory by building page tables * for the kernel and physical memory. */ void Init_VM(struct Boot_Info *bootInfo) { int numpages; int numpagetables; int i,j; pde_t *pd; pte_t *pt; PrintBoth("Intitialing Virtual Memory\n"); if (checkPaging()) { SerialPrintLevel(100,"Paging is currently ON\n"); return ; } SerialPrintLevel(100,"Paging is currently OFF - initializing the pages for a 1-1 map\n"); numpages=bootInfo->memSizeKB / (PAGE_SIZE/1024); numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 ); SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables); pd = (pde_t*)Alloc_Page(); if (!pd) { SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n"); return; } else { SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd); } for (i=0;i=numpagetables) { pd[i].present=0; pd[i].flags=0; pd[i].accessed=0; pd[i].reserved=0; pd[i].largePages=0; pd[i].globalPage=0; pd[i].kernelInfo=0; pd[i].pageTableBaseAddr=0; } else { pt = (pte_t*)Alloc_Page(); if (!pt) { SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i); } else { //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt); } pd[i].present=1; pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER; pd[i].accessed=0; pd[i].reserved=0; pd[i].largePages=0; pd[i].globalPage=0; pd[i].kernelInfo=0; pd[i].pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt); for (j=0;j= numpages) { pt[j].present=0; pt[j].flags=0; pt[j].accessed=0; pt[j].dirty=0; pt[j].pteAttribute=0; pt[j].globalPage=0; pt[j].kernelInfo=0; pt[j].pageBaseAddr=0; } else { pt[j].present=1; pt[j].flags=VM_READ | VM_WRITE | VM_EXEC | VM_USER; pt[j].accessed=0; pt[j].dirty=0; pt[j].pteAttribute=0; pt[j].globalPage=0; pt[j].kernelInfo=0; pt[j].pageBaseAddr=(i*NUM_PAGE_TABLE_ENTRIES + j); } } } } SerialPrintLevel(100,"Done creating 1<->1 initial page tables\n"); SerialPrintLevel(100,"Now installing page fault handler\n"); // SerialDumpPageTables(pd); Install_Interrupt_Handler(14,Page_Fault_Handler); SerialPrintLevel(100,"Now turning on the paging bit!\n"); Enable_Paging(pd); SerialPrintLevel(100,"We are still alive after paging turned on!\n"); SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging()); } // pte_t *LookupPage(void *vaddr) { uint_t pde_offset = ((uint_t)vaddr) >> 22; uint_t pte_offset = (((uint_t)vaddr) >> 12) & 0x3ff; pte_t *pte; pde_t *pde = Get_PDBR(); KASSERT(pde); pde+=pde_offset; if (!(pde->present)) { return 0; } pte = (pte_t *)((pde->pageTableBaseAddr)<<12); pte+=pte_offset; return pte; } pte_t *CreateAndAddPageTable(void *vaddr, uint_t flags) { int i; KASSERT(!(PAGE_OFFSET(vaddr))); pte_t *pt = Alloc_Page(); KASSERT(pt); for (i=0;ipresent)); pde->present=1; pde->flags=flags; pde->accessed=0; pde->reserved=0; pde->largePages=0; pde->globalPage=0; pde->kernelInfo=0; pde->pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt); return pt; } pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde) { pte_t *oldpte = LookupPage(vaddr); if (!pte) { if (alloc_pde) { CreateAndAddPageTable(vaddr,pte->flags); oldpte = LookupPage(vaddr); KASSERT(pte); } else { return 0; } } *oldpte = *pte; return oldpte; } pte_t *UnMapPage(void *vaddr) { pte_t *oldpte = LookupPage(vaddr); if (!oldpte) { return 0; } oldpte->present=0; return oldpte; } /** * Initialize paging file data structures. * All filesystems should be mounted before this function * is called, to ensure that the paging file is available. */ void Init_Paging(void) { PrintBoth("Initializing Paging\n"); } /** * Find a free bit of disk on the paging file for this page. * Interrupts must be disabled. * @return index of free page sized chunk of disk space in * the paging file, or -1 if the paging file is full */ int Find_Space_On_Paging_File(void) { KASSERT(!Interrupts_Enabled()); TODO("Find free page in paging file"); } /** * Free a page-sized chunk of disk space in the paging file. * Interrupts must be disabled. * @param pagefileIndex index of the chunk of disk space */ void Free_Space_On_Paging_File(int pagefileIndex) { KASSERT(!Interrupts_Enabled()); TODO("Free page in paging file"); } /** * Write the contents of given page to the indicated block * of space in the paging file. * @param paddr a pointer to the physical memory of the page * @param vaddr virtual address where page is mapped in user memory * @param pagefileIndex the index of the page sized chunk of space * in the paging file */ void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex) { struct Page *page = Get_Page((ulong_t) paddr); KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */ TODO("Write page data to paging file"); } /** * Read the contents of the indicated block * of space in the paging file into the given page. * @param paddr a pointer to the physical memory of the page * @param vaddr virtual address where page will be re-mapped in * user memory * @param pagefileIndex the index of the page sized chunk of space * in the paging file */ void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex) { struct Page *page = Get_Page((ulong_t) paddr); KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */ TODO("Read page data from paging file"); }