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.


symbiotic swap updates
[palacios.git] / palacios / src / palacios / vmm_shadow_paging.c
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 #include <palacios/vmm_shadow_paging.h>
22
23
24 #include <palacios/vmm.h>
25 #include <palacios/vm_guest_mem.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vmm_ctrl_regs.h>
28
29 #include <palacios/vmm_hashtable.h>
30
31 #include <palacios/vmm_direct_paging.h>
32
33 #ifdef CONFIG_SYMBIOTIC_SWAP
34 #include <palacios/vmm_sym_swap.h>
35 #endif
36
37 #ifndef CONFIG_DEBUG_SHADOW_PAGING
38 #undef PrintDebug
39 #define PrintDebug(fmt, args...)
40 #endif
41
42
43 /*** 
44  ***  There be dragons
45  ***/
46
47
48 struct shadow_page_data {
49     v3_reg_t cr3;
50     addr_t page_pa;
51   
52     struct list_head page_list_node;
53 };
54
55
56
57 static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info);
58 static int inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code);
59 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access);
60
61
62 #include "vmm_shadow_paging_32.h"
63 #include "vmm_shadow_paging_32pae.h"
64 #include "vmm_shadow_paging_64.h"
65
66
67
68 int v3_init_shadow_page_state(struct guest_info * info) {
69     struct shadow_page_state * state = &(info->shdw_pg_state);
70   
71     state->guest_cr3 = 0;
72     state->guest_cr0 = 0;
73     state->guest_efer.value = 0x0LL;
74
75     INIT_LIST_HEAD(&(state->page_list));
76   
77     return 0;
78 }
79
80
81
82 // Reads the guest CR3 register
83 // creates new shadow page tables
84 // updates the shadow CR3 register to point to the new pts
85 int v3_activate_shadow_pt(struct guest_info * info) {
86     switch (v3_get_vm_cpu_mode(info)) {
87
88         case PROTECTED:
89             return activate_shadow_pt_32(info);
90         case PROTECTED_PAE:
91             return activate_shadow_pt_32pae(info);
92         case LONG:
93         case LONG_32_COMPAT:
94         case LONG_16_COMPAT:
95             return activate_shadow_pt_64(info);
96         default:
97             PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(info)));
98             return -1;
99     }
100
101     return 0;
102 }
103
104
105
106 // This must flush any caches
107 // and reset the cr3 value to the correct value
108 int v3_invalidate_shadow_pts(struct guest_info * info) {
109     return v3_activate_shadow_pt(info);
110 }
111
112
113 int v3_handle_shadow_pagefault(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
114   
115     if (v3_get_vm_mem_mode(info) == PHYSICAL_MEM) {
116         // If paging is not turned on we need to handle the special cases
117         return v3_handle_passthrough_pagefault(info, fault_addr, error_code);
118     } else if (v3_get_vm_mem_mode(info) == VIRTUAL_MEM) {
119
120         switch (v3_get_vm_cpu_mode(info)) {
121             case PROTECTED:
122                 return handle_shadow_pagefault_32(info, fault_addr, error_code);
123                 break;
124             case PROTECTED_PAE:
125                 return handle_shadow_pagefault_32pae(info, fault_addr, error_code);
126             case LONG:
127             case LONG_32_COMPAT:
128             case LONG_16_COMPAT:
129                 return handle_shadow_pagefault_64(info, fault_addr, error_code);
130                 break;
131             default:
132                 PrintError("Unhandled CPU Mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(info)));
133                 return -1;
134         }
135     } else {
136         PrintError("Invalid Memory mode\n");
137         return -1;
138     }
139 }
140
141
142 int v3_handle_shadow_invlpg(struct guest_info * info) {
143     uchar_t instr[15];
144     struct x86_instr dec_instr;
145     int ret = 0;
146     addr_t vaddr = 0;
147
148     if (v3_get_vm_mem_mode(info) != VIRTUAL_MEM) {
149         // Paging must be turned on...
150         // should handle with some sort of fault I think
151         PrintError("ERROR: INVLPG called in non paged mode\n");
152         return -1;
153     }
154
155     if (v3_get_vm_mem_mode(info) == PHYSICAL_MEM) { 
156         ret = read_guest_pa_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
157     } else { 
158         ret = read_guest_va_memory(info, get_addr_linear(info, info->rip, &(info->segments.cs)), 15, instr);
159     }
160
161     if (ret == -1) {
162         PrintError("Could not read instruction into buffer\n");
163         return -1;
164     }
165
166     if (v3_decode(info, (addr_t)instr, &dec_instr) == -1) {
167         PrintError("Decoding Error\n");
168         return -1;
169     }
170   
171     if ((dec_instr.op_type != V3_OP_INVLPG) || 
172         (dec_instr.num_operands != 1) ||
173         (dec_instr.dst_operand.type != MEM_OPERAND)) {
174         PrintError("Decoder Error: Not a valid INVLPG instruction...\n");
175         return -1;
176     }
177
178     vaddr = dec_instr.dst_operand.operand;
179
180     info->rip += dec_instr.instr_length;
181
182     switch (v3_get_vm_cpu_mode(info)) {
183         case PROTECTED:
184             return handle_shadow_invlpg_32(info, vaddr);
185         case PROTECTED_PAE:
186             return handle_shadow_invlpg_32pae(info, vaddr);
187         case LONG:
188         case LONG_32_COMPAT:
189         case LONG_16_COMPAT:
190             return handle_shadow_invlpg_64(info, vaddr);
191         default:
192             PrintError("Invalid CPU mode: %s\n", v3_cpu_mode_to_str(v3_get_vm_cpu_mode(info)));
193             return -1;
194     }
195 }
196
197
198
199
200 static struct shadow_page_data * create_new_shadow_pt(struct guest_info * info) {
201     struct shadow_page_state * state = &(info->shdw_pg_state);
202     v3_reg_t cur_cr3 = info->ctrl_regs.cr3;
203     struct shadow_page_data * page_tail = NULL;
204     addr_t shdw_page = 0;
205
206     if (!list_empty(&(state->page_list))) {
207         page_tail = list_tail_entry(&(state->page_list), struct shadow_page_data, page_list_node);
208     
209         if (page_tail->cr3 != cur_cr3) {
210             PrintDebug("Reusing old shadow Page: %p (cur_CR3=%p)(page_cr3=%p) \n",
211                        (void *)(addr_t)page_tail->page_pa, 
212                        (void *)(addr_t)cur_cr3, 
213                        (void *)(addr_t)(page_tail->cr3));
214
215             list_move(&(page_tail->page_list_node), &(state->page_list));
216
217             memset(V3_VAddr((void *)(page_tail->page_pa)), 0, PAGE_SIZE_4KB);
218
219
220             return page_tail;
221         }
222     }
223
224     // else  
225
226     page_tail = (struct shadow_page_data *)V3_Malloc(sizeof(struct shadow_page_data));
227     page_tail->page_pa = (addr_t)V3_AllocPages(1);
228
229     PrintDebug("Allocating new shadow Page: %p (cur_cr3=%p)\n", 
230                (void *)(addr_t)page_tail->page_pa, 
231                (void *)(addr_t)cur_cr3);
232
233     page_tail->cr3 = cur_cr3;
234     list_add(&(page_tail->page_list_node), &(state->page_list));
235
236     shdw_page = (addr_t)V3_VAddr((void *)(page_tail->page_pa));
237     memset((void *)shdw_page, 0, PAGE_SIZE_4KB);
238
239     return page_tail;
240 }
241
242
243 static int inject_guest_pf(struct guest_info * info, addr_t fault_addr, pf_error_t error_code) {
244
245 #ifdef CONFIG_PROFILE_VMM
246     if (info->enable_profiler) {
247         info->profiler.guest_pf_cnt++;
248     }
249 #endif
250
251     info->ctrl_regs.cr2 = fault_addr;
252
253     return v3_raise_exception_with_error(info, PF_EXCEPTION, *(uint_t *)&error_code);
254 }
255
256
257 static int is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
258     /* basically the reasoning is that there can be multiple reasons for a page fault:
259        If there is a permissions failure for a page present in the guest _BUT_
260        the reason for the fault was that the page is not present in the shadow,
261        _THEN_ we have to map the shadow page in and reexecute, this will generate
262        a permissions fault which is _THEN_ valid to send to the guest
263        _UNLESS_ both the guest and shadow have marked the page as not present
264
265        whew...
266     */
267     if (guest_access != PT_ACCESS_OK) {
268         // Guest Access Error
269
270         if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
271             (guest_access != PT_ACCESS_NOT_PRESENT)) {
272             // aka (guest permission error)
273             return 1;
274         }
275
276         /*
277           if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
278           (guest_access == PT_ACCESS_NOT_PRESENT)) {
279           // Page tables completely blank, handle guest first
280           return 1;
281           }
282         */
283
284         if (guest_access == PT_ACCESS_NOT_PRESENT) {
285             // Page tables completely blank, handle guest first
286             return 1;
287         }
288         
289         // Otherwise we'll handle the guest fault later...?
290     }
291
292     return 0;
293 }
294
295