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.


Context-based output infrastructure (V3_Print, etc) and modifications to use it
[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
35
36 #ifdef V3_CONFIG_SHADOW_PAGING_TELEMETRY
37 #include <palacios/vmm_telemetry.h>
38 #endif
39
40 #ifdef V3_CONFIG_SYMBIOTIC_SWAP
41 #include <palacios/vmm_sym_swap.h>
42 #endif
43
44 #ifndef V3_CONFIG_DEBUG_SHADOW_PAGING
45 #undef PrintDebug
46 #define PrintDebug(fmt, args...)
47 #endif
48
49
50 static const char default_strategy[] = "VTLB";
51
52
53 static struct hashtable * master_shdw_pg_table = NULL;
54
55
56 struct event_callback {
57     int (*callback)(struct guest_info *core, struct v3_shdw_pg_event *event, void *priv_data);
58     void *priv_data;
59
60     struct list_head node;
61 };
62
63 static uint_t shdw_pg_hash_fn(addr_t key) {
64     char * name = (char *)key;
65     return v3_hash_buffer((uint8_t *)name, strlen(name));
66 }
67
68 static int shdw_pg_eq_fn(addr_t key1, addr_t key2) {
69     char * name1 = (char *)key1;
70     char * name2 = (char *)key2;
71
72     return (strcmp(name1, name2) == 0);
73 }
74
75 static int have_callbacks(struct guest_info *core)
76 {
77     return !list_empty(&(core->vm_info->shdw_impl.event_callback_list));
78 }
79
80 static void dispatch_event(struct guest_info *core, struct v3_shdw_pg_event *event)
81 {
82     struct event_callback *cb,*temp;
83     
84     list_for_each_entry_safe(cb,
85                              temp,
86                              &(core->vm_info->shdw_impl.event_callback_list),
87                              node) {
88         cb->callback(core,event,cb->priv_data);
89     }
90 }
91
92
93 int V3_init_shdw_paging() {
94     extern struct v3_shdw_pg_impl * __start__v3_shdw_pg_impls[];
95     extern struct v3_shdw_pg_impl * __stop__v3_shdw_pg_impls[];
96     struct v3_shdw_pg_impl ** tmp_impl = __start__v3_shdw_pg_impls;
97     int i = 0;
98
99     master_shdw_pg_table = v3_create_htable(0, shdw_pg_hash_fn, shdw_pg_eq_fn);
100
101
102     while (tmp_impl != __stop__v3_shdw_pg_impls) {
103         V3_Print(VM_NONE, VCORE_NONE, "Registering Shadow Paging Impl (%s)\n", (*tmp_impl)->name);
104
105         if (v3_htable_search(master_shdw_pg_table, (addr_t)((*tmp_impl)->name))) {
106             PrintError(VM_NONE, VCORE_NONE, "Multiple instances of shadow paging impl (%s)\n", (*tmp_impl)->name);
107             return -1;
108         }
109
110         if (v3_htable_insert(master_shdw_pg_table, 
111                              (addr_t)((*tmp_impl)->name),
112                              (addr_t)(*tmp_impl)) == 0) {
113             PrintError(VM_NONE, VCORE_NONE, "Could not register shadow paging impl (%s)\n", (*tmp_impl)->name);
114             return -1;
115         }
116
117         tmp_impl = &(__start__v3_shdw_pg_impls[++i]);
118     }
119
120     return 0;
121 }
122
123 int V3_deinit_shdw_paging() {
124     v3_free_htable(master_shdw_pg_table, 0, 0);
125     return 0;
126 }
127
128
129
130 /*** 
131  ***  There be dragons
132  ***/
133
134
135 #ifdef V3_CONFIG_SHADOW_PAGING_TELEMETRY
136 static void telemetry_cb(struct v3_vm_info * vm, void * private_data, char * hdr) {
137     int i = 0;
138     for (i = 0; i < vm->num_cores; i++) {
139         struct guest_info * core = &(vm->cores[i]);
140
141         V3_Print(vm, core, "%s Guest Page faults: %d\n", hdr, core->shdw_pg_state.guest_faults);
142     }
143 }
144 #endif
145
146
147
148 int v3_init_shdw_pg_state(struct guest_info * core) {
149     struct v3_shdw_pg_state * state = &(core->shdw_pg_state);
150     struct v3_shdw_pg_impl * impl = core->vm_info->shdw_impl.current_impl;
151   
152
153     state->guest_cr3 = 0;
154     state->guest_cr0 = 0;
155     state->guest_efer.value = 0x0LL;
156
157     if (impl->local_init(core) == -1) {
158         PrintError(core->vm_info, core, "Error in Shadow paging local initialization (%s)\n", impl->name);
159         return -1;
160     }
161
162
163 #ifdef V3_CONFIG_SHADOW_PAGING_TELEMETRY
164     v3_add_telemetry_cb(core->vm_info, telemetry_cb, NULL);
165 #endif
166   
167
168     return 0;
169 }
170
171
172 int v3_deinit_shdw_pg_state(struct guest_info * core) {
173     struct v3_shdw_pg_impl * impl = core->vm_info->shdw_impl.current_impl;
174
175     if (impl->local_deinit(core) == -1) {
176         PrintError(core->vm_info, core, "Error deinitializing shadow paging state\n");
177         return -1;
178     }
179
180
181     return 0;
182 }
183
184
185
186 int v3_init_shdw_impl(struct v3_vm_info * vm) {
187     struct v3_shdw_impl_state * impl_state = &(vm->shdw_impl);
188     v3_cfg_tree_t * pg_cfg = v3_cfg_subtree(vm->cfg_data->cfg, "paging");
189     char * pg_mode = v3_cfg_val(pg_cfg, "mode");
190     char * pg_strat = v3_cfg_val(pg_cfg, "strategy");
191     struct v3_shdw_pg_impl * impl = NULL;
192    
193     PrintDebug(vm, VCORE_NONE, "Checking if shadow paging requested.\n");
194     if ((pg_mode != NULL) && (strcasecmp(pg_mode, "nested") == 0)) {
195         PrintDebug(vm, VCORE_NONE, "Nested paging specified - not initializing shadow paging.\n");
196         return 0;
197     }
198
199     if (pg_strat == NULL) {
200         pg_strat = (char *)default_strategy;
201     }
202         
203     V3_Print(vm, VCORE_NONE,"Initialization of Shadow Paging implementation\n");
204
205     impl = (struct v3_shdw_pg_impl *)v3_htable_search(master_shdw_pg_table, (addr_t)pg_strat);
206
207     if (impl == NULL) {
208         PrintError(vm, VCORE_NONE, "Could not find shadow paging impl (%s)\n", pg_strat);
209         return -1;
210     }
211
212     INIT_LIST_HEAD(&(impl_state->event_callback_list));
213    
214     impl_state->current_impl = impl;
215
216     if (impl->init(vm, pg_cfg) == -1) {
217         PrintError(vm, VCORE_NONE, "Could not initialize Shadow paging implemenation (%s)\n", impl->name);
218         return -1;
219     }
220
221
222
223     return 0;
224 }
225
226 int v3_deinit_shdw_impl(struct v3_vm_info * vm) {
227     struct v3_shdw_pg_impl * impl = vm->shdw_impl.current_impl;
228     struct event_callback *cb,*temp;
229
230     if (impl == NULL) {
231         // Shadow paging not implemented
232         return 0;
233     }
234
235     if (impl->deinit(vm) == -1) {
236         PrintError(vm, VCORE_NONE,"Error deinitializing shadow paging implementation\n");
237         return -1;
238     }
239
240     list_for_each_entry_safe(cb,
241                              temp,
242                              &(vm->shdw_impl.event_callback_list),
243                              node) {
244         list_del(&(cb->node));
245         V3_Free(cb);
246     }
247
248     return 0;
249 }
250
251
252 // Reads the guest CR3 register
253 // creates new shadow page tables
254 // updates the shadow CR3 register to point to the new pts
255 int v3_activate_shadow_pt(struct guest_info * core) {
256     struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
257     struct v3_shdw_pg_impl * impl = state->current_impl;
258     
259     if (!have_callbacks(core)) { 
260         return impl->activate_shdw_pt(core);
261     } else {
262         int rc;
263         struct v3_shdw_pg_event event_pre={SHADOW_ACTIVATE,SHADOW_PREIMPL,0,{0,0,0,0,0,0}};
264         struct v3_shdw_pg_event event_post={SHADOW_ACTIVATE,SHADOW_POSTIMPL,0,{0,0,0,0,0,0}};
265         
266         dispatch_event(core,&event_pre);
267
268         rc =impl->activate_shdw_pt(core);
269
270         dispatch_event(core,&event_post);
271         
272         return rc;
273     }
274 }
275
276
277
278 // This must flush any caches
279 // and reset the cr3 value to the correct value
280 int v3_invalidate_shadow_pts(struct guest_info * core) {
281     struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
282     struct v3_shdw_pg_impl * impl = state->current_impl;
283
284     if (!have_callbacks(core)) { 
285         return impl->invalidate_shdw_pt(core);
286     } else {
287         int rc;
288         struct v3_shdw_pg_event event_pre={SHADOW_INVALIDATE,SHADOW_PREIMPL,0,{0,0,0,0,0,0}};
289         struct v3_shdw_pg_event event_post={SHADOW_INVALIDATE,SHADOW_POSTIMPL,0,{0,0,0,0,0,0}};
290         
291         dispatch_event(core,&event_pre);
292
293         rc = impl->invalidate_shdw_pt(core);
294
295         dispatch_event(core,&event_post);
296         
297         return rc;
298     }
299 }
300
301
302 int v3_handle_shadow_pagefault(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) 
303 {
304     int rc;
305    
306
307     if (have_callbacks(core)) { 
308         struct v3_shdw_pg_event event={SHADOW_PAGEFAULT,SHADOW_PREIMPL,fault_addr,error_code};
309         dispatch_event(core,&event);
310     }
311     
312     if (v3_get_vm_mem_mode(core) == PHYSICAL_MEM) {
313         // If paging is not turned on we need to handle the special cases
314         rc = v3_handle_passthrough_pagefault(core, fault_addr, error_code);
315     } else if (v3_get_vm_mem_mode(core) == VIRTUAL_MEM) {
316         struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
317         struct v3_shdw_pg_impl * impl = state->current_impl;
318         
319         rc = impl->handle_pagefault(core, fault_addr, error_code);
320     } else {
321         PrintError(core->vm_info, core, "Invalid Memory mode\n");
322         rc = -1;
323     }
324     
325     if (have_callbacks(core)) {
326         struct v3_shdw_pg_event event={SHADOW_PAGEFAULT,SHADOW_POSTIMPL,fault_addr,error_code};
327         dispatch_event(core,&event);
328     }
329     
330     return rc;
331 }
332
333
334 int v3_handle_shadow_invlpg(struct guest_info * core) {
335     uchar_t instr[15];
336     struct x86_instr dec_instr;
337     int ret = 0;
338     addr_t vaddr = 0;
339
340     if (v3_get_vm_mem_mode(core) != VIRTUAL_MEM) {
341         // Paging must be turned on...
342         // should handle with some sort of fault I think
343         PrintError(core->vm_info, core, "ERROR: INVLPG called in non paged mode\n");
344         return -1;
345     }
346
347     if (v3_get_vm_mem_mode(core) == PHYSICAL_MEM) { 
348         ret = v3_read_gpa_memory(core, get_addr_linear(core, core->rip, &(core->segments.cs)), 15, instr);
349     } else { 
350         ret = v3_read_gva_memory(core, get_addr_linear(core, core->rip, &(core->segments.cs)), 15, instr);
351     }
352
353     if (ret == -1) {
354         PrintError(core->vm_info, core, "Could not read instruction into buffer\n");
355         return -1;
356     }
357
358     if (v3_decode(core, (addr_t)instr, &dec_instr) == -1) {
359         PrintError(core->vm_info, core, "Decoding Error\n");
360         return -1;
361     }
362   
363     if ((dec_instr.op_type != V3_OP_INVLPG) || 
364         (dec_instr.num_operands != 1) ||
365         (dec_instr.dst_operand.type != MEM_OPERAND)) {
366         PrintError(core->vm_info, core, "Decoder Error: Not a valid INVLPG instruction...\n");
367         return -1;
368     }
369
370     vaddr = dec_instr.dst_operand.operand;
371
372     core->rip += dec_instr.instr_length;
373
374     {
375         struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
376         struct v3_shdw_pg_impl * impl = state->current_impl;
377         int rc;
378
379         if (have_callbacks(core)) { 
380             struct v3_shdw_pg_event event={SHADOW_INVLPG,SHADOW_PREIMPL,vaddr,{0,0,0,0,0,0}};
381             dispatch_event(core,&event);
382         }
383
384         rc=impl->handle_invlpg(core, vaddr);
385
386         if (have_callbacks(core)) { 
387             struct v3_shdw_pg_event event={SHADOW_INVLPG,SHADOW_POSTIMPL,vaddr,{0,0,0,0,0,0}};
388             dispatch_event(core,&event);
389         }
390
391         return rc;
392     }
393 }
394
395
396
397
398
399
400 int v3_inject_guest_pf(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
401     core->ctrl_regs.cr2 = fault_addr;
402
403 #ifdef V3_CONFIG_SHADOW_PAGING_TELEMETRY
404     core->shdw_pg_state.guest_faults++;
405 #endif
406
407     return v3_raise_exception_with_error(core, PF_EXCEPTION, *(uint_t *)&error_code);
408 }
409
410
411 int v3_is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
412     /* basically the reasoning is that there can be multiple reasons for a page fault:
413        If there is a permissions failure for a page present in the guest _BUT_
414        the reason for the fault was that the page is not present in the shadow,
415        _THEN_ we have to map the shadow page in and reexecute, this will generate
416        a permissions fault which is _THEN_ valid to send to the guest
417        _UNLESS_ both the guest and shadow have marked the page as not present
418
419        whew...
420     */
421     if (guest_access != PT_ACCESS_OK) {
422         // Guest Access Error
423
424         if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
425             (guest_access != PT_ACCESS_NOT_PRESENT)) {
426             // aka (guest permission error)
427             return 1;
428         }
429
430         /*
431           if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
432           (guest_access == PT_ACCESS_NOT_PRESENT)) {
433           // Page tables completely blank, handle guest first
434           return 1;
435           }
436         */
437
438         if (guest_access == PT_ACCESS_NOT_PRESENT) {
439             // Page tables completely blank, handle guest first
440             return 1;
441         }
442         
443         // Otherwise we'll handle the guest fault later...?
444     }
445
446     return 0;
447 }
448
449
450 int v3_register_shadow_paging_event_callback(struct v3_vm_info *vm,
451                                              int (*callback)(struct guest_info *core, 
452                                                              struct v3_shdw_pg_event *event,
453                                                              void      *priv_data),
454                                              void *priv_data)
455 {
456     struct event_callback *ec = V3_Malloc(sizeof(struct event_callback));
457
458     if (!ec) { 
459         PrintError(vm, VCORE_NONE, "Unable to allocate for a shadow paging event callback\n");
460         return -1;
461     }
462     
463     ec->callback = callback;
464     ec->priv_data = priv_data;
465
466     list_add(&(ec->node),&(vm->shdw_impl.event_callback_list));
467
468     return 0;
469
470 }
471
472 int v3_unregister_shadow_paging_event_callback(struct v3_vm_info *vm,
473                                                int (*callback)(struct guest_info *core, 
474                                                                struct v3_shdw_pg_event *event,
475                                                                void      *priv_data),
476                                                void *priv_data)
477 {
478     struct event_callback *cb,*temp;
479
480     list_for_each_entry_safe(cb,
481                              temp,
482                              &(vm->shdw_impl.event_callback_list),
483                              node) {
484         if ((callback == cb->callback) && (priv_data == cb->priv_data)) { 
485             list_del(&(cb->node));
486             V3_Free(cb);
487             return 0;
488         }
489     }
490     
491     PrintError(vm, VCORE_NONE, "No callback found!\n");
492     
493     return -1;
494 }
495
496