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 internal memory map routines over to new flags structure instead of the hardcod...
[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
165
166         shadow_pde->pt_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
167     } else {
168         shadow_pt = (pte32_t *)V3_VAddr((void *)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr));
169     }
170
171
172       
173     if (guest_pde->large_page == 0) {
174         if (guest_pa_to_host_va(info, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
175             // Machine check the guest
176             PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
177             v3_raise_exception(info, MC_EXCEPTION);
178             return 0;
179         }
180
181         if (handle_pte_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
182             PrintError("Error handling Page fault caused by PTE\n");
183             return -1;
184         }
185     } else {
186         if (handle_4MB_shadow_pagefault_32(info, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
187             PrintError("Error handling large pagefault\n");
188             return -1;
189         }       
190     }
191
192     return 0;
193 }
194
195
196 static int handle_pte_shadow_pagefault_32(struct guest_info * info, addr_t fault_addr, pf_error_t error_code,
197                                           pte32_t * shadow_pt, pte32_t * guest_pt) {
198
199     pt_access_status_t guest_pte_access;
200     pt_access_status_t shadow_pte_access;
201     pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
202     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
203     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
204
205     struct v3_shadow_region * shdw_reg =  v3_get_shadow_region(info->vm_info, info->cpu_id, guest_pa);
206
207     if (shdw_reg == NULL) {
208         // Inject a machine check in the guest
209         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
210         v3_raise_exception(info, MC_EXCEPTION);
211         return 0;
212     }
213
214     // Check the guest page permissions
215     guest_pte_access = v3_can_access_pte32(guest_pt, fault_addr, error_code);
216
217     // Check the shadow page permissions
218     shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
219   
220   
221     /* Was the page fault caused by the Guest's page tables? */
222     if (v3_is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
223
224         PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
225                    guest_pte_access, *(uint_t*)&error_code);
226         
227
228         //   inject:
229         if (v3_inject_guest_pf(info, fault_addr, error_code) == -1) {
230             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
231             return -1;
232         }       
233
234         return 0; 
235     }
236
237   
238   
239     if (shadow_pte_access == PT_ACCESS_OK) {
240         // Inconsistent state...
241         // Guest Re-Entry will flush page tables and everything should now work
242         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
243         return 0;
244     }
245
246
247     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
248         // Page Table Entry Not Present
249         PrintDebug("guest_pa =%p\n", (void *)guest_pa);
250
251         if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) ||
252             (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
253             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_pa);
254       
255             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
256
257             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
258       
259             shadow_pte->present = guest_pte->present;
260             shadow_pte->user_page = guest_pte->user_page;
261       
262             //set according to VMM policy
263             shadow_pte->write_through = guest_pte->write_through;
264             shadow_pte->cache_disable = guest_pte->cache_disable;
265             shadow_pte->global_page = guest_pte->global_page;
266             //
267       
268             guest_pte->accessed = 1;
269       
270             if (guest_pte->dirty == 1) {
271                 shadow_pte->writable = guest_pte->writable;
272             } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
273                 shadow_pte->writable = guest_pte->writable;
274                 guest_pte->dirty = 1;
275             } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {
276                 shadow_pte->writable = 0;
277             }
278
279
280
281             // Write hooks trump all, and are set Read Only
282             if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
283                 shadow_pte->writable = 0;
284             }
285
286         } else {
287             // Page fault handled by hook functions
288
289             if (v3_handle_mem_hook(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->host_type == SHDW_REGION_WRITE_HOOK) {
298             if (v3_handle_mem_hook(info, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
299                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
300                 return -1;
301             }
302         } else {
303             PrintDebug("Shadow PTE Write Error\n");
304             shadow_pte->writable = guest_pte->writable;
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_shadow_region * shdw_reg = v3_get_shadow_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->host_type == SHDW_REGION_ALLOCATED) || 
361             (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
362             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, info->cpu_id, guest_fault_pa);
363
364             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
365
366             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
367
368             shadow_pte->present = 1;
369
370             /* We are assuming that the PDE entry has precedence
371              * so the Shadow PDE will mirror the guest PDE settings, 
372              * and we don't have to worry about them here
373              * Allow everything
374              */
375             shadow_pte->user_page = 1;
376
377             if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
378                 shadow_pte->writable = 0;
379             } else {
380                 shadow_pte->writable = 1;
381             }
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         } else {
390             if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
391                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
392                 return -1;
393             }
394         }
395     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
396
397         if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
398
399             if (v3_handle_mem_hook(info, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
400                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
401                 return -1;
402             }
403         }
404
405     } else {
406         PrintError("Error in large page fault handler...\n");
407         PrintError("This case should have been handled at the top level handler\n");
408         return -1;
409     }
410
411     PrintDebug("Returning from large page fault handler\n");
412     return 0;
413 }
414
415
416
417
418
419
420
421
422
423
424
425
426 /* If we start to optimize we should look up the guest pages in the cache... */
427 static inline int handle_shadow_invlpg_32(struct guest_info * info, addr_t vaddr) {
428     pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(info->ctrl_regs.cr3);
429     pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)];
430
431     addr_t guest_cr3 =  CR3_TO_PDE32_PA(info->shdw_pg_state.guest_cr3);
432     pde32_t * guest_pd = NULL;
433     pde32_t * guest_pde;
434
435     if (guest_pa_to_host_va(info, guest_cr3, (addr_t*)&guest_pd) == -1) {
436         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
437         return -1;
438     }
439   
440     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]);
441   
442     if (guest_pde->large_page == 1) {
443         shadow_pde->present = 0;
444         PrintDebug("Invalidating Large Page\n");
445     } else if (shadow_pde->present == 1) {
446         pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr);
447         pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] );
448     
449         PrintDebug("Setting not present\n");
450     
451         shadow_pte->present = 0;
452     }
453     return 0;
454 }