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) {
info->time_state.guest_cycles = 0;
PrintDebug("Starting time for core %d at host time %llu/guest time %llu.\n",
info->vcpu_id, t, info->time_state.guest_cycles);
- v3_yield(info);
+ v3_yield(info,-1);
return 0;
}
void * private_data) {
struct v3_timer * timer = NULL;
timer = (struct v3_timer *)V3_Malloc(sizeof(struct v3_timer));
+
+ if (!timer) {
+ PrintError("Cannot allocate in adding a timer\n");
+ return NULL;
+ }
+
V3_ASSERT(timer != NULL);
timer->ops = ops;
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) ||
(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;