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