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.


Addition of basic multiboot functionality plus refactor of HVM
[palacios.git] / palacios / src / palacios / vm_guest.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
22
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_ctrl_regs.h>
25 #include <palacios/vmm.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vmcb.h>
28 #include <palacios/vm_guest_mem.h>
29 #include <palacios/vmm_lowlevel.h>
30 #include <palacios/vmm_sprintf.h>
31 #include <palacios/vmm_xed.h>
32 #include <palacios/vmm_direct_paging.h>
33 #include <palacios/vmm_barrier.h>
34 #include <palacios/vmm_debug.h>
35
36 #ifdef V3_CONFIG_MEM_TRACK
37 #include <palacios/vmm_mem_track.h>
38 #endif
39
40
41 v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) {
42     struct cr0_32 * cr0;
43     struct efer_64 * efer;
44     struct v3_segment * cs = &(info->segments.cs);
45     struct cr4_32 * cr4;
46
47     if (info->shdw_pg_mode == SHADOW_PAGING) {
48         cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
49         efer = (struct efer_64 *)&(info->shdw_pg_state.guest_efer);
50         cr4 = (struct cr4_32 *)&(info->shdw_pg_state.guest_cr4);
51     } else if (info->shdw_pg_mode == NESTED_PAGING) {
52         cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
53         efer = (struct efer_64 *)&(info->ctrl_regs.efer);
54         cr4 = (struct cr4_32 *)&(info->ctrl_regs.cr4);
55     } else {
56         PrintError(info->vm_info, info, "Invalid Paging Mode...\n");
57         V3_ASSERT(info->vm_info, info, 0);
58         return -1;
59     }
60
61     if (cr0->pe == 0) {
62         return REAL;
63     } else if ((cr4->pae == 0) && (efer->lme == 0)) {
64         return PROTECTED;
65     } else if (efer->lme == 0) {
66         return PROTECTED_PAE;
67     } else if ((efer->lme == 1) && (cs->long_mode == 1)) {
68         return LONG;
69     } else {
70         // What about LONG_16_COMPAT???
71         return LONG_32_COMPAT;
72     }
73 }
74
75 // Get address width in bytes
76 uint_t v3_get_addr_width(struct guest_info * info) {
77     struct cr0_32 * cr0;
78     struct cr4_32 * cr4 = (struct cr4_32 *)&(info->ctrl_regs.cr4);
79     struct efer_64 * efer;
80     struct v3_segment * cs = &(info->segments.cs);
81
82
83     if (info->shdw_pg_mode == SHADOW_PAGING) {
84         cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
85         efer = (struct efer_64 *)&(info->shdw_pg_state.guest_efer);
86     } else if (info->shdw_pg_mode == NESTED_PAGING) {
87         cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
88         efer = (struct efer_64 *)&(info->ctrl_regs.efer);
89     } else {
90         PrintError(info->vm_info, info, "Invalid Paging Mode...\n");
91         V3_ASSERT(info->vm_info, info, 0);
92         return -1;
93     }
94
95     if (cr0->pe == 0) {
96         return 2;
97     } else if ((cr4->pae == 0) && (efer->lme == 0)) {
98         return 4;
99     } else if (efer->lme == 0) {
100         return 4;
101     } else if ((efer->lme == 1) && (cs->long_mode == 1)) {
102         return 8;
103     } else {
104         // What about LONG_16_COMPAT???
105         return 4;
106     }
107 }
108
109
110 static const uchar_t REAL_STR[] = "Real";
111 static const uchar_t PROTECTED_STR[] = "Protected";
112 static const uchar_t PROTECTED_PAE_STR[] = "Protected+PAE";
113 static const uchar_t LONG_STR[] = "Long";
114 static const uchar_t LONG_32_COMPAT_STR[] = "32bit Compat";
115 static const uchar_t LONG_16_COMPAT_STR[] = "16bit Compat";
116
117 const uchar_t * v3_cpu_mode_to_str(v3_cpu_mode_t mode) {
118     switch (mode) {
119         case REAL:
120             return REAL_STR;
121         case PROTECTED:
122             return PROTECTED_STR;
123         case PROTECTED_PAE:
124             return PROTECTED_PAE_STR;
125         case LONG:
126             return LONG_STR;
127         case LONG_32_COMPAT:
128             return LONG_32_COMPAT_STR;
129         case LONG_16_COMPAT:
130             return LONG_16_COMPAT_STR;
131         default:
132             return NULL;
133     }
134 }
135
136 v3_mem_mode_t v3_get_vm_mem_mode(struct guest_info * info) {
137     struct cr0_32 * cr0;
138
139     if (info->shdw_pg_mode == SHADOW_PAGING) {
140         cr0 = (struct cr0_32 *)&(info->shdw_pg_state.guest_cr0);
141     } else if (info->shdw_pg_mode == NESTED_PAGING) {
142         cr0 = (struct cr0_32 *)&(info->ctrl_regs.cr0);
143     } else {
144         PrintError(info->vm_info, info, "Invalid Paging Mode...\n");
145         V3_ASSERT(info->vm_info, info, 0);
146         return -1;
147     }
148
149     if (cr0->pg == 0) {
150         return PHYSICAL_MEM;
151     } else {
152         return VIRTUAL_MEM;
153     }
154 }
155
156 static const uchar_t PHYS_MEM_STR[] = "Physical Memory";
157 static const uchar_t VIRT_MEM_STR[] = "Virtual Memory";
158
159 const uchar_t * v3_mem_mode_to_str(v3_mem_mode_t mode) {
160     switch (mode) {
161         case PHYSICAL_MEM:
162             return PHYS_MEM_STR;
163         case VIRTUAL_MEM:
164             return VIRT_MEM_STR;
165         default:
166             return NULL;
167     }
168 }
169
170
171
172
173
174
175
176 #include <palacios/vmcs.h>
177 #include <palacios/vmcb.h>
178 static int info_hcall(struct guest_info * core, uint_t hcall_id, void * priv_data) {
179     extern v3_cpu_arch_t v3_mach_type;
180     int cpu_valid = 0;
181
182     V3_Print(core->vm_info, core, "************** Guest State ************\n");
183     v3_print_guest_state(core);
184     
185     // init SVM/VMX
186 #ifdef V3_CONFIG_SVM
187     if ((v3_mach_type == V3_SVM_CPU) || (v3_mach_type == V3_SVM_REV3_CPU)) {
188         cpu_valid = 1;
189         PrintDebugVMCB((vmcb_t *)(core->vmm_data));
190     }
191 #endif
192 #ifdef V3_CONFIG_VMX
193     if ((v3_mach_type == V3_VMX_CPU) || (v3_mach_type == V3_VMX_EPT_CPU) || (v3_mach_type == V3_VMX_EPT_UG_CPU)) {
194         cpu_valid = 1;
195         v3_print_vmcs();
196     }
197 #endif
198     if (!cpu_valid) {
199         PrintError(core->vm_info, core, "Invalid CPU Type 0x%x\n", v3_mach_type);
200         return -1;
201     }
202     
203
204     return 0;
205 }
206
207
208 #ifdef V3_CONFIG_SVM
209 #include <palacios/svm.h>
210 #include <palacios/svm_io.h>
211 #include <palacios/svm_msr.h>
212 #include <palacios/svm_exits.h>
213 #endif
214
215 #ifdef V3_CONFIG_VMX
216 #include <palacios/vmx.h>
217 #include <palacios/vmx_io.h>
218 #include <palacios/vmx_msr.h>
219 #include <palacios/vmx_exits.h>
220 #endif
221
222
223 int v3_init_vm(struct v3_vm_info * vm) {
224     extern v3_cpu_arch_t v3_mach_type;
225
226     v3_init_events(vm);
227
228 #ifdef V3_CONFIG_TELEMETRY
229     v3_init_telemetry(vm);
230 #endif
231
232     v3_init_exit_hooks(vm);
233     v3_init_hypercall_map(vm);
234     v3_init_io_map(vm);
235     v3_init_msr_map(vm);
236     v3_init_cpuid_map(vm);
237     v3_init_host_events(vm);
238
239     v3_init_intr_routers(vm);
240     v3_init_ext_manager(vm);
241
242     v3_init_barrier(vm);
243
244     // Initialize the memory map
245     if (v3_init_mem_map(vm) == -1) {
246         PrintError(vm, VCORE_NONE, "Could not initialize shadow map\n");
247         return -1;
248     }
249
250     v3_init_mem_hooks(vm);
251
252     if (v3_init_shdw_impl(vm) == -1) {
253         PrintError(vm, VCORE_NONE, "VM initialization error in shadow implementaion\n");
254         return -1;
255     }
256
257     if (v3_init_passthrough_paging(vm) == -1) {
258         PrintError(vm, VCORE_NONE, "VM initialization error in passthrough paging\n");
259         return -1;
260     }
261
262     if (v3_init_nested_paging(vm) == -1) {
263         PrintError(vm, VCORE_NONE, "VM initialization error in nested paging\n");
264         return -1;
265     }
266
267 #ifdef V3_CONFIG_MEM_TRACK
268     v3_mem_track_init(vm);
269 #endif
270
271     v3_init_time_vm(vm);
272
273     v3_init_vm_debugging(vm);
274
275
276 #ifdef V3_CONFIG_SYMBIOTIC
277     v3_init_symbiotic_vm(vm);
278 #endif
279
280     v3_init_dev_mgr(vm);
281
282
283     // init SVM/VMX
284     switch (v3_mach_type) {
285 #ifdef V3_CONFIG_SVM
286         case V3_SVM_CPU:
287         case V3_SVM_REV3_CPU:
288             v3_init_svm_io_map(vm);
289             v3_init_svm_msr_map(vm);
290             v3_init_svm_exits(vm);
291             break;
292 #endif
293 #ifdef V3_CONFIG_VMX
294         case V3_VMX_CPU:
295         case V3_VMX_EPT_CPU:
296         case V3_VMX_EPT_UG_CPU:
297             v3_init_vmx_io_map(vm);
298             v3_init_vmx_msr_map(vm);
299             v3_init_vmx_exits(vm);
300             break;
301 #endif
302         default:
303             PrintError(vm, VCORE_NONE, "Invalid CPU Type 0x%x\n", v3_mach_type);
304             return -1;
305     }
306     
307     v3_register_hypercall(vm, GUEST_INFO_HCALL, info_hcall, NULL);
308
309     V3_Print(vm, VCORE_NONE, "GUEST_INFO_HCALL=%x\n", GUEST_INFO_HCALL);
310
311     return 0;
312 }
313
314
315 int v3_free_vm_internal(struct v3_vm_info * vm) {
316     extern v3_cpu_arch_t v3_mach_type;
317
318     v3_remove_hypercall(vm, GUEST_INFO_HCALL);
319
320
321 #ifdef V3_CONFIG_HVM
322     v3_deinit_hvm_vm(vm);
323 #endif
324
325 #ifdef V3_CONFIG_MULTIBOOT
326     v3_deinit_multiboot_vm(vm);
327 #endif
328
329
330 #ifdef V3_CONFIG_SYMBIOTIC
331     v3_deinit_symbiotic_vm(vm);
332 #endif
333
334     // init SVM/VMX
335     switch (v3_mach_type) {
336 #ifdef V3_CONFIG_SVM
337         case V3_SVM_CPU:
338         case V3_SVM_REV3_CPU:
339             v3_deinit_svm_io_map(vm);
340             v3_deinit_svm_msr_map(vm);
341             break;
342 #endif
343 #ifdef V3_CONFIG_VMX
344         case V3_VMX_CPU:
345         case V3_VMX_EPT_CPU:
346         case V3_VMX_EPT_UG_CPU:
347             v3_deinit_vmx_io_map(vm);
348             v3_deinit_vmx_msr_map(vm);
349             break;
350 #endif
351         default:
352             PrintError(vm, VCORE_NONE, "Invalid CPU Type 0x%x\n", v3_mach_type);
353             return -1;
354     }
355
356     v3_deinit_dev_mgr(vm);
357
358     v3_deinit_time_vm(vm);
359
360     v3_deinit_mem_hooks(vm);
361
362 #ifdef V3_CONFIG_SWAPPING
363     v3_deinit_swapping_vm(vm);
364 #endif
365
366     v3_delete_mem_map(vm);
367     v3_deinit_shdw_impl(vm);
368     v3_deinit_passthrough_paging(vm);
369     v3_deinit_nested_paging(vm);
370
371     v3_deinit_ext_manager(vm);
372     v3_deinit_intr_routers(vm);
373     v3_deinit_host_events(vm);
374
375     v3_deinit_barrier(vm);
376
377     v3_deinit_cpuid_map(vm);
378     v3_deinit_msr_map(vm);
379     v3_deinit_io_map(vm);
380     v3_deinit_hypercall_map(vm);
381
382     v3_deinit_exit_hooks(vm);
383
384 #ifdef V3_CONFIG_TELEMETRY
385     v3_deinit_telemetry(vm);
386 #endif
387
388
389     v3_deinit_events(vm);
390
391 #ifdef V3_CONFIG_MEM_TRACK
392     v3_mem_track_deinit(vm);
393 #endif
394
395     v3_fw_cfg_deinit(vm);
396
397
398     return 0;
399 }
400
401
402 int v3_init_core(struct guest_info * core) {
403     extern v3_cpu_arch_t v3_mach_type;
404     struct v3_vm_info * vm = core->vm_info;
405
406
407
408     /*
409      * Initialize the subsystem data strutures
410      */
411 #ifdef V3_CONFIG_TELEMETRY
412     v3_init_core_telemetry(core);
413 #endif
414
415     if (core->shdw_pg_mode == SHADOW_PAGING) {
416         v3_init_passthrough_paging_core(core);
417         v3_init_shdw_pg_state(core);
418     } else {
419         //done later due to SVM/VMX differences 
420         //v3_init_nested_paging_core(core);
421     }
422
423     v3_init_time_core(core);
424     v3_init_intr_controllers(core);
425     v3_init_exception_state(core);
426
427     v3_init_decoder(core);
428
429
430 #ifdef V3_CONFIG_SYMBIOTIC
431     v3_init_symbiotic_core(core);
432 #endif
433
434     // init SVM/VMX
435
436
437     switch (v3_mach_type) {
438 #ifdef V3_CONFIG_SVM
439         case V3_SVM_CPU:
440         case V3_SVM_REV3_CPU:
441             if (v3_init_svm_vmcb(core, vm->vm_class) == -1) {
442                 PrintError(vm, core, "Error in SVM initialization\n");
443                 return -1;
444             }
445             break;
446 #endif
447 #ifdef V3_CONFIG_VMX
448         case V3_VMX_CPU:
449         case V3_VMX_EPT_CPU:
450         case V3_VMX_EPT_UG_CPU:
451             if (v3_init_vmx_vmcs(core, vm->vm_class) == -1) {
452                 PrintError(vm, core, "Error in VMX initialization\n");
453                 return -1;
454             }
455             break;
456 #endif
457         default:
458             PrintError(vm, core, "Invalid CPU Type 0x%x\n", v3_mach_type);
459             return -1;
460     }
461     
462     v3_init_exit_hooks_core(core);
463
464
465     return 0;
466 }
467
468
469
470 int v3_free_core(struct guest_info * core) {
471     extern v3_cpu_arch_t v3_mach_type;
472
473     
474 #ifdef V3_CONFIG_SYMBIOTIC
475     v3_deinit_symbiotic_core(core);
476 #endif
477
478 #ifdef V3_CONFIG_HVM
479     v3_deinit_hvm_core(core);
480 #endif
481
482 #ifdef V3_CONFIG_MULTIBOOT
483     v3_deinit_multiboot_core(core);
484 #endif
485
486     v3_deinit_decoder(core);
487
488     v3_deinit_intr_controllers(core);
489     v3_deinit_time_core(core);
490
491     if (core->shdw_pg_mode == SHADOW_PAGING) {
492         v3_deinit_shdw_pg_state(core);
493         v3_deinit_passthrough_paging_core(core);
494    } else {
495         v3_deinit_nested_paging_core(core);
496     }
497
498     v3_free_passthrough_pts(core);
499
500 #ifdef V3_CONFIG_TELEMETRY
501     v3_deinit_core_telemetry(core);
502 #endif
503
504
505     switch (v3_mach_type) {
506 #ifdef V3_CONFIG_SVM
507         case V3_SVM_CPU:
508         case V3_SVM_REV3_CPU:
509             if (v3_deinit_svm_vmcb(core) == -1) {
510                 PrintError(VM_NONE,VCORE_NONE, "Error in SVM deinitialization\n");
511                 return -1;
512             }
513             break;
514 #endif
515 #ifdef V3_CONFIG_VMX
516         case V3_VMX_CPU:
517         case V3_VMX_EPT_CPU:
518         case V3_VMX_EPT_UG_CPU:
519             if (v3_deinit_vmx_vmcs(core) == -1) {
520                 PrintError(VM_NONE, VCORE_NONE, "Error in VMX initialization\n");
521                 return -1;
522             }
523             break;
524 #endif
525         default:
526             PrintError(core->vm_info, core, "Invalid CPU Type 0x%x\n", v3_mach_type);
527             return -1;
528     }
529
530     return 0;
531 }
532
533
534