From 617d4311ef314ca79bdabe1c1087e42eabba09b8 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Fri, 26 Oct 2007 09:56:54 +0100 Subject: [PATCH] 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 Signed-off-by: Keir Fraser --- tools/python/xen/xend/XendConfig.py | 2 +- tools/python/xen/xend/XendConstants.py | 1 + tools/python/xen/xend/XendDomainInfo.py | 5 +++ tools/python/xen/xm/create.py | 7 +++- tools/python/xen/xm/xenapi_create.py | 2 +- xen/arch/x86/domain.c | 2 +- xen/arch/x86/hvm/hvm.c | 14 +++++--- xen/arch/x86/hvm/vlapic.c | 13 +++++-- xen/arch/x86/hvm/vpt.c | 47 +++++++++++++++++-------- xen/include/asm-x86/hvm/hvm.h | 6 ++-- xen/include/asm-x86/hvm/vpt.h | 4 +-- xen/include/public/hvm/params.h | 20 +++++++++-- 12 files changed, 91 insertions(+), 32 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 54b29ddc23..9debec185e 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -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. diff --git a/tools/python/xen/xend/XendConstants.py b/tools/python/xen/xend/XendConstants.py index befabb4e16..ecf911c141 100644 --- a/tools/python/xen/xend/XendConstants.py +++ b/tools/python/xen/xend/XendConstants.py @@ -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", diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index d07926bb7d..d3a8623f6b 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -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'])) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index b9bd16258d..b90e29d286 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -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', diff --git a/tools/python/xen/xm/xenapi_create.py b/tools/python/xen/xm/xenapi_create.py index 8140ca35c5..29ef6efb70 100644 --- a/tools/python/xen/xm/xenapi_create.py +++ b/tools/python/xen/xm/xenapi_create.py @@ -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") diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 295ad77145..e874ad7eb2 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -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); diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 908cd1c47f..84ede3fe82 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -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; diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index cc63c89df3..fafc85f7c7 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -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, " diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c index 743f19eaa0..9ce8991594 100644 --- a/xen/arch/x86/hvm/vpt.c +++ b/xen/arch/x86/hvm/vpt.c @@ -23,6 +23,12 @@ #include #include +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; diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 52a59fc463..0a2983a850 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -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)) diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h index 1327235c6c..4471fd990d 100644 --- a/xen/include/asm-x86/hvm/vpt.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -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); diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h index 36dfdb2ee1..dbf2fb0b44 100644 --- a/xen/include/public/hvm/params.h +++ b/xen/include/public/hvm/params.h @@ -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__ */ -- 2.30.2