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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jarusl@cs.northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_intr.h>
22 #include <palacios/vmm_config.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_ctrl_regs.h>
25 #include <palacios/vmm_lowlevel.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vmm_extensions.h>
28 #include <palacios/vmm_timeout.h>
32 #include <palacios/svm.h>
35 #include <palacios/vmx.h>
38 #ifdef V3_CONFIG_CHECKPOINT
39 #include <palacios/vmm_checkpoint.h>
43 v3_cpu_arch_t v3_cpu_types[V3_CONFIG_MAX_CPUS];
44 v3_cpu_arch_t v3_mach_type = V3_INVALID_CPU;
46 struct v3_os_hooks * os_hooks = NULL;
47 int v3_dbg_enable = 0;
52 static void init_cpu(void * arg) {
53 uint32_t cpu_id = (uint32_t)(addr_t)arg;
56 if (v3_is_svm_capable()) {
57 PrintDebug("Machine is SVM Capable\n");
58 v3_init_svm_cpu(cpu_id);
63 if (v3_is_vmx_capable()) {
64 PrintDebug("Machine is VMX Capable\n");
65 v3_init_vmx_cpu(cpu_id);
70 PrintError("CPU has no virtualization Extensions\n");
75 static void deinit_cpu(void * arg) {
76 uint32_t cpu_id = (uint32_t)(addr_t)arg;
79 switch (v3_cpu_types[cpu_id]) {
83 PrintDebug("Deinitializing SVM CPU %d\n", cpu_id);
84 v3_deinit_svm_cpu(cpu_id);
90 case V3_VMX_EPT_UG_CPU:
91 PrintDebug("Deinitializing VMX CPU %d\n", cpu_id);
92 v3_deinit_vmx_cpu(cpu_id);
97 PrintError("CPU has no virtualization Extensions\n");
103 void Init_V3(struct v3_os_hooks * hooks, char * cpu_mask, int num_cpus) {
108 V3_Print("V3 Print statement to fix a Kitten page fault bug\n");
110 // Set global variables.
113 // Determine the global machine type
114 v3_mach_type = V3_INVALID_CPU;
116 for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
117 v3_cpu_types[i] = V3_INVALID_CPU;
120 // Register all the possible device types
123 // Register all shadow paging handlers
124 V3_init_shdw_paging();
126 // Register all extensions
127 V3_init_extensions();
130 #ifdef V3_CONFIG_SYMMOD
134 #ifdef V3_CONFIG_CHECKPOINT
135 V3_init_checkpoint();
138 if ((hooks) && (hooks->call_on_cpu)) {
140 for (i = 0; i < num_cpus; i++) {
144 if ((cpu_mask == NULL) || (*(cpu_mask + major) & (0x1 << minor))) {
145 V3_Print("Initializing VMM extensions on cpu %d\n", i);
146 hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
148 if (v3_mach_type == V3_INVALID_CPU) {
149 v3_mach_type = v3_cpu_types[i];
162 V3_deinit_shdw_paging();
164 V3_deinit_extensions();
166 #ifdef V3_CONFIG_SYMMOD
170 #ifdef V3_CONFIG_CHECKPOINT
171 V3_deinit_checkpoint();
175 if ((os_hooks) && (os_hooks->call_on_cpu)) {
176 for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
177 if (v3_cpu_types[i] != V3_INVALID_CPU) {
178 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
179 //deinit_cpu((void *)(addr_t)i);
187 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
188 return v3_cpu_types[cpu_id];
192 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name) {
193 struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
196 PrintError("Could not configure guest\n");
200 V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
204 } else if (strlen(name) >= 128) {
205 PrintError("VM name is too long. Will be truncated to 128 chars.\n");
208 memset(vm->name, 0, 128);
209 strncpy(vm->name, name, 127);
217 static int start_core(void * p)
219 struct guest_info * core = (struct guest_info *)p;
222 PrintDebug("virtual core %u (on logical core %u): in start_core (RIP=%p)\n",
223 core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
225 switch (v3_mach_type) {
228 case V3_SVM_REV3_CPU:
229 return v3_start_svm_guest(core);
235 case V3_VMX_EPT_UG_CPU:
236 return v3_start_vmx_guest(core);
240 PrintError("Attempting to enter a guest on an invalid CPU\n");
248 // For the moment very ugly. Eventually we will shift the cpu_mask to an arbitrary sized type...
252 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
254 uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
255 uint32_t avail_cores = 0;
259 if (vm->run_state != VM_STOPPED) {
260 PrintError("VM has already been launched (state=%d)\n", (int)vm->run_state);
264 /// CHECK IF WE ARE MULTICORE ENABLED....
266 V3_Print("V3 -- Starting VM (%u cores)\n", vm->num_cores);
267 V3_Print("CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
270 // Check that enough cores are present in the mask to handle vcores
271 for (i = 0; i < MAX_CORES; i++) {
275 if (core_mask[major] & (0x1 << minor)) {
276 if (v3_cpu_types[i] == V3_INVALID_CPU) {
277 core_mask[major] &= ~(0x1 << minor);
285 if (vm->num_cores > avail_cores) {
286 PrintError("Attempted to start a VM with too many cores (vm->num_cores = %d, avail_cores = %d, MAX=%d)\n",
287 vm->num_cores, avail_cores, MAX_CORES);
291 vm->run_state = VM_RUNNING;
293 // Spawn off threads for each core.
294 // We work backwards, so that core 0 is always started last.
295 for (i = 0, vcore_id = vm->num_cores - 1; (i < MAX_CORES) && (vcore_id >= 0); i++) {
298 struct guest_info * core = &(vm->cores[vcore_id]);
299 char * specified_cpu = v3_cfg_val(core->core_cfg_data, "target_cpu");
300 uint32_t core_idx = 0;
302 if (specified_cpu != NULL) {
303 core_idx = atoi(specified_cpu);
305 if ((core_idx < 0) || (core_idx >= MAX_CORES)) {
306 PrintError("Target CPU out of bounds (%d) (MAX_CORES=%d)\n", core_idx, MAX_CORES);
309 i--; // We reset the logical core idx. Not strictly necessary I guess...
314 major = core_idx / 8;
315 minor = core_idx % 8;
317 if ((core_mask[major] & (0x1 << minor)) == 0) {
318 PrintError("Logical CPU %d not available for virtual core %d; not started\n",
321 if (specified_cpu != NULL) {
322 PrintError("CPU was specified explicitly (%d). HARD ERROR\n", core_idx);
330 PrintDebug("Starting virtual core %u on logical core %u\n",
333 sprintf(core->exec_name, "%s-%u", vm->name, vcore_id);
335 PrintDebug("run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
336 core_idx, start_core, core, core->exec_name);
338 core->core_run_state = CORE_STOPPED; // core zero will turn itself on
339 core->pcpu_id = core_idx;
340 core->core_thread = V3_CREATE_THREAD_ON_CPU(core_idx, start_core, core, core->exec_name);
342 if (core->core_thread == NULL) {
343 PrintError("Thread launch failed\n");
352 PrintError("Error starting VM: Not enough available CPU cores\n");
363 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
365 switch (v3_cpu_types[core->pcpu_id]) {
368 case V3_SVM_REV3_CPU:
369 PrintDebug("Resetting SVM Guest CPU %d\n", core->vcpu_id);
370 return v3_reset_svm_vm_core(core, rip);
375 case V3_VMX_EPT_UG_CPU:
376 PrintDebug("Resetting VMX Guest CPU %d\n", core->vcpu_id);
377 return v3_reset_vmx_vm_core(core, rip);
381 PrintError("CPU has no virtualization Extensions\n");
390 /* move a virtual core to different physical core */
391 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
392 struct guest_info * core = NULL;
394 if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
395 PrintError("Attempted to migrate invalid virtual core (%d)\n", vcore_id);
399 core = &(vm->cores[vcore_id]);
401 if (target_cpu == core->pcpu_id) {
402 PrintError("Attempted to migrate to local core (%d)\n", target_cpu);
403 // well that was pointless
407 if (core->core_thread == NULL) {
408 PrintError("Attempted to migrate a core without a valid thread context\n");
412 while (v3_raise_barrier(vm, NULL) == -1);
414 V3_Print("Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
416 // Double check that we weren't preemptively migrated
417 if (target_cpu != core->pcpu_id) {
419 V3_Print("Moving Core\n");
423 switch (v3_cpu_types[core->pcpu_id]) {
426 case V3_VMX_EPT_UG_CPU:
427 PrintDebug("Flushing VMX Guest CPU %d\n", core->vcpu_id);
428 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
435 if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
436 PrintError("Failed to move Vcore %d to CPU %d\n",
437 core->vcpu_id, target_cpu);
438 v3_lower_barrier(vm);
442 /* There will be a benign race window here:
443 core->pcpu_id will be set to the target core before its fully "migrated"
444 However the core will NEVER run on the old core again, its just in flight to the new core
446 core->pcpu_id = target_cpu;
448 V3_Print("core now at %d\n", core->pcpu_id);
451 v3_lower_barrier(vm);
458 int v3_stop_vm(struct v3_vm_info * vm) {
460 if ((vm->run_state != VM_RUNNING) &&
461 (vm->run_state != VM_SIMULATING)) {
462 PrintError("Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
466 vm->run_state = VM_STOPPED;
468 // Sanity check to catch any weird execution states
469 if (v3_wait_for_barrier(vm, NULL) == 0) {
470 v3_lower_barrier(vm);
473 // XXX force exit all cores via a cross call/IPI XXX
477 int still_running = 0;
479 for (i = 0; i < vm->num_cores; i++) {
480 if (vm->cores[i].core_run_state != CORE_STOPPED) {
485 if (still_running == 0) {
492 V3_Print("VM stopped. Returning\n");
498 int v3_pause_vm(struct v3_vm_info * vm) {
500 if (vm->run_state != VM_RUNNING) {
501 PrintError("Tried to pause a VM that was not running\n");
505 while (v3_raise_barrier(vm, NULL) == -1);
507 vm->run_state = VM_PAUSED;
513 int v3_continue_vm(struct v3_vm_info * vm) {
515 if (vm->run_state != VM_PAUSED) {
516 PrintError("Tried to continue a VM that was not paused\n");
520 vm->run_state = VM_RUNNING;
522 v3_lower_barrier(vm);
529 static int sim_callback(struct guest_info * core, void * private_data) {
530 struct v3_bitmap * timeout_map = private_data;
532 v3_bitmap_set(timeout_map, core->vcpu_id);
534 V3_Print("Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
536 while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
546 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
547 struct v3_bitmap timeout_map;
551 uint64_t cpu_khz = V3_CPU_KHZ();
553 if (vm->run_state != VM_PAUSED) {
554 PrintError("VM must be paused before simulation begins\n");
558 /* AT this point VM is paused */
561 v3_bitmap_init(&timeout_map, vm->num_cores);
566 // calculate cycles from msecs...
567 // IMPORTANT: Floating point not allowed.
568 cycles = (msecs * cpu_khz);
572 V3_Print("Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
576 for (i = 0; i < vm->num_cores; i++) {
577 if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
578 PrintError("Could not register simulation timeout for core %d\n", i);
583 V3_Print("timeouts set on all cores\n ");
586 // Run the simulation
587 // vm->run_state = VM_SIMULATING;
588 vm->run_state = VM_RUNNING;
589 v3_lower_barrier(vm);
592 V3_Print("Barrier lowered: We are now Simulating!!\n");
594 // block until simulation is complete
595 while (all_blocked == 0) {
598 for (i = 0; i < vm->num_cores; i++) {
599 if (v3_bitmap_check(&timeout_map, i) == 0) {
604 if (all_blocked == 1) {
612 V3_Print("Simulation is complete\n");
614 // Simulation is complete
615 // Reset back to PAUSED state
617 v3_raise_barrier_nowait(vm, NULL);
618 vm->run_state = VM_PAUSED;
620 v3_bitmap_reset(&timeout_map);
622 v3_wait_for_barrier(vm, NULL);
628 #ifdef V3_CONFIG_CHECKPOINT
629 #include <palacios/vmm_checkpoint.h>
631 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url) {
632 return v3_chkpt_save_vm(vm, store, url);
636 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url) {
637 return v3_chkpt_load_vm(vm, store, url);
640 #ifdef V3_CONFIG_LIVE_MIGRATION
641 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url) {
642 return v3_chkpt_send_vm(vm, store, url);
646 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url) {
647 return v3_chkpt_receive_vm(vm, store, url);
654 int v3_free_vm(struct v3_vm_info * vm) {
656 // deinitialize guest (free memory, etc...)
658 if ((vm->run_state != VM_STOPPED) &&
659 (vm->run_state != VM_ERROR)) {
660 PrintError("Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
664 v3_free_vm_devices(vm);
667 for (i = 0; i < vm->num_cores; i++) {
668 v3_free_core(&(vm->cores[i]));
672 v3_free_vm_internal(vm);
684 v3_cpu_mode_t v3_get_host_cpu_mode() {
694 cr4 = (struct cr4_32 *)&(cr4_val);
697 return PROTECTED_PAE;
705 v3_cpu_mode_t v3_get_host_cpu_mode() {
715 void v3_yield_cond(struct guest_info * info, int usec) {
717 cur_cycle = v3_get_host_time(&info->time_state);
719 if (cur_cycle > (info->yield_start_cycle + info->vm_info->yield_cycle_period)) {
720 //PrintDebug("Conditional Yield (cur_cyle=%p, start_cycle=%p, period=%p)\n",
721 // (void *)cur_cycle, (void *)info->yield_start_cycle,
722 // (void *)info->yield_cycle_period);
727 V3_Yield_Timed(usec);
730 info->yield_start_cycle += info->vm_info->yield_cycle_period;
736 * unconditional cpu yield
737 * if the yielding thread is a guest context, the guest quantum is reset on resumption
738 * Non guest context threads should call this function with a NULL argument
740 * usec <0 => the non-timed yield is used
741 * usec >=0 => the timed yield is used, which also usually implies interruptible
743 void v3_yield(struct guest_info * info, int usec) {
747 V3_Yield_Timed(usec);
751 info->yield_start_cycle += info->vm_info->yield_cycle_period;
758 void v3_print_cond(const char * fmt, ...) {
759 if (v3_dbg_enable == 1) {
764 vsnprintf(buf, 2048, fmt, ap);
773 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
774 extern struct v3_os_hooks * os_hooks;
776 if ((os_hooks) && (os_hooks)->interrupt_cpu) {
777 (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
783 int v3_vm_enter(struct guest_info * info) {
784 switch (v3_mach_type) {
787 case V3_SVM_REV3_CPU:
788 return v3_svm_enter(info);
794 case V3_VMX_EPT_UG_CPU:
795 return v3_vmx_enter(info);
799 PrintError("Attemping to enter a guest on an invalid CPU\n");