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;
+ 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;
static int
handle_time_configuration(struct v3_vm_info * vm, v3_cfg_tree_t *cfg) {
- v3_cfg_tree_t * slave;
+ char *source, *dilation, *tsc;
- vm->time_state.flags = 0;
+ vm->time_state.flags = V3_TIME_SLAVE_HOST;
vm->time_state.td_num = vm->time_state.td_denom = 1;
if (!cfg) return 0;
- slave = v3_cfg_subtree(cfg, "slave");
-
- if (slave) {
- char *source = v3_cfg_val(slave, "source");
- v3_cfg_tree_t *dilation = v3_cfg_subtree(slave, "dilation");
- if (source) {
- if (strcasecmp(source, "host") == 0) {
- PrintDebug("Slaving VM guest time to host time.\n");
- vm->time_state.flags |= V3_TIME_SLAVE_HOST;
- } else {
- PrintError("Unknown time source for slaving.\n");
+ source = v3_cfg_val(cfg, "source");
+ if (source) {
+ if (strcasecmp(source, "none") == 0) {
+ vm->time_state.flags &= ~V3_TIME_SLAVE_HOST;
+ } else if (strcasecmp(source, "host") != 0) {
+ PrintError("Unknown time source for VM core time management.\n");
+ } else {
+ PrintDebug("VM time slaved to host TSC.\n");
+ }
+ }
+
+ // 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.");
}
- }
- if (dilation && (vm->time_state.flags & V3_TIME_SLAVE_HOST)) {
- char *str1, *str2;
+ 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)) {
+ PrintError("Time dilation only valid when slaved to host time.\n");
+ } else {
uint32_t num = 1, denom = 1;
- if ((str1 = v3_cfg_val(dilation, "value"))) {
- denom = atoi(str1);
- } else if ((str1 = v3_cfg_val(dilation, "num"))
- && (str2 = v3_cfg_val(dilation, "denom"))) {
- num = atoi(str1);
- denom = atoi(str2);
- }
+ denom = atoi(dilation);
if ((num > 0) && (denom > 0)) {
vm->time_state.td_num = num;
vm->time_state.td_denom = denom;
}
- if ((vm->time_state.td_num != 1)
- || (vm->time_state.td_denom != 1)) {
- V3_Print("Time dilated from host time by a factor of %d/%d"
- " in guest.\n", denom, num);
- } else {
- PrintError("Time dilation specifier in configuration did not"
- " result in actual time dilation in VM.\n");
- }
+ }
+ if ((vm->time_state.td_num != 1)
+ || (vm->time_state.td_denom != 1)) {
+ V3_Print("Time dilated from host time by a factor of %d/%d"
+ " in guest.\n", vm->time_state.td_denom,
+ vm->time_state.td_num);
+ } else {
+ PrintError("Time dilation specifier in configuration did not"
+ " result in actual time dilation in VM.\n");
}
}
return 0;
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"));
static uint32_t
gcd ( uint32_t a, uint32_t b )
{
- uint32_t c;
- while ( a != 0 ) {
- c = a; a = b%a; b = c;
- }
- return b;
+ uint32_t c;
+ while ( a != 0 ) {
+ c = a; a = b%a; b = c;
+ }
+ return b;
}
static int compute_core_ratios(struct guest_info * info,
}
if ( (khz == NULL) ||
- (time_state->guest_cpu_freq <= 0) ||
- (time_state->guest_cpu_freq > time_state->host_cpu_freq) ) {
-
+ (time_state->guest_cpu_freq <= 0)) {
+/* || (time_state->guest_cpu_freq > time_state->host_cpu_freq) ) { */
time_state->guest_cpu_freq = time_state->host_cpu_freq;
}
+ compute_core_ratios(info, time_state->host_cpu_freq,
+ time_state->guest_cpu_freq);
+
+ time_state->flags = 0;
+ 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) ||
+ (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;
+ }
+
PrintDebug("Logical Core %d (vcpu=%d) CPU frequency set to %d KHz (host CPU frequency = %d KHz).\n",
info->pcpu_id, info->vcpu_id,
time_state->guest_cpu_freq,
time_state->host_cpu_freq);
-
- compute_core_ratios(info, time_state->host_cpu_freq,
- time_state->guest_cpu_freq);
-
PrintDebug(" td_mult = %d/%d, cl_mult = %u/%u, ipc_mult = %u/%u.\n",
info->vm_info->time_state.td_num,
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(" time source = %s, tsc handling = %s\n",
+ (time_state->flags & VM_TIME_SLAVE_HOST) ? "host" : "none",
+ (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;
time_state->last_update = 0;
-
time_state->initial_host_time = 0;
- time_state->flags = 0;
- if (info->vm_info->time_state.flags & V3_TIME_SLAVE_HOST) {
- time_state->flags |= VM_TIME_SLAVE_HOST;
- }
- if ((time_state->clock_ratio_denom != 1) ||
- (time_state->clock_ratio_num != 1)) {
- time_state->flags |= VM_TIME_TRAP_RDTSC;
- }
-
INIT_LIST_HEAD(&(time_state->timers));
time_state->num_timers = 0;
-
+
time_state->tsc_aux.lo = 0;
time_state->tsc_aux.hi = 0;
}
list_for_each_entry_safe(tmr, tmp, &(time_state->timers), timer_link) {
v3_remove_timer(core, tmr);
}
-
}