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.


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