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.


code clean up
[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
16
17
18 static int handle_shadow_pte32_fault(struct guest_info* info, 
19                                      addr_t fault_addr, 
20                                      pf_error_t error_code,
21                                      pte32_t * shadow_pte, 
22                                      pte32_t * guest_pte);
23
24 static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
25
26 int init_shadow_page_state(struct shadow_page_state * state) {
27   state->guest_mode = PDE32;
28   state->shadow_mode = PDE32;
29   
30   state->guest_cr3 = 0;
31   state->shadow_cr3 = 0;
32
33   return 0;
34 }
35
36 int handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
37   
38   if (info->mem_mode == PHYSICAL_MEM) {
39     // If paging is not turned on we need to handle the special cases
40     return handle_special_page_fault(info, fault_addr, error_code);
41   } else if (info->mem_mode == VIRTUAL_MEM) {
42
43     switch (info->cpu_mode) {
44     case PROTECTED:
45       return handle_shadow_pagefault32(info, fault_addr, error_code);
46       break;
47     case PROTECTED_PAE:
48     case LONG:
49     default:
50       PrintError("Unhandled CPU Mode\n");
51       return -1;
52     }
53   } else {
54     PrintError("Invalid Memory mode\n");
55     return -1;
56   }
57 }
58
59 addr_t create_new_shadow_pt32(struct guest_info * info) {
60   void * host_pde = 0;
61
62   host_pde = V3_AllocPages(1);
63   memset(host_pde, 0, PAGE_SIZE);
64
65   return (addr_t)host_pde;
66 }
67
68
69 static int handle_pd32_nonaligned_4MB_page(struct guest_info * info, pte32_t * pt, addr_t guest_addr, pde32_4MB_t * large_shadow_pde) {
70   uint_t i = 0;
71   pte32_t * pte_cursor;
72   addr_t guest_pa = 0;
73
74   for (i = 0; i < 1024; i++) {
75     guest_pa = guest_addr + (PAGE_SIZE * i);
76     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
77     
78     pte_cursor = &(pt[i]);
79
80     if (host_page_type == HOST_REGION_INVALID) {
81       // Currently we don't support this, but in theory we could
82       PrintError("Invalid Host Memory Type\n");
83       return -1;
84     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
85       addr_t shadow_pa = get_shadow_addr(info, guest_pa);
86
87
88       pte_cursor->page_base_addr = PT32_BASE_ADDR(shadow_pa);
89       pte_cursor->present = 1;
90       pte_cursor->writable = large_shadow_pde->writable;
91       pte_cursor->user_page = large_shadow_pde->user_page;
92       pte_cursor->write_through = 0;  
93       pte_cursor->cache_disable = 0;
94       pte_cursor->global_page = 0;
95
96     } else {
97       PrintError("Unsupported Host Memory Type\n");
98       return -1;
99     }
100   }
101   return 0;
102 }
103
104 static int handle_shadow_pagefault32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
105   pde32_t * guest_pd = NULL;
106   pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
107   addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
108   pt_access_status_t guest_pde_access;
109   pt_access_status_t shadow_pde_access;
110   pde32_t * guest_pde = NULL;
111   pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
112
113   if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
114     PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
115     return -1;
116   }
117
118
119   guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
120
121   // Check the guest page permissions
122   guest_pde_access = can_access_pde32(guest_pd, fault_addr, error_code);
123
124   // Check the shadow page permissions
125   shadow_pde_access = can_access_pde32(shadow_pd, fault_addr, error_code);
126   
127   /* This should be redone, 
128      but basically the reasoning is that there can be multiple reasons for a page fault:
129      If there is a permissions failure for a page present in the guest _BUT_ 
130      the reason for the fault was that the page is not present in the shadow, 
131      _THEN_ we have to map the shadow page in and reexecute, this will generate 
132      a permissions fault which is _THEN_ valid to send to the guest
133      _UNLESS_ both the guest and shadow have marked the page as not present
134
135      whew...
136   */
137   if ((guest_pde_access != PT_ACCESS_OK) &&
138       (
139        ( (shadow_pde_access != PT_ENTRY_NOT_PRESENT) &&
140          (guest_pde_access != PT_ENTRY_NOT_PRESENT))  // aka (guest permission error)
141        || 
142        ( (shadow_pde_access == PT_ENTRY_NOT_PRESENT) && 
143         (guest_pde_access == PT_ENTRY_NOT_PRESENT)))) {
144     // inject page fault to the guest (Guest PDE fault)
145
146         info->ctrl_regs.cr2 = fault_addr;
147     v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
148
149
150     PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (pf error code=%d)\n", guest_pde_access, error_code);
151     return 0;
152
153  
154 #ifdef DEBUG_SHADOW_PAGING
155         PrintDebug("Guest CR3=%x\n", guest_cr3);
156         PrintDebug("Guest PD\n");
157         PrintPD32(guest_pd);
158         PrintDebug("Shadow PD\n");
159         PrintPD32(shadow_pd);
160 #endif
161
162     return -1;
163   }
164
165
166   //shadow_pde_access = can_access_pde32(shadow_pd, fault_addr, error_code);
167
168
169   if (shadow_pde_access == PT_ENTRY_NOT_PRESENT) {
170
171     shadow_pde->present = 1;
172     shadow_pde->user_page = guest_pde->user_page;
173     shadow_pde->large_page = guest_pde->large_page;
174
175
176     // VMM Specific options
177     shadow_pde->write_through = 0;
178     shadow_pde->cache_disable = 0;
179     shadow_pde->global_page = 0;
180     //
181
182     guest_pde->accessed = 1;
183     
184     if (guest_pde->large_page == 0) {
185       pte32_t * shadow_pt = NULL;
186       
187       shadow_pt = V3_AllocPages(1);
188       memset(shadow_pt, 0, PAGE_SIZE);
189       
190       shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
191
192       shadow_pde->writable = guest_pde->writable;
193     } else {
194       struct shadow_region * mem_reg;
195       pde32_4MB_t * large_guest_pde = (pde32_4MB_t *)guest_pde;
196       pde32_4MB_t * large_shadow_pde = (pde32_4MB_t *)shadow_pde;
197       host_region_type_t host_page_type;
198       addr_t guest_start_addr = PDE32_4MB_T_ADDR(*large_guest_pde);
199       //    addr_t guest_end_addr = guest_start_addr + PAGE_SIZE_4MB; // start address + 4MB
200
201
202       // Check that the Guest PDE entry points to valid memory
203       // else Machine Check the guest
204       PrintDebug("Large Page: Page Base Addr=%x\n", guest_start_addr);
205
206       host_page_type = get_shadow_addr_type(info, guest_start_addr);
207
208       if (host_page_type == HOST_REGION_INVALID) {
209
210         v3_raise_exception(info, MC_EXCEPTION);
211         PrintError("Invalid guest address in large page (0x%x)\n", guest_start_addr);
212         return -1;
213       } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
214         addr_t host_start_addr = 0;
215         addr_t region_end_addr = 0;
216
217         // Check for a large enough region in host memory
218         mem_reg = get_shadow_region_by_addr(&(info->mem_map), guest_start_addr);
219         PrintDebug("Host region: host_addr=%x (guest_start=%x, end=%x)\n", 
220                    mem_reg->host_addr, mem_reg->guest_start, mem_reg->guest_end);
221         host_start_addr = mem_reg->host_addr + (guest_start_addr - mem_reg->guest_start);
222         region_end_addr = mem_reg->host_addr + (mem_reg->guest_end - mem_reg->guest_start);
223
224         PrintDebug("Host Start Addr=%x; Region End Addr=%x\n", host_start_addr, region_end_addr);
225
226
227
228
229         //4f
230         if (large_guest_pde->dirty == 1) { // dirty
231           large_shadow_pde->writable = guest_pde->writable;
232         } else if (error_code.write == 1) { // not dirty, access is write
233           large_shadow_pde->writable = guest_pde->writable;
234           large_guest_pde->dirty = 1;
235         } else { // not dirty, access is read
236           large_shadow_pde->writable = 0;
237         }
238
239
240         // Check if the region is at least an additional 4MB
241
242
243         //4b.
244         if ((PD32_4MB_PAGE_OFFSET(host_start_addr) == 0) && 
245             (region_end_addr >= host_start_addr + PAGE_SIZE_4MB)) {     // if 4MB boundary
246           large_shadow_pde->page_base_addr = PD32_4MB_BASE_ADDR(host_start_addr);
247         } else {          // else generate 4k pages
248           pte32_t * shadow_pt = NULL;
249           PrintDebug("Handling non aligned large page\n");
250
251           shadow_pde->large_page = 0;
252       
253           shadow_pt = V3_AllocPages(1);
254           memset(shadow_pt, 0, PAGE_SIZE);
255
256           if (handle_pd32_nonaligned_4MB_page(info, shadow_pt, guest_start_addr, large_shadow_pde) == -1) {
257             PrintError("Non Aligned Large Page Error\n");
258             V3_Free(shadow_pt);
259             return -1;
260           }
261
262
263 #ifdef DEBUG_SHADOW_PAGING
264             PrintDebug("non-aligned Shadow PT\n");
265             PrintPT32(PT32_PAGE_ADDR(fault_addr), shadow_pt);     
266 #endif
267           shadow_pde->pt_base_addr = PD32_BASE_ADDR(shadow_pt);
268         }
269
270         
271       } else {
272         // Handle hooked pages as well as other special pages
273         if (handle_special_page_fault(info, fault_addr, error_code) == -1) {
274           PrintError("Special Page Fault handler returned error for address: %x\n", fault_addr);
275           return -1;
276         }
277       }
278     }
279
280   } else if ((shadow_pde_access == PT_WRITE_ERROR) && 
281              (guest_pde->large_page = 1) && 
282              (((pde32_4MB_t *)guest_pde)->dirty == 0)) {
283
284     //
285     // Page Directory Entry marked read-only
286     //
287
288     ((pde32_4MB_t *)guest_pde)->dirty = 1;
289     shadow_pde->writable = guest_pde->writable;
290     return 0;
291
292   } else if (shadow_pde_access == PT_USER_ERROR) {
293
294     //
295     // Page Directory Entry marked non-user
296     //
297     
298     PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x - injecting into guest\n", shadow_pde_access, guest_pde_access);
299     info->ctrl_regs.cr2 = fault_addr;
300     v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
301     return 0;
302
303   } else if (shadow_pde_access == PT_ACCESS_OK) {
304     pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
305     pte32_t * guest_pt = NULL;
306
307     // Page Table Entry fault
308     
309     if (guest_pa_to_host_va(info, PDE32_T_ADDR((*guest_pde)), (addr_t*)&guest_pt) == -1) {
310       PrintDebug("Invalid Guest PTE Address: 0x%x\n", PDE32_T_ADDR((*guest_pde)));
311       // Machine check the guest
312
313       v3_raise_exception(info, MC_EXCEPTION);
314       
315       return 0;
316     }
317
318
319     if (handle_shadow_pte32_fault(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
320       PrintError("Error handling Page fault caused by PTE\n");
321       return -1;
322     }
323
324  } else {
325     // Unknown error raise page fault in guest
326     info->ctrl_regs.cr2 = fault_addr;
327     v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
328
329     // For debugging we will return an error here for the time being, 
330     // this probably shouldn't ever happen
331     PrintDebug("Unknown Error occurred\n");
332     PrintDebug("Manual Says to inject page fault into guest\n");
333
334
335     return 0;
336
337   }
338
339   //PrintDebugPageTables(shadow_pd);
340   PrintDebug("Returning end of PDE function (rip=%x)\n", info->rip);
341   return 0;
342 }
343
344
345
346 /* 
347  * We assume the the guest pte pointer has already been translated to a host virtual address
348  */
349 static int handle_shadow_pte32_fault(struct guest_info * info, 
350                               addr_t fault_addr, 
351                               pf_error_t error_code,
352                               pte32_t * shadow_pt, 
353                               pte32_t * guest_pt) {
354
355   pt_access_status_t guest_pte_access;
356   pt_access_status_t shadow_pte_access;
357   pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
358   pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
359
360
361   // Check the guest page permissions
362   guest_pte_access = can_access_pte32(guest_pt, fault_addr, error_code);
363
364   // Check the shadow page permissions
365   shadow_pte_access = can_access_pte32(shadow_pt, fault_addr, error_code);
366   
367 #ifdef DEBUG_SHADOW_PAGING
368   PrintDebug("Guest PTE: (access=%d)\n\t", guest_pte_access);
369   PrintPTE32(fault_addr, guest_pte);
370   PrintDebug("Shadow PTE: (access=%d)\n\t", shadow_pte_access);
371   PrintPTE32(fault_addr, shadow_pte);
372 #endif
373   
374   /* This should be redone, 
375      but basically the reasoning is that there can be multiple reasons for a page fault:
376      If there is a permissions failure for a page present in the guest _BUT_ 
377      the reason for the fault was that the page is not present in the shadow, 
378      _THEN_ we have to map the shadow page in and reexecute, this will generate 
379      a permissions fault which is _THEN_ valid to send to the guest
380      _UNLESS_ both the guest and shadow have marked the page as not present
381
382      whew...
383   */
384   if ((guest_pte_access != PT_ACCESS_OK) && 
385       ( 
386        ((shadow_pte_access != PT_ENTRY_NOT_PRESENT) &&
387         (guest_pte_access != PT_ENTRY_NOT_PRESENT)) // aka (guest permission error)
388        ||
389        ((shadow_pte_access == PT_ENTRY_NOT_PRESENT) &&
390         (guest_pte_access == PT_ENTRY_NOT_PRESENT)))) {
391     // Inject page fault into the guest 
392     
393     info->ctrl_regs.cr2 = fault_addr;
394     v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
395     
396     PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", guest_pte_access, *(uint_t*)&error_code);
397     return 0; 
398   }
399   
400   
401
402
403   if (shadow_pte_access == PT_ACCESS_OK) {
404     // Inconsistent state...
405     // Guest Re-Entry will flush page tables and everything should now work
406     PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
407     return 0;
408   } else if (shadow_pte_access == PT_ENTRY_NOT_PRESENT) {
409     addr_t shadow_pa;
410     addr_t guest_pa = PTE32_T_ADDR((*guest_pte));
411
412     // Page Table Entry Not Present
413
414     host_region_type_t host_page_type = get_shadow_addr_type(info, guest_pa);
415
416     if (host_page_type == HOST_REGION_INVALID) {
417       // Inject a machine check in the guest
418
419       v3_raise_exception(info, MC_EXCEPTION);
420 #ifdef DEBUG_SHADOW_PAGING
421       PrintDebug("Invalid Guest Address in page table (0x%x)\n", guest_pa);
422       PrintDebug("fault_addr=0x%x next are guest and shadow ptes \n",fault_addr);
423       PrintPTE32(fault_addr,guest_pte);
424       PrintPTE32(fault_addr,shadow_pte);
425       PrintDebug("Done.\n");
426 #endif
427       return 0;
428
429     } else if (host_page_type == HOST_REGION_PHYSICAL_MEMORY) {
430       
431       shadow_pa = get_shadow_addr(info, guest_pa);
432       
433       shadow_pte->page_base_addr = PT32_BASE_ADDR(shadow_pa);
434       
435       shadow_pte->present = guest_pte->present;
436       shadow_pte->user_page = guest_pte->user_page;
437       
438       //set according to VMM policy
439       shadow_pte->write_through = 0;
440       shadow_pte->cache_disable = 0;
441       shadow_pte->global_page = 0;
442       //
443       
444       guest_pte->accessed = 1;
445       
446       if (guest_pte->dirty == 1) {
447         shadow_pte->writable = guest_pte->writable;
448       } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
449         shadow_pte->writable = guest_pte->writable;
450         guest_pte->dirty = 1;
451       } else if ((guest_pte->dirty = 0) && (error_code.write == 0)) {
452         shadow_pte->writable = 0;
453       }
454     } else {
455       // Page fault handled by hook functions
456       if (handle_special_page_fault(info, fault_addr, error_code) == -1) {
457         PrintError("Special Page fault handler returned error for address: %x\n", fault_addr);
458         return -1;
459       }
460     }
461
462   } else if ((shadow_pte_access == PT_WRITE_ERROR) &&
463              (guest_pte->dirty == 0)) {
464     guest_pte->dirty = 1;
465     shadow_pte->writable = guest_pte->writable;
466
467     PrintDebug("Shadow PTE Write Error\n");
468
469     return 0;
470   } else {
471     // Inject page fault into the guest 
472         
473     info->ctrl_regs.cr2 = fault_addr;
474     v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
475
476     PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
477     PrintError("Manual Says to inject page fault into guest\n");
478     return -1;
479   }
480
481   PrintDebug("Returning end of function\n");
482   return 0;
483 }
484
485
486
487
488
489
490 /* Currently Does not work with Segmentation!!! */
491 int handle_shadow_invlpg(struct guest_info * info) {
492   if (info->mem_mode != VIRTUAL_MEM) {
493     // Paging must be turned on...
494     // should handle with some sort of fault I think
495     PrintError("ERROR: INVLPG called in non paged mode\n");
496     return -1;
497   }
498
499
500   if (info->cpu_mode == PROTECTED) {
501     char instr[15];
502     int ret;
503     int index = 0;
504
505     ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
506     if (ret != 15) {
507       PrintError("Could not read instruction 0x%x (ret=%d)\n", info->rip, ret);
508       return -1;
509     }
510
511    
512     /* Can INVLPG work with Segments?? */
513     while (is_prefix_byte(instr[index])) {
514       index++;
515     }
516     
517     
518     if ((instr[index] == (uchar_t)0x0f) &&
519         (instr[index + 1] == (uchar_t)0x01)) {
520
521       addr_t first_operand;
522       addr_t second_operand;
523       operand_type_t addr_type;
524       addr_t guest_cr3 = CR3_TO_PDE32(info->shdw_pg_state.guest_cr3);
525
526       pde32_t * guest_pd = NULL;
527
528       if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
529         PrintError("Invalid Guest PDE Address: 0x%x\n", guest_cr3);
530         return -1;
531       }
532
533       
534
535
536       index += 2;
537
538       addr_type = decode_operands32(&(info->vm_regs), instr + index, &index, &first_operand, &second_operand, REG32);
539
540       if (addr_type == MEM_OPERAND) {
541         pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32(info->shdw_pg_state.shadow_cr3);
542         pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(first_operand)];
543         pde32_t * guest_pde;
544
545         //PrintDebug("PDE Index=%d\n", PDE32_INDEX(first_operand));
546         //PrintDebug("FirstOperand = %x\n", first_operand);
547
548         PrintDebug("Invalidating page for %x\n", first_operand);
549
550         guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(first_operand)]);
551
552         if (guest_pde->large_page == 1) {
553           shadow_pde->present = 0;
554           PrintDebug("Invalidating Large Page\n");
555         } else {
556          
557           if (shadow_pde->present == 1) {
558             pte32_t * shadow_pt = (pte32_t *)PDE32_T_ADDR((*shadow_pde));
559             pte32_t * shadow_pte = (pte32_t *)&shadow_pt[PTE32_INDEX(first_operand)];
560
561 #ifdef DEBUG_SHADOW_PAGING
562             PrintDebug("Setting not present\n");
563             PrintPTE32(first_operand, shadow_pte);
564 #endif
565
566             shadow_pte->present = 0;
567           }
568         }
569
570         info->rip += index;
571
572       } else {
573         PrintError("Invalid Operand type\n");
574         return -1;
575       }
576     } else {
577       PrintError("invalid Instruction Opcode\n");
578       PrintTraceMemDump(instr, 15);
579       return -1;
580     }
581   }
582
583   return 0;
584 }
585
586