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.


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