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.


VM reset capability
Peter Dinda [Thu, 18 Jun 2015 22:20:37 +0000 (17:20 -0500)]
Allows reset of "normal" VM, a multiboot VM, or either the
ROS or HRT components of an HVM

palacios/include/palacios/vm_guest.h
palacios/include/palacios/vmm.h
palacios/include/palacios/vmm_types.h
palacios/src/palacios/vmm.c
palacios/src/palacios/vmm_halt.c

index e646c86..7a78c0a 100644 (file)
@@ -39,6 +39,7 @@
 #include <palacios/vmm_regs.h>
 #include <palacios/vmm_extensions.h>
 #include <palacios/vmm_barrier.h>
+#include <palacios/vmm_subset.h>
 #include <palacios/vmm_timeout.h>
 #include <palacios/vmm_exits.h>
 #include <palacios/vmm_events.h>
@@ -276,6 +277,8 @@ struct v3_vm_info {
     struct v3_vm_hvm  hvm_state;
 #endif
 
+    // used to implement reset of regular VM and ROS
+    v3_counting_barrier_t  reset_barrier;
 
     uint64_t yield_cycle_period;  
 
index c00e10f..b6cc1e6 100644 (file)
@@ -413,8 +413,8 @@ struct v3_interrupt {
 };
 
 
-typedef enum {V3_VM_UNKNOWN, V3_VM_INVALID, V3_VM_RUNNING, V3_VM_STOPPED, V3_VM_PAUSED, V3_VM_ERROR, V3_VM_SIMULATING} v3_vm_state_t;
-typedef enum {V3_VCORE_UNKNOWN, V3_VCORE_INVALID, V3_VCORE_RUNNING, V3_VCORE_STOPPED} v3_vcore_state_t;
+typedef enum {V3_VM_UNKNOWN, V3_VM_INVALID, V3_VM_RUNNING, V3_VM_STOPPED, V3_VM_PAUSED, V3_VM_ERROR, V3_VM_SIMULATING, V3_VM_RESETTING} v3_vm_state_t;
+typedef enum {V3_VCORE_UNKNOWN, V3_VCORE_INVALID, V3_VCORE_RUNNING, V3_VCORE_STOPPED, V3_VCORE_RESETTING } v3_vcore_state_t;
 typedef enum {V3_VCORE_CPU_UNKNOWN, V3_VCORE_CPU_REAL, V3_VCORE_CPU_PROTECTED, V3_VCORE_CPU_PROTECTED_PAE, V3_VCORE_CPU_LONG, V3_VCORE_CPU_LONG_32_COMPAT, V3_VCORE_CPU_LONG_16_COMPAT} v3_vcore_cpu_mode_t;
 
 typedef enum {V3_VCORE_MEM_STATE_UNKNOWN, V3_VCORE_MEM_STATE_SHADOW, V3_VCORE_MEM_STATE_NESTED} v3_vcore_mem_state_t;
@@ -465,6 +465,10 @@ int v3_pause_vm(struct v3_vm_info * vm);
 int v3_continue_vm(struct v3_vm_info * vm);
 int v3_simulate_vm(struct v3_vm_info * vm, unsigned int msecs);
 
+int v3_reset_vm(struct v3_vm_info *vm);
+typedef enum {V3_VM_RESET_ALL,V3_VM_RESET_HRT,V3_VM_RESET_ROS,V3_VM_RESET_CORE_RANGE} v3_vm_reset_type;
+int v3_reset_vm_extended(struct v3_vm_info *vm, v3_vm_reset_type t, void *data);
+
 int v3_save_vm(struct v3_vm_info * vm, char * store, char * url, unsigned long long opts);
 int v3_load_vm(struct v3_vm_info * vm, char * store, char * url, unsigned long long opts);
 
index 01e22b7..e4f8ed4 100644 (file)
@@ -27,8 +27,8 @@
 
 
 typedef enum {SHADOW_PAGING, NESTED_PAGING} v3_paging_mode_t;
-typedef enum {VM_INVALID, VM_RUNNING, VM_STOPPED, VM_PAUSED, VM_ERROR, VM_SIMULATING} v3_vm_operating_mode_t;
-typedef enum {CORE_INVALID, CORE_RUNNING, CORE_STOPPED} v3_core_operating_mode_t;
+typedef enum {VM_INVALID, VM_RUNNING, VM_STOPPED, VM_PAUSED, VM_ERROR, VM_SIMULATING, VM_RESETTING } v3_vm_operating_mode_t;
+typedef enum {CORE_INVALID, CORE_RUNNING, CORE_STOPPED, CORE_RESETTING } v3_core_operating_mode_t;
 
 typedef enum {REAL, /*UNREAL,*/ PROTECTED, PROTECTED_PAE, LONG, LONG_32_COMPAT, LONG_16_COMPAT} v3_cpu_mode_t;
 typedef enum {PHYSICAL_MEM, VIRTUAL_MEM} v3_mem_mode_t;
index 6257294..ffaf15c 100644 (file)
@@ -484,6 +484,99 @@ int v3_reset_vm_core(struct guest_info * core, addr_t rip) {
 }
 
 
+// resets the whole VM (non-HVM) or the ROS (HVM) 
+int v3_reset_vm(struct v3_vm_info *vm)
+{
+#ifdef V3_CONFIG_HVM
+    if (vm->hvm_state.is_hvm) { 
+       return v3_reset_vm_extended(vm,V3_VM_RESET_ROS,0);
+    } else {
+       return v3_reset_vm_extended(vm,V3_VM_RESET_ALL,0);
+    }
+#else
+    return v3_reset_vm_extended(vm,V3_VM_RESET_ALL,0);
+#endif
+}
+
+int v3_reset_vm_extended(struct v3_vm_info *vm, v3_vm_reset_type t, void *data)
+{
+    uint32_t start, end, i;
+    uint32_t newcount;
+
+    if (vm->run_state != VM_RUNNING) { 
+       PrintError(vm,VCORE_NONE,"Attempt to reset VM in state %d (must be in running state)\n",vm->run_state);
+       return -1;
+    }
+       
+
+    switch (t) { 
+       case V3_VM_RESET_ALL:
+#ifdef V3_CONFIG_HVM
+           if (vm->hvm_state.is_hvm) { 
+               PrintError(vm,VCORE_NONE,"Attempt to do ALL reset of HVM (not allowed)\n");
+               return -1;
+           }
+#endif
+           start=0; end=vm->num_cores-1;
+           break;
+#ifdef V3_CONFIG_HVM
+       case V3_VM_RESET_HRT:
+       case V3_VM_RESET_ROS:
+           if (vm->hvm_state.is_hvm) { 
+               if (t==V3_VM_RESET_HRT) { 
+                   start = vm->hvm_state.first_hrt_core;
+                   end = vm->num_cores-1;
+               } else {
+                   start = 0;
+                   end = vm->hvm_state.first_hrt_core-1;
+               }
+           } else {
+               PrintError(vm,VCORE_NONE,"This is not an HVM and so HVM-specific resets do not apply\n");
+               return -1;
+           }
+#endif
+           break;
+       case V3_VM_RESET_CORE_RANGE:
+           start = ((uint32_t*)data)[0];
+           end = ((uint32_t*)data)[1];
+           break;
+       default:
+           PrintError(vm,VCORE_NONE,"Unsupported reset type %d for this VM\n",t);
+           return -1;
+           break;
+    }
+
+    PrintDebug(vm,VCORE_NONE,"Resetting cores %d through %d\n",start,end);
+
+    newcount = end-start+1;
+    
+    for (i=start;i<=end;i++) { 
+       if (!(vm->cores[i].core_run_state == CORE_RUNNING || vm->cores[i].core_run_state == CORE_STOPPED)) {
+           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);
+           return -1;
+       }
+    }
+
+
+    // This had better be the only thread using the barrier at this point...
+    v3_init_counting_barrier(&vm->reset_barrier,newcount);
+
+    // OK, I am the reseter, tell the relevant cores what to do
+    // each will atomically decrement the reset countdown and then
+    // spin waiting for it to hit zero.
+
+    for (i=start;i<=end;i++) { 
+       vm->cores[i].core_run_state = CORE_RESETTING;
+       // force exit of core
+       v3_interrupt_cpu(vm, vm->cores[i].pcpu_id, 0);
+    }
+    
+    // we don't wait for reset to finish
+    // because reset could have been initiated by a core
+
+    return 0;
+}
+
 
 /* move a virtual core to different physical core */
 int v3_move_vm_core(struct v3_vm_info * vm, int vcore_id, int target_cpu) {
@@ -900,6 +993,7 @@ int v3_get_state_vm(struct v3_vm_info        *vm,
        case VM_PAUSED: base->state = V3_VM_PAUSED; break;
        case VM_ERROR: base->state = V3_VM_ERROR; break;
        case VM_SIMULATING: base->state = V3_VM_SIMULATING; break;
+       case VM_RESETTING: base->state = V3_VM_RESETTING; break;
        default: base->state = V3_VM_UNKNOWN; break;
     }
 
@@ -908,6 +1002,7 @@ int v3_get_state_vm(struct v3_vm_info        *vm,
            case CORE_INVALID: core->vcore[i].state = V3_VCORE_INVALID; break;
            case CORE_RUNNING: core->vcore[i].state = V3_VCORE_RUNNING; break;
            case CORE_STOPPED: core->vcore[i].state = V3_VCORE_STOPPED; break;
+           case CORE_RESETTING: core->vcore[i].state = V3_VCORE_RESETTING; break;
            default: core->vcore[i].state = V3_VCORE_UNKNOWN; break;
        }
        switch (vm->cores[i].cpu_mode) {
index 741b2d9..57aee0f 100644 (file)
@@ -73,8 +73,8 @@ int v3_handle_halt(struct guest_info * info)
            // participate in any barrier that might be raised
            v3_wait_at_barrier(info);
 
-           // stop if the VM is being halted
-           if (info->core_run_state == CORE_STOPPED) { 
+           // stop if the VM is being halted or core is being reset
+           if (info->core_run_state == CORE_STOPPED || info->core_run_state == CORE_RESETTING) { 
                break;
            }