From: Patrick G. Bridges Date: Tue, 19 Oct 2010 20:13:04 +0000 (-0600) Subject: More updates getting basic version of time handling working. X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=cd3edffa0e451af761b9dcee021ca06ebb301345;p=palacios.git More updates getting basic version of time handling working. --- diff --git a/palacios/include/palacios/vmm_time.h b/palacios/include/palacios/vmm_time.h index 0377be8..4364358 100644 --- a/palacios/include/palacios/vmm_time.h +++ b/palacios/include/palacios/vmm_time.h @@ -30,21 +30,16 @@ 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 diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 12c277f..48be0b0 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -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); diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index 7dbbf2d..fe22f0b 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -365,23 +365,25 @@ void v3_print_GPRs(struct guest_info * info) { #include 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; } diff --git a/palacios/src/palacios/vmm_time.c b/palacios/src/palacios/vmm_time.c index dc49b1b..2d5c74e 100644 --- a/palacios/src/palacios/vmm_time.c +++ b/palacios/src/palacios/vmm_time.c @@ -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; + } } + + + + + + diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index ad3d321..f12e17f 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -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++;