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.


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