// Installed Timers slaved off of the guest monotonic TSC
uint_t num_timers;
struct list_head timers;
+
+ // Installed timeout handlers, and the time (in monotonic guest time) of hte
+ // next timeout.
+ uint64_t next_timeout;
+ struct list_head timeout_hooks;
};
struct v3_timer_ops {
void * private_data;
struct v3_timer_ops * ops;
+ // Need to add accuracy/resolution fields later.
+
struct list_head timer_link;
};
+typedef void (*v3_timeout_callback_t)(struct guest_info * info, void * priv_data);
+struct v3_timeout_hook {
+ void * private_data;
+ v3_timeout_callback_t callback;
+
+ struct list_head hook_link;
+};
+
// Basic functions for handling passage of time in palacios
void v3_init_time_core(struct guest_info * core);
int v3_init_time_vm(struct v3_vm_info * vm);
int v3_adjust_time(struct guest_info * core);
int v3_offset_time(struct guest_info * core, sint64_t offset);
-// Basic functions for attaching timers to the passage of time
+// Basic functions for attaching timers to the passage of time - these timers
+// should eventually specify their accuracy and resolution.
struct v3_timer * v3_add_timer(struct guest_info * info, struct v3_timer_ops * ops, void * private_data);
int v3_remove_timer(struct guest_info * info, struct v3_timer * timer);
void v3_update_timers(struct guest_info * info);
+// Functions for handling one-shot timeouts in Palacios. Note that only one
+// timeout is every currently outstanding (the soonest scheduled one!), and that
+// all hooks are called on any timeout. If a hook gets called before the desired
+// timeout time, that hook should reschedule its own timeout if desired.
+struct v3_timeout_hook * v3_add_timeout_hook(struct guest_info * info, v3_timeout_callback_t callback, void * priv_data);
+int v3_remove_timeout_hook(struct guest_info * info, struct v3_timeout_hook * hook);
+int v3_schedule_timeout(struct guest_info * info, ullong_t cycles);
+int v3_check_timeout(struct guest_info * info);
+
// Functions to return the different notions of time in Palacios.
static inline uint64_t v3_get_host_time(struct vm_time *t) {
uint64_t tmp;
// Perform any additional yielding needed for time adjustment
v3_adjust_time(info);
+ // Check for timeout - since this calls generic hooks in devices
+ // that may do things like pause the VM, it cannot be with interrupts
+ // disabled.
+ v3_check_timeout(info);
+
// disable global interrupts for vm state transition
v3_clgi();
}
}
+/* Handle TSC timeout hooks */
+struct v3_timeout_hook *
+v3_add_timeout_hook(struct guest_info * info, v3_timeout_callback_t callback,
+ void * priv_data) {
+ struct v3_timeout_hook * timeout = NULL;
+ timeout = (struct v3_timeout_hook *)V3_Malloc(sizeof(struct v3_timeout_hook));
+ V3_ASSERT(timeout != NULL);
+
+ timeout->callback = callback;
+ timeout->private_data = priv_data;
+
+ list_add(&(timeout->hook_link), &(info->time_state.timeout_hooks));
+ return timeout;
+}
+
+int
+v3_remove_timeout_hook(struct guest_info * info, struct v3_timeout_hook * hook) {
+ list_del(&(hook->hook_link));
+ V3_Free(hook);
+ return 0;
+}
+
+int v3_schedule_timeout(struct guest_info * info, ullong_t guest_timeout) {
+ struct vm_time *time_state = &info->time_state;
+ /* Note that virtualization architectures that support it (like newer
+ * VMX systems) will turn on an active preemption timeout if
+ * available to get this timeout as closely as possible. Other systems
+ * only catch it in the periodic interrupt and so are less precise */
+ if (guest_timeout < time_state->next_timeout) {
+ time_state->next_timeout = guest_timeout;
+ }
+ return 0;
+}
+
+int v3_check_timeout( struct guest_info * info ) {
+ struct vm_time *time_state = &info->time_state;
+ if (time_state->next_timeout <= v3_get_guest_time(time_state)) {
+ struct v3_timeout_hook * tmp_timeout;
+ time_state->next_timeout = (ullong_t)-1;
+ list_for_each_entry(tmp_timeout, &(time_state->timeout_hooks), hook_link) {
+ tmp_timeout->callback(info, tmp_timeout->private_data);
+ }
+ }
+ return 0;
+}
+
/*
* Handle full virtualization of the time stamp counter. As noted
* above, we don't store the actual value of the TSC, only the guest's
time_state->guest_host_offset = 0;
time_state->tsc_guest_offset = 0;
+ INIT_LIST_HEAD(&(time_state->timeout_hooks));
+ time_state->next_timeout = (ullong_t)-1;
+
INIT_LIST_HEAD(&(time_state->timers));
time_state->num_timers = 0;
}
+int
+v3_vmx_schedule_timeout(struct guest_info * info)
+{
+ struct vmx_data * vmx_state = (struct vmx_data *)(info->vmm_data);
+ sint64_t cycles;
+ uint32_t timeout;
+
+ /* Check if the hardware supports an active timeout */
+#define VMX_ACTIVE_PREEMPT_TIMER_PIN 0x40
+ if (hw_info.pin_ctrls.req_mask & VMX_ACTIVE_PREEMPT_TIMER_PIN) {
+ return 0;
+ }
+
+ /* Check if we have one to schedule */
+ cycles = (sint64_t)info->time_state.next_timeout - (sint64_t)v3_get_guest_time(&info->time_state);
+ if ((info->time_state.next_timeout == (ullong_t) -1) || (cycles < 0)) {
+ vmx_state->pin_ctrls.active_preempt_timer = 0;
+ } else {
+ /* The hardware supports scheduling a timeout, and we have one to
+ * schedule */
+ timeout = (uint32_t)cycles >> hw_info.misc_info.tsc_multiple;
+ vmx_state->pin_ctrls.active_preempt_timer = 1;
+ check_vmcs_write(VMCS_PREEMPT_TIMER, timeout);
+ }
+ check_vmcs_write(VMCS_PIN_CTRLS, vmx_state->pin_ctrls.value);
+ return 0;
+}
+
/*
* CAUTION and DANGER!!!
*
// Perform any additional yielding needed for time adjustment
v3_adjust_time(info);
+ // Check for timeout - since this calls generic hooks in devices
+ // that may do things like pause the VM, it cannot be with interrupts
+ // disabled.
+ v3_check_timeout(info);
+
// disable global interrupts for vm state transition
v3_disable_ints();
// Update timer devices late after being in the VM so that as much
- // of hte time in the VM is accounted for as possible. Also do it before
+ // of the time in the VM is accounted for as possible. Also do it before
// updating IRQ entry state so that any interrupts the timers raise get
// handled on the next VM entry. Must be done with interrupts disabled.
v3_update_timers(info);
vmcs_write(VMCS_GUEST_CR3, guest_cr3);
}
+ // Update vmx active preemption timer to exit at the next timeout if
+ // the hardware supports it.
+ v3_vmx_schedule_timeout(info);
+
// Perform last-minute time bookkeeping prior to entering the VM
v3_time_enter_vm(info);