and, more importantly, and to control vmx offseting of TSC appropriately.
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;
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);
};
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
#include <palacios/vm_guest.h>
-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;
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) {
static struct vm_timer_ops timer_ops = {
- .update_time = pit_update_time,
- .advance_timer = pit_advance_time,
+ .update_timer = pit_update_timer,
};
/* 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__
static struct vm_timer_ops timer_ops = {
- .update_time = apic_update_time,
+ .update_timer = apic_update_timer,
};
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;
}
#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
}
#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);
}
}
#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;
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
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);
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);
}
-
-
-
}
*/
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
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));
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);
PrintDebug("Launching VMX guest\n");
- rdtscll(info->time_state.cached_host_tsc);
-
+ v3_start_time(info);
while (1) {
if (v3_vmx_enter(info) == -1) {