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.


added lookup functions for all page table forms,
[palacios.git] / palacios / src / palacios / vmm_shadow_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
21 #include <palacios/vmm_shadow_paging.h>
22
23
24 #include <palacios/vmm.h>
25 #include <palacios/vm_guest_mem.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vmm_ctrl_regs.h>
28
29 #ifndef DEBUG_SHADOW_PAGING
30 #undef PrintDebug
31 #define PrintDebug(fmt, args...)
32 #endif
33
34
35 /*** 
36  ***  There be dragons
37  ***/
38
39
40
41
42
43 DEFINE_HASHTABLE_INSERT(add_cr3_to_cache, addr_t, struct hashtable *);
44 DEFINE_HASHTABLE_SEARCH(find_cr3_in_cache, addr_t, struct hashtable *);
45 DEFINE_HASHTABLE_REMOVE(del_cr3_from_cache, addr_t, struct hashtable *, 0);
46
47
48 DEFINE_HASHTABLE_INSERT(add_pte_map, addr_t, addr_t);
49 DEFINE_HASHTABLE_SEARCH(find_pte_map, addr_t, addr_t);
50 DEFINE_HASHTABLE_REMOVE(del_pte_map, addr_t, addr_t, 0);
51
52
53
54 static uint_t pte_hash_fn(addr_t key) {
55   return hash_long(key, 32);
56 }
57
58 static int pte_equals(addr_t key1, addr_t key2) {
59   return (key1 == key2);
60 }
61
62 static uint_t cr3_hash_fn(addr_t key) {
63   return hash_long(key, 32);
64 }
65
66 static int cr3_equals(addr_t key1, addr_t key2) {
67   return (key1 == key2);
68 }
69
70
71
72 static int activate_shadow_pt_32(struct guest_info * info);
73 static int activate_shadow_pt_32pae(struct guest_info * info);
74 static int activate_shadow_pt_64(struct guest_info * info);
75
76
77 static int handle_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
78 static int handle_shadow_pagefault_32pae(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
79 static int handle_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
80
81 int v3_init_shadow_page_state(struct guest_info * info) {
82   struct shadow_page_state * state = &(info->shdw_pg_state);
83   
84   state->guest_cr3 = 0;
85   state->guest_cr0 = 0;
86
87   state->cr3_cache = create_hashtable(0, &cr3_hash_fn, &cr3_equals);
88
89   state->cached_cr3 = 0;
90   state->cached_ptes = NULL;
91
92   return 0;
93 }
94
95
96
97
98 /*
99  For now we'll do something a little more lightweight
100 int cache_page_tables32(struct guest_info * info, addr_t pde) {
101   struct shadow_page_state * state = &(info->shdw_pg_state);
102   addr_t pde_host_addr;
103   pde32_t * tmp_pde;
104   struct hashtable * pte_cache = NULL;
105   int i = 0;
106
107
108   pte_cache = (struct hashtable *)find_cr3_in_cache(state->cr3_cache, pde);
109   if (pte_cache != NULL) {
110     PrintError("CR3 already present in cache\n");
111     state->current_ptes = pte_cache;
112     return 1;
113   } else {
114     PrintError("Creating new CR3 cache entry\n");
115     pte_cache = create_hashtable(0, &pte_hash_fn, &pte_equals);
116     state->current_ptes = pte_cache;
117     add_cr3_to_cache(state->cr3_cache, pde, pte_cache);
118   }
119
120   if (guest_pa_to_host_va(info, pde, &pde_host_addr) == -1) {
121     PrintError("Could not lookup host address of guest PDE\n");
122     return -1;
123   }
124
125   tmp_pde = (pde32_t *)pde_host_addr;
126
127   add_pte_map(pte_cache, pde, pde_host_addr);
128
129
130   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
131     if ((tmp_pde[i].present) && (tmp_pde[i].large_page == 0)) {
132       addr_t pte_host_addr;
133
134       if (guest_pa_to_host_va(info, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), &pte_host_addr) == -1) {
135         PrintError("Could not lookup host address of guest PDE\n");
136         return -1;
137       }
138
139       add_pte_map(pte_cache, (addr_t)(PDE32_T_ADDR(tmp_pde[i])), pte_host_addr); 
140     }
141   }
142
143
144   return 0;
145 }
146 */
147
148
149 int v3_cache_page_tables(struct guest_info * info, addr_t cr3) {
150   switch(v3_get_cpu_mode(info)) {
151   case PROTECTED:
152     return v3_cache_page_tables32(info, CR3_TO_PDE32_PA(cr3));
153   default:
154     return -1;
155   }
156 }
157
158 int v3_cache_page_tables32(struct guest_info * info, addr_t pde) {
159   struct shadow_page_state * state = &(info->shdw_pg_state);
160   addr_t pde_host_addr;
161   pde32_t * tmp_pde;
162   struct hashtable * pte_cache = NULL;
163   int i = 0;
164
165   if (pde == state->cached_cr3) {
166     return 1;
167   }
168
169   if (state->cached_ptes != NULL) {
170     hashtable_destroy(state->cached_ptes, 0, 0);
171     state->cached_ptes = NULL;
172   }
173
174   state->cached_cr3 = pde;
175
176   pte_cache = create_hashtable(0, &pte_hash_fn, &pte_equals);
177   state->cached_ptes = pte_cache;
178
179   if (guest_pa_to_host_va(info, pde, &pde_host_addr) == -1) {
180     PrintError("Could not lookup host address of guest PDE\n");
181     return -1;
182   }
183
184   tmp_pde = (pde32_t *)pde_host_addr;
185
186   add_pte_map(pte_cache, pde, pde_host_addr);
187
188
189   for (i = 0; i < MAX_PDE32_ENTRIES; i++) {
190     if ((tmp_pde[i].present) && (tmp_pde[i].large_page == 0)) {
191       addr_t pte_host_addr;
192
193       if (guest_pa_to_host_va(info, (addr_t)(BASE_TO_PAGE_ADDR(tmp_pde[i].pt_base_addr)), &pte_host_addr) == -1) {
194         PrintError("Could not lookup host address of guest PDE\n");
195         return -1;
196       }
197
198       add_pte_map(pte_cache, (addr_t)(BASE_TO_PAGE_ADDR(tmp_pde[i].pt_base_addr)), pte_host_addr); 
199     }
200   }
201
202   return 0;
203
204 }
205
206
207
208 int v3_replace_shdw_page32(struct guest_info * info, addr_t location, pte32_t * new_page, pte32_t * old_page) {
209   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
210   pde32_t * shadow_pde =  (pde32_t *)&(shadow_pd[PDE32_INDEX(location)]);
211
212   if (shadow_pde->large_page == 0) {
213     pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr);
214     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(location)]);
215
216     //if (shadow_pte->present == 1) {
217     *(uint_t *)old_page = *(uint_t *)shadow_pte;
218     //}
219
220     *(uint_t *)shadow_pte = *(uint_t *)new_page;
221
222   } else {
223     // currently unhandled
224     return -1;
225   }
226   
227   return 0;
228 }
229
230
231
232
233
234 // We assume that shdw_pg_state.guest_cr3 is pointing to the page tables we want to activate
235 // We also assume that the CPU mode has not changed during this page table transition
236 static int activate_shadow_pt_32(struct guest_info * info) {
237     struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(info->ctrl_regs.cr3);
238     struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(info->shdw_pg_state.guest_cr3);
239     int cached = 0;
240
241     // Check if shadow page tables are in the cache
242     cached = v3_cache_page_tables32(info, CR3_TO_PDE32_PA(*(addr_t *)guest_cr3));
243     
244     if (cached == -1) {
245       PrintError("CR3 Cache failed\n");
246       return -1;
247     } else if (cached == 0) {
248       addr_t shadow_pt;
249       
250       PrintDebug("New CR3 is different - flushing shadow page table %p\n", shadow_cr3 );
251       delete_page_tables_32(CR3_TO_PDE32_VA(*(uint_t*)shadow_cr3));
252       
253       shadow_pt = v3_create_new_shadow_pt();
254       
255       shadow_cr3->pdt_base_addr = (addr_t)V3_PAddr((void *)(addr_t)PAGE_BASE_ADDR(shadow_pt));
256       PrintDebug( "Created new shadow page table %p\n", (void *)(addr_t)shadow_cr3->pdt_base_addr );
257     } else {
258       PrintDebug("Reusing cached shadow Page table\n");
259     }
260    
261     shadow_cr3->pwt = guest_cr3->pwt;
262     shadow_cr3->pcd = guest_cr3->pcd;
263
264     return 0;
265 }
266
267 static int activate_shadow_pt_32pae(struct guest_info * info) {
268   PrintError("Activating 32 bit PAE page tables not implemented\n");
269   return -1;
270 }
271
272 static int activate_shadow_pt_64(struct guest_info * info) {
273   PrintError("Activating 64 bit page tables not implemented\n");
274   return -1;
275 }
276
277
278 // Reads the guest CR3 register
279 // creates new shadow page tables
280 // updates the shadow CR3 register to point to the new pts
281 int v3_activate_shadow_pt(struct guest_info * info) {
282   switch (info->cpu_mode) {
283
284   case PROTECTED:
285     return activate_shadow_pt_32(info);
286   case PROTECTED_PAE:
287     return activate_shadow_pt_32pae(info);
288   case LONG:
289   case LONG_32_COMPAT:
290   case LONG_16_COMPAT:
291     return activate_shadow_pt_64(info);
292   default:
293     PrintError("Invalid CPU mode: %d\n", info->cpu_mode);
294     return -1;
295   }
296
297   return 0;
298 }
299
300
301 int v3_activate_passthrough_pt(struct guest_info * info) {
302   // For now... But we need to change this....
303   // As soon as shadow paging becomes active the passthrough tables are hosed
304   // So this will cause chaos if it is called at that time
305
306   info->ctrl_regs.cr3 = *(addr_t*)&(info->direct_map_pt);
307   //PrintError("Activate Passthrough Page tables not implemented\n");
308   return 0;
309 }
310
311
312
313 int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
314   
315   if (info->mem_mode == PHYSICAL_MEM) {
316     // If paging is not turned on we need to handle the special cases
317
318 #ifdef DEBUG_SHADOW_PAGING
319     PrintPageTree(info->cpu_mode, fault_addr, info->ctrl_regs.cr3);
320 #endif
321
322     return handle_special_page_fault(info, fault_addr, fault_addr, error_code);
323   } else if (info->mem_mode == VIRTUAL_MEM) {
324
325     switch (info->cpu_mode) {
326     case PROTECTED:
327       return handle_shadow_pagefault_32(info, fault_addr, error_code);
328       break;
329     case PROTECTED_PAE:
330       return handle_shadow_pagefault_32pae(info, fault_addr, error_code);
331     case LONG:
332       return handle_shadow_pagefault_64(info, fault_addr, error_code);
333       break;
334     default:
335       PrintError("Unhandled CPU Mode\n");
336       return -1;
337     }
338   } else {
339     PrintError("Invalid Memory mode\n");
340     return -1;
341   }
342 }
343
344 addr_t v3_create_new_shadow_pt() {
345   void * host_pde = 0;
346
347   host_pde = V3_VAddr(V3_AllocPages(1));
348   memset(host_pde, 0, PAGE_SIZE);
349
350   return (addr_t)host_pde;
351 }
352
353
354 static void inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
355   info->ctrl_regs.cr2 = fault_addr;
356   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
357 }
358
359
360 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
361   /* basically the reasoning is that there can be multiple reasons for a page fault:
362      If there is a permissions failure for a page present in the guest _BUT_ 
363      the reason for the fault was that the page is not present in the shadow, 
364      _THEN_ we have to map the shadow page in and reexecute, this will generate 
365      a permissions fault which is _THEN_ valid to send to the guest
366      _UNLESS_ both the guest and shadow have marked the page as not present
367
368      whew...
369   */
370   if (guest_access != PT_ACCESS_OK) {
371     // Guest Access Error
372     
373     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
374         (guest_access != PT_ACCESS_NOT_PRESENT)) {
375       // aka (guest permission error)
376       return 1;
377     }
378
379     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
380         (guest_access == PT_ACCESS_NOT_PRESENT)) {      
381       // Page tables completely blank, handle guest first
382       return 1;
383     }
384
385     // Otherwise we'll handle the guest fault later...?
386   }
387
388   return 0;
389 }
390
391
392
393
394 /* 
395  * *
396  * * 
397  * * 64 bit Page table fault handlers
398  * *
399  * *
400  */
401
402 static int handle_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
403   PrintError("64 bit shadow paging not implemented\n");
404   return -1;
405 }
406
407
408 /* 
409  * *
410  * * 
411  * * 32 bit PAE  Page table fault handlers
412  * *
413  * *
414  */
415
416 static int handle_shadow_pagefault_32pae(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
417   PrintError("32 bit PAE shadow paging not implemented\n");
418   return -1;
419 }
420
421
422
423
424
425
426
427 /* 
428  * *
429  * * 
430  * * 32 bit Page table fault handlers
431  * *
432  * *
433  */
434 static int handle_large_pagefault_32(struct guest_info * info, 
435                                     addr_t fault_addr, pf_error_t error_code, 
436                                      pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde);
437
438 static int handle_shadow_pte32_fault(struct guest_info * info, 
439                                      addr_t fault_addr, 
440                                      pf_error_t error_code,
441                                      pte32_t * shadow_pt, 
442                                      pte32_t * guest_pt);
443
444
445 static int handle_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
446   pde32_t * guest_pd = NULL;
447   pde32_t * shadow_pd = CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
448   addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
449   pt_access_status_t guest_pde_access;
450   pt_access_status_t shadow_pde_access;
451   pde32_t * guest_pde = NULL;
452   pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
453
454   PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
455
456   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
457     PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
458     return -1;
459   } 
460
461   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
462
463
464   // Check the guest page permissions
465   guest_pde_access = can_access_pde32(guest_pd, fault_addr, error_code);
466
467   // Check the shadow page permissions
468   shadow_pde_access = can_access_pde32(shadow_pd, fault_addr, error_code);
469   
470   /* Was the page fault caused by the Guest's page tables? */
471   if (is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
472     PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", 
473                *(uint_t *)&guest_pde_access, *(uint_t *)&error_code);
474     inject_guest_pf(info, fault_addr, error_code);
475     return 0;
476   }
477
478   
479   if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) 
480     {
481       pte32_t * shadow_pt =  (pte32_t *)v3_create_new_shadow_pt();
482
483       shadow_pde->present = 1;
484       shadow_pde->user_page = guest_pde->user_page;
485       //    shadow_pde->large_page = guest_pde->large_page;
486       shadow_pde->large_page = 0;
487       
488
489       // VMM Specific options
490       shadow_pde->write_through = 0;
491       shadow_pde->cache_disable = 0;
492       shadow_pde->global_page = 0;
493       //
494       
495       guest_pde->accessed = 1;
496       
497       shadow_pde->pt_base_addr = PAGE_BASE_ADDR((addr_t)V3_PAddr(shadow_pt));
498       
499       if (guest_pde->large_page == 0) {
500         shadow_pde->writable = guest_pde->writable;
501       } else {
502         // ??  What if guest pde is dirty a this point?
503         ((pde32_4MB_t *)guest_pde)->dirty = 0;
504         shadow_pde->writable = 0;
505       }
506     }
507   else if (shadow_pde_access == PT_ACCESS_OK) 
508     {
509       //
510       // PTE fault
511       //
512       pte32_t * shadow_pt = (pte32_t *)V3_VAddr( (void*)(addr_t) BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr) );
513
514       if (guest_pde->large_page == 0) {
515         pte32_t * guest_pt = NULL;
516         if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
517           // Machine check the guest
518           PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
519           v3_raise_exception(info, MC_EXCEPTION);
520           return 0;
521         }
522         
523         if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
524           PrintError("Error handling Page fault caused by PTE\n");
525           return -1;
526         }
527       } else if (guest_pde->large_page == 1) {
528         if (handle_large_pagefault_32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
529           PrintError("Error handling large pagefault\n");
530           return -1;
531         }
532       }
533     }
534   else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
535            (guest_pde->large_page == 1) && 
536            (((pde32_4MB_t *)guest_pde)->dirty == 0)) 
537     {
538       //
539       // Page Directory Entry marked read-only
540       // Its a large page and we need to update the dirty bit in the guest
541       //
542
543       PrintDebug("Large page write error... Setting dirty bit and returning\n");
544       ((pde32_4MB_t *)guest_pde)->dirty = 1;
545       shadow_pde->writable = guest_pde->writable;
546       return 0;
547       
548     } 
549   else if (shadow_pde_access == PT_ACCESS_USER_ERROR) 
550     {
551       //
552       // Page Directory Entry marked non-user
553       //      
554       PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
555                  shadow_pde_access, guest_pde_access);
556       inject_guest_pf(info, fault_addr, error_code);
557       return 0;
558     }
559   else 
560     {
561       // inject page fault in guest
562       inject_guest_pf(info, fault_addr, error_code);
563       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
564       PrintDebug("Manual Says to inject page fault into guest\n");
565 #ifdef DEBUG_SHADOW_PAGING
566       PrintDebug("Guest PDE: (access=%d)\n\t", guest_pde_access);
567       PrintPDE32(fault_addr, guest_pde);
568       PrintDebug("Shadow PDE: (access=%d)\n\t", shadow_pde_access);
569       PrintPDE32(fault_addr, shadow_pde);
570 #endif
571
572       return 0; 
573     }
574
575   PrintDebug("Returning end of PDE function (rip=%p)\n", (void *)(addr_t)(info->rip));
576   return 0;
577 }
578
579
580
581 /* The guest status checks have already been done,
582  * only special case shadow checks remain
583  */
584 static int handle_large_pagefault_32(struct guest_info * info, 
585                                     addr_t fault_addr, pf_error_t error_code, 
586                                     pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
587 {
588   pt_access_status_t shadow_pte_access = can_access_pte32(shadow_pt, fault_addr, error_code);
589   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
590   
591   if (shadow_pte_access == PT_ACCESS_OK) {
592     // Inconsistent state...
593     // Guest Re-Entry will flush tables and everything should now workd
594     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
595     return 0;
596   }
597
598   
599   if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
600     // Get the guest physical address of the fault
601     addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);
602     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_fault_pa);
603  
604
605     if (host_page_type == HOST_REGION_INVALID) {
606       // Inject a machine check in the guest
607       PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
608       v3_raise_exception(info, MC_EXCEPTION);
609       return 0;
610     }
611
612     if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
613       struct shadow_page_state * state = &(info->shdw_pg_state);
614       addr_t shadow_pa = get_shadow_addr(info, guest_fault_pa);
615
616       shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
617
618       shadow_pte->present = 1;
619
620       /* We are assuming that the PDE entry has precedence
621        * so the Shadow PDE will mirror the guest PDE settings, 
622        * and we don't have to worry about them here
623        * Allow everything
624        */
625       shadow_pte->user_page = 1;
626
627       if (find_pte_map(state->cached_ptes, PAGE_ADDR(guest_fault_pa)) != NULL) {
628         // Check if the entry is a page table...
629         PrintDebug("Marking page as Guest Page Table (large page)\n");
630         shadow_pte->vmm_info = PT32_GUEST_PT;
631         shadow_pte->writable = 0;
632       } else {
633         shadow_pte->writable = 1;
634       }
635
636
637       //set according to VMM policy
638       shadow_pte->write_through = 0;
639       shadow_pte->cache_disable = 0;
640       shadow_pte->global_page = 0;
641       //
642       
643     } else {
644       // Handle hooked pages as well as other special pages
645       if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) {
646         PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
647         return -1;
648       }
649     }
650   } else if ((shadow_pte_access == PT_ACCESS_WRITE_ERROR) && 
651              (shadow_pte->vmm_info == PT32_GUEST_PT)) {
652
653     struct shadow_page_state * state = &(info->shdw_pg_state);
654     PrintDebug("Write operation on Guest PAge Table Page (large page)\n");
655     state->cached_cr3 = 0;
656     shadow_pte->writable = 1;
657
658   } else {
659     PrintError("Error in large page fault handler...\n");
660     PrintError("This case should have been handled at the top level handler\n");
661     return -1;
662   }
663
664   PrintDebug("Returning from large page fault handler\n");
665   return 0;
666 }
667
668
669
670
671 /* 
672  * We assume the the guest pte pointer has already been translated to a host virtual address
673  */
674 static int handle_shadow_pte32_fault(struct guest_info * info, 
675                                      addr_t fault_addr, 
676                                      pf_error_t error_code,
677                                      pte32_t * shadow_pt, 
678                                      pte32_t * guest_pt) {
679
680   pt_access_status_t guest_pte_access;
681   pt_access_status_t shadow_pte_access;
682   pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
683   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
684
685
686   // Check the guest page permissions
687   guest_pte_access = can_access_pte32(guest_pt, fault_addr, error_code);
688
689   // Check the shadow page permissions
690   shadow_pte_access = can_access_pte32(shadow_pt, fault_addr, error_code);
691   
692 #ifdef DEBUG_SHADOW_PAGING
693   PrintDebug("Guest PTE: (access=%d)\n\t", guest_pte_access);
694   PrintPTE32(fault_addr, guest_pte);
695   PrintDebug("Shadow PTE: (access=%d)\n\t", shadow_pte_access);
696   PrintPTE32(fault_addr, shadow_pte);
697 #endif
698   
699   /* Was the page fault caused by the Guest's page tables? */
700   if (is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
701     PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
702                guest_pte_access, *(uint_t*)&error_code);    
703     inject_guest_pf(info, fault_addr, error_code);
704     return 0; 
705   }
706   
707   
708   if (shadow_pte_access == PT_ACCESS_OK) {
709     // Inconsistent state...
710     // Guest Re-Entry will flush page tables and everything should now work
711     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
712     return 0;
713   }
714
715
716   if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
717
718     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
719
720     // Page Table Entry Not Present
721     PrintDebug("guest_pa =%p\n", (void *)guest_pa);
722
723     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
724
725     if (host_page_type == HOST_REGION_INVALID) {
726       // Inject a machine check in the guest
727       PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
728       v3_raise_exception(info, MC_EXCEPTION);
729       return 0;
730     }
731
732     // else...
733
734     if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
735       struct shadow_page_state * state = &(info->shdw_pg_state);
736       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
737       
738       shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
739       
740       shadow_pte->present = guest_pte->present;
741       shadow_pte->user_page = guest_pte->user_page;
742       
743       //set according to VMM policy
744       shadow_pte->write_through = 0;
745       shadow_pte->cache_disable = 0;
746       shadow_pte->global_page = 0;
747       //
748       
749       guest_pte->accessed = 1;
750       
751       if (find_pte_map(state->cached_ptes, PAGE_ADDR(guest_pa)) != NULL) {
752         // Check if the entry is a page table...
753         PrintDebug("Marking page as Guest Page Table %d\n", shadow_pte->writable);
754         shadow_pte->vmm_info = PT32_GUEST_PT;
755       }
756
757       if (guest_pte->dirty == 1) {
758         shadow_pte->writable = guest_pte->writable;
759       } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
760         shadow_pte->writable = guest_pte->writable;
761         guest_pte->dirty = 1;
762         
763         if (shadow_pte->vmm_info == PT32_GUEST_PT) {
764           // Well that was quick...
765           struct shadow_page_state * state = &(info->shdw_pg_state);
766           PrintDebug("Immediate Write operation on Guest PAge Table Page\n");
767           state->cached_cr3 = 0;
768         }
769
770       } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {  // was =
771         shadow_pte->writable = 0;
772       }
773
774
775
776     } else {
777       // Page fault handled by hook functions
778       if (handle_special_page_fault(info, fault_addr, guest_pa, error_code) == -1) {
779         PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
780         return -1;
781       }
782     }
783
784   } else if ((shadow_pte_access == PT_ACCESS_WRITE_ERROR) &&
785              (guest_pte->dirty == 0)) {
786
787     PrintDebug("Shadow PTE Write Error\n");
788     guest_pte->dirty = 1;
789     shadow_pte->writable = guest_pte->writable;
790
791     if (shadow_pte->vmm_info == PT32_GUEST_PT) {
792       struct shadow_page_state * state = &(info->shdw_pg_state);
793       PrintDebug("Write operation on Guest PAge Table Page\n");
794       state->cached_cr3 = 0;
795     }
796     
797     return 0;
798
799   } else {
800     // Inject page fault into the guest 
801     inject_guest_pf(info, fault_addr, error_code);
802     PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
803     PrintError("Manual Says to inject page fault into guest\n");
804     return -1;
805   }
806
807   PrintDebug("Returning end of function\n");
808   return 0;
809 }
810
811
812
813
814
815
816 /* Currently Does not work with Segmentation!!! */
817 int v3_handle_shadow_invlpg(struct guest_info * info)
818 {
819   if (info->mem_mode != VIRTUAL_MEM) {
820     // Paging must be turned on...
821     // should handle with some sort of fault I think
822     PrintError("ERROR: INVLPG called in non paged mode\n");
823     return -1;
824   }
825   
826   
827   if (info->cpu_mode != PROTECTED) {
828     return 0;
829   }
830   
831   uchar_t instr[15];
832   int index = 0;
833   
834   int ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
835   if (ret != 15) {
836     PrintError("Could not read instruction 0x%p (ret=%d)\n",  (void *)(addr_t)(info->rip), ret);
837     return -1;
838   }
839   
840   
841   /* Can INVLPG work with Segments?? */
842   while (is_prefix_byte(instr[index])) {
843     index++;
844   }
845     
846     
847   if( (instr[index + 0] != (uchar_t) 0x0f) ||  
848       (instr[index + 1] != (uchar_t) 0x01) ) {
849     PrintError("invalid Instruction Opcode\n");
850     PrintTraceMemDump(instr, 15);
851     return -1;
852   }
853   
854   addr_t first_operand;
855   addr_t second_operand;
856   addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
857   
858   pde32_t * guest_pd = NULL;
859   
860   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
861     PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
862     return -1;
863   }
864   
865   index += 2;
866
867   v3_operand_type_t addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
868   
869   if (addr_type != MEM_OPERAND) {
870     PrintError("Invalid Operand type\n");
871     return -1;
872   }
873   
874   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
875   pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
876   pde32_t * guest_pde;
877   
878   //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
879   //PrintDebug("FirstOperand = %x\n", first_operand);
880   
881   PrintDebug("Invalidating page for %p\n", (void *)first_operand);
882   
883   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
884   
885   if (guest_pde->large_page == 1) {
886     shadow_pde->present = 0;
887     PrintDebug("Invalidating Large Page\n");
888   } else
889     if (shadow_pde->present == 1) {
890       pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr);
891       pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(first_operand)] );
892       
893 #ifdef DEBUG_SHADOW_PAGING
894       PrintDebug("Setting not present\n");
895       PrintPTE32(first_operand, shadow_pte );
896 #endif
897       
898       shadow_pte->present = 0;
899     }
900   
901   info->rip += index;
902   
903   return 0;
904 }
905
906
907 /*
908
909
910 static int create_pd32_nonaligned_4MB_page(struct guest_info * info, pte32_t * pt, addr_t guest_addr, pde32_4MB_t * large_shadow_pde) {
911   uint_t i = 0;
912   pte32_t * pte_cursor;
913   addr_t guest_pa = 0;
914
915   for (i = 0; i < 1024; i++) {
916     guest_pa = guest_addr + (PAGE_SIZE * i);
917     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
918     
919     pte_cursor = &(pt[i]);
920
921     if (host_page_type == HOST_REGION_INVALID) {
922       // Currently we don't support this, but in theory we could
923       PrintError("Invalid Host Memory Type\n");
924       return -1;
925     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
926       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
927
928
929       pte_cursor->page_base_addr = PT32_BASE_ADDR(shadow_pa);
930       pte_cursor->present = 1;
931       pte_cursor->writable = large_shadow_pde->writable;
932       pte_cursor->user_page = large_shadow_pde->user_page;
933       pte_cursor->write_through = 0;  
934       pte_cursor->cache_disable = 0;
935       pte_cursor->global_page = 0;
936
937     } else {
938       PrintError("Unsupported Host Memory Type\n");
939       return -1;
940     }
941   }
942   return 0;
943 }
944
945
946 static int handle_large_pagefault32(struct guest_info * info, 
947                                     pde32_t * guest_pde, pde32_t * shadow_pde, 
948                                     addr_t fault_addr, pf_error_t error_code ) {
949   struct shadow_region * mem_reg;
950   pde32_4MB_t * large_guest_pde = (pde32_4MB_t *)guest_pde;
951   pde32_4MB_t * large_shadow_pde = (pde32_4MB_t *)shadow_pde;
952   host_region_type_t host_page_type;
953   addr_t guest_start_addr = PDE32_4MB_T_ADDR(*large_guest_pde);
954   //    addr_t guest_end_addr = guest_start_addr + PAGE_SIZE_4MB; // start address + 4MB
955   
956   
957   // Check that the Guest PDE entry points to valid memory
958   // else Machine Check the guest
959   PrintDebug("Large Page: Page Base Addr=%x\n", guest_start_addr);
960   
961   host_page_type = get_shadow_addr_type(info, guest_start_addr);
962   
963   if (host_page_type == HOST_REGION_INVALID) {
964     PrintError("Invalid guest address in large page (0x%x)\n", guest_start_addr);
965     v3_raise_exception(info, MC_EXCEPTION);
966     return -1;
967   }
968   
969   // else...
970
971   if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
972
973     addr_t host_start_addr = 0;
974     addr_t region_end_addr = 0;
975     
976     // Check for a large enough region in host memory
977     mem_reg = get_shadow_region_by_addr(&(info->mem_map), guest_start_addr);
978     PrintDebug("Host region: host_addr=%x (guest_start=%x, end=%x)\n", 
979                mem_reg->host_addr, mem_reg->guest_start, mem_reg->guest_end);
980     host_start_addr = mem_reg->host_addr + (guest_start_addr - mem_reg->guest_start);
981     region_end_addr = mem_reg->host_addr + (mem_reg->guest_end - mem_reg->guest_start);
982     
983     PrintDebug("Host Start Addr=%x; Region End Addr=%x\n", host_start_addr, region_end_addr);
984     
985     
986     //4f
987     if (large_guest_pde->dirty == 1) { // dirty
988       large_shadow_pde->writable = guest_pde->writable;
989     } else if (error_code.write == 1) { // not dirty, access is write
990       large_shadow_pde->writable = guest_pde->writable;
991       large_guest_pde->dirty = 1;
992     } else { // not dirty, access is read
993       large_shadow_pde->writable = 0;
994     }
995     
996     
997     // Check if the region is at least an additional 4MB
998     
999     
1000     //4b.
1001     if ((PD32_4MB_PAGE_OFFSET(host_start_addr) == 0) && 
1002         (region_end_addr >= host_start_addr + PAGE_SIZE_4MB)) {         // if 4MB boundary
1003       large_shadow_pde->page_base_addr = PD32_4MB_BASE_ADDR(host_start_addr);
1004     } else {      // else generate 4k pages
1005       pte32_t * shadow_pt = NULL;
1006       PrintDebug("Handling non aligned large page\n");
1007       
1008       shadow_pde->large_page = 0;
1009       
1010       shadow_pt = create_new_shadow_pt32();
1011
1012       if (create_pd32_nonaligned_4MB_page(info, shadow_pt, guest_start_addr, large_shadow_pde) == -1) {
1013         PrintError("Non Aligned Large Page Error\n");
1014         V3_Free(shadow_pt);
1015         return -1;
1016       }
1017       
1018       
1019 #ifdef DEBUG_SHADOW_PAGING
1020       PrintDebug("non-aligned Shadow PT\n");
1021       PrintPT32(PT32_PAGE_ADDR(fault_addr), shadow_pt);   
1022 #endif
1023       shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
1024     }
1025     
1026   } else {
1027     // Handle hooked pages as well as other special pages
1028     if (handle_special_page_fault(info, fault_addr, guest_start_addr, error_code) == -1) {
1029       PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
1030       return -1;
1031     }
1032   }
1033
1034   return 0;
1035 }
1036 */