Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of ssh://palacios@newskysaw.cs.northwestern.edu/home/palacios...
[palacios.git] / geekos / src / geekos / paging.c
1 /*
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> 
8  * $Revision: 1.2 $
9  * 
10  * This is free software.  You are permitted to use,
11  * redistribute, and modify it as specified in the file "COPYING".
12  */
13
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>
30
31 /* ----------------------------------------------------------------------
32  * Public data
33  * ---------------------------------------------------------------------- */
34
35 /* ----------------------------------------------------------------------
36  * Private functions/data
37  * ---------------------------------------------------------------------- */
38
39 #define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE)
40
41 /*
42  * flag to indicate if debugging paging code
43  */
44 int debugFaults = 0;
45 #define Debug(args...) if (debugFaults) Print(args)
46
47
48
49 void SerialPrintPD(pde_t *pde)
50 {
51   int i;
52
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]));
56   }
57 }
58
59 void SerialPrintPT(void *starting_address, pte_t *pte) 
60 {
61   int i;
62
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]));
66   }
67 }
68
69
70 void SerialPrintPDE(void *virtual_address, pde_t *pde)
71 {
72   SerialPrint("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
73               virtual_address,
74               (void*) (pde->pageTableBaseAddr << PAGE_POWER),
75               pde->present,
76               pde->flags,
77               pde->accessed,
78               pde->reserved,
79               pde->largePages,
80               pde->globalPage,
81               pde->kernelInfo);
82 }
83   
84 void SerialPrintPTE(void *virtual_address, pte_t *pte)
85 {
86   SerialPrint("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n",
87               virtual_address,
88               (void*)(pte->pageBaseAddr << PAGE_POWER),
89               pte->present,
90               pte->flags,
91               pte->accessed,
92               pte->dirty,
93               pte->pteAttribute,
94               pte->globalPage,
95               pte->kernelInfo);
96 }
97
98
99 void SerialDumpPageTables(pde_t *pde)
100 {
101   int i;
102   
103   SerialPrint("Dumping the pages starting with the pde page at %p\n",pde);
104
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));
108   }
109 }
110     
111     
112     
113
114
115 int checkPaging()
116 {
117   unsigned long reg=0;
118   __asm__ __volatile__( "movl %%cr0, %0" : "=a" (reg));
119   Print("Paging on ? : %d\n", (reg & (1<<31)) != 0);
120   return (reg & (1<<31)) != 0;
121 }
122
123
124 /*
125  * Print diagnostic information for a page fault.
126  */
127 static void Print_Fault_Info(uint_t address, faultcode_t faultCode)
128 {
129     extern uint_t g_freePageCount;
130
131     g_freePageCount+=0;
132
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, ");
137     else
138         SerialPrintLevel(100,"   Non-present page, ");
139     if (faultCode.writeFault)
140         SerialPrintLevel(100,"Write Fault, ");
141     else
142         SerialPrintLevel(100,"Read Fault, ");
143     if (faultCode.userModeFault)
144         SerialPrintLevel(100,"in User Mode\n");
145     else
146         SerialPrintLevel(100,"in Supervisor Mode\n");
147 }
148
149 /*
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.
153  */
154 /*static*/ void Page_Fault_Handler(struct Interrupt_State* state)
155 {
156     ulong_t address;
157     faultcode_t faultCode;
158
159     KASSERT(!Interrupts_Enabled());
160
161     /* Get the address that caused the page fault */
162     address = Get_Page_Fault_Address();
163     Debug("Page fault @%lx\n", address);
164
165     /* Get the fault code */
166     faultCode = *((faultcode_t *) &(state->errorCode));
167
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);
176         KASSERT(0);
177     }
178     /* For now, just kill the thread/process. */
179     Exit(-1);
180 }
181
182 /* ----------------------------------------------------------------------
183  * Public functions
184  * ---------------------------------------------------------------------- */
185
186
187
188 /*
189  * Initialize virtual memory by building page tables
190  * for the kernel and physical memory.
191  */
192 void Init_VM(struct Boot_Info *bootInfo)
193 {
194   int numpages;
195   int numpagetables;
196   int i,j;
197
198   pde_t *pd;
199   pte_t *pt;
200
201   PrintBoth("Intitialing Virtual Memory\n");
202
203   if (checkPaging()) { 
204     SerialPrintLevel(100,"Paging is currently ON\n");
205     return ;
206   }
207
208   PrintBoth("initializing Direct mapped pages for %dKB of RAM\n", bootInfo->memSizeKB);
209   
210   numpages = bootInfo->memSizeKB / (PAGE_SIZE / 1024);
211   numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 );
212
213   SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables);
214   
215   pd = (pde_t*)Alloc_Page();
216   
217   if (!pd) { 
218     SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n");
219     return;
220   } else {
221     SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd);
222   }
223   
224   for (i=0;i<NUM_PAGE_DIR_ENTRIES;i++) { 
225     if (i>=numpagetables) { 
226       pd[i].present=0;
227       pd[i].flags=0;
228       pd[i].accessed=0;
229       pd[i].reserved=0;
230       pd[i].largePages=0;
231       pd[i].globalPage=0;
232       pd[i].kernelInfo=0;
233       pd[i].pageTableBaseAddr=0;
234     } else {
235       pt = (pte_t*)Alloc_Page();
236       if (!pt) { 
237         SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i);
238       } else {
239         //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt);
240       }
241       pd[i].present=1;
242       pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER;
243       pd[i].accessed=0;
244       pd[i].reserved=0;
245       pd[i].largePages=0;
246       pd[i].globalPage=0;
247       pd[i].kernelInfo=0;
248       pd[i].pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
249       
250       for (j=0;j<NUM_PAGE_TABLE_ENTRIES;j++) { 
251         if (i*NUM_PAGE_TABLE_ENTRIES + j >= numpages) {
252           pt[j].present=0;
253           pt[j].flags=0;
254           pt[j].accessed=0;
255           pt[j].dirty=0;
256           pt[j].pteAttribute=0;
257           pt[j].globalPage=0;
258           pt[j].kernelInfo=0;
259           pt[j].pageBaseAddr=0;
260         } else {
261           pt[j].present=1;
262           pt[j].flags=VM_READ | VM_WRITE | VM_EXEC | VM_USER;
263           pt[j].accessed=0;
264           pt[j].dirty=0;
265           pt[j].pteAttribute=0;
266           pt[j].globalPage=0;
267           pt[j].kernelInfo=0;
268           pt[j].pageBaseAddr=(i*NUM_PAGE_TABLE_ENTRIES + j);
269         }
270       }
271     }
272   }
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");
278   Enable_Paging(pd);
279   SerialPrintLevel(100,"We are still alive after paging turned on!\n");
280   SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging());
281 }
282
283
284 //
285 pte_t *LookupPage(void *vaddr)
286 {
287   uint_t pde_offset = ((uint_t)vaddr) >> 22;
288   uint_t pte_offset = (((uint_t)vaddr) >> 12) & 0x3ff;
289   pte_t *pte; 
290   pde_t *pde = Get_PDBR();
291
292   KASSERT(pde);
293
294   pde+=pde_offset;
295
296   if (!(pde->present)) { 
297     return 0;
298   }
299
300   pte = (pte_t *)((pde->pageTableBaseAddr)<<12);
301
302   pte+=pte_offset;
303
304   return pte;
305 }
306
307
308 pte_t *CreateAndAddPageTable(void *vaddr, uint_t flags)
309 {
310   int i;
311
312   KASSERT(!(PAGE_OFFSET(vaddr)));
313   
314   pte_t *pt = Alloc_Page();
315   
316   KASSERT(pt);
317   
318   for (i=0;i<NUM_PAGE_TABLE_ENTRIES;i++) { 
319     pt[i].present=0;
320   }
321
322   pde_t *pde = Get_PDBR();
323   
324   pde=&(pde[PAGE_DIRECTORY_INDEX(vaddr)]);
325
326   KASSERT(!(pde->present));
327   
328   pde->present=1;
329   pde->flags=flags;
330   pde->accessed=0;
331   pde->reserved=0;
332   pde->largePages=0;
333   pde->globalPage=0;
334   pde->kernelInfo=0;
335   pde->pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
336
337   return pt;
338 }
339
340 pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde)
341 {
342   pte_t *oldpte = LookupPage(vaddr);
343
344   if (!pte) {
345     if (alloc_pde) { 
346       CreateAndAddPageTable(vaddr,pte->flags);
347       oldpte = LookupPage(vaddr);
348       KASSERT(pte);
349     } else {
350       return 0;
351     }
352   }
353
354   *oldpte = *pte;
355   
356   return oldpte;
357 }
358
359 pte_t *UnMapPage(void *vaddr)
360 {
361   pte_t *oldpte = LookupPage(vaddr);
362
363   if (!oldpte) {
364     return 0;
365   }
366   oldpte->present=0;
367   
368   return oldpte;
369 }
370
371   
372
373 /**
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.
377  */
378 void Init_Paging(void)
379 {
380   PrintBoth("Initializing Paging\n");
381 }
382
383 /**
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
388  */
389 int Find_Space_On_Paging_File(void)
390 {
391     KASSERT(!Interrupts_Enabled());
392     TODO("Find free page in paging file");
393 }
394
395 /**
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
399  */
400 void Free_Space_On_Paging_File(int pagefileIndex)
401 {
402     KASSERT(!Interrupts_Enabled());
403     TODO("Free page in paging file");
404 }
405
406 /**
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
412  *   in the paging file
413  */
414 void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
415 {
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");
419 }
420
421 /**
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
426  *   user memory
427  * @param pagefileIndex the index of the page sized chunk of space
428  *   in the paging file
429  */
430 void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
431 {
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");
435 }
436