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.


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