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.


Release 1.0
[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) KASSERT(0);
175
176     /* For now, just kill the thread/process. */
177     Exit(-1);
178 }
179
180 /* ----------------------------------------------------------------------
181  * Public functions
182  * ---------------------------------------------------------------------- */
183
184
185
186 /*
187  * Initialize virtual memory by building page tables
188  * for the kernel and physical memory.
189  */
190 void Init_VM(struct Boot_Info *bootInfo)
191 {
192   int numpages;
193   int numpagetables;
194   int i,j;
195
196   pde_t *pd;
197   pte_t *pt;
198
199   PrintBoth("Intitialing Virtual Memory\n");
200
201   if (checkPaging()) { 
202     SerialPrintLevel(100,"Paging is currently ON\n");
203     return ;
204   }
205
206   SerialPrintLevel(100,"Paging is currently OFF - initializing the pages for a 1-1 map\n");
207   
208   numpages=bootInfo->memSizeKB / (PAGE_SIZE/1024);
209   numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 );
210
211   SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables);
212   
213   pd = (pde_t*)Alloc_Page();
214   
215   if (!pd) { 
216     SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n");
217     return;
218   } else {
219     SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd);
220   }
221   
222   for (i=0;i<NUM_PAGE_DIR_ENTRIES;i++) { 
223     if (i>=numpagetables) { 
224       pd[i].present=0;
225       pd[i].flags=0;
226       pd[i].accessed=0;
227       pd[i].reserved=0;
228       pd[i].largePages=0;
229       pd[i].globalPage=0;
230       pd[i].kernelInfo=0;
231       pd[i].pageTableBaseAddr=0;
232     } else {
233       pt = (pte_t*)Alloc_Page();
234       if (!pt) { 
235         SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i);
236       } else {
237         //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt);
238       }
239       pd[i].present=1;
240       pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER;
241       pd[i].accessed=0;
242       pd[i].reserved=0;
243       pd[i].largePages=0;
244       pd[i].globalPage=0;
245       pd[i].kernelInfo=0;
246       pd[i].pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
247       
248       for (j=0;j<NUM_PAGE_TABLE_ENTRIES;j++) { 
249         if (i*NUM_PAGE_TABLE_ENTRIES + j >= numpages) {
250           pt[j].present=0;
251           pt[j].flags=0;
252           pt[j].accessed=0;
253           pt[j].dirty=0;
254           pt[j].pteAttribute=0;
255           pt[j].globalPage=0;
256           pt[j].kernelInfo=0;
257           pt[j].pageBaseAddr=0;
258         } else {
259           pt[j].present=1;
260           pt[j].flags=VM_READ | VM_WRITE | VM_EXEC | VM_USER;
261           pt[j].accessed=0;
262           pt[j].dirty=0;
263           pt[j].pteAttribute=0;
264           pt[j].globalPage=0;
265           pt[j].kernelInfo=0;
266           pt[j].pageBaseAddr=(i*NUM_PAGE_TABLE_ENTRIES + j);
267         }
268       }
269     }
270   }
271   SerialPrintLevel(100,"Done creating 1<->1 initial page tables\n");
272   SerialPrintLevel(100,"Now installing page fault handler\n");
273   //  SerialDumpPageTables(pd);
274   Install_Interrupt_Handler(14,Page_Fault_Handler);
275   SerialPrintLevel(100,"Now turning on the paging bit!\n");
276   Enable_Paging(pd);
277   SerialPrintLevel(100,"We are still alive after paging turned on!\n");
278   SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging());
279 }
280
281
282 //
283 pte_t *LookupPage(void *vaddr)
284 {
285   uint_t pde_offset = ((uint_t)vaddr) >> 22;
286   uint_t pte_offset = (((uint_t)vaddr) >> 12) & 0x3ff;
287   pte_t *pte; 
288   pde_t *pde = Get_PDBR();
289
290   KASSERT(pde);
291
292   pde+=pde_offset;
293
294   if (!(pde->present)) { 
295     return 0;
296   }
297
298   pte = (pte_t *)((pde->pageTableBaseAddr)<<12);
299
300   pte+=pte_offset;
301
302   return pte;
303 }
304
305
306 pte_t *CreateAndAddPageTable(void *vaddr, uint_t flags)
307 {
308   int i;
309
310   KASSERT(!(PAGE_OFFSET(vaddr)));
311   
312   pte_t *pt = Alloc_Page();
313   
314   KASSERT(pt);
315   
316   for (i=0;i<NUM_PAGE_TABLE_ENTRIES;i++) { 
317     pt[i].present=0;
318   }
319
320   pde_t *pde = Get_PDBR();
321   
322   pde=&(pde[PAGE_DIRECTORY_INDEX(vaddr)]);
323
324   KASSERT(!(pde->present));
325   
326   pde->present=1;
327   pde->flags=flags;
328   pde->accessed=0;
329   pde->reserved=0;
330   pde->largePages=0;
331   pde->globalPage=0;
332   pde->kernelInfo=0;
333   pde->pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
334
335   return pt;
336 }
337
338 pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde)
339 {
340   pte_t *oldpte = LookupPage(vaddr);
341
342   if (!pte) {
343     if (alloc_pde) { 
344       CreateAndAddPageTable(vaddr,pte->flags);
345       oldpte = LookupPage(vaddr);
346       KASSERT(pte);
347     } else {
348       return 0;
349     }
350   }
351
352   *oldpte = *pte;
353   
354   return oldpte;
355 }
356
357 pte_t *UnMapPage(void *vaddr)
358 {
359   pte_t *oldpte = LookupPage(vaddr);
360
361   if (!oldpte) {
362     return 0;
363   }
364   oldpte->present=0;
365   
366   return oldpte;
367 }
368
369   
370
371 /**
372  * Initialize paging file data structures.
373  * All filesystems should be mounted before this function
374  * is called, to ensure that the paging file is available.
375  */
376 void Init_Paging(void)
377 {
378   PrintBoth("Initializing Paging\n");
379 }
380
381 /**
382  * Find a free bit of disk on the paging file for this page.
383  * Interrupts must be disabled.
384  * @return index of free page sized chunk of disk space in
385  *   the paging file, or -1 if the paging file is full
386  */
387 int Find_Space_On_Paging_File(void)
388 {
389     KASSERT(!Interrupts_Enabled());
390     TODO("Find free page in paging file");
391 }
392
393 /**
394  * Free a page-sized chunk of disk space in the paging file.
395  * Interrupts must be disabled.
396  * @param pagefileIndex index of the chunk of disk space
397  */
398 void Free_Space_On_Paging_File(int pagefileIndex)
399 {
400     KASSERT(!Interrupts_Enabled());
401     TODO("Free page in paging file");
402 }
403
404 /**
405  * Write the contents of given page to the indicated block
406  * of space in the paging file.
407  * @param paddr a pointer to the physical memory of the page
408  * @param vaddr virtual address where page is mapped in user memory
409  * @param pagefileIndex the index of the page sized chunk of space
410  *   in the paging file
411  */
412 void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
413 {
414     struct Page *page = Get_Page((ulong_t) paddr);
415     KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */
416     TODO("Write page data to paging file");
417 }
418
419 /**
420  * Read the contents of the indicated block
421  * of space in the paging file into the given page.
422  * @param paddr a pointer to the physical memory of the page
423  * @param vaddr virtual address where page will be re-mapped in
424  *   user memory
425  * @param pagefileIndex the index of the page sized chunk of space
426  *   in the paging file
427  */
428 void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
429 {
430     struct Page *page = Get_Page((ulong_t) paddr);
431     KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */
432     TODO("Read page data from paging file");
433 }
434