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.


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