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.


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