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.


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