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_mem.h>
22 #include <palacios/vmm_intr.h>
23 #include <palacios/vmm_config.h>
24 #include <palacios/vm_guest.h>
25 #include <palacios/vmm_ctrl_regs.h>
26 #include <palacios/vmm_lowlevel.h>
27 #include <palacios/vmm_sprintf.h>
28 #include <palacios/vmm_extensions.h>
29 #include <palacios/vmm_timeout.h>
30 #include <palacios/vmm_options.h>
31 #include <palacios/vmm_cpu_mapper.h>
32 #include <palacios/vmm_direct_paging.h>
33 #include <interfaces/vmm_numa.h>
34 #include <interfaces/vmm_file.h>
37 #include <palacios/svm.h>
40 #include <palacios/vmx.h>
43 #ifdef V3_CONFIG_CHECKPOINT
44 #include <palacios/vmm_checkpoint.h>
48 v3_cpu_arch_t v3_cpu_types[V3_CONFIG_MAX_CPUS];
49 v3_cpu_arch_t v3_mach_type = V3_INVALID_CPU;
51 struct v3_os_hooks * os_hooks = NULL;
52 int v3_dbg_enable = 0;
56 static void init_cpu(void * arg) {
57 uint32_t cpu_id = (uint32_t)(addr_t)arg;
62 if (v3_is_svm_capable()) {
63 PrintDebug(VM_NONE, VCORE_NONE, "Machine is SVM Capable\n");
64 v3_init_svm_cpu(cpu_id);
69 if (v3_is_vmx_capable()) {
70 PrintDebug(VM_NONE, VCORE_NONE, "Machine is VMX Capable\n");
71 v3_init_vmx_cpu(cpu_id);
76 PrintError(VM_NONE, VCORE_NONE, "CPU has no virtualization Extensions\n");
81 static void deinit_cpu(void * arg) {
82 uint32_t cpu_id = (uint32_t)(addr_t)arg;
85 switch (v3_cpu_types[cpu_id]) {
89 PrintDebug(VM_NONE, VCORE_NONE, "Deinitializing SVM CPU %d\n", cpu_id);
90 v3_deinit_svm_cpu(cpu_id);
96 case V3_VMX_EPT_UG_CPU:
97 PrintDebug(VM_NONE, VCORE_NONE, "Deinitializing VMX CPU %d\n", cpu_id);
98 v3_deinit_vmx_cpu(cpu_id);
103 PrintError(VM_NONE, VCORE_NONE, "CPU has no virtualization Extensions\n");
112 static int in_long_mode()
116 v3_get_msr(0xc0000080,&high,&low); // EFER
118 return ((low & 0x500)== 0x500); // LMA and LME set
122 void Init_V3(struct v3_os_hooks * hooks, char * cpu_mask, int num_cpus, char *options) {
127 V3_Print(VM_NONE, VCORE_NONE, "V3 Print statement to fix a Kitten page fault bug\n");
132 #error Palacios does not support compilation for a 32 bit host OS!!!!
134 if (!in_long_mode()) {
135 PrintError(VM_NONE,VCORE_NONE,"Palacios supports execution only in long mode (64 bit).\n");
140 // Set global variables.
143 if (num_cpus>V3_CONFIG_MAX_CPUS) {
144 PrintError(VM_NONE,VCORE_NONE, "Requesting as many as %d cpus, but Palacios is compiled for a maximum of %d. Only the first %d cpus will be considered\n", num_cpus, V3_CONFIG_MAX_CPUS, V3_CONFIG_MAX_CPUS);
147 // Determine the global machine type
148 v3_mach_type = V3_INVALID_CPU;
150 for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
151 v3_cpu_types[i] = V3_INVALID_CPU;
154 // Parse host-os defined options into an easily-accessed format.
155 v3_parse_options(options);
157 #ifdef V3_CONFIG_MULTIBOOT
165 // Memory manager initialization
168 // Register all the possible device types
171 // Register all shadow paging handlers
172 V3_init_shdw_paging();
174 #ifdef V3_CONFIG_SWAPPING
178 // Initialize the cpu_mapper framework (must be before extensions)
179 V3_init_cpu_mapper();
181 // Initialize the scheduler framework (must be before extensions)
182 V3_init_scheduling();
184 // Register all extensions
185 V3_init_extensions();
187 // Enabling cpu_mapper
188 V3_enable_cpu_mapper();
190 // Enabling scheduler
191 V3_enable_scheduler();
194 #ifdef V3_CONFIG_SYMMOD
198 #ifdef V3_CONFIG_CHECKPOINT
199 V3_init_checkpoint();
202 if ((hooks) && (hooks->call_on_cpu)) {
204 for (i = 0; i < num_cpus && i < V3_CONFIG_MAX_CPUS; i++) {
208 if ((cpu_mask == NULL) || (*(cpu_mask + major) & (0x1 << minor))) {
209 V3_Print(VM_NONE, VCORE_NONE, "Initializing VMM extensions on cpu %d\n", i);
210 hooks->call_on_cpu(i, &init_cpu, (void *)(addr_t)i);
212 if (v3_mach_type == V3_INVALID_CPU) {
213 v3_mach_type = v3_cpu_types[i];
225 // Reverse order of Init_V3
229 if ((os_hooks) && (os_hooks->call_on_cpu)) {
230 for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
231 if (v3_cpu_types[i] != V3_INVALID_CPU) {
232 V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
233 //deinit_cpu((void *)(addr_t)i);
238 #ifdef V3_CONFIG_CHECKPOINT
239 V3_deinit_checkpoint();
242 #ifdef V3_CONFIG_SYMMOD
246 V3_disable_scheduler();
248 V3_disable_cpu_mapper();
250 V3_deinit_extensions();
252 V3_deinit_scheduling();
254 V3_deinit_cpu_mapper();
256 #ifdef V3_CONFIG_SWAPPING
257 v3_deinit_swapping();
260 V3_deinit_shdw_paging();
270 #ifdef V3_CONFIG_MULTIBOOT
271 v3_deinit_multiboot();
280 v3_cpu_arch_t v3_get_cpu_type(int cpu_id) {
281 return v3_cpu_types[cpu_id];
284 static int start_core(void * p)
286 struct guest_info * core = (struct guest_info *)p;
288 if (v3_scheduler_register_core(core) == -1){
289 PrintError(core->vm_info, core,"Error initializing scheduling in core %d\n", core->vcpu_id);
292 PrintDebug(core->vm_info,core,"virtual core %u (on logical core %u): in start_core (RIP=%p)\n",
293 core->vcpu_id, core->pcpu_id, (void *)(addr_t)core->rip);
295 switch (v3_mach_type) {
298 case V3_SVM_REV3_CPU:
299 return v3_start_svm_guest(core);
305 case V3_VMX_EPT_UG_CPU:
306 return v3_start_vmx_guest(core);
310 PrintError(core->vm_info, core, "Attempting to enter a guest on an invalid CPU\n");
317 struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name, unsigned int cpu_mask) {
318 struct v3_vm_info * vm = v3_config_guest(cfg, priv_data);
322 PrintError(VM_NONE, VCORE_NONE, "Could not configure guest\n");
326 V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
330 } else if (strlen(name) >= 128) {
331 PrintError(vm, VCORE_NONE,"VM name is too long. Will be truncated to 128 chars.\n");
334 memset(vm->name, 0, 128);
335 strncpy(vm->name, name, 127);
337 if(v3_cpu_mapper_register_vm(vm) == -1) {
339 PrintError(vm, VCORE_NONE,"Error registering VM with cpu_mapper\n");
343 * Register this VM with the palacios scheduler. It will ask for admission
346 if(v3_scheduler_register_vm(vm) == -1) {
348 PrintError(vm, VCORE_NONE,"Error registering VM with scheduler\n");
351 if (v3_cpu_mapper_admit_vm(vm,cpu_mask) != 0){
352 PrintError(vm, VCORE_NONE,"Error admitting VM %s for mapping", vm->name);
355 for (vcore_id = 0; vcore_id < vm->num_cores; vcore_id++) {
357 struct guest_info * core = &(vm->cores[vcore_id]);
359 PrintDebug(vm, VCORE_NONE, "Creating virtual core %u on logical core %u\n",
360 vcore_id, core->pcpu_id);
362 sprintf(core->exec_name, "%s-%d", vm->name, vcore_id);
364 PrintDebug(vm, VCORE_NONE, "run: core=%u, func=0x%p, arg=0x%p, name=%s\n",
365 core->pcpu_id, start_core, core, core->exec_name);
367 core->core_thread = V3_CREATE_THREAD_ON_CPU(core->pcpu_id, start_core, core, core->exec_name);
369 if (core->core_thread == NULL) {
370 PrintError(vm, VCORE_NONE, "Thread creation failed\n");
379 int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask) {
382 uint8_t * core_mask = (uint8_t *)&cpu_mask; // This is to make future expansion easier
383 uint32_t avail_cores = 0;
387 PrintError(VM_NONE, VCORE_NONE, "Asked to start nonexistent VM\n");
391 if (vm->run_state != VM_STOPPED) {
392 PrintError(vm, VCORE_NONE, "VM has already been launched (state=%d)\n", (int)vm->run_state);
396 #if V3_CONFIG_MULTIBOOT
397 if (v3_setup_multiboot_vm_for_boot(vm)) {
398 PrintError(vm, VCORE_NONE, "Multiboot setup for boot failed\n");
403 if (v3_setup_hvm_vm_for_boot(vm)) {
404 PrintError(vm, VCORE_NONE, "HVM setup for boot failed\n");
409 /// CHECK IF WE ARE MULTICORE ENABLED....
411 V3_Print(vm, VCORE_NONE, "V3 -- Starting VM (%u cores)\n", vm->num_cores);
412 V3_Print(vm, VCORE_NONE, "CORE 0 RIP=%p\n", (void *)(addr_t)(vm->cores[0].rip));
415 // Check that enough cores are present in the mask to handle vcores
416 for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
420 if (core_mask[major] & (0x1 << minor)) {
421 if (v3_cpu_types[i] == V3_INVALID_CPU) {
422 core_mask[major] &= ~(0x1 << minor);
429 vm->avail_cores = avail_cores;
431 if (v3_scheduler_admit_vm(vm) != 0){
432 PrintError(vm, VCORE_NONE,"Error admitting VM %s for scheduling", vm->name);
435 vm->run_state = VM_RUNNING;
437 for (vcore_id = 0; vcore_id < vm->num_cores; vcore_id++) {
439 struct guest_info * core = &(vm->cores[vcore_id]);
441 PrintDebug(vm, VCORE_NONE, "Starting virtual core %u on logical core %u\n",
442 vcore_id, core->pcpu_id);
444 if (core->core_run_state==CORE_INVALID) {
445 // launch of a fresh VM
446 core->core_run_state = CORE_STOPPED;
447 // core zero will turn itself on
449 // this is a resume - use whatever its current run_state is
452 V3_START_THREAD(core->core_thread);
461 int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
463 switch (v3_cpu_types[core->pcpu_id]) {
466 case V3_SVM_REV3_CPU:
467 PrintDebug(core->vm_info, core, "Resetting SVM Guest CPU %d\n", core->vcpu_id);
468 return v3_reset_svm_vm_core(core, rip);
473 case V3_VMX_EPT_UG_CPU:
474 PrintDebug(core->vm_info, core, "Resetting VMX Guest CPU %d\n", core->vcpu_id);
475 return v3_reset_vmx_vm_core(core, rip);
479 PrintError(core->vm_info, core, "CPU has no virtualization Extensions\n");
487 // resets the whole VM (non-HVM) or the ROS (HVM)
488 int v3_reset_vm(struct v3_vm_info *vm)
491 if (vm->hvm_state.is_hvm) {
492 return v3_reset_vm_extended(vm,V3_VM_RESET_ROS,0);
494 return v3_reset_vm_extended(vm,V3_VM_RESET_ALL,0);
497 return v3_reset_vm_extended(vm,V3_VM_RESET_ALL,0);
501 int v3_reset_vm_extended(struct v3_vm_info *vm, v3_vm_reset_type t, void *data)
503 uint32_t start, end, i;
506 if (vm->run_state != VM_RUNNING) {
507 PrintError(vm,VCORE_NONE,"Attempt to reset VM in state %d (must be in running state)\n",vm->run_state);
513 case V3_VM_RESET_ALL:
515 if (vm->hvm_state.is_hvm) {
516 PrintError(vm,VCORE_NONE,"Attempt to do ALL reset of HVM (not allowed)\n");
520 start=0; end=vm->num_cores-1;
523 case V3_VM_RESET_HRT:
524 case V3_VM_RESET_ROS:
525 if (vm->hvm_state.is_hvm) {
526 if (t==V3_VM_RESET_HRT) {
527 start = vm->hvm_state.first_hrt_core;
528 end = vm->num_cores-1;
531 end = vm->hvm_state.first_hrt_core-1;
534 PrintError(vm,VCORE_NONE,"This is not an HVM and so HVM-specific resets do not apply\n");
539 case V3_VM_RESET_CORE_RANGE:
541 start = ((uint32_t*)data)[0];
542 end = ((uint32_t*)data)[1];
548 PrintError(vm,VCORE_NONE,"Unsupported reset type %d for this VM\n",t);
553 PrintDebug(vm,VCORE_NONE,"Resetting cores %d through %d\n",start,end);
555 newcount = end-start+1;
557 for (i=start;i<=end;i++) {
558 if (!(vm->cores[i].core_run_state == CORE_RUNNING || vm->cores[i].core_run_state == CORE_STOPPED)) {
559 PrintError(vm,VCORE_NONE,"Cannot reset VM as core %u is in state %d (must be running or stopped)\n",i,vm->cores[i].core_run_state);
565 // This had better be the only thread using the barrier at this point...
566 v3_init_counting_barrier(&vm->reset_barrier,newcount);
568 // OK, I am the reseter, tell the relevant cores what to do
569 // each will atomically decrement the reset countdown and then
570 // spin waiting for it to hit zero.
572 for (i=start;i<=end;i++) {
573 vm->cores[i].core_run_state = CORE_RESETTING;
574 // force exit of core
575 v3_interrupt_cpu(vm, vm->cores[i].pcpu_id, 0);
578 // we don't wait for reset to finish
579 // because reset could have been initiated by a core
585 /* move a virtual core to different physical core */
586 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
587 struct guest_info * core = NULL;
590 PrintError(VM_NONE, VCORE_NONE, "Asked to move core of nonexistent VM\n");
594 if ((vcore_id < 0) || (vcore_id >= vm->num_cores)) {
595 PrintError(vm, VCORE_NONE, "Attempted to migrate invalid virtual core (%d)\n", vcore_id);
599 core = &(vm->cores[vcore_id]);
601 if (target_cpu == core->pcpu_id) {
602 PrintError(vm, core, "Attempted to migrate to local core (%d)\n", target_cpu);
603 // well that was pointless
607 if (core->core_thread == NULL) {
608 PrintError(vm, core, "Attempted to migrate a core without a valid thread context\n");
612 while (v3_raise_barrier(vm, NULL) == -1);
614 V3_Print(vm, core, "Performing Migration from %d to %d\n", core->pcpu_id, target_cpu);
616 // Double check that we weren't preemptively migrated
617 if (target_cpu != core->pcpu_id) {
619 V3_Print(vm, core, "Moving Core\n");
621 if(v3_cpu_mapper_admit_core(vm, vcore_id, target_cpu) == -1){
622 PrintError(vm, core, "Core %d can not be admitted in cpu %d\n",vcore_id, target_cpu);
628 switch (v3_cpu_types[core->pcpu_id]) {
631 case V3_VMX_EPT_UG_CPU:
632 PrintDebug(vm, core, "Flushing VMX Guest CPU %d\n", core->vcpu_id);
633 V3_Call_On_CPU(core->pcpu_id, (void (*)(void *))v3_flush_vmx_vm_core, (void *)core);
640 if (V3_MOVE_THREAD_TO_CPU(target_cpu, core->core_thread) != 0) {
641 PrintError(vm, core, "Failed to move Vcore %d to CPU %d\n",
642 core->vcpu_id, target_cpu);
643 v3_lower_barrier(vm);
647 /* There will be a benign race window here:
648 core->pcpu_id will be set to the target core before its fully "migrated"
649 However the core will NEVER run on the old core again, its just in flight to the new core
651 core->pcpu_id = target_cpu;
653 V3_Print(vm, core, "core now at %d\n", core->pcpu_id);
656 v3_lower_barrier(vm);
661 /* move a memory region to memory with affinity for a specific physical core */
662 int v3_move_vm_mem(struct v3_vm_info * vm, void *gpa, int target_cpu) {
665 struct v3_mem_region *reg;
672 PrintError(VM_NONE, VCORE_NONE, "Asked to move memory of nonexistent VM\n");
676 old_node = v3_numa_gpa_to_node(vm,(addr_t)gpa);
679 PrintError(vm, VCORE_NONE, "Cannot determine current node of gpa %p\n",gpa);
683 new_node = v3_numa_cpu_to_node(target_cpu);
686 PrintError(vm, VCORE_NONE, "Cannot determine current node of cpu %d\n",target_cpu);
690 if (new_node==old_node) {
691 PrintDebug(vm, VCORE_NONE, "Affinity is already established - ignoring request\n");
695 // We are now going to change the universe, so
696 // we'll barrier everyone first
698 while (v3_raise_barrier(vm, NULL) == -1);
702 reg = v3_get_mem_region(vm, V3_MEM_CORE_ANY, (addr_t) gpa);
705 PrintError(vm, VCORE_NONE, "Attempt to migrate non-existent memory\n");
709 if (!(reg->flags.base) || !(reg->flags.alloced)) {
710 PrintError(vm, VCORE_NONE, "Attempt to migrate invalid region: base=%d alloced=%d\n", reg->flags.base, reg->flags.alloced);
714 // we now have the allocated base region corresponding to - and not a copy
715 // we will rewrite this region after moving its contents
717 // first, let's double check that we are in fact changing the numa_id...
719 if (reg->numa_id==new_node) {
720 PrintDebug(vm, VCORE_NONE, "Affinity for this base region is already established - ignoring...\n");
724 // region uses exclusive addressing [guest_start,guest_end)
725 num_pages = (reg->guest_end-reg->guest_start)/PAGE_SIZE;
727 new_hpa = V3_AllocPagesExtended(num_pages,
730 0, 0); // no constraints given new shadow pager impl
733 PrintError(vm, VCORE_NONE, "Cannot allocate memory for new base region...\n");
737 // Note, assumes virtual contiguity in the host OS...
738 memcpy(V3_VAddr((void*)new_hpa), V3_VAddr((void*)(reg->host_addr)), num_pages*PAGE_SIZE);
740 old_hpa = (void*)(reg->host_addr);
741 old_node = (int)(reg->numa_id);
743 reg->host_addr = (addr_t)new_hpa;
744 reg->numa_id = v3_numa_hpa_to_node((addr_t)new_hpa);
746 // flush all page tables / kill all humans
748 for (i=0;i<vm->num_cores;i++) {
749 if (vm->cores[i].shdw_pg_mode==SHADOW_PAGING) {
750 v3_invalidate_shadow_pts(&(vm->cores[i]));
751 } else if (vm->cores[i].shdw_pg_mode==NESTED_PAGING) {
752 // nested invalidator uses inclusive addressing [start,end], not [start,end)
753 v3_invalidate_nested_addr_range(&(vm->cores[i]),reg->guest_start,reg->guest_end-1,NULL,NULL);
755 PrintError(vm,VCORE_NONE, "Cannot determine how to invalidate paging structures! Reverting to previous region.\n");
756 // We'll restore things...
757 reg->host_addr = (addr_t) old_hpa;
758 reg->numa_id = old_node;
759 V3_FreePages(new_hpa,num_pages);
764 // Now the old region can go away...
765 V3_FreePages(old_hpa,num_pages);
767 PrintDebug(vm,VCORE_NONE,"Migration of memory complete - new region is %p to %p\n",
768 (void*)(reg->host_addr),(void*)(reg->host_addr+num_pages*PAGE_SIZE-1));
771 v3_lower_barrier(vm);
776 v3_lower_barrier(vm);
780 int v3_stop_vm(struct v3_vm_info * vm) {
782 struct guest_info * running_core;
785 PrintError(VM_NONE, VCORE_NONE, "Asked to stop nonexistent VM\n");
789 if ((vm->run_state != VM_RUNNING) &&
790 (vm->run_state != VM_SIMULATING)) {
791 PrintError(vm, VCORE_NONE,"Tried to stop VM in invalid runstate (%d)\n", vm->run_state);
795 vm->run_state = VM_STOPPED;
797 // Sanity check to catch any weird execution states
798 if (v3_wait_for_barrier(vm, NULL) == 0) {
799 v3_lower_barrier(vm);
802 // XXX force exit all cores via a cross call/IPI XXX
806 int still_running = 0;
808 for (i = 0; i < vm->num_cores; i++) {
809 if (vm->cores[i].core_run_state != CORE_STOPPED) {
810 running_core = &vm->cores[i];
815 if (still_running == 0) {
819 v3_scheduler_stop_core(running_core);
822 V3_Print(vm, VCORE_NONE,"VM stopped. Returning\n");
828 int v3_pause_vm(struct v3_vm_info * vm) {
831 PrintError(VM_NONE, VCORE_NONE, "Asked to pause nonexistent VM\n");
835 if (vm->run_state != VM_RUNNING) {
836 PrintError(vm, VCORE_NONE,"Tried to pause a VM that was not running\n");
840 while (v3_raise_barrier(vm, NULL) == -1);
842 vm->run_state = VM_PAUSED;
848 int v3_continue_vm(struct v3_vm_info * vm) {
851 PrintError(VM_NONE, VCORE_NONE, "Asked to continue nonexistent VM\n");
855 if (vm->run_state != VM_PAUSED) {
856 PrintError(vm, VCORE_NONE,"Tried to continue a VM that was not paused\n");
860 vm->run_state = VM_RUNNING;
862 v3_lower_barrier(vm);
869 static int sim_callback(struct guest_info * core, void * private_data) {
870 struct v3_bitmap * timeout_map = private_data;
872 v3_bitmap_set(timeout_map, core->vcpu_id);
874 V3_Print(core->vm_info, core, "Simulation callback activated (guest_rip=%p)\n", (void *)core->rip);
876 while (v3_bitmap_check(timeout_map, core->vcpu_id) == 1) {
877 // We spin here if there is noone to yield to
887 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs) {
888 struct v3_bitmap timeout_map;
892 uint64_t cpu_khz = V3_CPU_KHZ();
895 PrintError(VM_NONE, VCORE_NONE, "Asked to simulate nonexistent VM\n");
899 if (vm->run_state != VM_PAUSED) {
900 PrintError(vm, VCORE_NONE,"VM must be paused before simulation begins\n");
904 /* AT this point VM is paused */
907 v3_bitmap_init(&timeout_map, vm->num_cores);
912 // calculate cycles from msecs...
913 // IMPORTANT: Floating point not allowed.
914 cycles = (msecs * cpu_khz);
918 V3_Print(vm, VCORE_NONE,"Simulating %u msecs (%llu cycles) [CPU_KHZ=%llu]\n", msecs, cycles, cpu_khz);
922 for (i = 0; i < vm->num_cores; i++) {
923 if (v3_add_core_timeout(&(vm->cores[i]), cycles, sim_callback, &timeout_map) == -1) {
924 PrintError(vm, VCORE_NONE,"Could not register simulation timeout for core %d\n", i);
929 V3_Print(vm, VCORE_NONE,"timeouts set on all cores\n ");
932 // Run the simulation
933 // vm->run_state = VM_SIMULATING;
934 vm->run_state = VM_RUNNING;
935 v3_lower_barrier(vm);
938 V3_Print(vm, VCORE_NONE,"Barrier lowered: We are now Simulating!!\n");
940 // block until simulation is complete
941 while (all_blocked == 0) {
944 for (i = 0; i < vm->num_cores; i++) {
945 if (v3_bitmap_check(&timeout_map, i) == 0) {
950 if (all_blocked == 1) {
954 // Intentionally spin if there is no one to yield to
959 V3_Print(vm, VCORE_NONE,"Simulation is complete\n");
961 // Simulation is complete
962 // Reset back to PAUSED state
964 v3_raise_barrier_nowait(vm, NULL);
965 vm->run_state = VM_PAUSED;
967 v3_bitmap_reset(&timeout_map);
969 v3_wait_for_barrier(vm, NULL);
975 int v3_get_state_vm(struct v3_vm_info *vm,
976 struct v3_vm_base_state *base,
977 struct v3_vm_core_state *core,
978 struct v3_vm_mem_state *mem)
983 extern uint64_t v3_mem_block_size;
986 if (!vm || !base || !core || !mem) {
987 PrintError(VM_NONE, VCORE_NONE, "Invalid request to v3_get_state_vm\n");
991 numcores = core->num_vcores > vm->num_cores ? vm->num_cores : core->num_vcores;
992 numregions = mem->num_regions > vm->mem_map.num_base_regions ? vm->mem_map.num_base_regions : mem->num_regions;
994 switch (vm->run_state) {
995 case VM_INVALID: base->state = V3_VM_INVALID; break;
996 case VM_RUNNING: base->state = V3_VM_RUNNING; break;
997 case VM_STOPPED: base->state = V3_VM_STOPPED; break;
998 case VM_PAUSED: base->state = V3_VM_PAUSED; break;
999 case VM_ERROR: base->state = V3_VM_ERROR; break;
1000 case VM_SIMULATING: base->state = V3_VM_SIMULATING; break;
1001 case VM_RESETTING: base->state = V3_VM_RESETTING; break;
1002 default: base->state = V3_VM_UNKNOWN; break;
1005 base->vm_type = V3_VM_GENERAL;
1007 #ifdef V3_CONFIG_HVM
1008 if (vm->hvm_state.is_hvm) {
1009 base->vm_type = V3_VM_HVM;
1013 for (i=0;i<numcores;i++) {
1014 switch (vm->cores[i].core_run_state) {
1015 case CORE_INVALID: core->vcore[i].state = V3_VCORE_INVALID; break;
1016 case CORE_RUNNING: core->vcore[i].state = V3_VCORE_RUNNING; break;
1017 case CORE_STOPPED: core->vcore[i].state = V3_VCORE_STOPPED; break;
1018 case CORE_RESETTING: core->vcore[i].state = V3_VCORE_RESETTING; break;
1019 default: core->vcore[i].state = V3_VCORE_UNKNOWN; break;
1021 switch (vm->cores[i].cpu_mode) {
1022 case REAL: core->vcore[i].cpu_mode = V3_VCORE_CPU_REAL; break;
1023 case PROTECTED: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED; break;
1024 case PROTECTED_PAE: core->vcore[i].cpu_mode = V3_VCORE_CPU_PROTECTED_PAE; break;
1025 case LONG: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG; break;
1026 case LONG_32_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_32_COMPAT; break;
1027 case LONG_16_COMPAT: core->vcore[i].cpu_mode = V3_VCORE_CPU_LONG_16_COMPAT; break;
1028 default: core->vcore[i].cpu_mode = V3_VCORE_CPU_UNKNOWN; break;
1030 switch (vm->cores[i].shdw_pg_mode) {
1031 case SHADOW_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_SHADOW; break;
1032 case NESTED_PAGING: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_NESTED; break;
1033 default: core->vcore[i].mem_state = V3_VCORE_MEM_STATE_UNKNOWN; break;
1035 switch (vm->cores[i].mem_mode) {
1036 case PHYSICAL_MEM: core->vcore[i].mem_mode = V3_VCORE_MEM_MODE_PHYSICAL; break;
1037 case VIRTUAL_MEM: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_VIRTUAL; break;
1038 default: core->vcore[i].mem_mode=V3_VCORE_MEM_MODE_UNKNOWN; break;
1041 core->vcore[i].vcore_type = V3_VCORE_GENERAL;
1043 #ifdef V3_CONFIG_HVM
1044 if (vm->hvm_state.is_hvm) {
1045 if (v3_is_hvm_ros_core(&vm->cores[i])) {
1046 core->vcore[i].vcore_type = V3_VCORE_ROS;
1048 core->vcore[i].vcore_type = V3_VCORE_HRT;
1053 core->vcore[i].pcore=vm->cores[i].pcpu_id;
1054 core->vcore[i].last_rip=(void*)(vm->cores[i].rip);
1055 core->vcore[i].num_exits=vm->cores[i].num_exits;
1058 core->num_vcores=numcores;
1062 for (i=0;i<numregions;i++) {
1063 mem->region[i].guest_paddr = cur_gpa;
1064 mem->region[i].host_paddr = (void*)(vm->mem_map.base_regions[i].host_addr);
1065 mem->region[i].size = v3_mem_block_size;
1066 #ifdef V3_CONFIG_SWAPPING
1067 mem->region[i].swapped = vm->mem_map.base_regions[i].flags.swapped;
1068 mem->region[i].pinned = vm->mem_map.base_regions[i].flags.pinned;
1070 mem->region[i].swapped = 0;
1071 mem->region[i].pinned = 0;
1074 cur_gpa += mem->region[i].size;
1077 mem->num_regions=numregions;
1080 mem->mem_size=vm->mem_size;
1081 mem->ros_mem_size=vm->mem_size;
1083 #ifdef V3_CONFIG_HVM
1084 if (vm->hvm_state.is_hvm) {
1085 mem->ros_mem_size=v3_get_hvm_ros_memsize(vm);
1092 int v3_get_state_sizes_vm(struct v3_vm_info *vm,
1093 unsigned long long *num_vcores,
1094 unsigned long long *num_regions)
1096 if (!vm || !num_vcores || !num_regions) {
1097 PrintError(VM_NONE, VCORE_NONE, "Invalid request to v3_get_state_sizes\n");
1101 *num_vcores = vm->num_cores;
1102 *num_regions = vm->mem_map.num_base_regions;
1108 #ifdef V3_CONFIG_CHECKPOINT
1109 #include <palacios/vmm_checkpoint.h>
1111 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
1112 if (!vm || !store || !url) {
1113 PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_save_vm\n");
1116 return v3_chkpt_save_vm(vm, store, url, opts);
1120 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
1121 if (!vm || !store || !url) {
1122 PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_load_vm\n");
1125 return v3_chkpt_load_vm(vm, store, url, opts);
1128 #ifdef V3_CONFIG_LIVE_MIGRATION
1129 int v3_send_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
1130 if (!vm || !store || !url) {
1131 PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_send_vm\n");
1134 return v3_chkpt_send_vm(vm, store, url, opts);
1138 int v3_receive_vm(struct v3_vm_info * vm, char * store, char * url, v3_chkpt_options_t opts) {
1139 if (!vm || !store || !url) {
1140 PrintError(VM_NONE,VCORE_NONE, "Incorrect arguemnts for v3_receive_vm\n");
1143 return v3_chkpt_receive_vm(vm, store, url, opts);
1150 int v3_free_vm(struct v3_vm_info * vm) {
1152 // deinitialize guest (free memory, etc...)
1155 PrintError(VM_NONE, VCORE_NONE, "Asked to free nonexistent VM\n");
1159 if ((vm->run_state != VM_STOPPED) &&
1160 (vm->run_state != VM_ERROR)) {
1161 PrintError(vm, VCORE_NONE,"Tried to Free VM in invalid runstate (%d)\n", vm->run_state);
1165 v3_free_vm_devices(vm);
1168 for (i = 0; i < vm->num_cores; i++) {
1169 v3_scheduler_free_core(&(vm->cores[i]));
1170 v3_free_core(&(vm->cores[i]));
1174 v3_scheduler_free_vm(vm);
1175 v3_free_vm_internal(vm);
1187 v3_cpu_mode_t v3_get_host_cpu_mode() {
1189 struct cr4_32 * cr4;
1197 cr4 = (struct cr4_32 *)&(cr4_val);
1199 if (cr4->pae == 1) {
1200 return PROTECTED_PAE;
1208 v3_cpu_mode_t v3_get_host_cpu_mode() {
1214 void v3_print_cond(const char * fmt, ...) {
1215 if (v3_dbg_enable == 1) {
1220 vsnprintf(buf, 2048, fmt, ap);
1223 V3_Print(VM_NONE, VCORE_NONE,"%s", buf);
1229 void v3_interrupt_cpu(struct v3_vm_info * vm, int logical_cpu, int vector) {
1230 extern struct v3_os_hooks * os_hooks;
1232 if ((os_hooks) && (os_hooks)->interrupt_cpu) {
1233 (os_hooks)->interrupt_cpu(vm, logical_cpu, vector);
1239 int v3_vm_enter(struct guest_info * info) {
1240 switch (v3_mach_type) {
1241 #ifdef V3_CONFIG_SVM
1243 case V3_SVM_REV3_CPU:
1244 return v3_svm_enter(info);
1249 case V3_VMX_EPT_CPU:
1250 case V3_VMX_EPT_UG_CPU:
1251 return v3_vmx_enter(info);
1255 PrintError(info->vm_info, info, "Attemping to enter a guest on an invalid CPU\n");
1261 void *v3_get_host_vm(struct v3_vm_info *x)
1264 return x->host_priv_data;
1270 int v3_get_vcore(struct guest_info *x)