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.


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