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.


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