From 0780df2a52fe136496ffc250e6dbca07b95b904c Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Wed, 20 Oct 2010 17:26:51 +0100 Subject: [PATCH] x86 hvm: When sending INIT-SIPI IPIs, pause the sending vcpu until the asynchronous tasklet completes its work. This is a little bit cleaner than busy-spinning in a retry loop. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vlapic.c | 49 +++++++++++++++++++++----------- xen/include/asm-x86/hvm/vlapic.h | 7 +++-- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 3274d4deda..3b94ca96a8 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -230,29 +230,29 @@ bool_t vlapic_match_dest( static void vlapic_init_sipi_action(unsigned long _vcpu) { - struct vcpu *v = (struct vcpu *)_vcpu; - struct domain *d = v->domain; - uint32_t icr = vcpu_vlapic(v)->init_sipi_tasklet_icr; + struct vcpu *origin = (struct vcpu *)_vcpu; + struct vcpu *target = vcpu_vlapic(origin)->init_sipi.target; + uint32_t icr = vcpu_vlapic(origin)->init_sipi.icr; - vcpu_pause(v); + vcpu_pause(target); switch ( icr & APIC_MODE_MASK ) { case APIC_DM_INIT: { bool_t fpu_initialised; - domain_lock(d); + domain_lock(target->domain); /* Reset necessary VCPU state. This does not include FPU state. */ - fpu_initialised = v->fpu_initialised; - vcpu_reset(v); - v->fpu_initialised = fpu_initialised; - vlapic_reset(vcpu_vlapic(v)); - domain_unlock(d); + fpu_initialised = target->fpu_initialised; + vcpu_reset(target); + target->fpu_initialised = fpu_initialised; + vlapic_reset(vcpu_vlapic(target)); + domain_unlock(target->domain); break; } case APIC_DM_STARTUP: { uint16_t reset_cs = (icr & 0xffu) << 8; - hvm_vcpu_reset_state(v, reset_cs, 0); + hvm_vcpu_reset_state(target, reset_cs, 0); break; } @@ -260,13 +260,28 @@ static void vlapic_init_sipi_action(unsigned long _vcpu) BUG(); } - vcpu_unpause(v); + vcpu_unpause(target); + + vcpu_vlapic(origin)->init_sipi.target = NULL; + vcpu_unpause(origin); } -static int vlapic_schedule_init_sipi_tasklet(struct vcpu *v, uint32_t icr) +static int vlapic_schedule_init_sipi_tasklet(struct vcpu *target, uint32_t icr) { - vcpu_vlapic(v)->init_sipi_tasklet_icr = icr; - tasklet_schedule(&vcpu_vlapic(v)->init_sipi_tasklet); + struct vcpu *origin = current; + + if ( vcpu_vlapic(origin)->init_sipi.target != NULL ) + { + WARN(); /* should be impossible but don't BUG, just in case */ + return X86EMUL_UNHANDLEABLE; + } + + vcpu_pause_nosync(origin); + + vcpu_vlapic(origin)->init_sipi.target = target; + vcpu_vlapic(origin)->init_sipi.icr = icr; + tasklet_schedule(&vcpu_vlapic(origin)->init_sipi.tasklet); + return X86EMUL_RETRY; } @@ -990,7 +1005,7 @@ int vlapic_init(struct vcpu *v) if ( v->vcpu_id == 0 ) vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP; - tasklet_init(&vlapic->init_sipi_tasklet, + tasklet_init(&vlapic->init_sipi.tasklet, vlapic_init_sipi_action, (unsigned long)v); @@ -1001,7 +1016,7 @@ void vlapic_destroy(struct vcpu *v) { struct vlapic *vlapic = vcpu_vlapic(v); - tasklet_kill(&vlapic->init_sipi_tasklet); + tasklet_kill(&vlapic->init_sipi.tasklet); destroy_periodic_time(&vlapic->pt); unmap_domain_page_global(vlapic->regs); free_domheap_page(vlapic->regs_page); diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index eda970f780..905fff8dae 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -59,8 +59,11 @@ struct vlapic { s_time_t timer_last_update; struct page_info *regs_page; /* INIT-SIPI-SIPI work gets deferred to a tasklet. */ - uint32_t init_sipi_tasklet_icr; - struct tasklet init_sipi_tasklet; + struct { + struct vcpu *target; + uint32_t icr; + struct tasklet tasklet; + } init_sipi; }; static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg) -- 2.30.2