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.


More updates getting basic version of time handling working.
Patrick G. Bridges [Tue, 19 Oct 2010 20:13:04 +0000 (14:13 -0600)]
palacios/include/palacios/vmm_time.h
palacios/src/palacios/svm.c
palacios/src/palacios/vm_guest.c
palacios/src/palacios/vmm_time.c
palacios/src/palacios/vmx.c

index 0377be8..4364358 100644 (file)
 struct guest_info;
 
 struct vm_time {
-    uint32_t cpu_freq;         // in kHZ in terms of guest CPU speed
-                               // which ideally can be different lower than
-                               // host CPU speed!
+    uint32_t host_cpu_freq;    // in kHZ 
+    uint32_t guest_cpu_freq;   // can be lower than host CPU freq!
          
-    uint32_t time_mult;        // Fields for computing monotonic guest time
-    uint32_t time_div;         // from host (tsc) time
-    sint64_t time_offset;      
-
-    sint64_t tsc_time_offset;  // Offset for computing guest TSC value from
-                               // monotonic guest time
+    sint64_t guest_host_offset;// Offset of monotonic guest time from host time
+    sint64_t tsc_guest_offset; // Offset of guest TSC from monotonic guest time
     
     uint64_t last_update;      // Last time (in monotonic guest time) the 
                                // timers were updated
 
-    uint64_t pause_time;       // Cache value to help calculate the guest_tsc
+    uint64_t initial_time;     // Time when VMM started. 
     
     struct v3_msr tsc_aux;     // Auxilliary MSR for RDTSCP
 
@@ -78,8 +73,7 @@ void v3_update_timers(struct guest_info * info);
 
 void v3_init_time(struct guest_info * info);
 int v3_start_time(struct guest_info * info);
-int v3_pause_time(struct guest_info * info);
-int v3_resume_time(struct guest_info * info);
+int v3_adjust_time(struct guest_info * info);
 
 // Returns host time
 static inline uint64_t v3_get_host_time(struct vm_time *t) {
@@ -90,15 +84,20 @@ static inline uint64_t v3_get_host_time(struct vm_time *t) {
 
 // Returns *monotonic* guest time.
 static inline uint64_t v3_get_guest_time(struct vm_time *t) {
-    if (t->pause_time) return t->pause_time;
-    else return v3_get_host_time(t) + t->time_offset;
+    return v3_get_host_time(t) + t->guest_host_offset;
 }
 
 // Returns the TSC value seen by the guest
 static inline uint64_t v3_get_guest_tsc(struct vm_time *t) {
-    return v3_get_guest_time(t) + t->tsc_time_offset;
+    return v3_get_guest_time(t) + t->tsc_guest_offset;
+}
+
+// Returns offset of guest TSC from host TSC
+static inline sint64_t v3_tsc_host_offset(struct vm_time *time_state) {
+    return time_state->guest_host_offset + time_state->tsc_guest_offset;
 }
 
+
 #define TSC_MSR     0x10
 #define TSC_AUX_MSR 0xC0000103
 
index 12c277f..48be0b0 100644 (file)
@@ -74,8 +74,6 @@ static void Init_VMCB_BIOS(vmcb_t * vmcb, struct guest_info * core) {
 
 
     //
-
-
     ctrl_area->svm_instrs.VMRUN = 1;
     ctrl_area->svm_instrs.VMMCALL = 1;
     ctrl_area->svm_instrs.VMLOAD = 1;
@@ -468,21 +466,15 @@ int v3_svm_enter(struct guest_info * info) {
     }
 #endif
 
-
     v3_update_timers(info);
-    v3_resume_time(info);
 
-    guest_ctrl->TSC_OFFSET = info->time_state.time_offset 
-       + info->time_state.tsc_time_offset;
+    guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
 
     //V3_Print("Calling v3_svm_launch\n");
 
     v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
 
-    v3_pause_time(info);
-#ifdef CONFIG_TIME_MASK_OVERHEAD
-    v3_offset_time(info, -SVM_ENTRY_OVERHEAD);
-#endif
+    v3_adjust_time(info);
 
     //V3_Print("SVM Returned: Exit Code: %x, guest_rip=%lx\n", (uint32_t)(guest_ctrl->exit_code), (unsigned long)guest_state->rip);
 
index 7dbbf2d..fe22f0b 100644 (file)
@@ -365,23 +365,25 @@ void v3_print_GPRs(struct guest_info * info) {
 #include <palacios/vmcb.h>
 static int info_hcall(struct guest_info * core, uint_t hcall_id, void * priv_data) {
     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
-    
+    int cpu_valid = 0;
+
     v3_print_guest_state(core);
     
-
     // init SVM/VMX
 #ifdef CONFIG_SVM
     if ((cpu_type == V3_SVM_CPU) || (cpu_type == V3_SVM_REV3_CPU)) {
+       cpu_valid = 1;
        PrintDebugVMCB((vmcb_t *)(core->vmm_data));
     }
 #endif
 #ifdef CONFIG_VMX
     if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
+       cpu_valid = 1;
        v3_print_vmcs();
     }
 #endif
-    else {
-       PrintError("Invalid CPU Type\n");
+    if (!cpu_valid) {
+       PrintError("Invalid CPU Type 0x%x\n", cpu_type);
        return -1;
     }
     
@@ -405,7 +407,7 @@ static int info_hcall(struct guest_info * core, uint_t hcall_id, void * priv_dat
 
 int v3_init_vm(struct v3_vm_info * vm) {
     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
-
+    int cpu_valid = 0;
 
     if (v3_get_foreground_vm() == NULL) {
        v3_set_foreground_vm(vm);
@@ -449,24 +451,23 @@ int v3_init_vm(struct v3_vm_info * vm) {
     if ((cpu_type == V3_SVM_CPU) || (cpu_type == V3_SVM_REV3_CPU)) {
        v3_init_svm_io_map(vm);
        v3_init_svm_msr_map(vm);
-    }
+       cpu_valid = 1;
+    } 
 #endif
 #ifdef CONFIG_VMX
     if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) {
        v3_init_vmx_io_map(vm);
        v3_init_vmx_msr_map(vm);
+       cpu_valid = 1;
     }
 #endif
-    else {
-       PrintError("Invalid CPU Type\n");
+    if (!cpu_valid) {
+       PrintError("Invalid CPU Type 0x%x\n", cpu_type);
        return -1;
     }
     
-
-
     v3_register_hypercall(vm, GUEST_INFO_HCALL, info_hcall, NULL);
 
-
     V3_Print("GUEST_INFO_HCALL=%x\n", GUEST_INFO_HCALL);
 
     return 0;
@@ -474,6 +475,7 @@ int v3_init_vm(struct v3_vm_info * vm) {
 
 int v3_init_core(struct guest_info * core) {
     v3_cpu_arch_t cpu_type = v3_get_cpu_type(v3_get_cpu_id());
+    int cpu_valid = 0;
     struct v3_vm_info * vm = core->vm_info;
 
     /*
@@ -505,6 +507,7 @@ int v3_init_core(struct guest_info * core) {
            PrintError("Error in SVM initialization\n");
            return -1;
        }
+       cpu_valid = 1;
     }
 #endif
 #ifdef CONFIG_VMX
@@ -513,10 +516,11 @@ int v3_init_core(struct guest_info * core) {
            PrintError("Error in VMX initialization\n");
            return -1;
        }
+       cpu_valid = 1;
     }
 #endif
-    else {
-       PrintError("Invalid CPU Type\n");
+    if (!cpu_valid) {
+       PrintError("Invalid CPU Type 0x%x\n", cpu_type);
        return -1;
     }
 
index dc49b1b..2d5c74e 100644 (file)
@@ -59,7 +59,7 @@
 static int handle_cpufreq_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
     struct vm_time * time_state = &(info->time_state);
 
-    info->vm_regs.rbx = time_state->cpu_freq;
+    info->vm_regs.rbx = time_state->guest_cpu_freq;
 
     PrintDebug("Guest request cpu frequency: return %ld\n", (long)info->vm_regs.rbx);
     
@@ -74,28 +74,27 @@ int v3_start_time(struct guest_info * info) {
 
     PrintDebug("Starting initial guest time as %llu\n", t);
     info->time_state.last_update = t;
-    info->time_state.pause_time = t;
+    info->time_state.initial_time = t;
     info->yield_start_cycle = t;
     return 0;
 }
 
-int v3_pause_time(struct guest_info * info) {
-    V3_ASSERT(info->time_state.pause_time == 0);
-    info->time_state.pause_time = v3_get_guest_time(&info->time_state);
-    PrintDebug("Time paused at guest time as %llu\n", 
-              info->time_state.pause_time);
-    return 0;
-}
-
-int v3_resume_time(struct guest_info * info) {
-    uint64_t t = v3_get_host_time(&info->time_state);
-    V3_ASSERT(info->time_state.pause_time != 0);
-    info->time_state.time_offset = 
-       (sint64_t)info->time_state.pause_time - (sint64_t)t;
-    info->time_state.pause_time = 0;
-    PrintDebug("Time resumed paused at guest time as %llu "
-              "offset %lld from host time.\n", t, info->time_state.time_offset);
+// If the guest is supposed to run slower than the host, yield out until
+// the host time is appropriately far along;
+int v3_adjust_time(struct guest_info * info)
+{
+    struct vm_time * time_state = &(info->time_state);
+    uint64_t guest_time, host_time, target_host_time;
+    guest_time = v3_get_guest_time(time_state);
+    host_time = v3_get_host_time(time_state);
+    target_host_time = (host_time - time_state->initial_time) *
+       time_state->host_cpu_freq / time_state->guest_cpu_freq;
 
+    while (host_time < target_host_time) {
+       v3_yield(info);
+       host_time = v3_get_host_time(time_state);
+    }
+    time_state->guest_host_offset = guest_time - host_time;
     return 0;
 }
 
@@ -132,7 +131,7 @@ void v3_update_timers(struct guest_info * info) {
     cycles = info->time_state.last_update - old_time;
 
     list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) {
-       tmp_timer->ops->update_timer(info, cycles, info->time_state.cpu_freq, tmp_timer->private_data);
+       tmp_timer->ops->update_timer(info, cycles, info->time_state.guest_cpu_freq, tmp_timer->private_data);
     }
 }
 
@@ -233,23 +232,41 @@ static int tsc_msr_write_hook(struct guest_info *info, uint_t msr_num,
     V3_ASSERT(msr_num == TSC_MSR);
     new_tsc = (((uint64_t)msr_val.hi) << 32) | (uint64_t)msr_val.lo;
     guest_time = v3_get_guest_time(time_state);
-    time_state->tsc_time_offset = (sint64_t)new_tsc - (sint64_t)guest_time; 
+    time_state->tsc_guest_offset = (sint64_t)new_tsc - (sint64_t)guest_time; 
 
     return 0;
 }
 
+static int init_vm_time(struct v3_vm_info *vm_info) {
+    int ret;
+
+    PrintDebug("Installing TSC MSR hook.\n");
+    ret = v3_hook_msr(vm_info, TSC_MSR, 
+                     tsc_msr_read_hook, tsc_msr_write_hook, NULL);
+
+    PrintDebug("Installing TSC_AUX MSR hook.\n");
+    if (ret) return ret;
+    ret = v3_hook_msr(vm_info, TSC_AUX_MSR, tsc_aux_msr_read_hook, 
+                     tsc_aux_msr_write_hook, NULL);
+    if (ret) return ret;
+
+    PrintDebug("Registering TIME_CPUFREQ hypercall.\n");
+    ret = v3_register_hypercall(vm_info, TIME_CPUFREQ_HCALL, 
+                               handle_cpufreq_hcall, NULL);
+    return ret;
+}
 
 void v3_init_time(struct guest_info * info) {
     struct vm_time * time_state = &(info->time_state);
+    static int one_time = 0;
 
-    time_state->cpu_freq = V3_CPU_KHZ();
+    time_state->host_cpu_freq = V3_CPU_KHZ();
+    time_state->guest_cpu_freq = V3_CPU_KHZ();
  
-    time_state->pause_time = 0;
+    time_state->initial_time = 0;
     time_state->last_update = 0;
-    time_state->time_offset = 0;
-    time_state->time_div = 1;
-    time_state->time_mult = 1;
-    time_state->tsc_time_offset = 0;
+    time_state->guest_host_offset = 0;
+    time_state->tsc_guest_offset = 0;
 
     INIT_LIST_HEAD(&(time_state->timers));
     time_state->num_timers = 0;
@@ -257,11 +274,14 @@ void v3_init_time(struct guest_info * info) {
     time_state->tsc_aux.lo = 0;
     time_state->tsc_aux.hi = 0;
 
-    /* does init_time get called once, or once *per core*??? */
-    v3_hook_msr(info->vm_info, TSC_MSR, 
-               tsc_msr_read_hook, tsc_msr_write_hook, NULL);
-    v3_hook_msr(info->vm_info, TSC_AUX_MSR, tsc_aux_msr_read_hook, 
-               tsc_aux_msr_write_hook, NULL);
-
-    v3_register_hypercall(info->vm_info, TIME_CPUFREQ_HCALL, handle_cpufreq_hcall, NULL);
+    if (!one_time) {
+       init_vm_time(info->vm_info);
+       one_time = 1;
+    }
 }
+
+
+
+
+
+
index ad3d321..f12e17f 100644 (file)
@@ -669,18 +669,13 @@ int v3_vmx_enter(struct guest_info * info) {
     }
 
     v3_update_timers(info);
-    v3_resume_time(info);
 
-    {
-       sint64_t total_tsc_offset = info->time_state.time_offset + info->time_state.tsc_time_offset;
-
-       tsc_offset_high = (uint32_t)((total_tsc_offset >> 32) & 0xffffffff);
-       tsc_offset_low = (uint32_t)(total_tsc_offset & 0xffffffff);
-       check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
-       check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
-    }
+    tsc_offset_high = (uint32_t)((v3_tsc_host_offset(&info->time_state) >> 32) & 0xffffffff);
+    tsc_offset_low = (uint32_t)(v3_tsc_host_offset(&info->time_state) & 0xffffffff);
+    check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high);
+    check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low);
 
-    PrintDebug("Stored 0x %x %x into vmcs TSC offset.\n", 
+    PrintDebug("Stored 0x%x_%x into vmcs TSC offset.\n", 
               tsc_offset_high, tsc_offset_low);
     if (info->vm_info->run_state == VM_STOPPED) {
        info->vm_info->run_state = VM_RUNNING;
@@ -700,10 +695,9 @@ int v3_vmx_enter(struct guest_info * info) {
        return -1;
     }
 
-    v3_pause_time(info);
-#ifdef CONFIG_TIME_MASK_OVERHEAD
-    v3_offset_time(info, -VMX_ENTRY_OVERHEAD);
-#endif
+    /* If this guest is frequency-lagged behind host time, wait 
+     * for the appropriate host time. */
+    v3_adjust_time(info);
 
     info->num_exits++;