mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
hvm, x86: Allow virtual timer mode to be specified.
In HVM config file:
timer_mode=0 # Default: virtual time is delayed when timer ticks are
# missed dur to preemption
timer_mode=1 # Virtual time always equals wall time, even while missed
# ticks are pending
From: Haitao Shan <haitao.shan@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
5afede5ce6
commit
617d4311ef
12 files changed
+91
-32
No files matched your search
@@ -127,7 +127,7 @@ XENAPI_PLATFORM_CFG = [ 'acpi', 'apic', 'boot', 'device_model', 'display',
|
||||
'fda', 'fdb', 'keymap', 'isa', 'localtime', 'monitor',
|
||||
'nographic', 'pae', 'rtc_timeoffset', 'serial', 'sdl',
|
||||
'soundhw','stdvga', 'usb', 'usbdevice', 'vnc',
|
||||
'vncconsole', 'vncdisplay', 'vnclisten',
|
||||
'vncconsole', 'vncdisplay', 'vnclisten', 'timer_mode',
|
||||
'vncpasswd', 'vncunused', 'xauthority', 'pci', 'vhpt']
|
||||
|
||||
# Xen API console 'other_config' keys.
|
||||
|
||||
@@ -46,6 +46,7 @@ HVM_PARAM_BUFIOREQ_PFN = 6
|
||||
HVM_PARAM_NVRAM_FD = 7
|
||||
HVM_PARAM_VHPT_SIZE = 8
|
||||
HVM_PARAM_BUFPIOREQ_PFN = 9
|
||||
HVM_PARAM_TIMER_MODE = 10
|
||||
|
||||
restart_modes = [
|
||||
"restart",
|
||||
|
||||
@@ -1596,6 +1596,11 @@ class XendDomainInfo:
|
||||
|
||||
self._recreateDom()
|
||||
|
||||
# Set timer configration of domain
|
||||
if hvm:
|
||||
xc.hvm_set_param(self.domid, HVM_PARAM_TIMER_MODE,
|
||||
long(self.info["platform"].get("timer_mode")))
|
||||
|
||||
# Set maximum number of vcpus in domain
|
||||
xc.domain_max_vcpus(self.domid, int(self.info['VCPUs_max']))
|
||||
|
||||
|
||||
@@ -194,6 +194,11 @@ gopts.var('pae', val='PAE',
|
||||
fn=set_int, default=1,
|
||||
use="Disable or enable PAE of HVM domain.")
|
||||
|
||||
gopts.var('timer_mode', val='TIMER_MODE',
|
||||
fn=set_int, default=0,
|
||||
use="""Timer mode (0=delay virtual time when ticks are missed;
|
||||
1=virtual time is always wallclock time.""")
|
||||
|
||||
gopts.var('acpi', val='ACPI',
|
||||
fn=set_int, default=1,
|
||||
use="Disable or enable ACPI of HVM domain.")
|
||||
@@ -724,7 +729,7 @@ def configure_vifs(config_devs, vals):
|
||||
def configure_hvm(config_image, vals):
|
||||
"""Create the config for HVM devices.
|
||||
"""
|
||||
args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb',
|
||||
args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'timer_mode',
|
||||
'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
|
||||
'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
|
||||
'sdl', 'display', 'xauthority', 'rtc_timeoffset', 'monitor',
|
||||
|
||||
@@ -818,7 +818,7 @@ class sxp2xml:
|
||||
|
||||
|
||||
def extract_platform(self, image, document):
|
||||
platform_keys = ['acpi', 'apic', 'pae', 'vhpt']
|
||||
platform_keys = ['acpi', 'apic', 'pae', 'vhpt', 'timer_mode']
|
||||
|
||||
def extract_platform_key(key):
|
||||
platform = document.createElement("platform")
|
||||
|
||||
@@ -1279,7 +1279,7 @@ void context_switch(struct vcpu *prev, struct vcpu *next)
|
||||
local_irq_disable();
|
||||
|
||||
if ( is_hvm_vcpu(prev) && !list_empty(&prev->arch.hvm_vcpu.tm_list) )
|
||||
pt_freeze_time(prev);
|
||||
pt_save_timer(prev);
|
||||
|
||||
set_current(next);
|
||||
|
||||
|
||||
+10
-4
@@ -89,17 +89,17 @@ void hvm_enable(struct hvm_function_table *fns)
|
||||
}
|
||||
}
|
||||
|
||||
void hvm_set_guest_time(struct vcpu *v, u64 gtime)
|
||||
void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc)
|
||||
{
|
||||
u64 host_tsc;
|
||||
|
||||
rdtscll(host_tsc);
|
||||
|
||||
v->arch.hvm_vcpu.cache_tsc_offset = gtime - host_tsc;
|
||||
v->arch.hvm_vcpu.cache_tsc_offset = guest_tsc - host_tsc;
|
||||
hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
|
||||
}
|
||||
|
||||
u64 hvm_get_guest_time(struct vcpu *v)
|
||||
u64 hvm_get_guest_tsc(struct vcpu *v)
|
||||
{
|
||||
u64 host_tsc;
|
||||
|
||||
@@ -121,7 +121,7 @@ void hvm_do_resume(struct vcpu *v)
|
||||
if ( !v->fpu_dirtied )
|
||||
hvm_funcs.stts(v);
|
||||
|
||||
pt_thaw_time(v);
|
||||
pt_restore_timer(v);
|
||||
|
||||
/* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
|
||||
p = &get_ioreq(v)->vp_ioreq;
|
||||
@@ -1843,6 +1843,12 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
|
||||
hvm_set_callback_via(d, a.value);
|
||||
hvm_latch_shinfo_size(d);
|
||||
break;
|
||||
case HVM_PARAM_TIMER_MODE:
|
||||
rc = -EINVAL;
|
||||
if ( (a.value != HVMPTM_delay_for_missed_ticks) &&
|
||||
(a.value != HVMPTM_no_delay_for_missed_ticks) )
|
||||
goto param_fail;
|
||||
break;
|
||||
}
|
||||
d->arch.hvm_domain.params[a.index] = a.value;
|
||||
rc = 0;
|
||||
|
||||
@@ -430,7 +430,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
|
||||
uint32_t tmcct, tmict = vlapic_get_reg(vlapic, APIC_TMICT);
|
||||
uint64_t counter_passed;
|
||||
|
||||
counter_passed = (hvm_get_guest_time(v) - vlapic->pt.last_plt_gtime) // TSC
|
||||
counter_passed = (hvm_get_guest_time(v) - vlapic->timer_last_update) // TSC
|
||||
* 1000000000ULL / ticks_per_sec(v) // NS
|
||||
/ APIC_BUS_CYCLE_NS / vlapic->hw.timer_divisor;
|
||||
tmcct = tmict - counter_passed;
|
||||
@@ -531,6 +531,11 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vlapic_pt_cb(struct vcpu *v, void *data)
|
||||
{
|
||||
*(s_time_t *)data = hvm_get_guest_time(v);
|
||||
}
|
||||
|
||||
static void vlapic_write(struct vcpu *v, unsigned long address,
|
||||
unsigned long len, unsigned long val)
|
||||
{
|
||||
@@ -660,7 +665,8 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
|
||||
|
||||
vlapic_set_reg(vlapic, APIC_TMICT, val);
|
||||
create_periodic_time(current, &vlapic->pt, period, vlapic->pt.irq,
|
||||
!vlapic_lvtt_period(vlapic), NULL, vlapic);
|
||||
!vlapic_lvtt_period(vlapic), vlapic_pt_cb,
|
||||
&vlapic->timer_last_update);
|
||||
|
||||
HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
|
||||
"bus cycle is %uns, "
|
||||
@@ -820,7 +826,8 @@ static void lapic_rearm(struct vlapic *s)
|
||||
|
||||
s->pt.irq = lvtt & APIC_VECTOR_MASK;
|
||||
create_periodic_time(vlapic_vcpu(s), &s->pt, period, s->pt.irq,
|
||||
!vlapic_lvtt_period(s), NULL, s);
|
||||
!vlapic_lvtt_period(s), vlapic_pt_cb,
|
||||
&s->timer_last_update);
|
||||
|
||||
printk("lapic_load to rearm the actimer:"
|
||||
"bus cycle is %uns, "
|
||||
|
||||
+33
-14
@@ -23,6 +23,12 @@
|
||||
#include <asm/hvm/vpt.h>
|
||||
#include <asm/event.h>
|
||||
|
||||
static int pt_support_time_frozen(struct domain *d)
|
||||
{
|
||||
return (d->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] ==
|
||||
HVMPTM_delay_for_missed_ticks);
|
||||
}
|
||||
|
||||
static void pt_lock(struct periodic_time *pt)
|
||||
{
|
||||
struct vcpu *v;
|
||||
@@ -67,7 +73,12 @@ static void missed_ticks(struct periodic_time *pt)
|
||||
pt->scheduled += missed_ticks * pt->period;
|
||||
}
|
||||
|
||||
void pt_freeze_time(struct vcpu *v)
|
||||
static __inline__ void pt_freeze_time(struct vcpu *v)
|
||||
{
|
||||
v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
|
||||
}
|
||||
|
||||
void pt_save_timer(struct vcpu *v)
|
||||
{
|
||||
struct list_head *head = &v->arch.hvm_vcpu.tm_list;
|
||||
struct periodic_time *pt;
|
||||
@@ -77,33 +88,40 @@ void pt_freeze_time(struct vcpu *v)
|
||||
|
||||
spin_lock(&v->arch.hvm_vcpu.tm_lock);
|
||||
|
||||
v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
|
||||
|
||||
list_for_each_entry ( pt, head, list )
|
||||
stop_timer(&pt->timer);
|
||||
|
||||
if ( pt_support_time_frozen(v->domain) )
|
||||
pt_freeze_time(v);
|
||||
|
||||
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
|
||||
}
|
||||
|
||||
void pt_thaw_time(struct vcpu *v)
|
||||
static __inline__ void pt_thaw_time(struct vcpu *v)
|
||||
{
|
||||
if ( v->arch.hvm_vcpu.guest_time )
|
||||
{
|
||||
hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
|
||||
v->arch.hvm_vcpu.guest_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void pt_restore_timer(struct vcpu *v)
|
||||
{
|
||||
struct list_head *head = &v->arch.hvm_vcpu.tm_list;
|
||||
struct periodic_time *pt;
|
||||
|
||||
spin_lock(&v->arch.hvm_vcpu.tm_lock);
|
||||
|
||||
if ( v->arch.hvm_vcpu.guest_time )
|
||||
list_for_each_entry ( pt, head, list )
|
||||
{
|
||||
hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
|
||||
v->arch.hvm_vcpu.guest_time = 0;
|
||||
|
||||
list_for_each_entry ( pt, head, list )
|
||||
{
|
||||
missed_ticks(pt);
|
||||
set_timer(&pt->timer, pt->scheduled);
|
||||
}
|
||||
missed_ticks(pt);
|
||||
set_timer(&pt->timer, pt->scheduled);
|
||||
}
|
||||
|
||||
if ( pt_support_time_frozen(v->domain) )
|
||||
pt_thaw_time(v);
|
||||
|
||||
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
|
||||
}
|
||||
|
||||
@@ -218,7 +236,8 @@ void pt_intr_post(struct vcpu *v, struct hvm_intack intack)
|
||||
pt->last_plt_gtime += pt->period_cycles;
|
||||
}
|
||||
|
||||
if ( hvm_get_guest_time(v) < pt->last_plt_gtime )
|
||||
if ( pt_support_time_frozen(v->domain) &&
|
||||
hvm_get_guest_time(v) < pt->last_plt_gtime )
|
||||
hvm_set_guest_time(v, pt->last_plt_gtime);
|
||||
|
||||
cb = pt->cb;
|
||||
|
||||
@@ -175,8 +175,10 @@ void hvm_vcpu_reset(struct vcpu *vcpu);
|
||||
|
||||
void hvm_send_assist_req(struct vcpu *v);
|
||||
|
||||
void hvm_set_guest_time(struct vcpu *v, u64 gtime);
|
||||
u64 hvm_get_guest_time(struct vcpu *v);
|
||||
void hvm_set_guest_tsc(struct vcpu *v, u64 guest_tsc);
|
||||
u64 hvm_get_guest_tsc(struct vcpu *v);
|
||||
#define hvm_set_guest_time(vcpu, gtime) hvm_set_guest_tsc(vcpu, gtime)
|
||||
#define hvm_get_guest_time(vcpu) hvm_get_guest_tsc(vcpu)
|
||||
|
||||
#define hvm_paging_enabled(v) \
|
||||
(!!((v)->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PG))
|
||||
|
||||
@@ -133,8 +133,8 @@ struct pl_time { /* platform time */
|
||||
|
||||
#define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
|
||||
|
||||
void pt_freeze_time(struct vcpu *v);
|
||||
void pt_thaw_time(struct vcpu *v);
|
||||
void pt_save_timer(struct vcpu *v);
|
||||
void pt_restore_timer(struct vcpu *v);
|
||||
void pt_update_irq(struct vcpu *v);
|
||||
void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
|
||||
void pt_reset(struct vcpu *v);
|
||||
|
||||
@@ -54,9 +54,23 @@
|
||||
#define HVM_PARAM_NVRAM_FD 7
|
||||
#define HVM_PARAM_VHPT_SIZE 8
|
||||
#define HVM_PARAM_BUFPIOREQ_PFN 9
|
||||
#define HVM_NR_PARAMS 10
|
||||
#else
|
||||
#define HVM_NR_PARAMS 7
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set mode for virtual timers (currently x86 only):
|
||||
* delay_for_missed_ticks (default):
|
||||
* Do not advance a vcpu's time beyond the correct delivery time for
|
||||
* interrupts that have been missed due to preemption. Deliver missed
|
||||
* interrupts when the vcpu is rescheduled and advance the vcpu's virtual
|
||||
* time stepwise for each one.
|
||||
* no_delay_for_missed_ticks:
|
||||
* As above, missed interrupts are delivered, but guest time always tracks
|
||||
* wallclock (i.e., real) time while doing so.
|
||||
*/
|
||||
#define HVM_PARAM_TIMER_MODE 10
|
||||
#define HVMPTM_delay_for_missed_ticks 0
|
||||
#define HVMPTM_no_delay_for_missed_ticks 1
|
||||
|
||||
#define HVM_NR_PARAMS 11
|
||||
|
||||
#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
|
||||