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] / palacios / src / palacios / vmm_paging.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm_paging.h>
21
22 #include <palacios/vmm.h>
23
24 #include <palacios/vm_guest_mem.h>
25
26
27
28
29   
30
31
32 void delete_page_tables_pde32(pde32_t * pde) {
33   int i;//, j;
34
35   if (pde == NULL) { 
36     return;
37   }
38
39   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) {
40     if (pde[i].present) {
41       // We double cast, first to an addr_t to handle 64 bit issues, then to the pointer
42       PrintDebug("PTE base addr %x \n", pde[i].pt_base_addr);
43       pte32_t * pte = (pte32_t *)((addr_t)(uint_t)(pde[i].pt_base_addr << PAGE_POWER));
44
45       /*
46         for (j = 0; (j < MAX_PTE32_ENTRIES); j++) {
47         if ((pte[j].present)) {
48         os_hooks->free_page((void *)(pte[j].page_base_addr << PAGE_POWER));
49         }
50         }
51       */
52       PrintDebug("Deleting PTE %d (%p)\n", i, pte);
53       V3_FreePage(pte);
54     }
55   }
56
57   PrintDebug("Deleting PDE (%p)\n", pde);
58   V3_FreePage(V3_PAddr(pde));
59 }
60
61
62
63
64
65 int pt32_lookup(pde32_t * pd, addr_t vaddr, addr_t * paddr) {
66   addr_t pde_entry;
67   pde32_entry_type_t pde_entry_type;
68
69   if (pd == 0) {
70     return -1;
71   }
72
73   pde_entry_type = pde32_lookup(pd, vaddr, &pde_entry);
74
75   if (pde_entry_type == PDE32_ENTRY_PTE32) {
76     return pte32_lookup((pte32_t *)pde_entry, vaddr, paddr);
77   } else if (pde_entry_type == PDE32_ENTRY_LARGE_PAGE) {
78     *paddr = pde_entry;
79     return 0;
80   }
81
82   return -1;
83 }
84
85
86
87 /* We can't do a full lookup because we don't know what context the page tables are in...
88  * The entry addresses could be pointing to either guest physical memory or host physical memory
89  * Instead we just return the entry address, and a flag to show if it points to a pte or a large page...
90  */
91 pde32_entry_type_t pde32_lookup(pde32_t * pd, addr_t addr, addr_t * entry) {
92   pde32_t * pde_entry = &(pd[PDE32_INDEX(addr)]);
93
94   if (!pde_entry->present) {
95     *entry = 0;
96     return PDE32_ENTRY_NOT_PRESENT;
97   } else  {
98
99     if (pde_entry->large_page) {
100       pde32_4MB_t * large_pde = (pde32_4MB_t *)pde_entry;
101
102       *entry = PDE32_4MB_T_ADDR(*large_pde);
103       *entry += PD32_4MB_PAGE_OFFSET(addr);
104       return PDE32_ENTRY_LARGE_PAGE;
105     } else {
106       *entry = PDE32_T_ADDR(*pde_entry);
107       return PDE32_ENTRY_PTE32;
108     }
109   }  
110   return PDE32_ENTRY_NOT_PRESENT;
111 }
112
113
114
115 /* Takes a virtual addr (addr) and returns the physical addr (entry) as defined in the page table
116  */
117 int pte32_lookup(pte32_t * pt, addr_t addr, addr_t * entry) {
118   pte32_t * pte_entry = &(pt[PTE32_INDEX(addr)]);
119
120   if (!pte_entry->present) {
121     *entry = 0;
122     PrintDebug("Lookup at non present page (index=%d)\n", PTE32_INDEX(addr));
123     return -1;
124   } else {
125     *entry = PTE32_T_ADDR(*pte_entry) + PT32_PAGE_OFFSET(addr);
126     return 0;
127   }
128
129   return -1;
130 }
131
132
133
134 pt_access_status_t can_access_pde32(pde32_t * pde, addr_t addr, pf_error_t access_type) {
135   pde32_t * entry = &pde[PDE32_INDEX(addr)];
136
137   if (entry->present == 0) {
138     return PT_ENTRY_NOT_PRESENT;
139   } else if ((entry->writable == 0) && (access_type.write == 1)) {
140     return PT_WRITE_ERROR;
141   } else if ((entry->user_page == 0) && (access_type.user == 1)) {
142     // Check CR0.WP?
143     return PT_USER_ERROR;
144   }
145
146   return PT_ACCESS_OK;
147 }
148
149
150 pt_access_status_t can_access_pte32(pte32_t * pte, addr_t addr, pf_error_t access_type) {
151   pte32_t * entry = &pte[PTE32_INDEX(addr)];
152
153   if (entry->present == 0) {
154     return PT_ENTRY_NOT_PRESENT;
155   } else if ((entry->writable == 0) && (access_type.write == 1)) {
156     return PT_WRITE_ERROR;
157   } else if ((entry->user_page == 0) && (access_type.user == 1)) {
158     // Check CR0.WP?
159     return PT_USER_ERROR;
160   }
161
162   return PT_ACCESS_OK;
163 }
164
165
166
167
168 /* We generate a page table to correspond to a given memory layout
169  * pulling pages from the mem_list when necessary
170  * If there are any gaps in the layout, we add them as unmapped pages
171  */
172 pde32_t * create_passthrough_pts_32(struct guest_info * guest_info) {
173   addr_t current_page_addr = 0;
174   int i, j;
175   struct shadow_map * map = &(guest_info->mem_map);
176
177   pde32_t * pde = V3_VAddr(V3_AllocPages(1));
178
179   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
180     int pte_present = 0;
181     pte32_t * pte = V3_VAddr(V3_AllocPages(1));
182     
183
184     for (j = 0; j < MAX_PTE32_ENTRIES; j++) {
185       struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr);
186
187       if (!region || 
188           (region->host_type == HOST_REGION_HOOK) || 
189           (region->host_type == HOST_REGION_UNALLOCATED) || 
190           (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || 
191           (region->host_type == HOST_REGION_REMOTE) ||
192           (region->host_type == HOST_REGION_SWAPPED)) {
193         pte[j].present = 0;
194         pte[j].writable = 0;
195         pte[j].user_page = 0;
196         pte[j].write_through = 0;
197         pte[j].cache_disable = 0;
198         pte[j].accessed = 0;
199         pte[j].dirty = 0;
200         pte[j].pte_attr = 0;
201         pte[j].global_page = 0;
202         pte[j].vmm_info = 0;
203         pte[j].page_base_addr = 0;
204       } else {
205         addr_t host_addr;
206         pte[j].present = 1;
207         pte[j].writable = 1;
208         pte[j].user_page = 1;
209         pte[j].write_through = 0;
210         pte[j].cache_disable = 0;
211         pte[j].accessed = 0;
212         pte[j].dirty = 0;
213         pte[j].pte_attr = 0;
214         pte[j].global_page = 0;
215         pte[j].vmm_info = 0;
216
217         if (guest_pa_to_host_pa(guest_info, current_page_addr, &host_addr) == -1) {
218           // BIG ERROR
219           // PANIC
220           return NULL;
221         }
222         
223         pte[j].page_base_addr = host_addr >> 12;
224         
225         pte_present = 1;
226       }
227
228       current_page_addr += PAGE_SIZE;
229     }
230
231     if (pte_present == 0) { 
232       V3_FreePage(V3_PAddr(pte));
233
234       pde[i].present = 0;
235       pde[i].writable = 0;
236       pde[i].user_page = 0;
237       pde[i].write_through = 0;
238       pde[i].cache_disable = 0;
239       pde[i].accessed = 0;
240       pde[i].reserved = 0;
241       pde[i].large_page = 0;
242       pde[i].global_page = 0;
243       pde[i].vmm_info = 0;
244       pde[i].pt_base_addr = 0;
245     } else {
246       pde[i].present = 1;
247       pde[i].writable = 1;
248       pde[i].user_page = 1;
249       pde[i].write_through = 0;
250       pde[i].cache_disable = 0;
251       pde[i].accessed = 0;
252       pde[i].reserved = 0;
253       pde[i].large_page = 0;
254       pde[i].global_page = 0;
255       pde[i].vmm_info = 0;
256       pde[i].pt_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pte));
257     }
258
259   }
260
261   return pde;
262 }
263
264
265
266
267 pml4e64_t * create_passthrough_pts_64(struct guest_info * info) {
268   addr_t current_page_addr = 0;
269   int i, j, k, m;
270   struct shadow_map * map = &(info->mem_map);
271   
272   pml4e64_t * pml = V3_VAddr(V3_AllocPages(1));
273
274   for (i = 0; i < 1; i++) {
275     int pdpe_present = 0;
276     pdpe64_t * pdpe = V3_VAddr(V3_AllocPages(1));
277
278     for (j = 0; j < 1; j++) {
279       int pde_present = 0;
280       pde64_t * pde = V3_VAddr(V3_AllocPages(1));
281
282       for (k = 0; k < MAX_PDE64_ENTRIES; k++) {
283         int pte_present = 0;
284         pte64_t * pte = V3_VAddr(V3_AllocPages(1));
285
286
287         for (m = 0; m < MAX_PTE64_ENTRIES; m++) {
288           struct shadow_region * region = get_shadow_region_by_addr(map, current_page_addr);
289           
290
291           
292           if (!region || 
293               (region->host_type == HOST_REGION_HOOK) || 
294               (region->host_type == HOST_REGION_UNALLOCATED) || 
295               (region->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) || 
296               (region->host_type == HOST_REGION_REMOTE) ||
297               (region->host_type == HOST_REGION_SWAPPED)) {
298             pte[m].present = 0;
299             pte[m].writable = 0;
300             pte[m].user_page = 0;
301             pte[m].write_through = 0;
302             pte[m].cache_disable = 0;
303             pte[m].accessed = 0;
304             pte[m].dirty = 0;
305             pte[m].pte_attr = 0;
306             pte[m].global_page = 0;
307             pte[m].vmm_info = 0;
308             pte[m].page_base_addr = 0;
309           } else {
310             addr_t host_addr;
311             pte[m].present = 1;
312             pte[m].writable = 1;
313             pte[m].user_page = 1;
314             pte[m].write_through = 0;
315             pte[m].cache_disable = 0;
316             pte[m].accessed = 0;
317             pte[m].dirty = 0;
318             pte[m].pte_attr = 0;
319             pte[m].global_page = 0;
320             pte[m].vmm_info = 0;
321             
322             if (guest_pa_to_host_pa(info, current_page_addr, &host_addr) == -1) {
323               // BIG ERROR
324               // PANIC
325               return NULL;
326             }
327
328             pte[m].page_base_addr = PTE64_BASE_ADDR(host_addr);
329
330             //PrintPTE64(current_page_addr, &(pte[m]));
331
332             pte_present = 1;      
333           }
334
335
336
337
338           current_page_addr += PAGE_SIZE;
339         }
340         
341         if (pte_present == 0) {
342           V3_FreePage(V3_PAddr(pte));
343
344           pde[k].present = 0;
345           pde[k].writable = 0;
346           pde[k].user_page = 0;
347           pde[k].write_through = 0;
348           pde[k].cache_disable = 0;
349           pde[k].accessed = 0;
350           pde[k].reserved = 0;
351           pde[k].large_page = 0;
352           //pde[k].global_page = 0;
353           pde[k].vmm_info = 0;
354           pde[k].pt_base_addr = 0;
355         } else {
356           pde[k].present = 1;
357           pde[k].writable = 1;
358           pde[k].user_page = 1;
359           pde[k].write_through = 0;
360           pde[k].cache_disable = 0;
361           pde[k].accessed = 0;
362           pde[k].reserved = 0;
363           pde[k].large_page = 0;
364           //pde[k].global_page = 0;
365           pde[k].vmm_info = 0;
366           pde[k].pt_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pte));
367
368           pde_present = 1;
369         }
370       }
371
372       if (pde_present == 0) {
373         V3_FreePage(V3_PAddr(pde));
374         
375         pdpe[j].present = 0;
376         pdpe[j].writable = 0;
377         pdpe[j].user_page = 0;
378         pdpe[j].write_through = 0;
379         pdpe[j].cache_disable = 0;
380         pdpe[j].accessed = 0;
381         pdpe[j].reserved = 0;
382         pdpe[j].large_page = 0;
383         //pdpe[j].global_page = 0;
384         pdpe[j].vmm_info = 0;
385         pdpe[j].pd_base_addr = 0;
386       } else {
387         pdpe[j].present = 1;
388         pdpe[j].writable = 1;
389         pdpe[j].user_page = 1;
390         pdpe[j].write_through = 0;
391         pdpe[j].cache_disable = 0;
392         pdpe[j].accessed = 0;
393         pdpe[j].reserved = 0;
394         pdpe[j].large_page = 0;
395         //pdpe[j].global_page = 0;
396         pdpe[j].vmm_info = 0;
397         pdpe[j].pd_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pde));
398
399
400         pdpe_present = 1;
401       }
402
403     }
404
405     PrintDebug("PML index=%d\n", i);
406
407     if (pdpe_present == 0) {
408       V3_FreePage(V3_PAddr(pdpe));
409       
410       pml[i].present = 0;
411       pml[i].writable = 0;
412       pml[i].user_page = 0;
413       pml[i].write_through = 0;
414       pml[i].cache_disable = 0;
415       pml[i].accessed = 0;
416       pml[i].reserved = 0;
417       //pml[i].large_page = 0;
418       //pml[i].global_page = 0;
419       pml[i].vmm_info = 0;
420       pml[i].pdp_base_addr = 0;
421     } else {
422       pml[i].present = 1;
423       pml[i].writable = 1;
424       pml[i].user_page = 1;
425       pml[i].write_through = 0;
426       pml[i].cache_disable = 0;
427       pml[i].accessed = 0;
428       pml[i].reserved = 0;
429       //pml[i].large_page = 0;
430       //pml[i].global_page = 0;
431       pml[i].vmm_info = 0;
432       pml[i].pdp_base_addr = PAGE_ALIGNED_ADDR((addr_t)V3_PAddr(pdpe));
433     }
434   }
435
436   return pml;
437 }
438
439
440
441
442
443 void PrintPDE32(addr_t virtual_address, pde32_t * pde)
444 {
445   PrintDebug("PDE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
446              (void *)virtual_address,
447              (void *)(addr_t) (pde->pt_base_addr << PAGE_POWER),
448              pde->present,
449              pde->writable,
450              pde->user_page, 
451              pde->write_through,
452              pde->cache_disable,
453              pde->accessed,
454              pde->reserved,
455              pde->large_page,
456              pde->global_page,
457              pde->vmm_info);
458 }
459
460   
461 void PrintPTE32(addr_t virtual_address, pte32_t * pte)
462 {
463   PrintDebug("PTE %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
464              (void *)virtual_address,
465              (void*)(addr_t)(pte->page_base_addr << PAGE_POWER),
466              pte->present,
467              pte->writable,
468              pte->user_page,
469              pte->write_through,
470              pte->cache_disable,
471              pte->accessed,
472              pte->dirty,
473              pte->pte_attr,
474              pte->global_page,
475              pte->vmm_info);
476 }
477
478
479 void PrintPDE64(addr_t virtual_address, pde64_t * pde)
480 {
481   PrintDebug("PDE64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, reserved=%x, largePages=%x, globalPage=%x, kernelInfo=%x\n",
482              (void *)virtual_address,
483              (void *)(addr_t) (pde->pt_base_addr << PAGE_POWER),
484              pde->present,
485              pde->writable,
486              pde->user_page, 
487              pde->write_through,
488              pde->cache_disable,
489              pde->accessed,
490              pde->reserved,
491              pde->large_page,
492              0,//pde->global_page,
493              pde->vmm_info);
494 }
495
496   
497 void PrintPTE64(addr_t virtual_address, pte64_t * pte)
498 {
499   PrintDebug("PTE64 %p -> %p : present=%x, writable=%x, user=%x, wt=%x, cd=%x, accessed=%x, dirty=%x, pteAttribute=%x, globalPage=%x, vmm_info=%x\n",
500              (void *)virtual_address,
501              (void*)(addr_t)(pte->page_base_addr << PAGE_POWER),
502              pte->present,
503              pte->writable,
504              pte->user_page,
505              pte->write_through,
506              pte->cache_disable,
507              pte->accessed,
508              pte->dirty,
509              pte->pte_attr,
510              pte->global_page,
511              pte->vmm_info);
512 }
513
514   
515
516
517
518
519 void PrintPD32(pde32_t * pde)
520 {
521   int i;
522
523   PrintDebug("Page Directory at %p:\n", pde);
524   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) { 
525     if ( pde[i].present) {
526       PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
527     }
528   }
529 }
530
531 void PrintPT32(addr_t starting_address, pte32_t * pte) 
532 {
533   int i;
534
535   PrintDebug("Page Table at %p:\n", pte);
536   for (i = 0; (i < MAX_PTE32_ENTRIES) ; i++) { 
537     if (pte[i].present) {
538       PrintPTE32(starting_address + (PAGE_SIZE * i), &(pte[i]));
539     }
540   }
541 }
542
543
544
545
546
547 void PrintDebugPageTables(pde32_t * pde)
548 {
549   int i;
550   
551   PrintDebug("Dumping the pages starting with the pde page at %p\n", pde);
552
553   for (i = 0; (i < MAX_PDE32_ENTRIES); i++) { 
554     if (pde[i].present) {
555       PrintPDE32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), &(pde[i]));
556       PrintPT32((addr_t)(PAGE_SIZE * MAX_PTE32_ENTRIES * i), (pte32_t *)V3_VAddr((void *)(addr_t)(pde[i].pt_base_addr << PAGE_POWER)));
557     }
558   }
559 }
560