aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/vlapic.c
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2010-10-20 17:26:51 +0100
committerKeir Fraser <keir@xen.org>2010-10-20 17:26:51 +0100
commit0780df2a52fe136496ffc250e6dbca07b95b904c (patch)
tree0051a62155ad8fcc442b8b674bd9d440d775ee02 /xen/arch/x86/hvm/vlapic.c
parentda7abb1417a92981a356abcb3a8fa85c97dfff31 (diff)
downloadxen-0780df2a52fe136496ffc250e6dbca07b95b904c.tar.gz
xen-0780df2a52fe136496ffc250e6dbca07b95b904c.tar.bz2
xen-0780df2a52fe136496ffc250e6dbca07b95b904c.zip
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 <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/hvm/vlapic.c')
-rw-r--r--xen/arch/x86/hvm/vlapic.c49
1 files changed, 32 insertions, 17 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);