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.


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