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.


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