To follow correctly what our bios ACPI tables say, we have to be able to program our irqchips with GSI routing mappings. This support is already in qemu-kvm
Signed-off-by: Glauber Costa <glom...@redhat.com> --- kvm-all.c | 6 ++- kvm.h | 3 + target-i386/kvm.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-) diff --git a/kvm-all.c b/kvm-all.c index 7a3671f..cf10abe 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -66,6 +66,8 @@ struct KVMState #endif int irqchip_in_kernel; int pit_in_kernel; + + KVMArchState *arch_state; }; static KVMState *kvm_state; @@ -539,12 +541,12 @@ int kvm_init(int smp_cpus) if (ret < 0) goto err; + kvm_state = s; + ret = kvm_arch_init(s, smp_cpus); if (ret < 0) goto err; - kvm_state = s; - return 0; err: diff --git a/kvm.h b/kvm.h index c5a0915..15df381 100644 --- a/kvm.h +++ b/kvm.h @@ -72,7 +72,10 @@ int kvm_set_irq(int irq, int level, int *status); /* internal API */ struct KVMState; +struct KVMArchState; + typedef struct KVMState KVMState; +typedef struct KVMArchState KVMArchState; int kvm_ioctl(KVMState *s, int type, ...); diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0224818..8439f2f 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -36,6 +36,16 @@ #ifdef KVM_CAP_EXT_CPUID +struct KVMArchState +{ + struct kvm_irq_routing *irq_routes; + int nr_allocated_irq_routes; + void *used_gsi_bitmap; + int max_gsi; +}; + +static KVMArchState *kvm_arch_state; + static struct kvm_cpuid2 *try_get_cpuid(KVMState *s, int max) { struct kvm_cpuid2 *cpuid; @@ -266,10 +276,118 @@ static int kvm_has_msr_star(CPUState *env) return 0; } +/* + * Setup x86 specific IRQ routing + */ +static inline void set_gsi(KVMArchState *s, unsigned int gsi) +{ + uint32_t *bitmap = s->used_gsi_bitmap; + + if (gsi < s->max_gsi) + bitmap[gsi / 32] |= 1U << (gsi % 32); + else + fprintf(stderr, "Invalid GSI %d\n", gsi); +} + +static int kvm_add_routing_entry(KVMArchState *s, struct kvm_irq_routing_entry *entry) +{ + struct kvm_irq_routing *z; + struct kvm_irq_routing_entry *new; + int n, size; + + if (s->irq_routes->nr == s->nr_allocated_irq_routes) { + n = s->nr_allocated_irq_routes * 2; + if (n < 64) + n = 64; + size = sizeof(struct kvm_irq_routing); + size += n * sizeof(*new); + z = realloc(s->irq_routes, size); + if (!z) + return -ENOMEM; + s->nr_allocated_irq_routes = n; + s->irq_routes = z; + } + n = s->irq_routes->nr++; + new = &s->irq_routes->entries[n]; + memset(new, 0, sizeof(*new)); + new->gsi = entry->gsi; + new->type = entry->type; + new->flags = entry->flags; + new->u = entry->u; + + set_gsi(s, entry->gsi); + + return 0; +} + +static int kvm_add_irq_route(KVMArchState *s, int gsi, int irqchip, int pin) +{ + struct kvm_irq_routing_entry e; + + e.gsi = gsi; + e.type = KVM_IRQ_ROUTING_IRQCHIP; + e.flags = 0; + e.u.irqchip.irqchip = irqchip; + e.u.irqchip.pin = pin; + return kvm_add_routing_entry(s, &e); +} + +static int kvm_init_irq_routing(KVMState *s) +{ + int i, r; + int gsi_count, gsi_bits; + + gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING); + if (!kvm_irqchip_in_kernel() && (gsi_count > 0)) { + return 0; + } + + /* Round up so we can search ints using ffs */ + gsi_bits = ((gsi_count - 31) & ~31); + kvm_arch_state->used_gsi_bitmap = qemu_mallocz(gsi_bits / 8); + kvm_arch_state->max_gsi = gsi_bits; + + /* Mark any over-allocated bits as already in use */ + for (i = gsi_count; i < gsi_bits; i++) { + set_gsi(kvm_arch_state, i); + } + + kvm_arch_state->irq_routes->nr = 0; + + for (i = 0; i < 8; ++i) { + if (i == 2) + continue; + r = kvm_add_irq_route(kvm_arch_state, i, KVM_IRQCHIP_PIC_MASTER, i); + if (r < 0) + return r; + } + for (i = 8; i < 16; ++i) { + r = kvm_add_irq_route(kvm_arch_state, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); + if (r < 0) + return r; + } + for (i = 0; i < 24; ++i) { + if (i == 0) { + r = kvm_add_irq_route(kvm_arch_state, i, KVM_IRQCHIP_IOAPIC, 2); + } else if (i != 2) { + r = kvm_add_irq_route(kvm_arch_state, i, KVM_IRQCHIP_IOAPIC, i); + } + if (r < 0) + return r; + } + + kvm_arch_state->irq_routes->flags = 0; + return kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, kvm_arch_state->irq_routes); +} int kvm_arch_init(KVMState *s, int smp_cpus) { int ret; + kvm_arch_state = qemu_mallocz(sizeof(*kvm_arch_state)); + kvm_arch_state->irq_routes = qemu_mallocz(sizeof(*kvm_arch_state->irq_routes)); + + kvm_init_irq_routing(s); + /* create vm86 tss. KVM uses vm86 mode to emulate 16-bit code * directly. In order to use vm86 mode, a TSS is needed. Since this * must be part of guest physical memory, we need to allocate it. Older -- 1.6.2.5