Palacios Public Git Repository

To checkout Palacios execute

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


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