[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 3/5] x86/vioapic: introduce support for multiple vIO APICS
Add support for multiple vIO APICs on the same domain, thus turning d->arch.hvm_domain.vioapic into an array of vIO APIC control structures. Note that this functionality is not exposed to unprivileged guests, and will only be used by PVHv2 Dom0. Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> --- Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- xen/arch/x86/domain_build.c | 2 +- xen/arch/x86/hvm/vioapic.c | 204 +++++++++++++++++++++++++++----------- xen/arch/x86/hvm/vlapic.c | 2 +- xen/arch/x86/hvm/vpt.c | 13 ++- xen/include/asm-x86/hvm/domain.h | 1 + xen/include/asm-x86/hvm/vioapic.h | 4 +- 6 files changed, 160 insertions(+), 66 deletions(-) diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 932fa4e..dad3b4e 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -2317,7 +2317,7 @@ static int __init pvh_setup_acpi_madt(struct domain *d, paddr_t *addr) io_apic = (void *)(madt + 1); io_apic->header.type = ACPI_MADT_TYPE_IO_APIC; io_apic->header.length = sizeof(*io_apic); - io_apic->id = domain_vioapic(d)->id; + io_apic->id = domain_vioapic(d, 0)->id; io_apic->address = VIOAPIC_DEFAULT_BASE_ADDRESS; x2apic = (void *)(io_apic + 1); diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index f469cbf..6421971 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -44,6 +44,56 @@ static void vioapic_deliver(struct domain *d, int irq); +static struct hvm_hw_vioapic *addr_vioapic(struct domain *d, + unsigned long addr) +{ + unsigned int i; + + for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ ) + { + struct hvm_hw_vioapic *vioapic = domain_vioapic(d, i); + + if ( addr >= vioapic->base_address && + addr < vioapic->base_address + VIOAPIC_MEM_LENGTH ) + return vioapic; + } + + return NULL; +} + +struct hvm_hw_vioapic *gsi_vioapic(struct domain *d, unsigned int gsi, + unsigned int *pin) +{ + unsigned int i, base_gsi = 0; + + for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ ) + { + struct hvm_hw_vioapic *vioapic = domain_vioapic(d, i); + + if ( gsi >= base_gsi && gsi < base_gsi + vioapic->nr_pins ) + { + if ( pin != NULL ) + *pin = gsi - base_gsi; + return vioapic; + } + base_gsi += vioapic->nr_pins; + } + + return NULL; +} + +static unsigned int pin_gsi(struct domain *d, struct hvm_hw_vioapic *vioapic, + unsigned int pin) +{ + struct hvm_hw_vioapic *tmp; + unsigned int base_gsi = 0; + + for ( tmp = domain_vioapic(d, 0); tmp != vioapic; tmp++ ) + base_gsi += tmp->nr_pins; + + return base_gsi + pin; +} + static uint32_t vioapic_read_indirect(const struct hvm_hw_vioapic *vioapic) { uint32_t result = 0; @@ -94,11 +144,14 @@ static int vioapic_read( struct vcpu *v, unsigned long addr, unsigned int length, unsigned long *pval) { - const struct hvm_hw_vioapic *vioapic = domain_vioapic(v->domain); + const struct hvm_hw_vioapic *vioapic; uint32_t result; HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "addr %lx", addr); + vioapic = addr_vioapic(v->domain, addr); + ASSERT(vioapic); + switch ( addr & 0xff ) { case VIOAPIC_REG_SELECT: @@ -119,13 +172,13 @@ static int vioapic_read( } static void vioapic_write_redirent( - struct domain *d, unsigned int idx, + struct domain *d, struct hvm_hw_vioapic *vioapic, unsigned int idx, int top_word, uint32_t val) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; union vioapic_redir_entry *pent, ent; int unmasked = 0; + unsigned int gsi = pin_gsi(d, vioapic, idx); spin_lock(&d->arch.hvm_domain.irq_lock); @@ -149,7 +202,7 @@ static void vioapic_write_redirent( *pent = ent; - if ( idx == 0 ) + if ( gsi == 0 ) { vlapic_adjust_i8259_target(d); } @@ -157,21 +210,22 @@ static void vioapic_write_redirent( pent->fields.remote_irr = 0; else if ( !ent.fields.mask && !ent.fields.remote_irr && - hvm_irq->gsi_assert_count[idx] ) + hvm_irq->gsi_assert_count[gsi] ) { pent->fields.remote_irr = 1; - vioapic_deliver(d, idx); + vioapic_deliver(d, gsi); } spin_unlock(&d->arch.hvm_domain.irq_lock); - if ( idx == 0 || unmasked ) + if ( gsi == 0 || unmasked ) pt_may_unmask_irq(d, NULL); } -static void vioapic_write_indirect(struct domain *d, uint32_t val) +static void vioapic_write_indirect(struct domain *d, unsigned long addr, + uint32_t val) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); + struct hvm_hw_vioapic *vioapic = addr_vioapic(d, addr); switch ( vioapic->ioregsel ) { @@ -205,7 +259,8 @@ static void vioapic_write_indirect(struct domain *d, uint32_t val) break; } - vioapic_write_redirent(d, redir_index, vioapic->ioregsel&1, val); + vioapic_write_redirent(d, vioapic, redir_index, vioapic->ioregsel&1, + val); break; } } @@ -215,7 +270,10 @@ static int vioapic_write( struct vcpu *v, unsigned long addr, unsigned int length, unsigned long val) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(v->domain); + struct hvm_hw_vioapic *vioapic; + + vioapic = addr_vioapic(v->domain, addr); + ASSERT(vioapic); switch ( addr & 0xff ) { @@ -224,7 +282,7 @@ static int vioapic_write( break; case VIOAPIC_REG_WINDOW: - vioapic_write_indirect(v->domain, val); + vioapic_write_indirect(v->domain, addr, val); break; #if VIOAPIC_VERSION_ID >= 0x20 @@ -242,10 +300,7 @@ static int vioapic_write( static int vioapic_range(struct vcpu *v, unsigned long addr) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(v->domain); - - return ((addr >= vioapic->base_address && - (addr < vioapic->base_address + VIOAPIC_MEM_LENGTH))); + return !!addr_vioapic(v->domain, addr); } static const struct hvm_mmio_ops vioapic_mmio_ops = { @@ -277,12 +332,13 @@ static inline int pit_channel0_enabled(void) static void vioapic_deliver(struct domain *d, int irq) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); - uint16_t dest = vioapic->redirtbl[irq].fields.dest_id; - uint8_t dest_mode = vioapic->redirtbl[irq].fields.dest_mode; - uint8_t delivery_mode = vioapic->redirtbl[irq].fields.delivery_mode; - uint8_t vector = vioapic->redirtbl[irq].fields.vector; - uint8_t trig_mode = vioapic->redirtbl[irq].fields.trig_mode; + unsigned int pin; + struct hvm_hw_vioapic *vioapic = gsi_vioapic(d, irq, &pin); + uint16_t dest = vioapic->redirtbl[pin].fields.dest_id; + uint8_t dest_mode = vioapic->redirtbl[pin].fields.dest_mode; + uint8_t delivery_mode = vioapic->redirtbl[pin].fields.delivery_mode; + uint8_t vector = vioapic->redirtbl[pin].fields.vector; + uint8_t trig_mode = vioapic->redirtbl[pin].fields.trig_mode; struct vlapic *target; struct vcpu *v; @@ -361,17 +417,18 @@ static void vioapic_deliver(struct domain *d, int irq) void vioapic_irq_positive_edge(struct domain *d, unsigned int irq) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); + unsigned int pin; + struct hvm_hw_vioapic *vioapic = gsi_vioapic(d, irq, &pin); union vioapic_redir_entry *ent; ASSERT(has_vioapic(d)); HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "irq %x", irq); - ASSERT(irq < vioapic->nr_pins); + ASSERT(pin < vioapic->nr_pins); ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock)); - ent = &vioapic->redirtbl[irq]; + ent = &vioapic->redirtbl[pin]; if ( ent->fields.mask ) return; @@ -388,37 +445,43 @@ void vioapic_irq_positive_edge(struct domain *d, unsigned int irq) void vioapic_update_EOI(struct domain *d, u8 vector) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; union vioapic_redir_entry *ent; - int gsi; + unsigned int i, base_gsi = 0; ASSERT(has_vioapic(d)); spin_lock(&d->arch.hvm_domain.irq_lock); - for ( gsi = 0; gsi < vioapic->nr_pins; gsi++ ) + for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ ) { - ent = &vioapic->redirtbl[gsi]; - if ( ent->fields.vector != vector ) - continue; - - ent->fields.remote_irr = 0; + struct hvm_hw_vioapic *vioapic = domain_vioapic(d, i); + unsigned int j; - if ( iommu_enabled ) + for ( j = 0; j < vioapic->nr_pins; j++ ) { - spin_unlock(&d->arch.hvm_domain.irq_lock); - hvm_dpci_eoi(d, gsi, ent); - spin_lock(&d->arch.hvm_domain.irq_lock); - } - - if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) && - !ent->fields.mask && - hvm_irq->gsi_assert_count[gsi] ) - { - ent->fields.remote_irr = 1; - vioapic_deliver(d, gsi); + ent = &vioapic->redirtbl[j]; + if ( ent->fields.vector != vector ) + continue; + + ent->fields.remote_irr = 0; + + if ( iommu_enabled ) + { + spin_unlock(&d->arch.hvm_domain.irq_lock); + hvm_dpci_eoi(d, base_gsi + j, ent); + spin_lock(&d->arch.hvm_domain.irq_lock); + } + + if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) && + !ent->fields.mask && + hvm_irq->gsi_assert_count[base_gsi + j] ) + { + ent->fields.remote_irr = 1; + vioapic_deliver(d, base_gsi + j); + } } + base_gsi += vioapic->nr_pins; } spin_unlock(&d->arch.hvm_domain.irq_lock); @@ -430,11 +493,14 @@ void vioapic_update_EOI(struct domain *d, u8 vector) static int vioapic_save(struct domain *d, hvm_domain_context_t *h) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); + struct hvm_hw_vioapic *vioapic = domain_vioapic(d, 0); if ( !has_vioapic(d) ) return 0; + if ( d->arch.hvm_domain.nr_vioapics != 1 ) + return -ENOSYS; + if ( vioapic->nr_pins != VIOAPIC_NUM_PINS ) return -ENOSYS; @@ -456,7 +522,7 @@ static int vioapic_load(struct domain *d, hvm_domain_context_t *h) unsigned int ioapic_nr = hvm_load_instance(h); const struct hvm_save_descriptor *desc; struct hvm_hw_vioapic_compat *ioapic_compat; - struct hvm_hw_vioapic *ioapic = domain_vioapic(d); + struct hvm_hw_vioapic *ioapic = domain_vioapic(d, 0); if ( !has_vioapic(d) ) return -ENODEV; @@ -546,40 +612,53 @@ __initcall(vioapic_register_save_and_restore); void vioapic_reset(struct domain *d) { - struct hvm_hw_vioapic *vioapic = domain_vioapic(d); unsigned int i; if ( !has_vioapic(d) ) + { + ASSERT(!d->arch.hvm_domain.nr_vioapics); return; + } - memset(vioapic->redirtbl, 0, - sizeof(*vioapic->redirtbl) * vioapic->nr_pins); - for ( i = 0; i < vioapic->nr_pins; i++ ) - vioapic->redirtbl[i].fields.mask = 1; - vioapic->base_address = VIOAPIC_DEFAULT_BASE_ADDRESS; - vioapic->id = 0; - vioapic->ioregsel = 0; + for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ ) + { + struct hvm_hw_vioapic *vioapic = domain_vioapic(d, i); + unsigned int j; + + memset(vioapic->redirtbl, 0, + sizeof(*vioapic->redirtbl) * vioapic->nr_pins); + for ( j = 0; j < vioapic->nr_pins; j++ ) + vioapic->redirtbl[j].fields.mask = 1; + vioapic->base_address = VIOAPIC_DEFAULT_BASE_ADDRESS + + VIOAPIC_MEM_LENGTH * i; + vioapic->id = i; + vioapic->ioregsel = 0; + } } int vioapic_init(struct domain *d) { if ( !has_vioapic(d) ) + { + d->arch.hvm_domain.nr_vioapics = 0; return 0; + } if ( (d->arch.hvm_domain.vioapic == NULL) && ((d->arch.hvm_domain.vioapic = xmalloc(struct hvm_hw_vioapic)) == NULL) ) return -ENOMEM; - domain_vioapic(d)->redirtbl = xmalloc_array(union vioapic_redir_entry, - VIOAPIC_NUM_PINS); - if ( !domain_vioapic(d)->redirtbl ) + domain_vioapic(d, 0)->redirtbl = xmalloc_array(union vioapic_redir_entry, + VIOAPIC_NUM_PINS); + if ( !domain_vioapic(d, 0)->redirtbl ) { xfree(d->arch.hvm_domain.vioapic); return -ENOMEM; } - domain_vioapic(d)->nr_pins = VIOAPIC_NUM_PINS; + domain_vioapic(d, 0)->nr_pins = VIOAPIC_NUM_PINS; + d->arch.hvm_domain.nr_vioapics = 1; vioapic_reset(d); register_mmio_handler(d, &vioapic_mmio_ops); @@ -589,9 +668,16 @@ int vioapic_init(struct domain *d) void vioapic_deinit(struct domain *d) { + unsigned int i; + if ( !has_vioapic(d) ) + { + ASSERT(!d->arch.hvm_domain.nr_vioapics); return; + } + for ( i = 0; i < d->arch.hvm_domain.nr_vioapics; i++ ) + xfree(domain_vioapic(d, i)->redirtbl); xfree(d->arch.hvm_domain.vioapic); d->arch.hvm_domain.vioapic = NULL; } diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 3fa3727..187f106 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -1120,7 +1120,7 @@ static int __vlapic_accept_pic_intr(struct vcpu *v) if ( !has_vioapic(d) ) return 0; - redir0 = domain_vioapic(d)->redirtbl[0]; + redir0 = domain_vioapic(d, 0)->redirtbl[0]; /* We deliver 8259 interrupts to the appropriate CPU as follows. */ return ((/* IOAPIC pin0 is unmasked and routing to this LAPIC? */ diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c index 5c48fdb..fd30dfb 100644 --- a/xen/arch/x86/hvm/vpt.c +++ b/xen/arch/x86/hvm/vpt.c @@ -78,7 +78,8 @@ void hvm_set_guest_time(struct vcpu *v, u64 guest_time) static int pt_irq_vector(struct periodic_time *pt, enum hvm_intsrc src) { struct vcpu *v = pt->vcpu; - unsigned int gsi, isa_irq; + struct hvm_hw_vioapic *vioapic; + unsigned int gsi, isa_irq, pin; if ( pt->source == PTSRC_lapic ) return pt->irq; @@ -91,13 +92,16 @@ static int pt_irq_vector(struct periodic_time *pt, enum hvm_intsrc src) + (isa_irq & 7)); ASSERT(src == hvm_intsrc_lapic); - return domain_vioapic(v->domain)->redirtbl[gsi].fields.vector; + vioapic = gsi_vioapic(v->domain, gsi, &pin); + + return vioapic->redirtbl[pin].fields.vector; } static int pt_irq_masked(struct periodic_time *pt) { struct vcpu *v = pt->vcpu; - unsigned int gsi, isa_irq; + unsigned int gsi, isa_irq, pin; + struct hvm_hw_vioapic *vioapic; uint8_t pic_imr; if ( pt->source == PTSRC_lapic ) @@ -110,9 +114,10 @@ static int pt_irq_masked(struct periodic_time *pt) isa_irq = pt->irq; gsi = hvm_isa_irq_to_gsi(isa_irq); pic_imr = v->domain->arch.hvm_domain.vpic[isa_irq >> 3].imr; + vioapic = gsi_vioapic(v->domain, gsi, &pin); return (((pic_imr & (1 << (isa_irq & 7))) || !vlapic_accept_pic_intr(v)) && - domain_vioapic(v->domain)->redirtbl[gsi].fields.mask); + vioapic->redirtbl[pin].fields.mask); } static void pt_lock(struct periodic_time *pt) diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index 5cf3398..cf1be37 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -128,6 +128,7 @@ struct hvm_domain { struct hvm_irq irq; struct hvm_hw_vpic vpic[2]; /* 0=master; 1=slave */ struct hvm_hw_vioapic *vioapic; + unsigned int nr_vioapics; struct hvm_hw_stdvga stdvga; /* diff --git a/xen/include/asm-x86/hvm/vioapic.h b/xen/include/asm-x86/hvm/vioapic.h index 6762835..6889b57 100644 --- a/xen/include/asm-x86/hvm/vioapic.h +++ b/xen/include/asm-x86/hvm/vioapic.h @@ -47,7 +47,9 @@ #define VIOAPIC_REG_ARB_ID 0x02 /* x86 IOAPIC only */ #define VIOAPIC_REG_RTE0 0x10 -#define domain_vioapic(d) ((d)->arch.hvm_domain.vioapic) +#define domain_vioapic(d, i) (&(d)->arch.hvm_domain.vioapic[i]) +struct hvm_hw_vioapic *gsi_vioapic(struct domain *d, unsigned int gsi, + unsigned int *pin); int vioapic_init(struct domain *d); void vioapic_deinit(struct domain *d); -- 2.10.1 (Apple Git-78) _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |