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.


moved the host_private_data assignment to earlier in the configuration phase to make...
[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 CONFIG_SHADOW_PAGING_TELEMETRY
37 #include <palacios/vmm_telemetry.h>
38 #endif
39
40 #ifdef CONFIG_SYMBIOTIC_SWAP
41 #include <palacios/vmm_sym_swap.h>
42 #endif
43
44 #ifndef 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 static uint_t shdw_pg_hash_fn(addr_t key) {
56     char * name = (char *)key;
57     return v3_hash_buffer((uint8_t *)name, strlen(name));
58 }
59
60 static int shdw_pg_eq_fn(addr_t key1, addr_t key2) {
61     char * name1 = (char *)key1;
62     char * name2 = (char *)key2;
63
64     return (strcmp(name1, name2) == 0);
65 }
66
67
68 int V3_init_shdw_paging() {
69     extern struct v3_shdw_pg_impl * __start__v3_shdw_pg_impls[];
70     extern struct v3_shdw_pg_impl * __stop__v3_shdw_pg_impls[];
71     struct v3_shdw_pg_impl ** tmp_impl = __start__v3_shdw_pg_impls;
72     int i = 0;
73
74     master_shdw_pg_table = v3_create_htable(0, shdw_pg_hash_fn, shdw_pg_eq_fn);
75
76
77     while (tmp_impl != __stop__v3_shdw_pg_impls) {
78         V3_Print("Registering Shadow Paging Impl (%s)\n", (*tmp_impl)->name);
79
80         if (v3_htable_search(master_shdw_pg_table, (addr_t)((*tmp_impl)->name))) {
81             PrintError("Multiple instances of shadow paging impl (%s)\n", (*tmp_impl)->name);
82             return -1;
83         }
84
85         if (v3_htable_insert(master_shdw_pg_table, 
86                              (addr_t)((*tmp_impl)->name),
87                              (addr_t)(*tmp_impl)) == 0) {
88             PrintError("Could not register shadow paging impl (%s)\n", (*tmp_impl)->name);
89             return -1;
90         }
91
92         tmp_impl = &(__start__v3_shdw_pg_impls[++i]);
93     }
94
95     return 0;
96 }
97
98
99
100 /*** 
101  ***  There be dragons
102  ***/
103
104
105 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
106 static void telemetry_cb(struct v3_vm_info * vm, void * private_data, char * hdr) {
107     int i = 0;
108     for (i = 0; i < vm->num_cores; i++) {
109         struct guest_info * core = &(vm->cores[i]);
110
111         V3_Print("%s Guest Page faults: %d\n", hdr, core->shdw_pg_state.guest_faults);
112     }
113 }
114 #endif
115
116
117
118 int v3_init_shdw_pg_state(struct guest_info * core) {
119     struct v3_shdw_pg_state * state = &(core->shdw_pg_state);
120     struct v3_shdw_pg_impl * impl = core->vm_info->shdw_impl.current_impl;
121   
122
123     state->guest_cr3 = 0;
124     state->guest_cr0 = 0;
125     state->guest_efer.value = 0x0LL;
126
127
128     if (impl->local_init(core) == -1) {
129         PrintError("Error in Shadow paging local initialization (%s)\n", impl->name);
130         return -1;
131     }
132
133
134 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
135     v3_add_telemetry_cb(core->vm_info, telemetry_cb, NULL);
136 #endif
137   
138     return 0;
139 }
140
141
142
143 int v3_init_shdw_impl(struct v3_vm_info * vm) {
144     struct v3_shdw_impl_state * impl_state = &(vm->shdw_impl);
145     v3_cfg_tree_t * pg_cfg = v3_cfg_subtree(vm->cfg_data->cfg, "paging");
146     char * pg_mode = v3_cfg_val(pg_cfg, "mode");
147     char * pg_strat = v3_cfg_val(pg_cfg, "strategy");
148     struct v3_shdw_pg_impl * impl = NULL;
149    
150     PrintDebug("Checking if shadow paging requested.\n");
151     if ((pg_mode != NULL) && (strcasecmp(pg_mode, "nested") == 0)) {
152         PrintDebug("Nested paging specified - not initializing shadow paging.\n");
153         return 0;
154     }
155
156     if (pg_strat == NULL) {
157         pg_strat = (char *)default_strategy;
158     }
159         
160     V3_Print("Initialization of Shadow Paging implementation\n");
161
162     impl = (struct v3_shdw_pg_impl *)v3_htable_search(master_shdw_pg_table, (addr_t)pg_strat);
163
164     if (impl == NULL) {
165         PrintError("Could not find shadow paging impl (%s)\n", pg_strat);
166         return -1;
167     }
168    
169     impl_state->current_impl = impl;
170
171     if (impl->init(vm, pg_cfg) == -1) {
172         PrintError("Could not initialize Shadow paging implemenation (%s)\n", impl->name);
173         return -1;
174     }
175
176     
177
178
179     return 0;
180 }
181
182
183 // Reads the guest CR3 register
184 // creates new shadow page tables
185 // updates the shadow CR3 register to point to the new pts
186 int v3_activate_shadow_pt(struct guest_info * core) {
187     struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
188     struct v3_shdw_pg_impl * impl = state->current_impl;
189     return impl->activate_shdw_pt(core);
190 }
191
192
193
194 // This must flush any caches
195 // and reset the cr3 value to the correct value
196 int v3_invalidate_shadow_pts(struct guest_info * core) {
197     struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
198     struct v3_shdw_pg_impl * impl = state->current_impl;
199     return impl->invalidate_shdw_pt(core);
200 }
201
202
203 int v3_handle_shadow_pagefault(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
204   
205     if (v3_get_vm_mem_mode(core) == PHYSICAL_MEM) {
206         // If paging is not turned on we need to handle the special cases
207         return v3_handle_passthrough_pagefault(core, fault_addr, error_code);
208     } else if (v3_get_vm_mem_mode(core) == VIRTUAL_MEM) {
209         struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
210         struct v3_shdw_pg_impl * impl = state->current_impl;
211
212         return impl->handle_pagefault(core, fault_addr, error_code);
213     } else {
214         PrintError("Invalid Memory mode\n");
215         return -1;
216     }
217 }
218
219
220 int v3_handle_shadow_invlpg(struct guest_info * core) {
221     uchar_t instr[15];
222     struct x86_instr dec_instr;
223     int ret = 0;
224     addr_t vaddr = 0;
225
226     if (v3_get_vm_mem_mode(core) != VIRTUAL_MEM) {
227         // Paging must be turned on...
228         // should handle with some sort of fault I think
229         PrintError("ERROR: INVLPG called in non paged mode\n");
230         return -1;
231     }
232
233     if (v3_get_vm_mem_mode(core) == PHYSICAL_MEM) { 
234         ret = v3_read_gpa_memory(core, get_addr_linear(core, core->rip, &(core->segments.cs)), 15, instr);
235     } else { 
236         ret = v3_read_gva_memory(core, get_addr_linear(core, core->rip, &(core->segments.cs)), 15, instr);
237     }
238
239     if (ret == -1) {
240         PrintError("Could not read instruction into buffer\n");
241         return -1;
242     }
243
244     if (v3_decode(core, (addr_t)instr, &dec_instr) == -1) {
245         PrintError("Decoding Error\n");
246         return -1;
247     }
248   
249     if ((dec_instr.op_type != V3_OP_INVLPG) || 
250         (dec_instr.num_operands != 1) ||
251         (dec_instr.dst_operand.type != MEM_OPERAND)) {
252         PrintError("Decoder Error: Not a valid INVLPG instruction...\n");
253         return -1;
254     }
255
256     vaddr = dec_instr.dst_operand.operand;
257
258     core->rip += dec_instr.instr_length;
259
260     {
261         struct v3_shdw_impl_state * state = &(core->vm_info->shdw_impl);
262         struct v3_shdw_pg_impl * impl = state->current_impl;
263
264         return impl->handle_invlpg(core, vaddr);
265     }
266 }
267
268
269
270
271
272
273 int v3_inject_guest_pf(struct guest_info * core, addr_t fault_addr, pf_error_t error_code) {
274     core->ctrl_regs.cr2 = fault_addr;
275
276 #ifdef CONFIG_SHADOW_PAGING_TELEMETRY
277     core->shdw_pg_state.guest_faults++;
278 #endif
279
280     return v3_raise_exception_with_error(core, PF_EXCEPTION, *(uint_t *)&error_code);
281 }
282
283
284 int v3_is_guest_pf(pt_access_status_t guest_access, pt_access_status_t shadow_access) {
285     /* basically the reasoning is that there can be multiple reasons for a page fault:
286        If there is a permissions failure for a page present in the guest _BUT_
287        the reason for the fault was that the page is not present in the shadow,
288        _THEN_ we have to map the shadow page in and reexecute, this will generate
289        a permissions fault which is _THEN_ valid to send to the guest
290        _UNLESS_ both the guest and shadow have marked the page as not present
291
292        whew...
293     */
294     if (guest_access != PT_ACCESS_OK) {
295         // Guest Access Error
296
297         if ((shadow_access != PT_ACCESS_NOT_PRESENT) &&
298             (guest_access != PT_ACCESS_NOT_PRESENT)) {
299             // aka (guest permission error)
300             return 1;
301         }
302
303         /*
304           if ((shadow_access == PT_ACCESS_NOT_PRESENT) &&
305           (guest_access == PT_ACCESS_NOT_PRESENT)) {
306           // Page tables completely blank, handle guest first
307           return 1;
308           }
309         */
310
311         if (guest_access == PT_ACCESS_NOT_PRESENT) {
312             // Page tables completely blank, handle guest first
313             return 1;
314         }
315         
316         // Otherwise we'll handle the guest fault later...?
317     }
318
319     return 0;
320 }
321
322