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.


build system fixes
[palacios.git] / palacios / src / palacios / mmu / vmm_shdw_pg_kvm_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 #ifdef CONFIG_SHADOW_CACHE
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
27     struct shadow_page_cache_data * shdw_page;
28
29     if (core->n_free_shadow_pages < MIN_FREE_SHADOW_PAGES) {    
30         shadow_free_some_pages(core);
31     }
32
33     shdw_page = shadow_page_get_page(core, (addr_t)(guest_cr3->pdt_base_addr), 2, 0, 0, 0, 0);
34     PrintDebug("act shdw pt: gcr3 %p\n",(void *)BASE_TO_PAGE_ADDR(guest_cr3->pdt_base_addr));
35
36     shdw_page->cr3 = shdw_page->page_pa;
37     
38     shadow_cr3->pdt_base_addr = PAGE_BASE_ADDR_4KB(shdw_page->page_pa);
39     PrintDebug( "Created new shadow page table %p\n", (void *)BASE_TO_PAGE_ADDR(shadow_cr3->pdt_base_addr));
40   
41     shadow_cr3->pwt = guest_cr3->pwt;
42     shadow_cr3->pcd = guest_cr3->pcd;
43
44     return 0;
45 }
46
47
48
49
50 /* 
51  * *
52  * * 
53  * * 32 bit Page table fault handlers
54  * *
55  * *
56  */
57
58 static inline int fix_read_pf_32(pte32_t * shadow_pte, uint_t vmm_info) {
59     PrintDebug("\trdipf, start vmm_info %d\n",vmm_info);
60     if((vmm_info & PT_USER_MASK) && !(shadow_pte->user_page)) {
61         shadow_pte->user_page = 1;
62         shadow_pte->writable = 0;
63         return 1;
64     }   
65     return 0;
66 }
67
68 static inline int fix_write_pf_32(struct guest_info * core, pte32_t * shadow_pte, pte32_t * guest_pte, 
69     int user, int * write_pt, addr_t guest_fn, uint_t vmm_info) {
70         
71     int writable_shadow;
72     struct cr0_32 * guest_cr0;
73     struct shadow_page_cache_data * page;
74     *write_pt = 0;
75
76     PrintDebug("\twripf, start vmm_info %d\n",vmm_info);
77         
78     if(shadow_pte->writable) {
79         return 0;
80     }
81
82     PrintDebug("\twrpf: pass writable\n");
83         
84     writable_shadow = vmm_info & PT_WRITABLE_MASK;
85
86     PrintDebug("\twrpf: writable_shadow %d\n",writable_shadow);
87         
88     if(user) {
89         if(!(vmm_info & PT_USER_MASK) || !writable_shadow) {
90             PrintDebug("\twrpf: 1st usr chk\n");
91             return 0;
92         }
93     } else {
94         if(!writable_shadow) {
95             guest_cr0 = (struct cr0_32 *)&(core->shdw_pg_state.guest_cr0);
96             PrintDebug("\twrpf: wp %d\n",guest_cr0->wp);
97
98             if (guest_cr0->wp) {
99                 return 0;
100             }
101             shadow_pte->user_page = 0;                          
102         }
103     }
104                         
105     if (guest_pte->present == 0) { 
106         memset((void *)shadow_pte, 0, sizeof(struct pte32));
107         PrintDebug("\twrpf: guest non present\n");
108         return 0;
109     }
110
111     if (user) {
112         while ((page = shadow_page_lookup_page(core, guest_fn, 0)) != NULL) {
113             shadow_zap_page(core,page);
114         }
115
116         PrintDebug("\twrpf: zap\n");
117
118     } else if((page = shadow_page_lookup_page(core, guest_fn,0))  != NULL)  {
119         if ((page = shadow_page_lookup_page(core, guest_fn,0)) != NULL) {
120             guest_pte->dirty = 1;
121             *write_pt = 1;
122             PrintDebug("\twrpf: write need\n");
123             return 0;
124         }
125     }   
126
127     shadow_pte->writable = 1; //will lost every pt update trap not sure for this
128     guest_pte->dirty = 1;       
129         
130     rmap_add(core, (addr_t)shadow_pte);
131         
132     PrintDebug("\twrpf: on writable\n");
133     return 1;
134 }
135
136 #endif
137
138
139 static int handle_4MB_shadow_pagefault_32(struct guest_info * core,  addr_t fault_addr, pf_error_t error_code, 
140                                           pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde);
141
142 static int handle_pte_shadow_pagefault_32(struct guest_info * core, addr_t fault_addr, pf_error_t error_code,
143                                           pte32_t * shadow_pt,  pte32_t * guest_pt);
144
145
146 static inline int handle_shadow_pagefault_32(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
147     pde32_t * guest_pd = NULL;
148     pde32_t * shadow_pd = CR3_TO_PDE32_VA(core->ctrl_regs.cr3);
149     addr_t guest_cr3 = CR3_TO_PDE32_PA(core->shdw_pg_state.guest_cr3);
150     pt_access_status_t guest_pde_access;
151     pt_access_status_t shadow_pde_access;
152     pde32_t * guest_pde = NULL;
153     pde32_t * shadow_pde = (pde32_t *)&(shadow_pd[PDE32_INDEX(fault_addr)]);
154
155     PrintDebug("Shadow page fault handler: %p\n", (void*) fault_addr );
156     PrintDebug("Handling PDE32 Fault\n");
157
158     if (guest_pa_to_host_va(core, guest_cr3, (addr_t*)&guest_pd) == -1) {
159         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
160         return -1;
161     } 
162
163     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(fault_addr)]);
164
165
166     // Check the guest page permissions
167     guest_pde_access = v3_can_access_pde32(guest_pd, fault_addr, error_code);
168
169     // Check the shadow page permissions
170     shadow_pde_access = v3_can_access_pde32(shadow_pd, fault_addr, error_code);
171   
172     /* Was the page fault caused by the Guest's page tables? */
173     if (v3_is_guest_pf(guest_pde_access, shadow_pde_access) == 1) {
174         PrintDebug("Injecting PDE pf to guest: (guest access error=%d) (shdw access error=%d)  (pf error code=%d)\n", 
175                    *(uint_t *)&guest_pde_access, *(uint_t *)&shadow_pde_access, *(uint_t *)&error_code);
176         if (v3_inject_guest_pf(core, fault_addr, error_code) == -1) {
177             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
178             return -1;
179         }
180         return 0;
181     }
182
183
184
185     if (shadow_pde_access == PT_ACCESS_USER_ERROR) {
186         // 
187         // PDE Entry marked non user
188         //
189         PrintDebug("Shadow Paging User access error (shadow_pde_access=0x%x, guest_pde_access=0x%x)\n", 
190                    shadow_pde_access, guest_pde_access);
191         
192         if (v3_inject_guest_pf(core, fault_addr, error_code) == -1) {
193             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
194             return -1;
195         }
196         return 0;
197     } else if ((shadow_pde_access == PT_ACCESS_WRITE_ERROR) && 
198                (guest_pde->large_page == 1)) {
199         
200         ((pde32_4MB_t *)guest_pde)->dirty = 1;
201         shadow_pde->writable = guest_pde->writable;
202         return 0;
203     } else if ((shadow_pde_access != PT_ACCESS_NOT_PRESENT) &&
204                (shadow_pde_access != PT_ACCESS_OK)) {
205         // inject page fault in guest
206         if (v3_inject_guest_pf(core, fault_addr, error_code) == -1) {
207             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
208             return -1;
209         }
210         PrintDebug("Unknown Error occurred (shadow_pde_access=%d)\n", shadow_pde_access);
211         PrintDebug("Manual Says to inject page fault into guest\n");
212         return 0;
213     }
214
215   
216     pte32_t * shadow_pt = NULL;
217     pte32_t * guest_pt = NULL;
218
219     // Get the next shadow page level, allocate if not present
220
221     if (shadow_pde_access == PT_ACCESS_NOT_PRESENT) {
222         struct shadow_page_data * shdw_page =  create_new_shadow_pt(core);
223         shadow_pt = (pte32_t *)V3_VAddr((void *)shdw_page->page_pa);
224
225         shadow_pde->present = 1;
226         shadow_pde->user_page = guest_pde->user_page;
227
228
229         if (guest_pde->large_page == 0) {
230             shadow_pde->writable = guest_pde->writable;
231         } else {
232             // This large page flag is temporary until we can get a working cache....
233             ((pde32_4MB_t *)guest_pde)->vmm_info = V3_LARGE_PG;
234
235             if (error_code.write) {
236                 shadow_pde->writable = guest_pde->writable;
237                 ((pde32_4MB_t *)guest_pde)->dirty = 1;
238             } else {
239                 shadow_pde->writable = 0;
240                 ((pde32_4MB_t *)guest_pde)->dirty = 0;
241             }
242         }
243       
244
245         // VMM Specific options
246         shadow_pde->write_through = guest_pde->write_through;
247         shadow_pde->cache_disable = guest_pde->cache_disable;
248         shadow_pde->global_page = guest_pde->global_page;
249         //
250       
251         guest_pde->accessed = 1;
252       
253
254
255
256         shadow_pde->pt_base_addr = PAGE_BASE_ADDR(shdw_page->page_pa);
257     } else {
258         shadow_pt = (pte32_t *)V3_VAddr((void *)BASE_TO_PAGE_ADDR(shadow_pde->pt_base_addr));
259     }
260
261
262       
263     if (guest_pde->large_page == 0) {
264         if (guest_pa_to_host_va(core, BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr), (addr_t*)&guest_pt) == -1) {
265             // Machine check the guest
266             PrintDebug("Invalid Guest PTE Address: 0x%p\n", (void *)BASE_TO_PAGE_ADDR(guest_pde->pt_base_addr));
267             v3_raise_exception(core, MC_EXCEPTION);
268             return 0;
269         }
270
271         if (handle_pte_shadow_pagefault_32(core, fault_addr, error_code, shadow_pt, guest_pt)  == -1) {
272             PrintError("Error handling Page fault caused by PTE\n");
273             return -1;
274         }
275     } else {
276         if (handle_4MB_shadow_pagefault_32(core, fault_addr, error_code, shadow_pt, (pde32_4MB_t *)guest_pde) == -1) {
277             PrintError("Error handling large pagefault\n");
278             return -1;
279         }       
280     }
281
282     return 0;
283 }
284
285
286 static int handle_pte_shadow_pagefault_32(struct guest_info * core, addr_t fault_addr, pf_error_t error_code,
287                                           pte32_t * shadow_pt, pte32_t * guest_pt) {
288
289     pt_access_status_t guest_pte_access;
290     pt_access_status_t shadow_pte_access;
291     pte32_t * guest_pte = (pte32_t *)&(guest_pt[PTE32_INDEX(fault_addr)]);;
292     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
293     addr_t guest_pa = BASE_TO_PAGE_ADDR((addr_t)(guest_pte->page_base_addr)) +  PAGE_OFFSET(fault_addr);
294
295     struct v3_shadow_region * shdw_reg =  v3_get_shadow_region(core->vm_info, core->cpu_id, guest_pa);
296
297     if (shdw_reg == NULL) {
298         // Inject a machine check in the guest
299         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_pa);
300         v3_raise_exception(core, MC_EXCEPTION);
301         return 0;
302     }
303
304     // Check the guest page permissions
305     guest_pte_access = v3_can_access_pte32(guest_pt, fault_addr, error_code);
306
307     // Check the shadow page permissions
308     shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
309   
310   
311     /* Was the page fault caused by the Guest's page tables? */
312     if (v3_is_guest_pf(guest_pte_access, shadow_pte_access) == 1) {
313
314         PrintDebug("Access error injecting pf to guest (guest access error=%d) (pf error code=%d)\n", 
315                    guest_pte_access, *(uint_t*)&error_code);
316         
317
318         //   inject:
319         if (v3_inject_guest_pf(core, fault_addr, error_code) == -1) {
320             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
321             return -1;
322         }       
323
324         return 0; 
325     }
326
327   
328   
329     if (shadow_pte_access == PT_ACCESS_OK) {
330         // Inconsistent state...
331         // Guest Re-Entry will flush page tables and everything should now work
332         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
333         return 0;
334     }
335
336
337     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
338         // Page Table Entry Not Present
339         PrintDebug("guest_pa =%p\n", (void *)guest_pa);
340
341         if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) ||
342             (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
343             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->cpu_id, guest_pa);
344       
345             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
346
347             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
348       
349             shadow_pte->present = guest_pte->present;
350             shadow_pte->user_page = guest_pte->user_page;
351       
352             //set according to VMM policy
353             shadow_pte->write_through = guest_pte->write_through;
354             shadow_pte->cache_disable = guest_pte->cache_disable;
355             shadow_pte->global_page = guest_pte->global_page;
356             //
357       
358             guest_pte->accessed = 1;
359       
360             if (guest_pte->dirty == 1) {
361                 shadow_pte->writable = guest_pte->writable;
362             } else if ((guest_pte->dirty == 0) && (error_code.write == 1)) {
363                 shadow_pte->writable = guest_pte->writable;
364                 guest_pte->dirty = 1;
365             } else if ((guest_pte->dirty == 0) && (error_code.write == 0)) {
366                 shadow_pte->writable = 0;
367             }
368
369
370
371             // Write hooks trump all, and are set Read Only
372             if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
373                 shadow_pte->writable = 0;
374             }
375
376         } else {
377             // Page fault handled by hook functions
378
379             if (v3_handle_mem_full_hook(core, fault_addr, guest_pa, shdw_reg, error_code) == -1) {
380                 PrintError("Special Page fault handler returned error for address: %p\n",  (void *)fault_addr);
381                 return -1;
382             }
383         }
384     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
385         guest_pte->dirty = 1;
386
387         if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
388             if (v3_handle_mem_wr_hook(core, fault_addr, guest_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         } else {
393             PrintDebug("Shadow PTE Write Error\n");
394             shadow_pte->writable = guest_pte->writable;
395         }
396
397
398         return 0;
399
400     } else {
401         // Inject page fault into the guest     
402         if (v3_inject_guest_pf(core, fault_addr, error_code) == -1) {
403             PrintError("Could not inject guest page fault for vaddr %p\n", (void *)fault_addr);
404             return -1;
405         }
406
407         PrintError("PTE Page fault fell through... Not sure if this should ever happen\n");
408         PrintError("Manual Says to inject page fault into guest\n");
409         return -1;
410     }
411
412     return 0;
413 }
414
415
416
417 static int handle_4MB_shadow_pagefault_32(struct guest_info * core, 
418                                      addr_t fault_addr, pf_error_t error_code, 
419                                      pte32_t * shadow_pt, pde32_4MB_t * large_guest_pde) 
420 {
421     pt_access_status_t shadow_pte_access = v3_can_access_pte32(shadow_pt, fault_addr, error_code);
422     pte32_t * shadow_pte = (pte32_t *)&(shadow_pt[PTE32_INDEX(fault_addr)]);
423     addr_t guest_fault_pa = BASE_TO_PAGE_ADDR_4MB(large_guest_pde->page_base_addr) + PAGE_OFFSET_4MB(fault_addr);  
424
425
426     PrintDebug("Handling 4MB fault (guest_fault_pa=%p) (error_code=%x)\n", (void *)guest_fault_pa, *(uint_t*)&error_code);
427     PrintDebug("ShadowPT=%p, LargeGuestPDE=%p\n", shadow_pt, large_guest_pde);
428
429     struct v3_shadow_region * shdw_reg = v3_get_shadow_region(core->vm_info, core->cpu_id, guest_fault_pa);
430
431  
432     if (shdw_reg == NULL) {
433         // Inject a machine check in the guest
434         PrintDebug("Invalid Guest Address in page table (0x%p)\n", (void *)guest_fault_pa);
435         v3_raise_exception(core, MC_EXCEPTION);
436         return -1;
437     }
438
439     if (shadow_pte_access == PT_ACCESS_OK) {
440         // Inconsistent state...
441         // Guest Re-Entry will flush tables and everything should now workd
442         PrintDebug("Inconsistent state... Guest re-entry should flush tlb\n");
443         return 0;
444     }
445
446   
447     if (shadow_pte_access == PT_ACCESS_NOT_PRESENT) {
448         // Get the guest physical address of the fault
449
450         if ((shdw_reg->host_type == SHDW_REGION_ALLOCATED) || 
451             (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK)) {
452             addr_t shadow_pa = v3_get_shadow_addr(shdw_reg, core->cpu_id, guest_fault_pa);
453
454             shadow_pte->page_base_addr = PAGE_BASE_ADDR(shadow_pa);
455
456             PrintDebug("\tMapping shadow page (%p)\n", (void *)BASE_TO_PAGE_ADDR(shadow_pte->page_base_addr));
457
458             shadow_pte->present = 1;
459
460             /* We are assuming that the PDE entry has precedence
461              * so the Shadow PDE will mirror the guest PDE settings, 
462              * and we don't have to worry about them here
463              * Allow everything
464              */
465             shadow_pte->user_page = 1;
466
467             if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
468                 shadow_pte->writable = 0;
469             } else {
470                 shadow_pte->writable = 1;
471             }
472
473             //set according to VMM policy
474             shadow_pte->write_through = large_guest_pde->write_through;
475             shadow_pte->cache_disable = large_guest_pde->cache_disable;
476             shadow_pte->global_page = large_guest_pde->global_page;
477             //
478       
479         } else {
480             if (v3_handle_mem_full_hook(core, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
481                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
482                 return -1;
483             }
484         }
485     } else if (shadow_pte_access == PT_ACCESS_WRITE_ERROR) {
486
487         if (shdw_reg->host_type == SHDW_REGION_WRITE_HOOK) {
488
489             if (v3_handle_mem_wr_hook(core, fault_addr, guest_fault_pa, shdw_reg, error_code) == -1) {
490                 PrintError("Special Page Fault handler returned error for address: %p\n", (void *)fault_addr);
491                 return -1;
492             }
493         }
494
495     } else {
496         PrintError("Error in large page fault handler...\n");
497         PrintError("This case should have been handled at the top level handler\n");
498         return -1;
499     }
500
501     PrintDebug("Returning from large page fault handler\n");
502     return 0;
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516 /* If we start to optimize we should look up the guest pages in the cache... */
517 static inline int handle_shadow_invlpg_32(struct guest_info * core, addr_t vaddr) {
518     pde32_t * shadow_pd = (pde32_t *)CR3_TO_PDE32_VA(core->ctrl_regs.cr3);
519     pde32_t * shadow_pde = (pde32_t *)&shadow_pd[PDE32_INDEX(vaddr)];
520
521     addr_t guest_cr3 =  CR3_TO_PDE32_PA(core->shdw_pg_state.guest_cr3);
522     pde32_t * guest_pd = NULL;
523     pde32_t * guest_pde;
524
525     if (guest_pa_to_host_va(core, guest_cr3, (addr_t*)&guest_pd) == -1) {
526         PrintError("Invalid Guest PDE Address: 0x%p\n",  (void *)guest_cr3);
527         return -1;
528     }
529   
530     guest_pde = (pde32_t *)&(guest_pd[PDE32_INDEX(vaddr)]);
531   
532     if (guest_pde->large_page == 1) {
533         shadow_pde->present = 0;
534         PrintDebug("Invalidating Large Page\n");
535     } else if (shadow_pde->present == 1) {
536         pte32_t * shadow_pt = (pte32_t *)(addr_t)BASE_TO_PAGE_ADDR_4KB(shadow_pde->pt_base_addr);
537         pte32_t * shadow_pte = (pte32_t *) V3_VAddr( (void*) &shadow_pt[PTE32_INDEX(vaddr)] );
538     
539         PrintDebug("Setting not present\n");
540     
541         shadow_pte->present = 0;
542     }
543     return 0;
544 }
545
546 #endif