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.


b2837dc28eb6358d1c6b78eb0b68d01a6b3e9ad4
[palacios.git] / misc / test_vm / 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  * $Revision: 1.1 $
6  * 
7  * This is free software.  You are permitted to use,
8  * redistribute, and modify it as specified in the file "COPYING".
9  */
10
11 #include <geekos/string.h>
12 #include <geekos/int.h>
13 #include <geekos/idt.h>
14 #include <geekos/kthread.h>
15 #include <geekos/kassert.h>
16 #include <geekos/screen.h>
17 #include <geekos/mem.h>
18 #include <geekos/malloc.h>
19 #include <geekos/gdt.h>
20 #include <geekos/segment.h>
21 //#include <geekos/user.h>
22 //#include <geekos/vfs.h>
23 #include <geekos/crc32.h>
24 #include <geekos/paging.h>
25 #include <geekos/serial.h>
26
27
28 /* ----------------------------------------------------------------------
29  * Public data
30  * ---------------------------------------------------------------------- */
31
32 /* ----------------------------------------------------------------------
33  * Private functions/data
34  * ---------------------------------------------------------------------- */
35
36 #define SECTORS_PER_PAGE (PAGE_SIZE / SECTOR_SIZE)
37
38 /*
39  * flag to indicate if debugging paging code
40  */
41 int debugFaults = 0;
42 #define Debug(args...) if (debugFaults) Print(args)
43
44
45
46 void SerialPrintPD(pde_t *pde)
47 {
48   int i;
49
50   SerialPrint("Page Directory at %p:\n",pde);
51   for (i=0;i<NUM_PAGE_DIR_ENTRIES && pde[i].present;i++) { 
52     SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
53   }
54 }
55
56 void SerialPrintPT(void *starting_address, pte_t *pte) 
57 {
58   int i;
59
60   SerialPrint("Page Table at %p:\n",pte);
61   for (i=0;i<NUM_PAGE_TABLE_ENTRIES && pte[i].present;i++) { 
62     SerialPrintPTE(starting_address + PAGE_SIZE*i,&(pte[i]));
63   }
64 }
65
66
67 void SerialPrintPDE(void *virtual_address, pde_t *pde)
68 {
69   SerialPrint("PDE %p -> %p : present=%x, flags=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
70               virtual_address,
71               (void*) (pde->pageTableBaseAddr << PAGE_POWER),
72               pde->present,
73               pde->flags,
74               pde->accessed,
75               pde->reserved,
76               pde->largePages,
77               pde->globalPage,
78               pde->kernelInfo);
79 }
80   
81 void SerialPrintPTE(void *virtual_address, pte_t *pte)
82 {
83   SerialPrint("PTE %p -> %p : present=%x, flags=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, kernelInfo=%x\n",
84               virtual_address,
85               (void*)(pte->pageBaseAddr << PAGE_POWER),
86               pte->present,
87               pte->flags,
88               pte->accessed,
89               pte->dirty,
90               pte->pteAttribute,
91               pte->globalPage,
92               pte->kernelInfo);
93 }
94
95
96 void SerialDumpPageTables(pde_t *pde)
97 {
98   int i;
99   
100   SerialPrint("Dumping the pages starting with the pde page at %p\n",pde);
101
102   for (i=0;i<NUM_PAGE_DIR_ENTRIES && pde[i].present;i++) { 
103     SerialPrintPDE((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),&(pde[i]));
104     SerialPrintPT((void*)(PAGE_SIZE*NUM_PAGE_TABLE_ENTRIES*i),(void*)(pde[i].pageTableBaseAddr<<PAGE_POWER));
105   }
106 }
107     
108     
109     
110
111
112 int checkPaging()
113 {
114   unsigned long reg=0;
115   __asm__ __volatile__( "movl %%cr0, %0" : "=a" (reg));
116   Print("Paging on ? : %d\n", (reg & (1<<31)) != 0);
117   return (reg & (1<<31)) != 0;
118 }
119
120
121 /*
122  * Print diagnostic information for a page fault.
123  */
124 static void Print_Fault_Info(uint_t address, faultcode_t faultCode)
125 {
126     extern uint_t g_freePageCount;
127
128     g_freePageCount+=0;
129
130     SerialPrintLevel(100,"Pid %d, Page Fault received, at address %x (%d pages free)\n",
131         g_currentThread->pid, address, g_freePageCount);
132     if (faultCode.protectionViolation)
133         SerialPrintLevel(100,"   Protection Violation, ");
134     else
135         SerialPrintLevel(100,"   Non-present page, ");
136     if (faultCode.writeFault)
137         SerialPrintLevel(100,"Write Fault, ");
138     else
139         SerialPrintLevel(100,"Read Fault, ");
140     if (faultCode.userModeFault)
141         SerialPrintLevel(100,"in User Mode\n");
142     else
143         SerialPrintLevel(100,"in Supervisor Mode\n");
144 }
145
146 /*
147  * Handler for page faults.
148  * You should call the Install_Interrupt_Handler() function to
149  * register this function as the handler for interrupt 14.
150  */
151 /*static*/ void Page_Fault_Handler(struct Interrupt_State* state)
152 {
153     ulong_t address;
154     faultcode_t faultCode;
155
156     KASSERT(!Interrupts_Enabled());
157
158     /* Get the address that caused the page fault */
159     address = Get_Page_Fault_Address();
160     Debug("Page fault @%lx\n", address);
161
162     /* Get the fault code */
163     faultCode = *((faultcode_t *) &(state->errorCode));
164
165     /* rest of your handling code here */
166     SerialPrintLevel(100,"Unexpected Page Fault received\n");
167     Print_Fault_Info(address, faultCode);
168     Dump_Interrupt_State(state);
169     /* user faults just kill the process */
170     if (!faultCode.userModeFault) KASSERT(0);
171
172     /* For now, just kill the thread/process. */
173     Exit(-1);
174 }
175
176 /* ----------------------------------------------------------------------
177  * Public functions
178  * ---------------------------------------------------------------------- */
179
180
181
182 /*
183  * Initialize virtual memory by building page tables
184  * for the kernel and physical memory.
185  */
186 void Init_VM(struct Boot_Info *bootInfo)
187 {
188   int numpages;
189   int numpagetables;
190   int i,j;
191
192   pde_t *pd;
193   pte_t *pt;
194
195   PrintBoth("Intitialing Virtual Memory\n");
196
197   if (checkPaging()) { 
198     SerialPrintLevel(100,"Paging is currently ON\n");
199     return ;
200   }
201
202   SerialPrintLevel(100,"Paging is currently OFF - initializing the pages for a 1-1 map\n");
203   
204   numpages=bootInfo->memSizeKB / (PAGE_SIZE/1024);
205   numpagetables = numpages / NUM_PAGE_TABLE_ENTRIES + ((numpages % NUM_PAGE_TABLE_ENTRIES) != 0 );
206
207   SerialPrintLevel(100,"We need %d pages, and thus %d page tables, and one page directory\n",numpages, numpagetables);
208   
209   pd = (pde_t*)Alloc_Page();
210   
211   if (!pd) { 
212     SerialPrintLevel(100,"We are giving up since we can't allocate a page directory!\n");
213     return;
214   } else {
215     SerialPrintLevel(100,"Our PDE is at physical address %p\n",pd);
216   }
217   
218   for (i=0;i<NUM_PAGE_DIR_ENTRIES;i++) { 
219     if (i>=numpagetables) { 
220       pd[i].present=0;
221       pd[i].flags=0;
222       pd[i].accessed=0;
223       pd[i].reserved=0;
224       pd[i].largePages=0;
225       pd[i].globalPage=0;
226       pd[i].kernelInfo=0;
227       pd[i].pageTableBaseAddr=0;
228     } else {
229       pt = (pte_t*)Alloc_Page();
230       if (!pt) { 
231         SerialPrintLevel(100,"We are giving up since we can't allocate page table %d\n",i);
232       } else {
233         //SerialPrintLevel(100,"Page Table %d is at physical address %p\n",i,pt);
234       }
235       pd[i].present=1;
236       pd[i].flags= VM_READ | VM_WRITE | VM_EXEC | VM_USER;
237       pd[i].accessed=0;
238       pd[i].reserved=0;
239       pd[i].largePages=0;
240       pd[i].globalPage=0;
241       pd[i].kernelInfo=0;
242       pd[i].pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
243       
244       for (j=0;j<NUM_PAGE_TABLE_ENTRIES;j++) { 
245         if (i*NUM_PAGE_TABLE_ENTRIES + j >= numpages) {
246           pt[j].present=0;
247           pt[j].flags=0;
248           pt[j].accessed=0;
249           pt[j].dirty=0;
250           pt[j].pteAttribute=0;
251           pt[j].globalPage=0;
252           pt[j].kernelInfo=0;
253           pt[j].pageBaseAddr=0;
254         } else {
255           pt[j].present=1;
256           pt[j].flags=VM_READ | VM_WRITE | VM_EXEC | VM_USER;
257           pt[j].accessed=0;
258           pt[j].dirty=0;
259           pt[j].pteAttribute=0;
260           pt[j].globalPage=0;
261           pt[j].kernelInfo=0;
262           pt[j].pageBaseAddr=(i*NUM_PAGE_TABLE_ENTRIES + j);
263         }
264       }
265     }
266   }
267   SerialPrintLevel(100,"Done creating 1<->1 initial page tables\n");
268   SerialPrintLevel(100,"Now installing page fault handler\n");
269   //  SerialDumpPageTables(pd);
270   Install_Interrupt_Handler(14,Page_Fault_Handler);
271   SerialPrintLevel(100,"Now turning on the paging bit!\n");
272   Enable_Paging(pd);
273   SerialPrintLevel(100,"We are still alive after paging turned on!\n");
274   SerialPrintLevel(100,"checkPaging returns %d\n",checkPaging());
275 }
276
277
278 //
279 pte_t *LookupPage(void *vaddr)
280 {
281   uint_t pde_offset = ((uint_t)vaddr) >> 22;
282   uint_t pte_offset = (((uint_t)vaddr) >> 12) & 0x3ff;
283   pte_t *pte; 
284   pde_t *pde = Get_PDBR();
285
286   KASSERT(pde);
287
288   pde+=pde_offset;
289
290   if (!(pde->present)) { 
291     return 0;
292   }
293
294   pte = (pte_t *)((pde->pageTableBaseAddr)<<12);
295
296   pte+=pte_offset;
297
298   return pte;
299 }
300
301
302 pte_t *CreateAndAddPageTable(void *vaddr, uint_t flags)
303 {
304   int i;
305
306   KASSERT(!(PAGE_OFFSET(vaddr)));
307   
308   pte_t *pt = Alloc_Page();
309   
310   KASSERT(pt);
311   
312   for (i=0;i<NUM_PAGE_TABLE_ENTRIES;i++) { 
313     pt[i].present=0;
314   }
315
316   pde_t *pde = Get_PDBR();
317   
318   pde=&(pde[PAGE_DIRECTORY_INDEX(vaddr)]);
319
320   KASSERT(!(pde->present));
321   
322   pde->present=1;
323   pde->flags=flags;
324   pde->accessed=0;
325   pde->reserved=0;
326   pde->largePages=0;
327   pde->globalPage=0;
328   pde->kernelInfo=0;
329   pde->pageTableBaseAddr = PAGE_ALLIGNED_ADDR(pt);
330
331   return pt;
332 }
333
334 pte_t *MapPage(void *vaddr, pte_t *pte, int alloc_pde)
335 {
336   pte_t *oldpte = LookupPage(vaddr);
337
338   if (!pte) {
339     if (alloc_pde) { 
340       CreateAndAddPageTable(vaddr,pte->flags);
341       oldpte = LookupPage(vaddr);
342       KASSERT(pte);
343     } else {
344       return 0;
345     }
346   }
347
348   *oldpte = *pte;
349   
350   return oldpte;
351 }
352
353 pte_t *UnMapPage(void *vaddr)
354 {
355   pte_t *oldpte = LookupPage(vaddr);
356
357   if (!oldpte) {
358     return 0;
359   }
360   oldpte->present=0;
361   
362   return oldpte;
363 }
364
365   
366
367 /**
368  * Initialize paging file data structures.
369  * All filesystems should be mounted before this function
370  * is called, to ensure that the paging file is available.
371  */
372 void Init_Paging(void)
373 {
374   PrintBoth("Initializing Paging\n");
375 }
376
377 /**
378  * Find a free bit of disk on the paging file for this page.
379  * Interrupts must be disabled.
380  * @return index of free page sized chunk of disk space in
381  *   the paging file, or -1 if the paging file is full
382  */
383 int Find_Space_On_Paging_File(void)
384 {
385     KASSERT(!Interrupts_Enabled());
386     TODO("Find free page in paging file");
387 }
388
389 /**
390  * Free a page-sized chunk of disk space in the paging file.
391  * Interrupts must be disabled.
392  * @param pagefileIndex index of the chunk of disk space
393  */
394 void Free_Space_On_Paging_File(int pagefileIndex)
395 {
396     KASSERT(!Interrupts_Enabled());
397     TODO("Free page in paging file");
398 }
399
400 /**
401  * Write the contents of given page to the indicated block
402  * of space in the paging file.
403  * @param paddr a pointer to the physical memory of the page
404  * @param vaddr virtual address where page is mapped in user memory
405  * @param pagefileIndex the index of the page sized chunk of space
406  *   in the paging file
407  */
408 void Write_To_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
409 {
410     struct Page *page = Get_Page((ulong_t) paddr);
411     KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */
412     TODO("Write page data to paging file");
413 }
414
415 /**
416  * Read the contents of the indicated block
417  * of space in the paging file into the given page.
418  * @param paddr a pointer to the physical memory of the page
419  * @param vaddr virtual address where page will be re-mapped in
420  *   user memory
421  * @param pagefileIndex the index of the page sized chunk of space
422  *   in the paging file
423  */
424 void Read_From_Paging_File(void *paddr, ulong_t vaddr, int pagefileIndex)
425 {
426     struct Page *page = Get_Page((ulong_t) paddr);
427     KASSERT(!(page->flags & PAGE_PAGEABLE)); /* Page must be locked! */
428     TODO("Read page data from paging file");
429 }
430