Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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