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 | |
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>
-rw-r--r-- | tools/firmware/hvmloader/hvmloader.c | 12 | ||||
-rw-r--r-- | tools/firmware/hvmloader/mp_tables.c | 40 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vioapic.c | 17 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vlapic.c | 44 | ||||
-rw-r--r-- | xen/arch/x86/hvm/vpic.c | 8 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/domain.h | 3 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/vlapic.h | 2 |
7 files changed, 83 insertions, 43 deletions
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index fef315821d..e42f0f74d1 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -141,13 +141,17 @@ static void init_hypercalls(void) static void apic_setup(void) { - /* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */ + /* Set the IOAPIC ID to the static value used in the MP/ACPI tables. */ ioapic_write(0x00, IOAPIC_ID); - /* Set up Virtual Wire mode. */ + /* NMIs are delivered direct to the BSP. */ lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF); - lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8); - lapic_write(APIC_LVT1, APIC_MODE_NMI << 8); + lapic_write(APIC_LVT0, (APIC_MODE_EXTINT << 8) | APIC_LVT_MASKED); + lapic_write(APIC_LVT1, APIC_MODE_NMI << 8); + + /* 8259A ExtInts are delivered through IOAPIC pin 0 (Virtual Wire Mode). */ + ioapic_write(0x10, APIC_DM_EXTINT); + ioapic_write(0x11, SET_APIC_ID(LAPIC_ID(0))); } static void pci_setup(void) diff --git a/tools/firmware/hvmloader/mp_tables.c b/tools/firmware/hvmloader/mp_tables.c index ad09edafa0..2a07b4ce72 100644 --- a/tools/firmware/hvmloader/mp_tables.c +++ b/tools/firmware/hvmloader/mp_tables.c @@ -233,21 +233,6 @@ static void fill_mp_ioapic_entry(struct mp_ioapic_entry *mpie) } -/* fills in an IO interrupt entry for IOAPIC 'ioapic_id' */ -static void fill_mp_io_intr_entry( - struct mp_io_intr_entry *mpiie, - int src_bus_id, int src_bus_irq, int ioapic_id, int dst_ioapic_intin) -{ - mpiie->type = ENTRY_TYPE_IO_INTR; - mpiie->intr_type = INTR_TYPE_INT; - mpiie->io_intr_flags = (PCI_ISA_IRQ_MASK & (1U<<src_bus_irq)) ? 0xf : 0x0; - mpiie->src_bus_id = src_bus_id; - mpiie->src_bus_irq = src_bus_irq; - mpiie->dst_ioapic_id = ioapic_id; - mpiie->dst_ioapic_intin = dst_ioapic_intin; -} - - /* fill in the mp floating processor structure */ static void fill_mpfps(struct mp_floating_pointer_struct *mpfps, uint32_t mpct) { @@ -316,6 +301,7 @@ void create_mp_tables(void) void *mp_table_base; char *p; int vcpu_nr, i, length; + struct mp_io_intr_entry *mpiie; vcpu_nr = hvm_info->nr_vcpus; @@ -343,12 +329,28 @@ void create_mp_tables(void) fill_mp_ioapic_entry((struct mp_ioapic_entry *)p); p += sizeof(struct mp_ioapic_entry); + /* I/O interrupt assignment: IOAPIC pin 0 is connected to 8259 ExtInt. */ + mpiie = (struct mp_io_intr_entry *)p; + memset(mpiie, 0, sizeof(*mpiie)); + mpiie->type = ENTRY_TYPE_IO_INTR; + mpiie->intr_type = INTR_TYPE_EXTINT; + mpiie->dst_ioapic_id = IOAPIC_ID; + p += sizeof(*mpiie); + + /* I/O interrupt assignment for every legacy 8259 interrupt source. */ for ( i = 0; i < 16; i++ ) { - if ( i == 2 ) continue; /* skip the slave PIC connection */ - fill_mp_io_intr_entry((struct mp_io_intr_entry *)p, - BUS_ID_ISA, i, IOAPIC_ID, (i == 0) ? 2 : i); - p += sizeof(struct mp_io_intr_entry); + if ( i == 2 ) + continue; /* skip the slave PIC connection */ + mpiie = (struct mp_io_intr_entry *)p; + mpiie->type = ENTRY_TYPE_IO_INTR; + mpiie->intr_type = INTR_TYPE_EXTINT; + mpiie->io_intr_flags = (PCI_ISA_IRQ_MASK & (1U << i)) ? 0xf : 0x0; + mpiie->src_bus_id = BUS_ID_ISA; + mpiie->src_bus_irq = i; + mpiie->dst_ioapic_id = IOAPIC_ID; + mpiie->dst_ioapic_intin = (i == 0) ? 2 : i; + p += sizeof(*mpiie); } length = p - (char *)mp_table_base; diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index 4860b74941..9afbe75655 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -146,10 +146,14 @@ static void vioapic_write_redirent( *pent = ent; - if ( (ent.fields.trig_mode == VIOAPIC_LEVEL_TRIG) && - !ent.fields.mask && - !ent.fields.remote_irr && - hvm_irq->gsi_assert_count[idx] ) + if ( idx == 0 ) + { + vlapic_adjust_i8259_target(d); + } + else if ( (ent.fields.trig_mode == VIOAPIC_LEVEL_TRIG) && + !ent.fields.mask && + !ent.fields.remote_irr && + hvm_irq->gsi_assert_count[idx] ) { pent->fields.remote_irr = 1; vioapic_deliver(vioapic, idx); @@ -159,8 +163,7 @@ static void vioapic_write_redirent( } static void vioapic_write_indirect( - struct hvm_hw_vioapic *vioapic, unsigned long addr, - unsigned long length, unsigned long val) + struct hvm_hw_vioapic *vioapic, unsigned long length, unsigned long val) { switch ( vioapic->ioregsel ) { @@ -213,7 +216,7 @@ static int vioapic_write( break; case VIOAPIC_REG_WINDOW: - vioapic_write_indirect(vioapic, addr, length, val); + vioapic_write_indirect(vioapic, length, val); break; #if VIOAPIC_IS_IOSAPIC 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; } diff --git a/xen/arch/x86/hvm/vpic.c b/xen/arch/x86/hvm/vpic.c index 5d320d4f82..81bfac5db7 100644 --- a/xen/arch/x86/hvm/vpic.c +++ b/xen/arch/x86/hvm/vpic.c @@ -109,11 +109,9 @@ static void vpic_update_int_output(struct hvm_hw_vpic *vpic) { if ( vpic->is_master ) { - /* Master INT line is connected to VCPU0's VLAPIC LVT0. */ - struct vcpu *v = vpic_domain(vpic)->vcpu ? - vpic_domain(vpic)->vcpu[0] : NULL; - - if ( (v != NULL) && vlapic_accept_pic_intr(v) ) + /* Master INT line is connected in Virtual Wire Mode. */ + struct vcpu *v = vpic_domain(vpic)->arch.hvm_domain.i8259_target; + if ( v != NULL ) vcpu_kick(v); } else diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index 5c7230487c..643eac8fd0 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -57,6 +57,9 @@ struct hvm_domain { struct hvm_vioapic *vioapic; struct hvm_hw_stdvga stdvga; + /* VCPU which is current target for 8259 interrupts. */ + struct vcpu *i8259_target; + /* hvm_print_line() logging. */ char pbuf[80]; int pbuf_idx; diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index 8c36ed5a00..64979a7668 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -93,6 +93,8 @@ void vlapic_msr_set(struct vlapic *vlapic, uint64_t value); int vlapic_accept_pic_intr(struct vcpu *v); +void vlapic_adjust_i8259_target(struct domain *d); + struct vlapic *apic_lowest_prio(struct domain *d, uint32_t bitmap); int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda); |