From: Patrick G. Bridges Date: Mon, 20 Sep 2010 19:58:46 +0000 (-0600) Subject: Implemented (but not yet tested) time interface changes for consistency X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=ef944e47f418cfbf344757e3fbab5e40927966fe Implemented (but not yet tested) time interface changes for consistency and, more importantly, and to control vmx offseting of TSC appropriately. --- diff --git a/palacios/include/palacios/vmm_time.h b/palacios/include/palacios/vmm_time.h index 120838d..3f1ad95 100644 --- a/palacios/include/palacios/vmm_time.h +++ b/palacios/include/palacios/vmm_time.h @@ -30,14 +30,14 @@ struct guest_info; struct vm_time { uint32_t cpu_freq; // in kHZ - // Total number of guest run time cycles - uint64_t guest_tsc; - + // Last time (in guest time) the timers were updated + uint64_t last_update; + // Cache value to help calculate the guest_tsc - uint64_t cached_host_tsc; + uint64_t pause_time; - // The number of cycles pending for notification to the timers - //ullong_t pending_cycles; + // Offset of guest time from host time. + sint64_t host_offset; // Installed Timers uint_t num_timers; @@ -48,7 +48,7 @@ struct vm_time { struct vm_timer_ops { - void (*update_time)(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data); + void (*update_timer)(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data); void (*advance_timer)(struct guest_info * info, void * private_data); }; @@ -64,14 +64,15 @@ struct vm_timer { int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops, void * private_data); int v3_remove_timer(struct guest_info * info, struct vm_timer * timer); - -void v3_advance_time(struct guest_info * info); - -void v3_update_time(struct guest_info * info, ullong_t cycles); +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); +uint64_t v3_get_host_time(struct guest_info * info); +uint64_t v3_get_guest_time(struct guest_info * info); #endif // !__V3VEE__ #endif diff --git a/palacios/src/devices/8254.c b/palacios/src/devices/8254.c index 51c3f04..ecb2fa0 100644 --- a/palacios/src/devices/8254.c +++ b/palacios/src/devices/8254.c @@ -236,7 +236,7 @@ static int handle_crystal_tics(struct vm_device * dev, struct channel * ch, uint #include -static void pit_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) { +static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * private_data) { struct vm_device * dev = (struct vm_device *)private_data; struct pit * state = (struct pit *)dev->private_data; // ullong_t tmp_ctr = state->pit_counter; @@ -313,14 +313,6 @@ static void pit_update_time(struct guest_info * info, ullong_t cpu_cycles, ullon return; } - -static void pit_advance_time(struct guest_info * core, void * private_data) { - - v3_raise_irq(core->vm_info, 0); -} - - - /* This should call out to handle_SQR_WAVE_write, etc... */ static int handle_channel_write(struct channel * ch, char val) { @@ -624,8 +616,7 @@ static int pit_write_command(struct guest_info * core, ushort_t port, void * src static struct vm_timer_ops timer_ops = { - .update_time = pit_update_time, - .advance_timer = pit_advance_time, + .update_timer = pit_update_timer, }; diff --git a/palacios/src/devices/apic.c b/palacios/src/devices/apic.c index c437c63..1880569 100644 --- a/palacios/src/devices/apic.c +++ b/palacios/src/devices/apic.c @@ -978,7 +978,7 @@ static int apic_begin_irq(struct guest_info * info, void * private_data, int irq /* Timer Functions */ -static void apic_update_time(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) { +static void apic_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data) { struct apic_state * apic = (struct apic_state *)(priv_data); // The 32 bit GCC runtime is a pile of shit #ifdef __V3_64BIT__ @@ -1071,7 +1071,7 @@ static struct intr_ctrl_ops intr_ops = { static struct vm_timer_ops timer_ops = { - .update_time = apic_update_time, + .update_timer = apic_update_timer, }; diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 34fed45..3131cf2 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -471,7 +471,7 @@ int v3_svm_enter(struct guest_info * info) { rdtscll(tmp_tsc); - v3_update_time(info, (tmp_tsc - info->time_state.cached_host_tsc)); + v3_update_timers(info, (tmp_tsc - info->time_state.cached_host_tsc)); rdtscll(info->time_state.cached_host_tsc); // guest_ctrl->TSC_OFFSET = info->time_state.guest_tsc - info->time_state.cached_host_tsc; diff --git a/palacios/src/palacios/vm_guest.c b/palacios/src/palacios/vm_guest.c index 4dddf6e..7dbbf2d 100644 --- a/palacios/src/palacios/vm_guest.c +++ b/palacios/src/palacios/vm_guest.c @@ -376,7 +376,7 @@ static int info_hcall(struct guest_info * core, uint_t hcall_id, void * priv_dat } #endif #ifdef CONFIG_VMX - else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) { + if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) { v3_print_vmcs(); } #endif @@ -452,7 +452,7 @@ int v3_init_vm(struct v3_vm_info * vm) { } #endif #ifdef CONFIG_VMX - else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) { + if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) { v3_init_vmx_io_map(vm); v3_init_vmx_msr_map(vm); } @@ -508,7 +508,7 @@ int v3_init_core(struct guest_info * core) { } #endif #ifdef CONFIG_VMX - else if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) { + if ((cpu_type == V3_VMX_CPU) || (cpu_type == V3_VMX_EPT_CPU)) { if (v3_init_vmx_vmcs(core, vm->vm_class) == -1) { PrintError("Error in VMX initialization\n"); return -1; diff --git a/palacios/src/palacios/vmm_halt.c b/palacios/src/palacios/vmm_halt.c index 5015046..7970a40 100644 --- a/palacios/src/palacios/vmm_halt.c +++ b/palacios/src/palacios/vmm_halt.c @@ -38,17 +38,12 @@ int v3_handle_halt(struct guest_info * info) { if (info->cpl != 0) { v3_raise_exception(info, GPF_EXCEPTION); } else { - uint64_t yield_start = 0; - PrintDebug("CPU Yield\n"); while (!v3_intr_pending(info)) { - rdtscll(yield_start); + /* Since we're in an exit, time is already paused here, so no need to pause again. */ v3_yield(info); - - v3_update_time(info, yield_start - info->time_state.cached_host_tsc); - - rdtscll(info->time_state.cached_host_tsc); + v3_update_timers(info); /* At this point, we either have some combination of interrupts, including perhaps a timer interrupt, or diff --git a/palacios/src/palacios/vmm_time.c b/palacios/src/palacios/vmm_time.c index b169669..4bd30ef 100644 --- a/palacios/src/palacios/vmm_time.c +++ b/palacios/src/palacios/vmm_time.c @@ -38,18 +38,54 @@ void v3_init_time(struct guest_info * info) { time_state->cpu_freq = V3_CPU_KHZ(); - time_state->guest_tsc = 0; - time_state->cached_host_tsc = 0; - // time_state->pending_cycles = 0; - + time_state->pause_time = 0; + time_state->last_update = 0; + time_state->host_offset = 0; + INIT_LIST_HEAD(&(time_state->timers)); time_state->num_timers = 0; v3_register_hypercall(info->vm_info, TIME_CPUFREQ_HCALL, handle_cpufreq_hcall, NULL); } +uint64_t v3_get_host_time(struct guest_info * info) { + uint64_t tmp; + rdtscll(tmp); + return tmp; +} + +uint64_t v3_get_guest_time(struct guest_info * info) { + return v3_get_host_time(info) + info->time_state.host_offset; +} + + +int v3_start_time(struct guest_info * info) { + /* We start running with guest_time == host_time */ + uint64_t t = v3_get_host_time(info); + info->time_state.last_update = t; + info->time_state.pause_time = 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); + return 0; +} + +int v3_resume_time(struct guest_info * info) { + uint64_t t = v3_get_host_time(info); + V3_ASSERT(info->time_state.pause_time != 0); +#ifdef OPTION_TIME_ADJUST_TSC_OFFSET +#endif + info->time_state.host_offset = + (sint64_t)info->time_state.pause_time - (sint64_t)t; + info->time_state.pause_time = 0; + return 0; +} -int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops, void * private_data) { +int v3_add_timer(struct guest_info * info, struct vm_timer_ops * ops, + void * private_data) { struct vm_timer * timer = NULL; timer = (struct vm_timer *)V3_Malloc(sizeof(struct vm_timer)); V3_ASSERT(timer != NULL); @@ -72,34 +108,15 @@ int v3_remove_timer(struct guest_info * info, struct vm_timer * timer) { return 0; } - - -void v3_update_time(struct guest_info * info, uint64_t cycles) { +void v3_update_timers(struct guest_info * info) { struct vm_timer * tmp_timer; - - // cycles *= 8; - -// cycles /= 150; + uint64_t old_time = info->time_state.last_update; + uint64_t cycles; - info->time_state.guest_tsc += cycles; + info->time_state.last_update = v3_get_guest_time(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_time(info, cycles, info->time_state.cpu_freq, tmp_timer->private_data); - } - - - - //info->time_state.pending_cycles = 0; -} - -void v3_advance_time(struct guest_info * core) { - struct vm_timer * tmp_timer; - - - list_for_each_entry(tmp_timer, &(core->time_state.timers), timer_link) { - tmp_timer->ops->advance_timer(core, tmp_timer->private_data); + tmp_timer->ops->update_timer(info, cycles, info->time_state.cpu_freq, tmp_timer->private_data); } - - - } diff --git a/palacios/src/palacios/vmx.c b/palacios/src/palacios/vmx.c index 18d183b..a297be2 100644 --- a/palacios/src/palacios/vmx.c +++ b/palacios/src/palacios/vmx.c @@ -636,13 +636,12 @@ static void print_exit_log(struct guest_info * info) { */ int v3_vmx_enter(struct guest_info * info) { int ret = 0; - uint64_t tmp_tsc = 0; + uint32_t tsc_offset_low, tsc_offset_high; struct vmx_exit_info exit_info; // Conditionally yield the CPU if the timeslice has expired v3_yield_cond(info); - // v3_print_guest_state(info); // disable global interrupts for vm state transition @@ -665,11 +664,15 @@ int v3_vmx_enter(struct guest_info * info) { vmcs_write(VMCS_GUEST_CR3, guest_cr3); } - // We do timer injection here to track real host time. - rdtscll(tmp_tsc); - v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc); - rdtscll(info->time_state.cached_host_tsc); + v3_update_timers(info); + v3_resume_time(info); + tsc_offset_high = + (uint32_t)((info->time_state.host_offset >> 32) & 0xffffffff); + tsc_offset_low = (uint32_t)(info->time_state.host_offset & 0xffffffff); + check_vmcs_write(VMCS_TSC_OFFSET_HIGH, tsc_offset_high); + check_vmcs_write(VMCS_TSC_OFFSET, tsc_offset_low); + if (info->vm_info->run_state == VM_STOPPED) { info->vm_info->run_state = VM_RUNNING; ret = v3_vmx_launch(&(info->vm_regs), info, &(info->ctrl_regs)); @@ -688,12 +691,13 @@ int v3_vmx_enter(struct guest_info * info) { return -1; } - // rdtscll(tmp_tsc); - // v3_update_time(info, tmp_tsc - info->time_state.cached_host_tsc); + v3_pause_time(info); +#ifdef OPTION_TIME_MASK_OVERHEAD + v3_offset_time(info, -VMX_ENTRY_OVERHEAD); +#endif info->num_exits++; - /* Update guest state */ v3_vmx_save_vmcs(info); @@ -744,8 +748,7 @@ int v3_start_vmx_guest(struct guest_info* info) { PrintDebug("Launching VMX guest\n"); - rdtscll(info->time_state.cached_host_tsc); - + v3_start_time(info); while (1) { if (v3_vmx_enter(info) == -1) {