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.


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