Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / palacios / src / palacios / vmm_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     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_VAddr(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%p)\n", (void *)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: %p\n", (void *)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 = (addr_t) V3_PAddr( 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: %p\n", (void*) fault_addr );
395
396   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
397     PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)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                *(uint_t *)&guest_pde_access, *(uint_t *)&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)V3_PAddr(shadow_pt));
438       
439       if (guest_pde->large_page == 0) {
440         shadow_pde->writable = guest_pde->writable;
441       } else {
442         // ??  What if guest pde is dirty a this point?
443         ((pde32_4MB_t *)guest_pde)->dirty = 0;
444         shadow_pde->writable = 0;
445       }
446     }
447   else if (shadow_pde_access == PT_ACCESS_OK) 
448     {
449       //
450       // PTE fault
451       //
452       pte32_t * shadow_pt = (pte32_t *)V3_VAddr( (void*)(addr_t) PDE32_T_ADDR(*shadow_pde) );
453
454       if (guest_pde->large_page == 0) {
455         pte32_t * guest_pt = NULL;
456         if (guest_pa_to_host_va(info, PDE32_T_ADDR((*guest_pde)), (addr_t*)&guest_pt) == -1) {
457           // Machine check the guest
458           PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde)));
459           v3_raise_exception(info, MC_EXCEPTION);
460           return 0;
461         }
462         
463         if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
464           PrintError("Error handling Page fault caused by PTE\n");
465           return -1;
466         }
467       } else if (guest_pde->large_page == 1) {
468         if (handle_large_pagefault32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
469           PrintError("Error handling large pagefault\n");
470           return -1;
471         }
472       }
473     }
474   else if ((shadow_pde_access == PT_WRITE_ERROR) && 
475            (guest_pde->large_page == 1) && 
476            (((pde32_4MB_t *)guest_pde)->dirty == 0)) 
477     {
478       //
479       // Page Directory Entry marked read-only
480       // Its a large page and we need to update the dirty bit in the guest
481       //
482
483       PrintDebug("Large page write error... Setting dirty bit and returning\n");
484       ((pde32_4MB_t *)guest_pde)->dirty = 1;
485       shadow_pde->writable = guest_pde->writable;
486       return 0;
487       
488     } 
489   else if (shadow_pde_access == PT_USER_ERROR) 
490     {
491       //
492       // Page Directory Entry marked non-user
493       //      
494       PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
495                  shadow_pde_access, guest_pde_access);
496       inject_guest_pf(info, fault_addr, error_code);
497       return 0;
498     }
499   else 
500     {
501       // inject page fault in guest
502       inject_guest_pf(info, fault_addr, error_code);
503       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
504       PrintDebug("Manual Says to inject page fault into guest\n");
505 #ifdef DEBUG_SHADOW_PAGING
506       PrintDebug("Guest PDE: (access=%d)\n\t", guest_pde_access);
507       PrintPDE32(fault_addr, guest_pde);
508       PrintDebug("Shadow PDE: (access=%d)\n\t", shadow_pde_access);
509       PrintPDE32(fault_addr, shadow_pde);
510 #endif
511
512       return 0; 
513     }
514
515   PrintDebug("Returning end of PDE function (rip=%p)\n", (void *)(info->rip));
516   return 0;
517 }
518
519
520
521 /* 
522  * We assume the the guest pte pointer has already been translated to a host virtual address
523  */
524 static int handle_shadow_pte32_fault(struct guest_info * info, 
525                                      addr_t fault_addr, 
526                                      pf_error_t error_code,
527                                      pte32_t * shadow_pt, 
528                                      pte32_t * guest_pt) {
529
530   pt_access_status_t guest_pte_access;
531   pt_access_status_t shadow_pte_access;
532   pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
533   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
534
535
536   // Check the guest page permissions
537   guest_pte_access = can_access_pte32(guest_pt, fault_addr, error_code);
538
539   // Check the shadow page permissions
540   shadow_pte_access = can_access_pte32(shadow_pt, fault_addr, error_code);
541   
542 #ifdef DEBUG_SHADOW_PAGING
543   PrintDebug("Guest PTE: (access=%d)\n\t", guest_pte_access);
544   PrintPTE32(fault_addr, guest_pte);
545   PrintDebug("Shadow PTE: (access=%d)\n\t", shadow_pte_access);
546   PrintPTE32(fault_addr, shadow_pte);
547 #endif
548   
549   /* Was the page fault caused by the Guest's page tables? */
550   if (is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
551     PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
552                guest_pte_access, *(uint_t*)&error_code);    
553     inject_guest_pf(info, fault_addr, error_code);
554     return 0; 
555   }
556   
557   
558   if (shadow_pte_access == PT_ACCESS_OK) {
559     // Inconsistent state...
560     // Guest Re-Entry will flush page tables and everything should now work
561     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
562     return 0;
563   }
564
565
566   if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
567
568     addr_t guest_pa = PTE32_T_ADDR((*guest_pte)) +  PT32_PAGE_OFFSET(fault_addr);
569
570     // Page Table Entry Not Present
571
572     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
573
574     if (host_page_type == HOST_REGION_INVALID) {
575       // Inject a machine check in the guest
576       PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
577       v3_raise_exception(info, MC_EXCEPTION);
578       return 0;
579     }
580
581     // else...
582
583     if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
584       struct shadow_page_state * state = &(info->shdw_pg_state);
585       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
586       
587       shadow_pte->page_base_addr = PT32_BASE_ADDR(shadow_pa);
588       
589       shadow_pte->present = guest_pte->present;
590       shadow_pte->user_page = guest_pte->user_page;
591       
592       //set according to VMM policy
593       shadow_pte->write_through = 0;
594       shadow_pte->cache_disable = 0;
595       shadow_pte->global_page = 0;
596       //
597       
598       guest_pte->accessed = 1;
599       
600       if (find_pte_map(state->cached_ptes, PT32_PAGE_ADDR(guest_pa)) != NULL) {
601         // Check if the entry is a page table...
602         PrintDebug("Marking page as Guest Page Table %d\n", shadow_pte->writable);
603         shadow_pte->vmm_info = PT32_GUEST_PT;
604       }
605
606       if (guest_pte->dirty == 1) {
607         shadow_pte->writable = guest_pte->writable;
608       } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
609         shadow_pte->writable = guest_pte->writable;
610         guest_pte->dirty = 1;
611         
612         if (shadow_pte->vmm_info == PT32_GUEST_PT) {
613           // Well that was quick...
614           struct shadow_page_state * state = &(info->shdw_pg_state);
615           PrintDebug("Immediate Write operation on Guest PAge Table Page\n");
616           state->cached_cr3 = 0;
617         }
618
619       } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {  // was =
620         shadow_pte->writable = 0;
621       }
622
623
624
625     } else {
626       // Page fault handled by hook functions
627       if (handle_special_page_fault(info, fault_addr, guest_pa, error_code) == -1) {
628         PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
629         return -1;
630       }
631     }
632
633   } else if ((shadow_pte_access == PT_WRITE_ERROR) &&
634              (guest_pte->dirty == 0)) {
635
636     PrintDebug("Shadow PTE Write Error\n");
637     guest_pte->dirty = 1;
638     shadow_pte->writable = guest_pte->writable;
639
640     if (shadow_pte->vmm_info == PT32_GUEST_PT) {
641       struct shadow_page_state * state = &(info->shdw_pg_state);
642       PrintDebug("Write operation on Guest PAge Table Page\n");
643       state->cached_cr3 = 0;
644     }
645     
646     return 0;
647
648   } else {
649     // Inject page fault into the guest 
650     inject_guest_pf(info, fault_addr, error_code);
651     PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
652     PrintError("Manual Says to inject page fault into guest\n");
653     return -1;
654   }
655
656   PrintDebug("Returning end of function\n");
657   return 0;
658 }
659
660
661
662
663
664
665 /* Currently Does not work with Segmentation!!! */
666 int v3_handle_shadow_invlpg(struct guest_info * info)
667 {
668         if (info->mem_mode != VIRTUAL_MEM) {
669                 // Paging must be turned on...
670                 // should handle with some sort of fault I think
671                 PrintError("ERROR: INVLPG called in non paged mode\n");
672                 return -1;
673         }
674
675
676         if (info->cpu_mode != PROTECTED)
677                 return 0;
678
679         uchar_t instr[15];
680         int index = 0;
681
682         int ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
683         if (ret != 15) {
684           PrintError("Could not read instruction 0x%p (ret=%d)\n",  (void *)(addr_t)(info->rip), ret);
685                 return -1;
686         }
687
688    
689         /* Can INVLPG work with Segments?? */
690         while (is_prefix_byte(instr[index])) {
691                 index++;
692         }
693     
694     
695         if( instr[index + 0] != (uchar_t) 0x0f
696         ||  instr[index + 1] != (uchar_t) 0x01
697         ) {
698                 PrintError("invalid Instruction Opcode\n");
699                 PrintTraceMemDump(instr, 15);
700                 return -1;
701         }
702
703         addr_t first_operand;
704         addr_t second_operand;
705         addr_t guest_cr3 = (addr_t)V3_PAddr( (void*)(addr_t) CR3_TO_PDE32(info->shdw_pg_state.guest_cr3) );
706
707         pde32_t * guest_pd = NULL;
708
709         if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1)
710         {
711                 PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
712                 return -1;
713         }
714
715         index += 2;
716
717         v3_operand_type_t addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
718
719         if (addr_type != MEM_OPERAND) {
720                 PrintError("Invalid Operand type\n");
721                 return -1;
722         }
723
724         pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
725         pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
726         pde32_t * guest_pde;
727
728         //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
729         //PrintDebug("FirstOperand = %x\n", first_operand);
730
731         PrintDebug("Invalidating page for %p\n", (void *)first_operand);
732
733         guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
734
735         if (guest_pde->large_page == 1) {
736                 shadow_pde->present = 0;
737                 PrintDebug("Invalidating Large Page\n");
738         } else
739         if (shadow_pde->present == 1) {
740                 pte32_t * shadow_pt = (pte32_t *)(addr_t)PDE32_T_ADDR((*shadow_pde));
741                 pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(first_operand)] );
742
743 #ifdef DEBUG_SHADOW_PAGING
744                 PrintDebug("Setting not present\n");
745                 PrintPTE32(first_operand, shadow_pte );
746 #endif
747
748                 shadow_pte->present = 0;
749         }
750
751         info->rip += index;
752
753         return 0;
754 }
755
756
757 /*
758
759
760 static int create_pd32_nonaligned_4MB_page(struct guest_info * info, pte32_t * pt, addr_t guest_addr, pde32_4MB_t * large_shadow_pde) {
761   uint_t i = 0;
762   pte32_t * pte_cursor;
763   addr_t guest_pa = 0;
764
765   for (i = 0; i < 1024; i++) {
766     guest_pa = guest_addr + (PAGE_SIZE * i);
767     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
768     
769     pte_cursor = &(pt[i]);
770
771     if (host_page_type == HOST_REGION_INVALID) {
772       // Currently we don't support this, but in theory we could
773       PrintError("Invalid Host Memory Type\n");
774       return -1;
775     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
776       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
777
778
779       pte_cursor->page_base_addr = PT32_BASE_ADDR(shadow_pa);
780       pte_cursor->present = 1;
781       pte_cursor->writable = large_shadow_pde->writable;
782       pte_cursor->user_page = large_shadow_pde->user_page;
783       pte_cursor->write_through = 0;  
784       pte_cursor->cache_disable = 0;
785       pte_cursor->global_page = 0;
786
787     } else {
788       PrintError("Unsupported Host Memory Type\n");
789       return -1;
790     }
791   }
792   return 0;
793 }
794
795
796 static int handle_large_pagefault32(struct guest_info * info, 
797                                     pde32_t * guest_pde, pde32_t * shadow_pde, 
798                                     addr_t fault_addr, pf_error_t error_code ) {
799   struct shadow_region * mem_reg;
800   pde32_4MB_t * large_guest_pde = (pde32_4MB_t *)guest_pde;
801   pde32_4MB_t * large_shadow_pde = (pde32_4MB_t *)shadow_pde;
802   host_region_type_t host_page_type;
803   addr_t guest_start_addr = PDE32_4MB_T_ADDR(*large_guest_pde);
804   //    addr_t guest_end_addr = guest_start_addr + PAGE_SIZE_4MB; // start address + 4MB
805   
806   
807   // Check that the Guest PDE entry points to valid memory
808   // else Machine Check the guest
809   PrintDebug("Large Page: Page Base Addr=%x\n", guest_start_addr);
810   
811   host_page_type = get_shadow_addr_type(info, guest_start_addr);
812   
813   if (host_page_type == HOST_REGION_INVALID) {
814     PrintError("Invalid guest address in large page (0x%x)\n", guest_start_addr);
815     v3_raise_exception(info, MC_EXCEPTION);
816     return -1;
817   }
818   
819   // else...
820
821   if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
822
823     addr_t host_start_addr = 0;
824     addr_t region_end_addr = 0;
825     
826     // Check for a large enough region in host memory
827     mem_reg = get_shadow_region_by_addr(&(info->mem_map), guest_start_addr);
828     PrintDebug("Host region: host_addr=%x (guest_start=%x, end=%x)\n", 
829                mem_reg->host_addr, mem_reg->guest_start, mem_reg->guest_end);
830     host_start_addr = mem_reg->host_addr + (guest_start_addr - mem_reg->guest_start);
831     region_end_addr = mem_reg->host_addr + (mem_reg->guest_end - mem_reg->guest_start);
832     
833     PrintDebug("Host Start Addr=%x; Region End Addr=%x\n", host_start_addr, region_end_addr);
834     
835     
836     //4f
837     if (large_guest_pde->dirty == 1) { // dirty
838       large_shadow_pde->writable = guest_pde->writable;
839     } else if (error_code.write == 1) { // not dirty, access is write
840       large_shadow_pde->writable = guest_pde->writable;
841       large_guest_pde->dirty = 1;
842     } else { // not dirty, access is read
843       large_shadow_pde->writable = 0;
844     }
845     
846     
847     // Check if the region is at least an additional 4MB
848     
849     
850     //4b.
851     if ((PD32_4MB_PAGE_OFFSET(host_start_addr) == 0) && 
852         (region_end_addr >= host_start_addr + PAGE_SIZE_4MB)) {         // if 4MB boundary
853       large_shadow_pde->page_base_addr = PD32_4MB_BASE_ADDR(host_start_addr);
854     } else {      // else generate 4k pages
855       pte32_t * shadow_pt = NULL;
856       PrintDebug("Handling non aligned large page\n");
857       
858       shadow_pde->large_page = 0;
859       
860       shadow_pt = create_new_shadow_pt32();
861
862       if (create_pd32_nonaligned_4MB_page(info, shadow_pt, guest_start_addr, large_shadow_pde) == -1) {
863         PrintError("Non Aligned Large Page Error\n");
864         V3_Free(shadow_pt);
865         return -1;
866       }
867       
868       
869 #ifdef DEBUG_SHADOW_PAGING
870       PrintDebug("non-aligned Shadow PT\n");
871       PrintPT32(PT32_PAGE_ADDR(fault_addr), shadow_pt);   
872 #endif
873       shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
874     }
875     
876   } else {
877     // Handle hooked pages as well as other special pages
878     if (handle_special_page_fault(info, fault_addr, guest_start_addr, error_code) == -1) {
879       PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
880       return -1;
881     }
882   }
883
884   return 0;
885 }
886 */