diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2009-07-01 20:22:29 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2009-07-01 20:22:29 +0100 |
commit | 89c6cf58e8adffa03ae33da6af2a5590a5d03054 (patch) | |
tree | 477b72d6e1f18fec540c23c585b7a0db5b4cb1ec /xen/arch/x86/hvm/vlapic.c | |
parent | 70116ff26048b92a3a2e808806a79d6fb44505aa (diff) | |
download | xen-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.c | 44 |
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; } |