return 0;
}
+static int handle_rdhtsc_hcall(struct guest_info * info, uint_t hcall_id, void * priv_data) {
+ struct vm_core_time * time_state = &(info->time_state);
+
+ info->vm_regs.rbx = v3_get_host_time(time_state);
+
+ // PrintDebug("Guest request host TSC: return %ld\n", (long)info->vm_regs.rbx);
+
+ return 0;
+}
+
int v3_start_time(struct guest_info * info) {
{
uint64_t guest_cycles;
- if (info->flags & VM_TIME_SLAVE_HOST) {
+ if (info->time_state.flags & VM_TIME_SLAVE_HOST) {
struct v3_time *vm_ts = &(info->vm_info->time_state);
uint64_t ht = v3_get_host_time(&info->time_state);
uint64_t host_elapsed = ht - info->time_state.initial_host_time;
}
int v3_handle_rdtsc(struct guest_info * info) {
+ PrintDebug("Handling virtual RDTSC call.\n");
v3_rdtsc(info);
info->vm_regs.rax &= 0x00000000ffffffffLL;
int v3_handle_rdtscp(struct guest_info * info) {
- PrintDebug("Handling virtual RDTSCP call.\n");
+ PrintDebug("Handling virtual RDTSCP call.\n");
v3_rdtscp(info);
struct v3_msr *msr_val, void *priv) {
uint64_t time = v3_get_guest_tsc(&info->time_state);
+ PrintDebug("Handling virtual TSC MSR read call.\n");
V3_ASSERT(msr_num == TSC_MSR);
msr_val->hi = time >> 32;
struct vm_core_time * time_state = &(info->time_state);
uint64_t guest_time, new_tsc;
- V3_ASSERT(msr_num == TSC_MSR);
+ PrintDebug("Handling virtual TSC MSR write call.\n");
+ 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 - guest_time);
+ 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 - guest_time);
- return 0;
- }
+ return 0;
+}
static int
handle_time_configuration(struct v3_vm_info * vm, v3_cfg_tree_t *cfg) {
- char *source, *dilation;
+ char *source, *dilation, *tsc;
vm->time_state.flags = V3_TIME_SLAVE_HOST;
vm->time_state.td_num = vm->time_state.td_denom = 1;
}
}
+ // Should we make a separate TSC device that handles this sort of thing?
+ tsc = v3_cfg_val(cfg, "tsc");
+ if (tsc) {
+ if (strcasecmp(tsc, "host") == 0) {
+ if (!(vm->time_state.flags & V3_TIME_SLAVE_HOST)) {
+ PrintError("WARNING: Guest TSC set to passthrough host TSC, but guest time not slaved to host time.");
+ }
+ vm->time_state.flags |= V3_TIME_TSC_PASSTHROUGH;
+ } else if (strcasecmp(source, "guest") != 0) {
+ PrintError("ERROR: Unknown TSC configuration in time configuration.\n");
+ }
+ }
+
dilation = v3_cfg_val(cfg, "dilation");
if (dilation) {
if (!(vm->time_state.flags & VM_TIME_SLAVE_HOST)) {
PrintDebug("Registering TIME_CPUFREQ hypercall.\n");
ret = v3_register_hypercall(vm, TIME_CPUFREQ_HCALL,
handle_cpufreq_hcall, NULL);
+ PrintDebug("Registering TIME_RDHTSC hypercall.\n");
+ ret = v3_register_hypercall(vm, TIME_RDHTSC_HCALL,
+ handle_rdhtsc_hcall, NULL);
handle_time_configuration(vm, v3_cfg_subtree(cfg_tree, "time"));
if (info->vm_info->time_state.flags & V3_TIME_SLAVE_HOST) {
time_state->flags |= VM_TIME_SLAVE_HOST;
}
+ if (info->vm_info->time_state.flags & V3_TIME_TSC_PASSTHROUGH) {
+ time_state->flags |= VM_TIME_TSC_PASSTHROUGH;
+ }
+
if ((time_state->clock_ratio_denom != 1) ||
- (time_state->clock_ratio_num != 1)) {
+ (time_state->clock_ratio_num != 1) ||
+ (info->vm_info->time_state.td_num != 1) ||
+ (info->vm_info->time_state.td_denom != 1)) {
+ if (time_state->flags | VM_TIME_TSC_PASSTHROUGH) {
+ PrintError("WARNING: Cannot use reqested passthrough TSC with clock or time modification also requested.\n");
+ time_state->flags &= ~VM_TIME_TSC_PASSTHROUGH;
+ }
time_state->flags |= VM_TIME_TRAP_RDTSC;
}
info->vm_info->time_state.td_denom,
time_state->clock_ratio_num, time_state->clock_ratio_denom,
time_state->ipc_ratio_num, time_state->ipc_ratio_denom);
- PrintDebug(" source = %s, rdtsc trapping = %s\n",
+ PrintDebug(" time source = %s, tsc handling = %s\n",
(time_state->flags & VM_TIME_SLAVE_HOST) ? "host" : "none",
- (time_state->flags & VM_TIME_TRAP_RDTSC) ? "true" : "false");
+ (time_state->flags & VM_TIME_TSC_PASSTHROUGH) ? "passthrough"
+ : (time_state->flags & VM_TIME_TRAP_RDTSC) ? "trapping"
+ : "offsettting");
time_state->guest_cycles = 0;
time_state->tsc_guest_offset = 0;