uint32_t host_cpu_freq; // in kHZ
uint32_t guest_cpu_freq; // can be lower than host CPU freq!
- sint64_t guest_host_offset;// Offset of monotonic guest time from host time
- sint64_t tsc_guest_offset; // Offset of guest TSC from monotonic guest time
+ uint64_t guest_cycles;
+ sint64_t tsc_guest_offset; // Offset of guest TSC from guest cycles
- uint64_t last_update; // Last time (in monotonic guest time) the
+ uint64_t last_update; // Last time (in guest cycles) the
// timers were updated
- uint64_t initial_time; // Time when VMM started.
+ uint64_t initial_time; // Host time when VMM started.
uint64_t enter_time; // Host time the guest was last entered
uint64_t exit_time; // Host time the the VM was exited to
- uint64_t pause_time; // Time at which the VM core was paused
struct v3_msr tsc_aux; // Auxilliary MSR for RDTSCP
// Installed Timers slaved off of the guest monotonic TSC
int v3_remove_timer(struct guest_info * info, struct v3_timer * timer);
void v3_update_timers(struct guest_info * info);
-
-
// Functions to return the different notions of time in Palacios.
static inline uint64_t v3_get_host_time(struct vm_core_time *t) {
uint64_t tmp;
}
// Returns *monotonic* guest time.
-static inline uint64_t v3_compute_guest_time(struct vm_core_time *t, uint64_t ht) {
- if (t->pause_time)
- return t->pause_time + t->guest_host_offset;
- else
- return ht + t->guest_host_offset;
-}
-
static inline uint64_t v3_get_guest_time(struct vm_core_time *t) {
- return v3_compute_guest_time(t, v3_get_host_time(t));
-}
-
-// Returns the TSC value seen by the guest
-static inline uint64_t v3_compute_guest_tsc(struct vm_core_time *t, uint64_t ht) {
- return v3_compute_guest_time(t, ht) + t->tsc_guest_offset;
+ return t->guest_cycles;
}
static inline uint64_t v3_get_guest_tsc(struct vm_core_time *t) {
- return v3_compute_guest_tsc(t, v3_get_host_time(t));
+ return v3_get_guest_time(t) + t->tsc_guest_offset;
}
// Returns offset of guest TSC from host TSC
static inline sint64_t v3_tsc_host_offset(struct vm_core_time *time_state) {
- return time_state->guest_host_offset + time_state->tsc_guest_offset;
+ uint64_t host_time = v3_get_host_time(time_state);
+ return ((sint64_t)host_time - (sint64_t)time_state->guest_cycles) + time_state->tsc_guest_offset;
}
// Functions for handling exits on the TSC when fully virtualizing
/* We start running with guest_time == host_time */
uint64_t t = v3_get_host_time(&info->time_state);
- PrintDebug("Starting initial guest time as %llu\n", t);
-
info->time_state.enter_time = 0;
info->time_state.exit_time = t;
- info->time_state.last_update = t;
info->time_state.initial_time = t;
info->yield_start_cycle = t;
- return 0;
-}
-
-int v3_pause_time( struct guest_info * info )
-{
- struct vm_core_time * time_state = &(info->time_state);
- if (time_state->pause_time != 0) {
- PrintError("Attempted to pause time when time already paused.\n");
- return -1;
- }
- time_state->pause_time = v3_get_host_time( time_state );
-
- return 0;
-}
-
-int v3_resume_time( struct guest_info * info )
-{
- struct vm_core_time * time_state = &(info->time_state);
- uint64_t host_time, guest_time;
- sint64_t offset;
-
- if (time_state->pause_time == 0) {
- PrintError("Attempted to resume time when time not paused.\n");
- return -1;
- }
-
- host_time = v3_get_host_time(time_state);
- guest_time = v3_compute_guest_time(time_state, host_time);
- offset = (sint64_t)guest_time - (sint64_t)host_time;
- time_state->guest_host_offset = offset;
- time_state->pause_time = 0;
-
+ info->time_state.last_update = 0;
+ 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);
return 0;
}
{
struct vm_core_time * time_state = &(info->time_state);
PrintDebug("Adding additional offset of %lld to guest time.\n", offset);
- time_state->guest_host_offset += offset;
+ time_state->guest_cycles += offset;
return 0;
}
* time to account for the time paused even if the geust isn't
* usually paused in the VMM. */
host_time = v3_get_host_time(time_state);
- old_guest_time = v3_compute_guest_time(time_state, host_time);
+ old_guest_time = v3_get_guest_time(time_state);
target_host_time = compute_target_host_time(info, old_guest_time);
while (target_host_time > host_time) {
host_time = v3_get_host_time(time_state);
}
- guest_time = v3_compute_guest_time(time_state, host_time);
+ guest_time = v3_get_guest_time(time_state);
/* We do *not* assume the guest timer was paused in the VM. If it was
* this offseting is 0. If it wasn't, we need this. */
struct vm_core_time * time_state = &(info->time_state);
time_state->exit_time = v3_get_host_time(time_state);
-
-#ifdef V3_CONFIG_TIME_DILATION
- v3_pause_time( info );
-#endif
-
+ if (guest_cycles) {
+ time_state->guest_cycles += *guest_cycles;
+ } else {
+ uint64_t cycles_exec;
+ cycles_exec = time_state->exit_time - time_state->enter_time;
+ time_state->guest_cycles += cycles_exec;
+ }
return 0;
}
v3_time_enter_vm( struct guest_info * info )
{
struct vm_core_time * time_state = &(info->time_state);
- uint64_t host_time;
+ uint64_t host_time, vmm_cycles;
host_time = v3_get_host_time(time_state);
time_state->enter_time = host_time;
-#ifdef V3_CONFIG_TIME_DILATION
- v3_resume_time( info );
-#else
- time_state->guest_host_offset = 0;
-#endif
-
+ vmm_cycles = host_time - time_state->exit_time;
+ /* XXX How do we want to take into account host/guest CPU speed differences
+ * and time dilation here? Probably time just won't advance in the VMM in that
+ * case so its irrelvant XXX */
+ time_state->guest_cycles += vmm_cycles;
return 0;
}
ret = v3_register_hypercall(vm, TIME_CPUFREQ_HCALL,
handle_cpufreq_hcall, NULL);
- PrintDebug("Setting base time dilation factor.\n");
vm->time_state.td_mult = 1;
+ PrintDebug("Setting base time dilation factor to %d.\n", vm->time_state.td_mult);
return ret;
}
time_state->initial_time = 0;
time_state->last_update = 0;
- time_state->guest_host_offset = 0;
time_state->tsc_guest_offset = 0;
time_state->enter_time = 0;
time_state->exit_time = 0;
- time_state->pause_time = 0;
-
+ time_state->guest_cycles = 0;
INIT_LIST_HEAD(&(time_state->timers));
time_state->num_timers = 0;