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;
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;
/* Yield until that host time is reached */
host_time = v3_get_host_time(time_state);
+
while (host_time < target_host_time) {
v3_yield(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) {
}
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);
}
}
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;
* ra/c/dx here since they're modified by this instruction anyway. */
info->vm_regs.rcx = TSC_AUX_MSR;
ret = v3_handle_msr_read(info);
- if (ret) return ret;
+
+ if (ret != 0) {
+ return ret;
+ }
+
info->vm_regs.rcx = info->vm_regs.rax;
/* Now do the TSC half of the instruction */
ret = v3_rdtsc(info);
- if (ret) return ret;
-
+
+ if (ret != 0) {
+ return ret;
+ }
+
return 0;
}
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;
struct vm_time * time_state = &(info->time_state);
V3_ASSERT(msr_num == TSC_AUX_MSR);
+
msr_val->lo = time_state->tsc_aux.lo;
msr_val->hi = time_state->tsc_aux.hi;
struct vm_time * time_state = &(info->time_state);
V3_ASSERT(msr_num == TSC_AUX_MSR);
+
time_state->tsc_aux.lo = msr_val.lo;
time_state->tsc_aux.hi = msr_val.hi;
uint64_t time = v3_get_guest_tsc(&info->time_state);
V3_ASSERT(msr_num == TSC_MSR);
+
msr_val->hi = time >> 32;
msr_val->lo = time & 0xffffffffLL;
struct v3_msr msr_val, void *priv) {
struct vm_time * time_state = &(info->time_state);
uint64_t guest_time, new_tsc;
+
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_guest_offset = (sint64_t)new_tsc - (sint64_t)guest_time;
}
-static int init_vm_time(struct v3_vm_info *vm_info) {
+int v3_init_time_vm(struct v3_vm_info * vm) {
int ret;
PrintDebug("Installing TSC MSR hook.\n");
- ret = v3_hook_msr(vm_info, TSC_MSR,
+ ret = v3_hook_msr(vm, TSC_MSR,
tsc_msr_read_hook, tsc_msr_write_hook, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
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,
+ ret = v3_hook_msr(vm, TSC_AUX_MSR, tsc_aux_msr_read_hook,
tsc_aux_msr_write_hook, NULL);
- if (ret) return ret;
+
+ if (ret != 0) {
+ return ret;
+ }
PrintDebug("Registering TIME_CPUFREQ hypercall.\n");
- ret = v3_register_hypercall(vm_info, TIME_CPUFREQ_HCALL,
+ ret = v3_register_hypercall(vm, TIME_CPUFREQ_HCALL,
handle_cpufreq_hcall, NULL);
+
return ret;
}
-void v3_init_time(struct guest_info * info) {
+void v3_deinit_time_vm(struct v3_vm_info * vm) {
+ v3_unhook_msr(vm, TSC_MSR);
+ v3_unhook_msr(vm, TSC_AUX_MSR);
+
+ v3_remove_hypercall(vm, TIME_CPUFREQ_HCALL);
+}
+
+void v3_init_time_core(struct guest_info * info) {
struct vm_time * time_state = &(info->time_state);
v3_cfg_tree_t * cfg_tree = info->core_cfg_data;
- static int one_time = 0;
- char *khz;
+ char * khz = NULL;
time_state->host_cpu_freq = V3_CPU_KHZ();
khz = v3_cfg_val(cfg_tree, "khz");
+
if (khz) {
time_state->guest_cpu_freq = atoi(khz);
PrintDebug("Core %d CPU frequency requested at %d khz.\n",
info->cpu_id, time_state->guest_cpu_freq);
}
- if (!khz || time_state->guest_cpu_freq > time_state->host_cpu_freq) {
+ if ((khz == NULL) || (time_state->guest_cpu_freq > time_state->host_cpu_freq)) {
time_state->guest_cpu_freq = time_state->host_cpu_freq;
}
- PrintDebug("Core %d CPU frequency set to %d KHz (host CPU frequency = %d KHz).\n", info->cpu_id, time_state->guest_cpu_freq, time_state->host_cpu_freq);
+
+ PrintDebug("Core %d CPU frequency set to %d KHz (host CPU frequency = %d KHz).\n",
+ info->cpu_id,
+ time_state->guest_cpu_freq,
+ time_state->host_cpu_freq);
time_state->initial_time = 0;
time_state->last_update = 0;
time_state->tsc_aux.lo = 0;
time_state->tsc_aux.hi = 0;
- if (!one_time) {
- init_vm_time(info->vm_info);
- one_time = 1;
- }
+
}
+void v3_deinit_time_core(struct guest_info * core) {
+ struct vm_time * time_state = &(core->time_state);
+ struct v3_timer * tmr = NULL;
+ struct v3_timer * tmp = NULL;
+ list_for_each_entry_safe(tmr, tmp, &(time_state->timers), timer_link) {
+ v3_remove_timer(core, tmr);
+ }
+
+}