1 /* 2 * KVM in-kernel IOPIC support 3 * 4 * Copyright (c) 2011 Siemens AG 5 * 6 * Authors: 7 * Jan Kiszka <jan.kiszka@siemens.com> 8 * 9 * This work is licensed under the terms of the GNU GPL version 2. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "monitor/monitor.h" 14 #include "hw/i386/pc.h" 15 #include "hw/i386/ioapic_internal.h" 16 #include "hw/i386/apic_internal.h" 17 #include "sysemu/kvm.h" 18 19 /* PC Utility function */ 20 void kvm_pc_setup_irq_routing(bool pci_enabled) 21 { 22 KVMState *s = kvm_state; 23 int i; 24 25 if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) { 26 for (i = 0; i < 8; ++i) { 27 if (i == 2) { 28 continue; 29 } 30 kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_MASTER, i); 31 } 32 for (i = 8; i < 16; ++i) { 33 kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8); 34 } 35 if (pci_enabled) { 36 for (i = 0; i < 24; ++i) { 37 if (i == 0) { 38 kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, 2); 39 } else if (i != 2) { 40 kvm_irqchip_add_irq_route(s, i, KVM_IRQCHIP_IOAPIC, i); 41 } 42 } 43 } 44 kvm_irqchip_commit_routes(s); 45 } 46 } 47 48 void kvm_pc_gsi_handler(void *opaque, int n, int level) 49 { 50 GSIState *s = opaque; 51 52 if (n < ISA_NUM_IRQS) { 53 /* Kernel will forward to both PIC and IOAPIC */ 54 qemu_set_irq(s->i8259_irq[n], level); 55 } else { 56 qemu_set_irq(s->ioapic_irq[n], level); 57 } 58 } 59 60 typedef struct KVMIOAPICState KVMIOAPICState; 61 62 struct KVMIOAPICState { 63 IOAPICCommonState ioapic; 64 uint32_t kvm_gsi_base; 65 }; 66 67 static void kvm_ioapic_get(IOAPICCommonState *s) 68 { 69 struct kvm_irqchip chip; 70 struct kvm_ioapic_state *kioapic; 71 int ret, i; 72 73 chip.chip_id = KVM_IRQCHIP_IOAPIC; 74 ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip); 75 if (ret < 0) { 76 fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); 77 abort(); 78 } 79 80 kioapic = &chip.chip.ioapic; 81 82 s->id = kioapic->id; 83 s->ioregsel = kioapic->ioregsel; 84 s->irr = kioapic->irr; 85 for (i = 0; i < IOAPIC_NUM_PINS; i++) { 86 s->ioredtbl[i] = kioapic->redirtbl[i].bits; 87 } 88 } 89 90 static void kvm_ioapic_put(IOAPICCommonState *s) 91 { 92 struct kvm_irqchip chip; 93 struct kvm_ioapic_state *kioapic; 94 int ret, i; 95 96 chip.chip_id = KVM_IRQCHIP_IOAPIC; 97 kioapic = &chip.chip.ioapic; 98 99 kioapic->id = s->id; 100 kioapic->ioregsel = s->ioregsel; 101 kioapic->base_address = s->busdev.mmio[0].addr; 102 kioapic->irr = s->irr; 103 for (i = 0; i < IOAPIC_NUM_PINS; i++) { 104 kioapic->redirtbl[i].bits = s->ioredtbl[i]; 105 } 106 107 ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip); 108 if (ret < 0) { 109 fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret)); 110 abort(); 111 } 112 } 113 114 void kvm_ioapic_dump_state(Monitor *mon, const QDict *qdict) 115 { 116 IOAPICCommonState s; 117 118 kvm_ioapic_get(&s); 119 120 ioapic_print_redtbl(mon, &s); 121 } 122 123 static void kvm_ioapic_reset(DeviceState *dev) 124 { 125 IOAPICCommonState *s = IOAPIC_COMMON(dev); 126 127 ioapic_reset_common(dev); 128 kvm_ioapic_put(s); 129 } 130 131 static void kvm_ioapic_set_irq(void *opaque, int irq, int level) 132 { 133 KVMIOAPICState *s = opaque; 134 int delivered; 135 136 delivered = kvm_set_irq(kvm_state, s->kvm_gsi_base + irq, level); 137 apic_report_irq_delivered(delivered); 138 } 139 140 static void kvm_ioapic_realize(DeviceState *dev, Error **errp) 141 { 142 IOAPICCommonState *s = IOAPIC_COMMON(dev); 143 144 memory_region_init_reservation(&s->io_memory, NULL, "kvm-ioapic", 0x1000); 145 146 qdev_init_gpio_in(dev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS); 147 } 148 149 static Property kvm_ioapic_properties[] = { 150 DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0), 151 DEFINE_PROP_END_OF_LIST() 152 }; 153 154 static void kvm_ioapic_class_init(ObjectClass *klass, void *data) 155 { 156 IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); 157 DeviceClass *dc = DEVICE_CLASS(klass); 158 159 k->realize = kvm_ioapic_realize; 160 k->pre_save = kvm_ioapic_get; 161 k->post_load = kvm_ioapic_put; 162 dc->reset = kvm_ioapic_reset; 163 dc->props = kvm_ioapic_properties; 164 } 165 166 static const TypeInfo kvm_ioapic_info = { 167 .name = "kvm-ioapic", 168 .parent = TYPE_IOAPIC_COMMON, 169 .instance_size = sizeof(KVMIOAPICState), 170 .class_init = kvm_ioapic_class_init, 171 }; 172 173 static void kvm_ioapic_register_types(void) 174 { 175 type_register_static(&kvm_ioapic_info); 176 } 177 178 type_init(kvm_ioapic_register_types) 179