aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--tools/firmware/hvmloader/hvmloader.c12
-rw-r--r--tools/firmware/hvmloader/mp_tables.c40
-rw-r--r--xen/arch/x86/hvm/vioapic.c17
-rw-r--r--xen/arch/x86/hvm/vlapic.c44
-rw-r--r--xen/arch/x86/hvm/vpic.c8
-rw-r--r--xen/include/asm-x86/hvm/domain.h3
-rw-r--r--xen/include/asm-x86/hvm/vlapic.h2
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);