2 * Paging (virtual memory) support
3 * Copyright (c) 2003, Jeffrey K. Hollingsworth <hollings@cs.umd.edu>
4 * Copyright (c) 2003,2004 David H. Hovemeyer <daveho@cs.umd.edu>
5 * (c) 2008, Peter Dinda <pdinda@northwestern.edu>
6 * (c) 2008, Jack Lange <jarusl@cs.northwestern.edu>
7 * (c) 2008, The V3VEE Project <http://www.v3vee.org>
10 * This is free software. You are permitted to use,
11 * redistribute, and modify it as specified in the file "COPYING".
14 #include <geekos/string.h>
15 #include <geekos/int.h>
16 #include <geekos/idt.h>
17 #include <geekos/kthread.h>
18 #include <geekos/kassert.h>
19 #include <geekos/screen.h>
20 #include <geekos/mem.h>
21 #include <geekos/malloc.h>
22 #include <geekos/gdt.h>
23 #include <geekos/segment.h>
24 //#include <geekos/user.h>
25 //#include <geekos/vfs.h>
26 #include <geekos/crc32.h>
27 #include <geekos/paging.h>
28 #include <geekos/serial.h>
29 #include <geekos/debug.h>
31 /* ----------------------------------------------------------------------
33 * ---------------------------------------------------------------------- */
35 /* ----------------------------------------------------------------------
36 * Private functions/data
37 * ---------------------------------------------------------------------- */
39 #define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE)
42 * flag to indicate if debugging paging code
45 #define Debug(args...) if (debugFaults) Print(args)
49 void SerialPrintPD(pde_t *pde)
53 SerialPrint("Page Directory at %p:\n",pde);
54 for (i=0;i<NUM_PAGE_DIR_ENTRIES && pde[i].present;i++) {
55 SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
59 void SerialPrintPT(void *starting_address, pte_t *pte)
63 SerialPrint("Page Table at %p:\n",pte);
64 for (i=0;i<NUM_PAGE_TABLE_ENTRIES && pte[i].present;i++) {
65 SerialPrintPTE(starting_address + PAGE_SIZE*i,&(pte[i]));
70 void SerialPrintPDE(void *virtual_address, pde_t *pde)
72 SerialPrint("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
74 (void*) (pde->pageTableBaseAddr << PAGE_POWER),
84 void SerialPrintPTE(void *virtual_address, pte_t *pte)
86 SerialPrint("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n",
88 (void*)(pte->pageBaseAddr << PAGE_POWER),
99 void SerialDumpPageTables(pde_t *pde)
103 SerialPrint("Dumping the pages starting with the pde page at %p\n",pde);
105 for (i=0;i<NUM_PAGE_DIR_ENTRIES && pde[i].present;i++) {
106 SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
107 SerialPrintPT((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),(void*)(pde[i].pageTableBaseAddr<<PAGE_POWER));
118 __asm__ __volatile__( "movl %%cr0, %0" : "=a" (reg));
119 Print("Paging on ? : %d\n", (reg & (1<<31)) != 0);
120 return (reg & (1<<31)) != 0;
125 * Print diagnostic information for a page fault.
127 static void Print_Fault_Info(uint_t address, faultcode_t faultCode)
129 extern uint_t g_freePageCount;
133 SerialPrintLevel(100,"Pid %d, Page Fault received, at address %x (%d pages free)\n",
134 g_currentThread->pid, address, g_freePageCount);
135 if (faultCode.protectionViolation)
136 SerialPrintLevel(100," Protection Violation, ");
138 SerialPrintLevel(100," Non-present page, ");
139 if (faultCode.writeFault)
140 SerialPrintLevel(100,"Write Fault, ");
142 SerialPrintLevel(100,"Read Fault, ");
143 if (faultCode.userModeFault)
144 SerialPrintLevel(100,"in User Mode\n");
146 SerialPrintLevel(100,"in Supervisor Mode\n");
150 * Handler for page faults.
151 * You should call the Install_Interrupt_Handler() function to
152 * register this function as the handler for interrupt 14.
154 /*static*/ void Page_Fault_Handler(struct Interrupt_State* state)
157 faultcode_t faultCode;
159 KASSERT(!Interrupts_Enabled());
161 /* Get the address that caused the page fault */
162 address = Get_Page_Fault_Address();
163 Debug("Page fault @%lx\n", address);
165 /* Get the fault code */
166 faultCode = *((faultcode_t *) &(state->errorCode));
168 /* rest of your handling code here */
169 SerialPrintLevel(100,"Unexpected Page Fault received\n");
170 Print_Fault_Info(address, faultCode);
171 Dump_Interrupt_State(state);
172 //SerialPrint_VMCS_ALL();
173 /* user faults just kill the process */
174 if (!faultCode.userModeFault) {
175 PrintBoth("Invalid Fault at %p\n", address);
178 /* For now, just kill the thread/process. */
182 /* ----------------------------------------------------------------------
184 * ---------------------------------------------------------------------- */
189 * Initialize virtual memory by building page tables
190 * for the kernel and physical memory.
192 void Init_VM(struct Boot_Info *bootInfo)
201 PrintBoth("Intitialing Virtual Memory\n");
204 SerialPrintLevel(100,"Paging is currently ON\n");
208 PrintBoth("initializing Direct mapped pages for %dKB of RAM\n", bootInfo->memSizeKB);
210 numpages = bootInfo->memSizeKB / (PAGE_SIZE / 1024);
211 numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 );
213 SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables);
215 pd = (pde_t*)Alloc_Page();
218 SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n");
221 SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd);
224 for (i=0;i<NUM_PAGE_DIR_ENTRIES;i++) {
225 if (i>=numpagetables) {
233 pd[i].pageTableBaseAddr=0;
235 pt = (pte_t*)Alloc_Page();
237 SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i);
239 //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt);
242 pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER;
248 pd[i].pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
250 for (j=0;j<NUM_PAGE_TABLE_ENTRIES;j++) {
251 if (i*NUM_PAGE_TABLE_ENTRIES + j >= numpages) {
256 pt[j].pteAttribute=0;
259 pt[j].pageBaseAddr=0;
262 pt[j].flags=VM_READ | VM_WRITE | VM_EXEC | VM_USER;
265 pt[j].pteAttribute=0;
268 pt[j].pageBaseAddr=(i*NUM_PAGE_TABLE_ENTRIES + j);
273 SerialPrintLevel(100,"Done creating 1<->1 initial page tables\n");
274 SerialPrintLevel(100,"Now installing page fault handler\n");
275 // SerialDumpPageTables(pd);
276 Install_Interrupt_Handler(14,Page_Fault_Handler);
277 SerialPrintLevel(100,"Now turning on the paging bit!\n");
279 SerialPrintLevel(100,"We are still alive after paging turned on!\n");
280 SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging());
285 pte_t *LookupPage(void *vaddr)
287 uint_t pde_offset = ((uint_t)vaddr) >> 22;
288 uint_t pte_offset = (((uint_t)vaddr) >> 12) & 0x3ff;
290 pde_t *pde = Get_PDBR();
296 if (!(pde->present)) {
300 pte = (pte_t *)((pde->pageTableBaseAddr)<<12);
308 pte_t *CreateAndAddPageTable(void *vaddr, uint_t flags)
312 KASSERT(!(PAGE_OFFSET(vaddr)));
314 pte_t *pt = Alloc_Page();
318 for (i=0;i<NUM_PAGE_TABLE_ENTRIES;i++) {
322 pde_t *pde = Get_PDBR();
324 pde=&(pde[PAGE_DIRECTORY_INDEX(vaddr)]);
326 KASSERT(!(pde->present));
335 pde->pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
340 pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde)
342 pte_t *oldpte = LookupPage(vaddr);
346 CreateAndAddPageTable(vaddr,pte->flags);
347 oldpte = LookupPage(vaddr);
359 pte_t *UnMapPage(void *vaddr)
361 pte_t *oldpte = LookupPage(vaddr);
374 * Initialize paging file data structures.
375 * All filesystems should be mounted before this function
376 * is called, to ensure that the paging file is available.
378 void Init_Paging(void)
380 PrintBoth("Initializing Paging\n");
384 * Find a free bit of disk on the paging file for this page.
385 * Interrupts must be disabled.
386 * @return index of free page sized chunk of disk space in
387 * the paging file, or -1 if the paging file is full
389 int Find_Space_On_Paging_File(void)
391 KASSERT(!Interrupts_Enabled());
392 TODO("Find free page in paging file");
396 * Free a page-sized chunk of disk space in the paging file.
397 * Interrupts must be disabled.
398 * @param pagefileIndex index of the chunk of disk space
400 void Free_Space_On_Paging_File(int pagefileIndex)
402 KASSERT(!Interrupts_Enabled());
403 TODO("Free page in paging file");
407 * Write the contents of given page to the indicated block
408 * of space in the paging file.
409 * @param paddr a pointer to the physical memory of the page
410 * @param vaddr virtual address where page is mapped in user memory
411 * @param pagefileIndex the index of the page sized chunk of space
414 void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
416 struct Page *page = Get_Page((ulong_t) paddr);
417 KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */
418 TODO("Write page data to paging file");
422 * Read the contents of the indicated block
423 * of space in the paging file into the given page.
424 * @param paddr a pointer to the physical memory of the page
425 * @param vaddr virtual address where page will be re-mapped in
427 * @param pagefileIndex the index of the page sized chunk of space
430 void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
432 struct Page *page = Get_Page((ulong_t) paddr);
433 KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */
434 TODO("Read page data from paging file");