aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/vlapic.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-07-01 20:22:29 +0100
committerKeir Fraser <keir.fraser@citrix.com>2009-07-01 20:22:29 +0100
commit89c6cf58e8adffa03ae33da6af2a5590a5d03054 (patch)
tree477b72d6e1f18fec540c23c585b7a0db5b4cb1ec /xen/arch/x86/hvm/vlapic.c
parent70116ff26048b92a3a2e808806a79d6fb44505aa (diff)
downloadxen-89c6cf58e8adffa03ae33da6af2a5590a5d03054.tar.gz
xen-89c6cf58e8adffa03ae33da6af2a5590a5d03054.tar.bz2
xen-89c6cf58e8adffa03ae33da6af2a5590a5d03054.zip
x86 hvm: Allow delivery of legacy 8259 interrupts to VCPUs != 0.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/hvm/vlapic.c')
-rw-r--r--xen/arch/x86/hvm/vlapic.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c
index fd353c9342..cfa6ecf95e 100644
--- a/xen/arch/x86/hvm/vlapic.c
+++ b/xen/arch/x86/hvm/vlapic.c
@@ -697,6 +697,8 @@ static int vlapic_write(struct vcpu *v, unsigned long address,
val |= APIC_LVT_MASKED;
val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
vlapic_set_reg(vlapic, offset, val);
+ if ( offset == APIC_LVT0 )
+ vlapic_adjust_i8259_target(v->domain);
break;
case APIC_TMICT:
@@ -776,20 +778,45 @@ void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
"apic base msr is 0x%016"PRIx64, vlapic->hw.apic_base_msr);
}
-int vlapic_accept_pic_intr(struct vcpu *v)
+static int __vlapic_accept_pic_intr(struct vcpu *v)
{
+ struct domain *d = v->domain;
struct vlapic *vlapic = vcpu_vlapic(v);
uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
-
- /*
- * Only CPU0 is wired to the 8259A. INTA cycles occur if LINT0 is set up
- * accept ExtInts, or if the LAPIC is disabled (so LINT0 behaves as INTR).
- */
- return ((v->vcpu_id == 0) &&
- (((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
+ union vioapic_redir_entry redir0 = domain_vioapic(d)->redirtbl[0];
+
+ /* We deliver 8259 interrupts to the appropriate CPU as follows. */
+ return ((/* IOAPIC pin0 is unmasked and routing to this LAPIC? */
+ ((redir0.fields.delivery_mode == dest_ExtINT) &&
+ !redir0.fields.mask &&
+ redir0.fields.dest_id == VLAPIC_ID(vlapic) &&
+ !vlapic_disabled(vlapic)) ||
+ /* LAPIC has LVT0 unmasked for ExtInts? */
+ ((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
+ /* LAPIC is fully disabled? */
vlapic_hw_disabled(vlapic)));
}
+int vlapic_accept_pic_intr(struct vcpu *v)
+{
+ return ((v == v->domain->arch.hvm_domain.i8259_target) &&
+ __vlapic_accept_pic_intr(v));
+}
+
+void vlapic_adjust_i8259_target(struct domain *d)
+{
+ struct vcpu *v;
+
+ for_each_vcpu ( d, v )
+ if ( __vlapic_accept_pic_intr(v) )
+ goto found;
+
+ v = d->vcpu ? d->vcpu[0] : NULL;
+
+ found:
+ d->arch.hvm_domain.i8259_target = v;
+}
+
int vlapic_has_pending_irq(struct vcpu *v)
{
struct vlapic *vlapic = vcpu_vlapic(v);
@@ -946,6 +973,7 @@ static int lapic_load_regs(struct domain *d, hvm_domain_context_t *h)
if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 )
return -EINVAL;
+ vlapic_adjust_i8259_target(d);
lapic_rearm(s);
return 0;
}