From: Patrick G. Bridges Date: Thu, 17 Feb 2011 18:51:32 +0000 (-0600) Subject: Fixes to time code to allow virtualization to hide costs of running in the X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=89034c39d340e3f6b24a8288ceeb506ddbdf7057 Fixes to time code to allow virtualization to hide costs of running in the VM and attempt to hide hte costs of entering the VM. --- diff --git a/Kconfig b/Kconfig index dcee752..0eb9692 100644 --- a/Kconfig +++ b/Kconfig @@ -226,14 +226,40 @@ endmenu menu "Time Management" +config TIME_HIDE_VM_COST + bool "Hide VMM Run Cost" + default n + help + Offset guest time from host time sufficiently to hide the cost of + running in the virtual machine. This can aid the consistency of + time between multiple timers, but can cause the guest to run + slightly slower than the host. + +config TIME_HIDE_EXIT_COST + bool "Hide VMM Exit Cost" + default n + depends on TIME_HIDE_VM_COST + help + Add additional TSC offset to hide VMM exit costs from the guest. + +config TIME_EXIT_COST_ADJUST + int "Exit cost adjustment for hiding VM exits" + default 2000 + depends on TIME_HIDE_EXIT_COST + help + Amount to adjust the time to hide the exit cost of fully virtualizing + the timestamp counter. Used to hide the cost of fully virtualizing + the TSC for OSes that assume that reading the TSC is inexpensive + (e.g. Linux TSC-based timer calibration). + config TIME_VIRTUALIZE_TSC - bool "Virtualize guest TSC" + bool "Fully virtualize guest TSC" default n help Virtualize the processor time stamp counter in the guest, generally increasing consistency between various time sources but also potentially making guest time run slower than real time. - + endmenu menu "Symbiotic Functions" diff --git a/palacios/include/palacios/vmm_time.h b/palacios/include/palacios/vmm_time.h index 9f1c432..6513e30 100644 --- a/palacios/include/palacios/vmm_time.h +++ b/palacios/include/palacios/vmm_time.h @@ -7,11 +7,13 @@ * and the University of New Mexico. You can find out more at * http://www.v3vee.org * + * Copyright (c) 2010, Patrick Bridges * Copyright (c) 2008, Jack Lange * Copyright (c) 2008, The V3VEE Project * All rights reserved. * * Author: Jack Lange + * Patrick Bridges * * This is free software. You are permitted to use, * redistribute, and modify it as specified in the file "V3VEE_LICENSE". @@ -32,15 +34,15 @@ struct guest_info; struct vm_time { uint32_t host_cpu_freq; // in kHZ uint32_t guest_cpu_freq; // can be lower than host CPU freq! - + 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 initial_time; // Time when VMM started. - + uint64_t pause_time; // Host time when VM entered and paused. struct v3_msr tsc_aux; // Auxilliary MSR for RDTSCP // Installed Timers slaved off of the guest monotonic TSC @@ -67,9 +69,12 @@ int v3_init_time_vm(struct v3_vm_info * vm); void v3_deinit_time_core(struct guest_info * core); void v3_deinit_time_vm(struct v3_vm_info * vm); - int v3_start_time(struct guest_info * core); + int v3_adjust_time(struct guest_info * core); +int v3_pause_time(struct guest_info * core); +int v3_offset_time(struct guest_info * core, sint64_t offset); +int v3_restart_time(struct guest_info * core); // Basic functions for attaching timers to the passage of time struct v3_timer * v3_add_timer(struct guest_info * info, struct v3_timer_ops * ops, void * private_data); @@ -85,7 +90,11 @@ 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) { - return v3_get_host_time(t) + t->guest_host_offset; + if (t->pause_time) { + return t->pause_time + t->guest_host_offset; + } else { + return v3_get_host_time(t) + t->guest_host_offset; + } } // Returns the TSC value seen by the guest diff --git a/palacios/src/devices/8254.c b/palacios/src/devices/8254.c index 7bf6a8c..ffae665 100644 --- a/palacios/src/devices/8254.c +++ b/palacios/src/devices/8254.c @@ -299,10 +299,13 @@ static void pit_update_timer(struct guest_info * info, ullong_t cpu_cycles, ullo // update counter with remainder (mod reload) state->pit_counter = state->pit_reload - cpu_cycles; - //PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations); + if (oscillations) { + PrintDebug("8254 PIT: Handling %d crystal tics\n", oscillations); + } + if (handle_crystal_tics(state, &(state->ch_0), oscillations) == 1) { // raise interrupt - PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n"); + // PrintDebug("8254 PIT: Injecting Timer interrupt to guest\n"); v3_raise_irq(info->vm_info, 0); } diff --git a/palacios/src/devices/Kconfig b/palacios/src/devices/Kconfig index 671625f..99b788b 100644 --- a/palacios/src/devices/Kconfig +++ b/palacios/src/devices/Kconfig @@ -3,7 +3,6 @@ menu "Virtual Devices" config APIC bool "APIC" default y - depends on EXPERIMENTAL help Includes the Virtual APIC device @@ -19,7 +18,6 @@ config DEBUG_APIC config IO_APIC bool "IOAPIC" - depends on EXPERIMENTAL default y help Includes the Virtual IO APIC diff --git a/palacios/src/palacios/svm.c b/palacios/src/palacios/svm.c index 20adea3..7b1b919 100644 --- a/palacios/src/palacios/svm.c +++ b/palacios/src/palacios/svm.c @@ -451,11 +451,11 @@ int v3_svm_enter(struct guest_info * info) { vmcb_saved_state_t * guest_state = GET_VMCB_SAVE_STATE_AREA((vmcb_t*)(info->vmm_data)); addr_t exit_code = 0, exit_info1 = 0, exit_info2 = 0; - v3_adjust_time(info); - // Conditionally yield the CPU if the timeslice has expired v3_yield_cond(info); + v3_adjust_time(info); + // disable global interrupts for vm state transition v3_clgi(); @@ -504,6 +504,9 @@ int v3_svm_enter(struct guest_info * info) { #endif v3_update_timers(info); +#ifdef CONFIG_TIME_HIDE_VM_COST + v3_restart_time(info); +#endif guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state); //V3_Print("Calling v3_svm_launch\n"); @@ -514,6 +517,13 @@ int v3_svm_enter(struct guest_info * info) { v3_last_exit = (uint32_t)(guest_ctrl->exit_code); +#ifdef CONFIG_TIME_HIDE_VM_COST + v3_pause_time(info); +#ifdef CONFIG_TIME_HIDE_EXIT_COST + v3_offset_time(info, -CONFIG_TIME_EXIT_COST_ADJUST); +#endif +#endif + //PrintDebug("SVM Returned\n"); info->num_exits++; diff --git a/palacios/src/palacios/vmm_time.c b/palacios/src/palacios/vmm_time.c index 51fbba7..1cb6478 100644 --- a/palacios/src/palacios/vmm_time.c +++ b/palacios/src/palacios/vmm_time.c @@ -86,6 +86,11 @@ int v3_start_time(struct guest_info * info) { uint64_t t = v3_get_host_time(&info->time_state); PrintDebug("Starting initial guest time as %llu\n", t); +#ifdef CONFIG_TIME_HIDE_VM_COST + info->time_state.pause_time = t; +#else + info->time_state.pause_time = 0; +#endif info->time_state.last_update = t; info->time_state.initial_time = t; info->yield_start_cycle = t; @@ -97,9 +102,7 @@ int v3_start_time(struct guest_info * info) { int v3_adjust_time(struct guest_info * info) { struct vm_time * time_state = &(info->time_state); - if (time_state->host_cpu_freq == time_state->guest_cpu_freq) { - time_state->guest_host_offset = 0; - } else { + if (time_state->host_cpu_freq != time_state->guest_cpu_freq) { uint64_t guest_time, guest_elapsed, desired_elapsed; uint64_t host_time, target_host_time; @@ -118,12 +121,52 @@ int v3_adjust_time(struct guest_info * info) { host_time = v3_get_host_time(time_state); } + // This overrides any pause/unpause times because the difference + // is going to be too big for any pause/unpause the notice. time_state->guest_host_offset = (sint64_t)guest_time - (sint64_t)host_time; } return 0; } +int +v3_pause_time( struct guest_info * info ) +{ + struct vm_time * time_state = &(info->time_state); + if (time_state->pause_time == 0) { + time_state->pause_time = v3_get_host_time(time_state); +// PrintDebug("Pausing at host time %llu.\n", time_state->pause_time); + } else { + PrintError("Palacios timekeeping paused when already paused.\n"); + } + return 0; +} + +int +v3_restart_time( struct guest_info * info ) +{ + struct vm_time * time_state = &(info->time_state); + + if (time_state->pause_time) { + sint64_t pause_diff = (v3_get_host_time(time_state) - time_state->pause_time); + time_state->guest_host_offset -= pause_diff; + time_state->pause_time = 0; +// PrintDebug("Resuming time after %lld cycles with offset %lld.\n", pause_diff, time_state->guest_host_offset); + } else { + PrintError( "Palacios time keeping restarted when not paused."); + } + + return 0; +} + +int v3_offset_time( struct guest_info * info, sint64_t offset ) +{ + struct vm_time * time_state = &(info->time_state); +// PrintDebug("Adding additional offset of %lld to guest time.\n", offset); + time_state->guest_host_offset += offset; + return 0; +} + struct v3_timer * v3_add_timer(struct guest_info * info, struct v3_timer_ops * ops, void * private_data) { @@ -149,15 +192,19 @@ int v3_remove_timer(struct guest_info * info, struct v3_timer * timer) { } void v3_update_timers(struct guest_info * info) { + struct vm_time *time_state = &info->time_state; struct v3_timer * tmp_timer; uint64_t old_time = info->time_state.last_update; - uint64_t cycles; + sint64_t cycles; + + time_state->last_update = v3_get_guest_time(time_state); + cycles = time_state->last_update - old_time; - info->time_state.last_update = v3_get_guest_time(&info->time_state); - cycles = info->time_state.last_update - old_time; + // PrintDebug("Updating timer for %lld elapsed cycles (pt=%llu, offset=%lld).\n", + // cycles, time_state->pause_time, time_state->guest_host_offset); - list_for_each_entry(tmp_timer, &(info->time_state.timers), timer_link) { - tmp_timer->ops->update_timer(info, cycles, info->time_state.guest_cpu_freq, tmp_timer->private_data); + list_for_each_entry(tmp_timer, &(time_state->timers), timer_link) { + tmp_timer->ops->update_timer(info, cycles, time_state->guest_cpu_freq, tmp_timer->private_data); } } @@ -172,12 +219,14 @@ void v3_update_timers(struct guest_info * info) { int v3_rdtsc(struct guest_info * info) { uint64_t tscval = v3_get_guest_tsc(&info->time_state); + PrintDebug("Returning %llu as TSC.\n", tscval); info->vm_regs.rdx = tscval >> 32; info->vm_regs.rax = tscval & 0xffffffffLL; return 0; } int v3_handle_rdtsc(struct guest_info * info) { + PrintDebug("Handling virtual RDTSC call.\n"); v3_rdtsc(info); info->vm_regs.rax &= 0x00000000ffffffffLL; @@ -213,9 +262,10 @@ int v3_rdtscp(struct guest_info * info) { int v3_handle_rdtscp(struct guest_info * info) { + PrintDebug("Handling virtual RDTSCP call.\n"); v3_rdtscp(info); - + info->vm_regs.rax &= 0x00000000ffffffffLL; info->vm_regs.rcx &= 0x00000000ffffffffLL; info->vm_regs.rdx &= 0x00000000ffffffffLL; diff --git a/test/geekos_test_vm/build/depend.mak b/test/geekos_test_vm/build/depend.mak deleted file mode 100644 index e69de29..0000000