@@ -66,6 +66,8 @@ struct KVMState
#endif
int irqchip_in_kernel;
int pit_in_kernel;
+
+ KVMArchState *arch_state;
};
static KVMState *kvm_state;
@@ -522,12 +524,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:
@@ -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, ...);
@@ -37,6 +37,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;
@@ -272,10 +282,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
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 <glommer@redhat.com> --- kvm-all.c | 6 ++- kvm.h | 3 + target-i386/kvm.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 2 deletions(-)