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 memory hooks out of core memory map implementation,
[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             if (shdw_reg->flags.write == 0) {
278                 shadow_pte->writable = 0;
279             }
280
281         } else {
282             // Page fault on unhandled memory region
283             
284             if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
285                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
286                 return -1;
287             }
288         }
289     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
290         guest_pte->dirty = 1;
291
292         if (shdw_reg->flags.write == 1) {
293             PrintDebug("Shadow PTE Write Error\n");
294             shadow_pte->writable = guest_pte->writable;
295         } else {
296             if (shdw_reg->unhandled(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
297                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
298                 return -1;
299             }
300         }
301
302
303         return 0;
304
305     } else {
306         // Inject page fault into the guest     
307         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
308             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
309             return -1;
310         }
311
312         PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
313         PrintError("Manual Says to inject page fault into guest\n");
314         return -1;
315     }
316
317     return 0;
318 }
319
320
321
322 static int handle_4MB_shadow_pagefault_32(struct guest_info * info, 
323                                      addr_t fault_addr, pf_error_t error_code, 
324                                      pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
325 {
326     pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
327     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
328     addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
329
330
331     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
332     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
333
334     struct v3_shadow_region * shdw_reg = v3_get_shadow_region(info->vm_info, info->cpu_id, guest_fault_pa);
335
336  
337     if (shdw_reg == NULL) {
338         // Inject a machine check in the guest
339         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
340         v3_raise_exception(info, MC_EXCEPTION);
341         return -1;
342     }
343
344     if (shadow_pte_access == PT_ACCESS_OK) {
345         // Inconsistent state...
346         // Guest Re-Entry will flush tables and everything should now workd
347         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
348         return 0;
349     }
350
351   
352     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
353         // Get the guest physical address of the fault
354
355         if ((shdw_reg->flags.alloced == 1) && 
356             (shdw_reg->flags.read  == 1)) {
357             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_fault_pa);
358
359             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
360
361             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
362
363             shadow_pte->present = 1;
364
365             /* We are assuming that the PDE entry has precedence
366              * so the Shadow PDE will mirror the guest PDE settings, 
367              * and we don't have to worry about them here
368              * Allow everything
369              */
370             shadow_pte->user_page = 1;
371
372             //set according to VMM policy
373             shadow_pte->write_through = large_guest_pde->write_through;
374             shadow_pte->cache_disable = large_guest_pde->cache_disable;
375             shadow_pte->global_page = large_guest_pde->global_page;
376             //
377       
378
379             if (shdw_reg->flags.write == 0) {
380                 shadow_pte->writable = 0;
381             } else {
382                 shadow_pte->writable = 1;
383             }
384
385         } else {
386             if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
387                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
388                 return -1;
389             }
390         }
391     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
392
393         if (shdw_reg->flags.write == 0) {
394             if (shdw_reg->unhandled(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
395                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
396                 return -1;
397             }
398         }
399
400     } else {
401         PrintError("Error in large page fault handler...\n");
402         PrintError("This case should have been handled at the top level handler\n");
403         return -1;
404     }
405
406     PrintDebug("Returning from large page fault handler\n");
407     return 0;
408 }
409
410
411
412
413
414
415
416
417
418
419
420
421 /* If we start to optimize we should look up the guest pages in the cache... */
422 static inline int handle_shadow_invlpg_32(struct guest_info * info, addr_t vaddr) {
423     pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
424     pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)];
425
426     addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
427     pde32_t * guest_pd = NULL;
428     pde32_t * guest_pde;
429
430     if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
431         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
432         return -1;
433     }
434   
435     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]);
436   
437     if (guest_pde->large_page == 1) {
438         shadow_pde->present = 0;
439         PrintDebug("Invalidating Large Page\n");
440     } else if (shadow_pde->present == 1) {
441         pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr);
442         pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] );
443     
444         PrintDebug("Setting not present\n");
445     
446         shadow_pte->present = 0;
447     }
448     return 0;
449 }