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.


moved shadow paging implementations over to new memory region flags structure
[palacios.git] / palacios / src / palacios / mmu / vmm_shdw_pg_tlb_32.h
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Jack Lange <jarusl@cs.northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jarusl@cs.northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20
21
22
23 static inline int activate_shadow_pt_32(struct guest_info * core) {
24     struct cr3_32 * shadow_cr3 = (struct cr3_32 *)&(core->ctrl_regs.cr3);
25     struct cr3_32 * guest_cr3 = (struct cr3_32 *)&(core->shdw_pg_state.guest_cr3);
26     struct shadow_page_data * shdw_page = create_new_shadow_pt(core);
27
28     shdw_page->cr3 = shdw_page->page_pa;
29     
30     shadow_cr3->pdt_base_addr = PAGE_BASE_ADDR_4KB(shdw_page->page_pa);
31     PrintDebug( "Created new shadow page table %p\n", (void *)BASE_TO_PAGE_ADDR(shadow_cr3->pdt_base_addr));
32   
33     shadow_cr3->pwt = guest_cr3->pwt;
34     shadow_cr3->pcd = guest_cr3->pcd;
35
36     return 0;
37 }
38
39
40
41
42 /* 
43  * *
44  * * 
45  * * 32 bit Page table fault handlers
46  * *
47  * *
48  */
49 static int handle_4MB_shadow_pagefault_32(struct guest_info * info,  addr_t fault_addr, pf_error_t error_code, 
50                                           pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde);
51
52 static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
53                                           pte32_t * shadow_pt,  pte32_t * guest_pt);
54
55
56 static inline int handle_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
57     pde32_t * guest_pd = NULL;
58     pde32_t * shadow_pd = CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
59     addr_t guest_cr3 = CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
60     pt_access_status_t guest_pde_access;
61     pt_access_status_t shadow_pde_access;
62     pde32_t * guest_pde = NULL;
63     pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
64
65     PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
66     PrintDebug("Handling PDE32 Fault\n");
67
68     if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
69         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
70         return -1;
71     } 
72
73     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
74
75
76     // Check the guest page permissions
77     guest_pde_access = v3_can_access_pde32(guest_pd, fault_addr, error_code);
78
79     // Check the shadow page permissions
80     shadow_pde_access = v3_can_access_pde32(shadow_pd, fault_addr, error_code);
81   
82     /* Was the page fault caused by the Guest's page tables? */
83     if (v3_is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
84         PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (shdw access error=%d)  (pf error code=%d)\n", 
85                    *(uint_t *)&guest_pde_access, *(uint_t *)&shadow_pde_access, *(uint_t *)&error_code);
86         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
87             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
88             return -1;
89         }
90         return 0;
91     }
92
93
94
95     if (shadow_pde_access == PT_ACCESS_USER_ERROR) {
96         // 
97         // PDE Entry marked non user
98         //
99         PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
100                    shadow_pde_access, guest_pde_access);
101         
102         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
103             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
104             return -1;
105         }
106         return 0;
107     } else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
108                (guest_pde->large_page == 1)) {
109         
110         ((pde32_4MB_t *)guest_pde)->dirty = 1;
111         shadow_pde->writable = guest_pde->writable;
112         return 0;
113     } else if ((shadow_pde_access != PT_ACCESS_NOT_PRESENT) &&
114                (shadow_pde_access != PT_ACCESS_OK)) {
115         // inject page fault in guest
116         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
117             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
118             return -1;
119         }
120         PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
121         PrintDebug("Manual Says to inject page fault into guest\n");
122         return 0;
123     }
124
125   
126     pte32_t * shadow_pt = NULL;
127     pte32_t * guest_pt = NULL;
128
129     // Get the next shadow page level, allocate if not present
130
131     if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) {
132         struct shadow_page_data * shdw_page =  create_new_shadow_pt(info);
133         shadow_pt = (pte32_t *)V3_VAddr((void *)shdw_page->page_pa);
134
135         shadow_pde->present = 1;
136         shadow_pde->user_page = guest_pde->user_page;
137
138
139         if (guest_pde->large_page == 0) {
140             shadow_pde->writable = guest_pde->writable;
141         } else {
142             // This large page flag is temporary until we can get a working cache....
143             ((pde32_4MB_t *)guest_pde)->vmm_info = V3_LARGE_PG;
144
145             if (error_code.write) {
146                 shadow_pde->writable = guest_pde->writable;
147                 ((pde32_4MB_t *)guest_pde)->dirty = 1;
148             } else {
149                 shadow_pde->writable = 0;
150                 ((pde32_4MB_t *)guest_pde)->dirty = 0;
151             }
152         }
153       
154
155         // VMM Specific options
156         shadow_pde->write_through = guest_pde->write_through;
157         shadow_pde->cache_disable = guest_pde->cache_disable;
158         shadow_pde->global_page = guest_pde->global_page;
159         //
160       
161         guest_pde->accessed = 1;
162       
163
164         shadow_pde->pt_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
165     } else {
166         shadow_pt = (pte32_t *)V3_VAddr((void *)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr));
167     }
168
169
170       
171     if (guest_pde->large_page == 0) {
172         if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
173             // Machine check the guest
174             PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
175             v3_raise_exception(info, MC_EXCEPTION);
176             return 0;
177         }
178
179         if (handle_pte_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
180             PrintError("Error handling Page fault caused by PTE\n");
181             return -1;
182         }
183     } else {
184         if (handle_4MB_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
185             PrintError("Error handling large pagefault\n");
186             return -1;
187         }       
188     }
189
190     return 0;
191 }
192
193
194 static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
195                                           pte32_t * shadow_pt, pte32_t * guest_pt) {
196
197     pt_access_status_t guest_pte_access;
198     pt_access_status_t shadow_pte_access;
199     pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
200     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
201     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
202
203     struct v3_shadow_region * shdw_reg =  v3_get_shadow_region(info->vm_info, info->cpu_id, guest_pa);
204
205     if (shdw_reg == NULL) {
206         // Inject a machine check in the guest
207         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
208         v3_raise_exception(info, MC_EXCEPTION);
209         return 0;
210     }
211
212     // Check the guest page permissions
213     guest_pte_access = v3_can_access_pte32(guest_pt, fault_addr, error_code);
214
215     // Check the shadow page permissions
216     shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
217   
218   
219     /* Was the page fault caused by the Guest's page tables? */
220     if (v3_is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
221
222         PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
223                    guest_pte_access, *(uint_t*)&error_code);
224         
225
226         //   inject:
227         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
228             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
229             return -1;
230         }       
231
232         return 0; 
233     }
234
235   
236   
237     if (shadow_pte_access == PT_ACCESS_OK) {
238         // Inconsistent state...
239         // Guest Re-Entry will flush page tables and everything should now work
240         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
241         return 0;
242     }
243
244
245     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
246         // Page Table Entry Not Present
247         PrintDebug("guest_pa =%p\n", (void *)guest_pa);
248
249         if ((shdw_reg->flags.alloced == 1) && (shdw_reg->flags.read == 1)) {
250             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_pa);
251       
252             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
253
254             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
255       
256             shadow_pte->present = guest_pte->present;
257             shadow_pte->user_page = guest_pte->user_page;
258       
259             //set according to VMM policy
260             shadow_pte->write_through = guest_pte->write_through;
261             shadow_pte->cache_disable = guest_pte->cache_disable;
262             shadow_pte->global_page = guest_pte->global_page;
263             //
264       
265             guest_pte->accessed = 1;
266       
267             if (guest_pte->dirty == 1) {
268                 shadow_pte->writable = guest_pte->writable;
269             } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
270                 shadow_pte->writable = guest_pte->writable;
271                 guest_pte->dirty = 1;
272             } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {
273                 shadow_pte->writable = 0;
274             }
275
276
277
278             // Write hooks trump all, and are set Read Only
279             if (shdw_reg->flags.write == 0) {
280                 shadow_pte->writable = 0;
281             }
282
283         } else if (shdw_reg->flags.hook == 1) {
284             // Page fault handled by hook functions
285
286             if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
287                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
288                 return -1;
289             }
290         }
291     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
292         guest_pte->dirty = 1;
293
294         if (shdw_reg->flags.hook == 1) {
295             if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
296                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
297                 return -1;
298             }
299         } else {
300             PrintDebug("Shadow PTE Write Error\n");
301             shadow_pte->writable = guest_pte->writable;
302         }
303
304
305         return 0;
306
307     } else {
308         // Inject page fault into the guest     
309         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
310             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
311             return -1;
312         }
313
314         PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
315         PrintError("Manual Says to inject page fault into guest\n");
316         return -1;
317     }
318
319     return 0;
320 }
321
322
323
324 static int handle_4MB_shadow_pagefault_32(struct guest_info * info, 
325                                      addr_t fault_addr, pf_error_t error_code, 
326                                      pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
327 {
328     pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
329     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
330     addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
331
332
333     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
334     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
335
336     struct v3_shadow_region * shdw_reg = v3_get_shadow_region(info->vm_info, info->cpu_id, guest_fault_pa);
337
338  
339     if (shdw_reg == NULL) {
340         // Inject a machine check in the guest
341         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
342         v3_raise_exception(info, MC_EXCEPTION);
343         return -1;
344     }
345
346     if (shadow_pte_access == PT_ACCESS_OK) {
347         // Inconsistent state...
348         // Guest Re-Entry will flush tables and everything should now workd
349         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
350         return 0;
351     }
352
353   
354     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
355         // Get the guest physical address of the fault
356
357         if ((shdw_reg->flags.alloced == 1) && 
358             (shdw_reg->flags.read  == 1)) {
359             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_fault_pa);
360
361             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
362
363             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
364
365             shadow_pte->present = 1;
366
367             /* We are assuming that the PDE entry has precedence
368              * so the Shadow PDE will mirror the guest PDE settings, 
369              * and we don't have to worry about them here
370              * Allow everything
371              */
372             shadow_pte->user_page = 1;
373
374             //set according to VMM policy
375             shadow_pte->write_through = large_guest_pde->write_through;
376             shadow_pte->cache_disable = large_guest_pde->cache_disable;
377             shadow_pte->global_page = large_guest_pde->global_page;
378             //
379       
380
381             if (shdw_reg->flags.write == 0) {
382                 shadow_pte->writable = 0;
383             } else {
384                 shadow_pte->writable = 1;
385             }
386
387         } else if (shdw_reg->flags.hook == 1) {
388             if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
389                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
390                 return -1;
391             }
392         }
393     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
394
395         if (shdw_reg->flags.hook == 1) {
396             if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
397                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
398                 return -1;
399             }
400         }
401
402     } else {
403         PrintError("Error in large page fault handler...\n");
404         PrintError("This case should have been handled at the top level handler\n");
405         return -1;
406     }
407
408     PrintDebug("Returning from large page fault handler\n");
409     return 0;
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423 /* If we start to optimize we should look up the guest pages in the cache... */
424 static inline int handle_shadow_invlpg_32(struct guest_info * info, addr_t vaddr) {
425     pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
426     pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)];
427
428     addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
429     pde32_t * guest_pd = NULL;
430     pde32_t * guest_pde;
431
432     if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
433         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
434         return -1;
435     }
436   
437     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]);
438   
439     if (guest_pde->large_page == 1) {
440         shadow_pde->present = 0;
441         PrintDebug("Invalidating Large Page\n");
442     } else if (shadow_pde->present == 1) {
443         pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr);
444         pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] );
445     
446         PrintDebug("Setting not present\n");
447     
448         shadow_pte->present = 0;
449     }
450     return 0;
451 }