but no robust control in place yet.
source "Kconfig.stdlibs"
-
menu "Virtual Paging"
config SHADOW_PAGING
endmenu
+menu "Time Management"
+
+
+config TIME_VIRTUALIZE_TSC
+ bool "Virtualize guest TSC"
+ default n
+ help
+ Virtualize the processor time stamp counter in the guest,
+ generally increasing consistency between various time sources
+ but also potentially making guest time run slightly slower
+ than real time.
+
+config TIME_VIRTUAL_TSC_CONTROL
+ bool "Adjust virtual TSC towards real time when possible"
+ default y
+ depends on TIME_VIRTUALIZE_TSC
+ help
+ Enables control of TSC virtualization so that the TSC
+ attempts to catch up with real time when possible
+
+config TIME_MASK_OVERHEAD
+ bool "Hide virtualization overhead from guest timing"
+ default n
+ depends on TIME_VIRTUALIZE_TSC
+ help
+ Try to mask the overhead of virtualization from guests
+ by not including it in the time updates. Can dramatically
+ slow virtual time compared to real time if VIRTUAL_TSC_CONTROL
+ is not enabled.
+
+endmenu
+
menu "Symbiotic Functions"
config SYMBIOTIC
struct vm_time {
uint32_t cpu_freq; // in kHZ
- // Last time (in guest time) the timers were updated
- uint64_t last_update;
-
- // Cache value to help calculate the guest_tsc
- uint64_t pause_time;
-
- // Offset of guest time from host time.
- sint64_t host_offset;
+ uint64_t last_update; // Last time (in guest time) the timers were updated
+ uint64_t pause_time; // Cache value to help calculate the guest_tsc
+ sint64_t host_offset; // Offset of guest time from host time.
+ sint64_t offset_sum; // Sum of past and current host_offsets
// Installed Timers
uint_t num_timers;
}
static inline uint64_t v3_get_guest_time(struct vm_time *t) {
- return v3_get_host_time(t) + t->host_offset;
+ if (t->pause_time) return t->pause_time;
+ else return v3_get_host_time(t) + t->host_offset;
}
#endif // !__V3VEE__
v3_update_timers(info);
v3_resume_time(info);
+
+#ifdef CONFIG_TIME_TSC_OFFSET
guest_ctrl->TSC_OFFSET = info->time_state.host_offset;
+#endif
//V3_Print("Calling v3_svm_launch\n");
v3_svm_launch((vmcb_t *)V3_PAddr(info->vmm_data), &(info->vm_regs), (vmcb_t *)host_vmcbs[info->cpu_id]);
v3_pause_time(info);
-#ifdef OPTION_TIME_MASK_OVERHEAD
+#ifdef CONFIG_TIME_MASK_OVERHEAD
v3_offset_time(info, -SVM_ENTRY_OVERHEAD);
#endif
time_state->pause_time = 0;
time_state->last_update = 0;
time_state->host_offset = 0;
-
+ time_state->offset_sum = 0;
+
INIT_LIST_HEAD(&(time_state->timers));
time_state->num_timers = 0;
return 0;
}
+/* Use a control-theoretic approach, specifically a PI control approach,
+ * to adjust host_offset towards 0. Overall control documentation in
+ * palacios/docs/time_control.tex Control parameters are P and I,
+ * broken into rational numbers
+ */
+
+/* These numbers need to be actually determined by pole placement work. They're
+ * just blind guesses for now, which is a really bad idea. :) */
+#define P_NUM 1
+#define P_DENOM 2
+#define I_NUM 1
+#define I_DENOM 20
+
+void adjust_time_offset(struct guest_info * info) {
+ /* Set point for control: Desired offset = 0;
+ * Error = host_offset - 0 = host_offset */
+
+ sint64_t adjust;
+
+ /* Update the integral of the errror */
+ info->time_state.offset_sum += info->time_state.host_offset;
+ adjust = (P_NUM * info->time_state.host_offset) / P_DENOM +
+ (I_NUM * info->time_state.offset_sum) / I_DENOM;
+
+ /* We may want to constrain *adjust* because of
+ * resolution/accuracy constraints. Explore that later. */
+ info->time_state.host_offset -= adjust;
+ return;
+}
+
int v3_resume_time(struct guest_info * info) {
uint64_t t = v3_get_host_time(&info->time_state);
V3_ASSERT(info->time_state.pause_time != 0);
info->time_state.host_offset =
(sint64_t)info->time_state.pause_time - (sint64_t)t;
#ifdef CONFIG_TIME_TSC_OFFSET_ADJUST
- /* XXX Adjust host_offset towards zero based on resolution/accuracy
- * constraints. */
+ adjust_time_offset(info);
#endif
info->time_state.pause_time = 0;
PrintDebug("Time resumed paused at guest time as %llu "
vmx_state->pri_proc_ctrls.invlpg_exit = 1;
vmx_state->pri_proc_ctrls.use_msr_bitmap = 1;
vmx_state->pri_proc_ctrls.pause_exit = 1;
+#ifdef CONFIG_TIME_TSC_OFFSET
+ vmx_state->pri_proc_ctrls.tsc_offset = 1;
+#endif
vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_A_ADDR, (addr_t)V3_PAddr(info->vm_info->io_map.arch_data));
vmx_ret |= check_vmcs_write(VMCS_IO_BITMAP_B_ADDR,
}
v3_pause_time(info);
-#ifdef OPTION_TIME_MASK_OVERHEAD
+#ifdef CONFIG_TIME_MASK_OVERHEAD
v3_offset_time(info, -VMX_ENTRY_OVERHEAD);
#endif