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 profiling 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 #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   info->ctrl_regs.cr2 = fault_addr;
378   v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
379 }
380
381
382 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
383   /* basically the reasoning is that there can be multiple reasons for a page fault:
384      If there is a permissions failure for a page present in the guest _BUT_ 
385      the reason for the fault was that the page is not present in the shadow, 
386      _THEN_ we have to map the shadow page in and reexecute, this will generate 
387      a permissions fault which is _THEN_ valid to send to the guest
388      _UNLESS_ both the guest and shadow have marked the page as not present
389
390      whew...
391   */
392   if (guest_access != PT_ACCESS_OK) {
393     // Guest Access Error
394     
395     if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
396         (guest_access != PT_ACCESS_NOT_PRESENT)) {
397       // aka (guest permission error)
398       return 1;
399     }
400
401     if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
402         (guest_access == PT_ACCESS_NOT_PRESENT)) {      
403       // Page tables completely blank, handle guest first
404       return 1;
405     }
406
407     // Otherwise we'll handle the guest fault later...?
408   }
409
410   return 0;
411 }
412
413
414
415
416 /* 
417  * *
418  * * 
419  * * 64 bit Page table fault handlers
420  * *
421  * *
422  */
423
424 static int handle_shadow_pagefault_64(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
425   pt_access_status_t guest_access;
426   pt_access_status_t shadow_access;
427   int ret; 
428   PrintDebug("64 bit shadow page fault\n");
429
430   ret = v3_check_guest_pt_32(info, info->shdw_pg_state.guest_cr3, fault_addr, error_code, &guest_access);
431
432   PrintDebug("Guest Access Check: %d (access=%d)\n", ret, guest_access);
433
434   ret = v3_check_host_pt_32(info->ctrl_regs.cr3, fault_addr, error_code, &shadow_access);
435
436   PrintDebug("Shadow Access Check: %d (access=%d)\n", ret, shadow_access);
437   
438
439   PrintError("64 bit shadow paging not implemented\n");
440   return -1;
441 }
442
443
444 /* 
445  * *
446  * * 
447  * * 32 bit PAE  Page table fault handlers
448  * *
449  * *
450  */
451
452 static int handle_shadow_pagefault_32pae(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
453   PrintError("32 bit PAE shadow paging not implemented\n");
454   return -1;
455 }
456
457
458
459
460
461
462
463 /* 
464  * *
465  * * 
466  * * 32 bit Page table fault handlers
467  * *
468  * *
469  */
470 static int handle_large_pagefault_32(struct guest_info * info, 
471                                     addr_t fault_addr, pf_error_t error_code, 
472                                      pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde);
473
474 static int handle_shadow_pte32_fault(struct guest_info * info, 
475                                      addr_t fault_addr, 
476                                      pf_error_t error_code,
477                                      pte32_t * shadow_pt, 
478                                      pte32_t * guest_pt);
479
480
481 static int handle_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
482   pde32_t * guest_pd = NULL;
483   pde32_t * shadow_pd = CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
484   addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
485   pt_access_status_t guest_pde_access;
486   pt_access_status_t shadow_pde_access;
487   pde32_t * guest_pde = NULL;
488   pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
489
490   PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
491
492   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
493     PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
494     return -1;
495   } 
496
497   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
498
499
500   // Check the guest page permissions
501   guest_pde_access = v3_can_access_pde32(guest_pd, fault_addr, error_code);
502
503   // Check the shadow page permissions
504   shadow_pde_access = v3_can_access_pde32(shadow_pd, fault_addr, error_code);
505   
506   /* Was the page fault caused by the Guest's page tables? */
507   if (is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
508     PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", 
509                *(uint_t *)&guest_pde_access, *(uint_t *)&error_code);
510     inject_guest_pf(info, fault_addr, error_code);
511     return 0;
512   }
513
514   
515   if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) 
516     {
517       pte32_t * shadow_pt =  (pte32_t *)v3_create_new_shadow_pt();
518
519       shadow_pde->present = 1;
520       shadow_pde->user_page = guest_pde->user_page;
521       //    shadow_pde->large_page = guest_pde->large_page;
522       shadow_pde->large_page = 0;
523       
524
525       // VMM Specific options
526       shadow_pde->write_through = 0;
527       shadow_pde->cache_disable = 0;
528       shadow_pde->global_page = 0;
529       //
530       
531       guest_pde->accessed = 1;
532       
533       shadow_pde->pt_base_addr = PAGE_BASE_ADDR((addr_t)V3_PAddr(shadow_pt));
534       
535       if (guest_pde->large_page == 0) {
536         shadow_pde->writable = guest_pde->writable;
537       } else {
538         // ??  What if guest pde is dirty a this point?
539         ((pde32_4MB_t *)guest_pde)->dirty = 0;
540         shadow_pde->writable = 0;
541       }
542     }
543   else if (shadow_pde_access == PT_ACCESS_OK) 
544     {
545       //
546       // PTE fault
547       //
548       pte32_t * shadow_pt = (pte32_t *)V3_VAddr( (void*)(addr_t) BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr) );
549
550       if (guest_pde->large_page == 0) {
551         pte32_t * guest_pt = NULL;
552         if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
553           // Machine check the guest
554           PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
555           v3_raise_exception(info, MC_EXCEPTION);
556           return 0;
557         }
558         
559         if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
560           PrintError("Error handling Page fault caused by PTE\n");
561           return -1;
562         }
563       } else if (guest_pde->large_page == 1) {
564         if (handle_large_pagefault_32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
565           PrintError("Error handling large pagefault\n");
566           return -1;
567         }
568       }
569     }
570   else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
571            (guest_pde->large_page == 1) && 
572            (((pde32_4MB_t *)guest_pde)->dirty == 0)) 
573     {
574       //
575       // Page Directory Entry marked read-only
576       // Its a large page and we need to update the dirty bit in the guest
577       //
578
579       PrintDebug("Large page write error... Setting dirty bit and returning\n");
580       ((pde32_4MB_t *)guest_pde)->dirty = 1;
581       shadow_pde->writable = guest_pde->writable;
582       return 0;
583       
584     } 
585   else if (shadow_pde_access == PT_ACCESS_USER_ERROR) 
586     {
587       //
588       // Page Directory Entry marked non-user
589       //      
590       PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
591                  shadow_pde_access, guest_pde_access);
592       inject_guest_pf(info, fault_addr, error_code);
593       return 0;
594     }
595   else 
596     {
597       // inject page fault in guest
598       inject_guest_pf(info, fault_addr, error_code);
599       PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
600       PrintDebug("Manual Says to inject page fault into guest\n");
601 #ifdef DEBUG_SHADOW_PAGING
602       PrintDebug("Guest PDE: (access=%d)\n\t", guest_pde_access);
603       PrintPTEntry(PAGE_PD32, fault_addr, guest_pde);
604       PrintDebug("Shadow PDE: (access=%d)\n\t", shadow_pde_access);
605       PrintPTEntry(PAGE_PD32, fault_addr, shadow_pde);
606 #endif
607
608       return 0; 
609     }
610
611   PrintDebug("Returning end of PDE function (rip=%p)\n", (void *)(addr_t)(info->rip));
612   return 0;
613 }
614
615
616
617 /* The guest status checks have already been done,
618  * only special case shadow checks remain
619  */
620 static int handle_large_pagefault_32(struct guest_info * info, 
621                                     addr_t fault_addr, pf_error_t error_code, 
622                                     pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
623 {
624   pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
625   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
626   addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
627
628   struct v3_shadow_region * shdw_reg = v3_get_shadow_region(info, guest_fault_pa);
629
630  
631   if ((shdw_reg == NULL) || 
632       (shdw_reg->host_type == SHDW_REGION_INVALID)) {
633     // Inject a machine check in the guest
634     PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
635     v3_raise_exception(info, MC_EXCEPTION);
636     return -1;
637   }
638
639   if (shadow_pte_access == PT_ACCESS_OK) {
640     // Inconsistent state...
641     // Guest Re-Entry will flush tables and everything should now workd
642     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
643     return 0;
644   }
645
646   
647   if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
648     // Get the guest physical address of the fault
649
650     if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) || 
651         (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
652       struct shadow_page_state * state = &(info->shdw_pg_state);
653       addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, guest_fault_pa);
654
655       shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
656
657       shadow_pte->present = 1;
658
659       /* We are assuming that the PDE entry has precedence
660        * so the Shadow PDE will mirror the guest PDE settings, 
661        * and we don't have to worry about them here
662        * Allow everything
663        */
664       shadow_pte->user_page = 1;
665
666       if (find_pte_map(state->cached_ptes, PAGE_ADDR(guest_fault_pa)) != NULL) {
667         // Check if the entry is a page table...
668         PrintDebug("Marking page as Guest Page Table (large page)\n");
669         shadow_pte->vmm_info = PT32_GUEST_PT;
670         shadow_pte->writable = 0;
671       } else if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
672         shadow_pte->writable = 0;
673       } else {
674         shadow_pte->writable = 1;
675       }
676
677       //set according to VMM policy
678       shadow_pte->write_through = 0;
679       shadow_pte->cache_disable = 0;
680       shadow_pte->global_page = 0;
681       //
682       
683     } else {
684       // Handle hooked pages as well as other special pages
685       //      if (handle_special_page_fault(info, fault_addr, guest_fault_pa, error_code) == -1) {
686
687       if (v3_handle_mem_full_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
688         PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
689         return -1;
690       }
691     }
692   } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
693
694     if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
695
696       if (v3_handle_mem_wr_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
697         PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
698         return -1;
699       }
700     } else if (shadow_pte->vmm_info == PT32_GUEST_PT) {
701       struct shadow_page_state * state = &(info->shdw_pg_state);
702       PrintDebug("Write operation on Guest PAge Table Page (large page)\n");
703       state->cached_cr3 = 0;
704       shadow_pte->writable = 1;
705     }
706
707   } else {
708     PrintError("Error in large page fault handler...\n");
709     PrintError("This case should have been handled at the top level handler\n");
710     return -1;
711   }
712
713   PrintDebug("Returning from large page fault handler\n");
714   return 0;
715 }
716
717
718
719
720 /* 
721  * We assume the the guest pte pointer has already been translated to a host virtual address
722  */
723 static int handle_shadow_pte32_fault(struct guest_info * info, 
724                                      addr_t fault_addr, 
725                                      pf_error_t error_code,
726                                      pte32_t * shadow_pt, 
727                                      pte32_t * guest_pt) {
728
729   pt_access_status_t guest_pte_access;
730   pt_access_status_t shadow_pte_access;
731   pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
732   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
733   addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
734
735   struct v3_shadow_region * shdw_reg =  v3_get_shadow_region(info, guest_pa);
736
737   if ((shdw_reg == NULL) || 
738       (shdw_reg->host_type == SHDW_REGION_INVALID)) {
739     // Inject a machine check in the guest
740     PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
741     v3_raise_exception(info, MC_EXCEPTION);
742     return 0;
743   }
744
745   // Check the guest page permissions
746   guest_pte_access = v3_can_access_pte32(guest_pt, fault_addr, error_code);
747
748   // Check the shadow page permissions
749   shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
750   
751 #ifdef DEBUG_SHADOW_PAGING
752   PrintDebug("Guest PTE: (access=%d)\n\t", guest_pte_access);
753   PrintPTEntry(PAGE_PT32, fault_addr, guest_pte);
754   PrintDebug("Shadow PTE: (access=%d)\n\t", shadow_pte_access);
755   PrintPTEntry(PAGE_PT32, fault_addr, shadow_pte);
756 #endif
757   
758   /* Was the page fault caused by the Guest's page tables? */
759   if (is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
760     PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
761                guest_pte_access, *(uint_t*)&error_code);    
762     inject_guest_pf(info, fault_addr, error_code);
763     return 0; 
764   }
765   
766   
767   if (shadow_pte_access == PT_ACCESS_OK) {
768     // Inconsistent state...
769     // Guest Re-Entry will flush page tables and everything should now work
770     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
771     return 0;
772   }
773
774
775   if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
776     // Page Table Entry Not Present
777     PrintDebug("guest_pa =%p\n", (void *)guest_pa);
778
779     if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) ||
780         (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
781       struct shadow_page_state * state = &(info->shdw_pg_state);
782       addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, guest_pa);
783       
784       shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
785       
786       shadow_pte->present = guest_pte->present;
787       shadow_pte->user_page = guest_pte->user_page;
788       
789       //set according to VMM policy
790       shadow_pte->write_through = 0;
791       shadow_pte->cache_disable = 0;
792       shadow_pte->global_page = 0;
793       //
794       
795       guest_pte->accessed = 1;
796       
797       if (find_pte_map(state->cached_ptes, PAGE_ADDR(guest_pa)) != NULL) {
798         // Check if the entry is a page table...
799         PrintDebug("Marking page as Guest Page Table %d\n", shadow_pte->writable);
800         shadow_pte->vmm_info = PT32_GUEST_PT;
801       }
802
803       if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
804         shadow_pte->writable = 0;
805       } else if (guest_pte->dirty == 1) {
806         shadow_pte->writable = guest_pte->writable;
807       } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
808         shadow_pte->writable = guest_pte->writable;
809         guest_pte->dirty = 1;
810         
811         if (shadow_pte->vmm_info == PT32_GUEST_PT) {
812           // Well that was quick...
813           struct shadow_page_state * state = &(info->shdw_pg_state);
814           PrintDebug("Immediate Write operation on Guest PAge Table Page\n");
815           state->cached_cr3 = 0;
816         }
817
818       } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {  // was =
819         shadow_pte->writable = 0;
820       }
821
822     } else {
823       // Page fault handled by hook functions
824
825       if (v3_handle_mem_full_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
826         PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
827         return -1;
828       }
829     }
830     /*
831   } else if ((shadow_pte_access == PT_ACCESS_WRITE_ERROR) &&
832              (guest_pte->dirty == 0)) {
833     */
834   } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
835     guest_pte->dirty = 1;
836
837     if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
838       if (v3_handle_mem_wr_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
839         PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
840         return -1;
841       }
842     } else {
843       PrintDebug("Shadow PTE Write Error\n");
844       shadow_pte->writable = guest_pte->writable;
845     }
846
847     if (shadow_pte->vmm_info == PT32_GUEST_PT) {
848       struct shadow_page_state * state = &(info->shdw_pg_state);
849       PrintDebug("Write operation on Guest PAge Table Page\n");
850       state->cached_cr3 = 0;
851     }
852
853     return 0;
854
855   } else {
856     // Inject page fault into the guest 
857     inject_guest_pf(info, fault_addr, error_code);
858     PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
859     PrintError("Manual Says to inject page fault into guest\n");
860     return -1;
861   }
862
863   PrintDebug("Returning end of function\n");
864   return 0;
865 }
866
867
868
869
870
871
872 /* Currently Does not work with Segmentation!!! */
873 int v3_handle_shadow_invlpg(struct guest_info * info)
874 {
875   if (info->mem_mode != VIRTUAL_MEM) {
876     // Paging must be turned on...
877     // should handle with some sort of fault I think
878     PrintError("ERROR: INVLPG called in non paged mode\n");
879     return -1;
880   }
881   
882   
883   if (info->cpu_mode != PROTECTED) {
884     PrintError("Unsupported CPU mode (mode=%s)\n", v3_cpu_mode_to_str(info->cpu_mode));
885     return -1;
886   }
887   
888   uchar_t instr[15];
889   int index = 0;
890   
891   int ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
892   if (ret != 15) {
893     PrintError("Could not read instruction 0x%p (ret=%d)\n",  (void *)(addr_t)(info->rip), ret);
894     return -1;
895   }
896   
897   
898   /* Can INVLPG work with Segments?? */
899   while (is_prefix_byte(instr[index])) {
900     index++;
901   }
902     
903     
904   if( (instr[index + 0] != (uchar_t) 0x0f) ||  
905       (instr[index + 1] != (uchar_t) 0x01) ) {
906     PrintError("invalid Instruction Opcode\n");
907     PrintTraceMemDump(instr, 15);
908     return -1;
909   }
910   
911   addr_t first_operand;
912   addr_t second_operand;
913   addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
914   
915   pde32_t * guest_pd = NULL;
916   
917   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
918     PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
919     return -1;
920   }
921   
922   index += 2;
923
924   v3_operand_type_t addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
925   
926   if (addr_type != MEM_OPERAND) {
927     PrintError("Invalid Operand type\n");
928     return -1;
929   }
930   
931   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
932   pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
933   pde32_t * guest_pde;
934   
935   //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
936   //PrintDebug("FirstOperand = %x\n", first_operand);
937   
938   PrintDebug("Invalidating page for %p\n", (void *)first_operand);
939   
940   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
941   
942   if (guest_pde->large_page == 1) {
943     shadow_pde->present = 0;
944     PrintDebug("Invalidating Large Page\n");
945   } else
946     if (shadow_pde->present == 1) {
947       pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr);
948       pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(first_operand)] );
949       
950 #ifdef DEBUG_SHADOW_PAGING
951       PrintDebug("Setting not present\n");
952       PrintPTEntry(PAGE_PT32, first_operand, shadow_pte);
953 #endif
954       
955       shadow_pte->present = 0;
956     }
957   
958   info->rip += index;
959   
960   return 0;
961 }
962
963