// timers were updated
uint64_t initial_time; // Time when VMM started.
- uint64_t pause_time; // Host time when VM entered and paused.
+ uint64_t enter_time; // Host time the guest was last entered
+ uint64_t exit_time; // Host time the the VM was exited to
struct v3_msr tsc_aux; // Auxilliary MSR for RDTSCP
// Installed Timers slaved off of the guest monotonic TSC
int v3_start_time(struct guest_info * core);
+int v3_time_enter_vm(struct guest_info * core);
+int v3_time_exit_vm(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);
// Returns *monotonic* guest time.
static inline uint64_t v3_get_guest_time(struct vm_time *t) {
- if (t->pause_time) {
- return t->pause_time + t->guest_host_offset;
+#ifdef CONFIG_TIME_HIDE_VM_COST
+ if (t->exit_time) {
+ return t->exit_time + t->guest_host_offset;
} else {
return v3_get_host_time(t) + t->guest_host_offset;
}
+#else
+ return v3_get_host_time(t) + t->guest_host_offset;
+#endif
}
// Returns the TSC value seen by the guest
}
#endif
-#ifdef CONFIG_TIME_HIDE_VM_COST
- v3_restart_time(info);
-#endif
+ v3_time_enter_vm(info);
guest_ctrl->TSC_OFFSET = v3_tsc_host_offset(&info->time_state);
//V3_Print("Calling v3_svm_launch\n");
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
+ // Immediate exit from VM time bookkeeping
+ v3_time_exit_vm(info);
- //PrintDebug("SVM Returned\n");
-
info->num_exits++;
// Save Guest state from VMCB
PrintError("Invalid host core %d requested by"
" virtual cpu %d - ignored.\n", req_id, info->cpu_id);
} else {
- PrintDebug("Assigned host core %d to virtual core %d.\n", info->cpu_id, req_id, hcpu);
+ PrintDebug("Assigned host core %d to virtual core %d.\n", info->cpu_id, req_id);
info->host_cpu_id = req_id;
}
}
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.enter_time = 0;
+ info->time_state.exit_time = t;
info->time_state.last_update = t;
info->time_state.initial_time = t;
info->yield_start_cycle = t;
return 0;
}
+/* Called immediately upon entry in the the VMM */
int
-v3_pause_time( struct guest_info * info )
+v3_time_exit_vm( 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");
- }
+
+ time_state->exit_time = v3_get_host_time(time_state);
+
+#ifdef CONFIG_TIME_HIDE_EXIT_COST
+ // XXX should make the cost adjustment a runtime parameter
+ // so it can be set by the config file and/or tuned dynamically
+ v3_offset_time(info, -CONFIG_TIME_EXIT_COST_ADJUST);
+#endif
return 0;
}
+/* Called immediately prior to entry to the VM */
int
-v3_restart_time( struct guest_info * info )
+v3_time_enter_vm( 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->enter_time = v3_get_host_time(time_state);
+#ifdef CONFIG_TIME_HIDE_VM_COST
+ if (time_state->exit_time) {
+ sint64_t pause_diff = time_state->enter_time - time_state->exit_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.");
+ PrintError( "Time at which guest exited to VM not recorded!\n" );
}
+#endif
+ time_state->exit_time = 0;
return 0;
}
time_state->last_update = v3_get_guest_time(time_state);
cycles = 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, &(time_state->timers), timer_link) {
tmp_timer->ops->update_timer(info, cycles, time_state->guest_cpu_freq, tmp_timer->private_data);
}
#include <palacios/vmm_lowlevel.h>
#include <palacios/vmm_ctrl_regs.h>
#include <palacios/vmm_config.h>
+#include <palacios/vmm_time.h>
#include <palacios/vm_guest_mem.h>
#include <palacios/vmm_direct_paging.h>
#include <palacios/vmx_io.h>
// Conditionally yield the CPU if the timeslice has expired
v3_yield_cond(info);
- /* If this guest is frequency-lagged behind host time, wait
- * for the appropriate host time before resuming the guest. */
+ // Perform any additional yielding needed for time adjustment
v3_adjust_time(info);
- // v3_print_guest_state(info);
+ // Update timer devices prior to entering VM.
+ v3_update_timers(info);
// disable global interrupts for vm state transition
v3_disable_ints();
vmcs_write(VMCS_GUEST_CR3, guest_cr3);
}
- v3_update_timers(info);
+ // Perform last-minute time bookkeeping prior to entering the VM
+ v3_time_enter_vm(info);
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);
return -1;
}
+ // Immediate exit from VM time bookkeeping
+ v3_time_exit_vm(info);
+
info->num_exits++;
/* Update guest state */