int flags;
uint32_t td_num, td_denom;
};
-#define V3_TIME_SLAVE_HOST (1 << 1)
+#define V3_TIME_SLAVE_HOST (1 << 0)
+#define V3_TIME_TSC_PASSTHROUGH (1 << 1)
/* Per-core time information */
struct vm_core_time {
};
-#define VM_TIME_TRAP_RDTSC (1 << 0)
-#define VM_TIME_SLAVE_HOST (1 << 1)
+#define VM_TIME_SLAVE_HOST (1 << 0)
+#define VM_TIME_TSC_PASSTHROUGH (1 << 1)
+#define VM_TIME_TRAP_RDTSC (1 << 2)
struct v3_timer_ops {
void (*update_timer)(struct guest_info * info, ullong_t cpu_cycles, ullong_t cpu_freq, void * priv_data);
// Returns offset of guest TSC from host TSC
static inline sint64_t v3_tsc_host_offset(struct vm_core_time *time_state) {
uint64_t host_time = v3_get_host_time(time_state);
- return ((sint64_t)time_state->guest_cycles - (sint64_t)host_time) + time_state->tsc_guest_offset;
+ return (sint64_t)v3_get_guest_tsc(time_state) - (sint64_t)host_time;
}
// Functions for handling exits on the TSC when fully virtualizing
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)) {
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;