1610626afSaliguori /* 2610626afSaliguori * ioapic.c IOAPIC emulation logic 3610626afSaliguori * 4610626afSaliguori * Copyright (c) 2004-2005 Fabrice Bellard 5610626afSaliguori * 6610626afSaliguori * Split the ioapic logic from apic.c 7610626afSaliguori * Xiantao Zhang <xiantao.zhang@intel.com> 8610626afSaliguori * 9610626afSaliguori * This library is free software; you can redistribute it and/or 10610626afSaliguori * modify it under the terms of the GNU Lesser General Public 11610626afSaliguori * License as published by the Free Software Foundation; either 12610626afSaliguori * version 2 of the License, or (at your option) any later version. 13610626afSaliguori * 14610626afSaliguori * This library is distributed in the hope that it will be useful, 15610626afSaliguori * but WITHOUT ANY WARRANTY; without even the implied warranty of 16610626afSaliguori * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17610626afSaliguori * Lesser General Public License for more details. 18610626afSaliguori * 19610626afSaliguori * You should have received a copy of the GNU Lesser General Public 208167ee88SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21610626afSaliguori */ 22610626afSaliguori 23b6a0aa05SPeter Maydell #include "qemu/osdep.h" 246bde8fd6SPavel Butsykin #include "monitor/monitor.h" 2583c9f4caSPaolo Bonzini #include "hw/hw.h" 260d09e41aSPaolo Bonzini #include "hw/i386/pc.h" 27d613f8ccSPaolo Bonzini #include "hw/i386/apic.h" 280d09e41aSPaolo Bonzini #include "hw/i386/ioapic.h" 290d09e41aSPaolo Bonzini #include "hw/i386/ioapic_internal.h" 3015eafc2eSPaolo Bonzini #include "include/hw/pci/msi.h" 3115eafc2eSPaolo Bonzini #include "sysemu/kvm.h" 32610626afSaliguori 33610626afSaliguori //#define DEBUG_IOAPIC 34610626afSaliguori 359af9b330SBlue Swirl #ifdef DEBUG_IOAPIC 369af9b330SBlue Swirl #define DPRINTF(fmt, ...) \ 379af9b330SBlue Swirl do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0) 389af9b330SBlue Swirl #else 399af9b330SBlue Swirl #define DPRINTF(fmt, ...) 409af9b330SBlue Swirl #endif 419af9b330SBlue Swirl 4215eafc2eSPaolo Bonzini #define APIC_DELIVERY_MODE_SHIFT 8 4315eafc2eSPaolo Bonzini #define APIC_POLARITY_SHIFT 14 4415eafc2eSPaolo Bonzini #define APIC_TRIG_MODE_SHIFT 15 4515eafc2eSPaolo Bonzini 46244ac3afSJan Kiszka static IOAPICCommonState *ioapics[MAX_IOAPICS]; 470280b571SJan Kiszka 48db0f8888Sxiaoqiang zhao /* global variable from ioapic_common.c */ 49db0f8888Sxiaoqiang zhao extern int ioapic_no; 50db0f8888Sxiaoqiang zhao 51244ac3afSJan Kiszka static void ioapic_service(IOAPICCommonState *s) 52610626afSaliguori { 53610626afSaliguori uint8_t i; 54610626afSaliguori uint8_t trig_mode; 55610626afSaliguori uint8_t vector; 56610626afSaliguori uint8_t delivery_mode; 57610626afSaliguori uint32_t mask; 58610626afSaliguori uint64_t entry; 59610626afSaliguori uint8_t dest; 60610626afSaliguori uint8_t dest_mode; 61610626afSaliguori 62610626afSaliguori for (i = 0; i < IOAPIC_NUM_PINS; i++) { 63610626afSaliguori mask = 1 << i; 64610626afSaliguori if (s->irr & mask) { 6515eafc2eSPaolo Bonzini int coalesce = 0; 6615eafc2eSPaolo Bonzini 67610626afSaliguori entry = s->ioredtbl[i]; 68610626afSaliguori if (!(entry & IOAPIC_LVT_MASKED)) { 691f5e71a8SJan Kiszka trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); 701f5e71a8SJan Kiszka dest = entry >> IOAPIC_LVT_DEST_SHIFT; 711f5e71a8SJan Kiszka dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; 721f5e71a8SJan Kiszka delivery_mode = 731f5e71a8SJan Kiszka (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; 740280b571SJan Kiszka if (trig_mode == IOAPIC_TRIGGER_EDGE) { 75610626afSaliguori s->irr &= ~mask; 760280b571SJan Kiszka } else { 7715eafc2eSPaolo Bonzini coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR; 780280b571SJan Kiszka s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; 790280b571SJan Kiszka } 801f5e71a8SJan Kiszka if (delivery_mode == IOAPIC_DM_EXTINT) { 81610626afSaliguori vector = pic_read_irq(isa_pic); 821f5e71a8SJan Kiszka } else { 831f5e71a8SJan Kiszka vector = entry & IOAPIC_VECTOR_MASK; 841f5e71a8SJan Kiszka } 8515eafc2eSPaolo Bonzini #ifdef CONFIG_KVM 8615eafc2eSPaolo Bonzini if (kvm_irqchip_is_split()) { 8715eafc2eSPaolo Bonzini if (trig_mode == IOAPIC_TRIGGER_EDGE) { 8815eafc2eSPaolo Bonzini kvm_set_irq(kvm_state, i, 1); 8915eafc2eSPaolo Bonzini kvm_set_irq(kvm_state, i, 0); 9015eafc2eSPaolo Bonzini } else { 9115eafc2eSPaolo Bonzini if (!coalesce) { 9215eafc2eSPaolo Bonzini kvm_set_irq(kvm_state, i, 1); 9315eafc2eSPaolo Bonzini } 9415eafc2eSPaolo Bonzini } 9515eafc2eSPaolo Bonzini continue; 9615eafc2eSPaolo Bonzini } 9715eafc2eSPaolo Bonzini #else 9815eafc2eSPaolo Bonzini (void)coalesce; 9915eafc2eSPaolo Bonzini #endif 10015eafc2eSPaolo Bonzini apic_deliver_irq(dest, dest_mode, delivery_mode, vector, 10115eafc2eSPaolo Bonzini trig_mode); 102610626afSaliguori } 103610626afSaliguori } 104610626afSaliguori } 105610626afSaliguori } 106610626afSaliguori 1077d0500c4SBlue Swirl static void ioapic_set_irq(void *opaque, int vector, int level) 108610626afSaliguori { 109244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 110610626afSaliguori 111610626afSaliguori /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps 112610626afSaliguori * to GSI 2. GSI maps to ioapic 1-1. This is not 113610626afSaliguori * the cleanest way of doing it but it should work. */ 114610626afSaliguori 1159af9b330SBlue Swirl DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector); 1161f5e71a8SJan Kiszka if (vector == 0) { 117610626afSaliguori vector = 2; 1181f5e71a8SJan Kiszka } 119610626afSaliguori if (vector >= 0 && vector < IOAPIC_NUM_PINS) { 120610626afSaliguori uint32_t mask = 1 << vector; 121610626afSaliguori uint64_t entry = s->ioredtbl[vector]; 122610626afSaliguori 1231f5e71a8SJan Kiszka if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == 1241f5e71a8SJan Kiszka IOAPIC_TRIGGER_LEVEL) { 125610626afSaliguori /* level triggered */ 126610626afSaliguori if (level) { 127610626afSaliguori s->irr |= mask; 128c5955a56SPaolo Bonzini if (!(entry & IOAPIC_LVT_REMOTE_IRR)) { 129610626afSaliguori ioapic_service(s); 130c5955a56SPaolo Bonzini } 131610626afSaliguori } else { 132610626afSaliguori s->irr &= ~mask; 133610626afSaliguori } 134610626afSaliguori } else { 13547f7be39SJan Kiszka /* According to the 82093AA manual, we must ignore edge requests 13647f7be39SJan Kiszka * if the input pin is masked. */ 13747f7be39SJan Kiszka if (level && !(entry & IOAPIC_LVT_MASKED)) { 138610626afSaliguori s->irr |= mask; 139610626afSaliguori ioapic_service(s); 140610626afSaliguori } 141610626afSaliguori } 142610626afSaliguori } 143610626afSaliguori } 144610626afSaliguori 14515eafc2eSPaolo Bonzini static void ioapic_update_kvm_routes(IOAPICCommonState *s) 14615eafc2eSPaolo Bonzini { 14715eafc2eSPaolo Bonzini #ifdef CONFIG_KVM 14815eafc2eSPaolo Bonzini int i; 14915eafc2eSPaolo Bonzini 15015eafc2eSPaolo Bonzini if (kvm_irqchip_is_split()) { 15115eafc2eSPaolo Bonzini for (i = 0; i < IOAPIC_NUM_PINS; i++) { 15215eafc2eSPaolo Bonzini uint64_t entry = s->ioredtbl[i]; 15315eafc2eSPaolo Bonzini uint8_t trig_mode; 15415eafc2eSPaolo Bonzini uint8_t delivery_mode; 15515eafc2eSPaolo Bonzini uint8_t dest; 15615eafc2eSPaolo Bonzini uint8_t dest_mode; 15715eafc2eSPaolo Bonzini uint64_t pin_polarity; 15815eafc2eSPaolo Bonzini MSIMessage msg; 15915eafc2eSPaolo Bonzini 16015eafc2eSPaolo Bonzini trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); 16115eafc2eSPaolo Bonzini dest = entry >> IOAPIC_LVT_DEST_SHIFT; 16215eafc2eSPaolo Bonzini dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; 16315eafc2eSPaolo Bonzini pin_polarity = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1; 16415eafc2eSPaolo Bonzini delivery_mode = 16515eafc2eSPaolo Bonzini (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; 16615eafc2eSPaolo Bonzini 16715eafc2eSPaolo Bonzini msg.address = APIC_DEFAULT_ADDRESS; 16815eafc2eSPaolo Bonzini msg.address |= dest_mode << 2; 16915eafc2eSPaolo Bonzini msg.address |= dest << 12; 17015eafc2eSPaolo Bonzini 17115eafc2eSPaolo Bonzini msg.data = entry & IOAPIC_VECTOR_MASK; 17215eafc2eSPaolo Bonzini msg.data |= delivery_mode << APIC_DELIVERY_MODE_SHIFT; 17315eafc2eSPaolo Bonzini msg.data |= pin_polarity << APIC_POLARITY_SHIFT; 17415eafc2eSPaolo Bonzini msg.data |= trig_mode << APIC_TRIG_MODE_SHIFT; 17515eafc2eSPaolo Bonzini 17615eafc2eSPaolo Bonzini kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL); 17715eafc2eSPaolo Bonzini } 17815eafc2eSPaolo Bonzini kvm_irqchip_commit_routes(kvm_state); 17915eafc2eSPaolo Bonzini } 18015eafc2eSPaolo Bonzini #endif 18115eafc2eSPaolo Bonzini } 18215eafc2eSPaolo Bonzini 1830280b571SJan Kiszka void ioapic_eoi_broadcast(int vector) 1840280b571SJan Kiszka { 185244ac3afSJan Kiszka IOAPICCommonState *s; 1860280b571SJan Kiszka uint64_t entry; 1870280b571SJan Kiszka int i, n; 1880280b571SJan Kiszka 1890280b571SJan Kiszka for (i = 0; i < MAX_IOAPICS; i++) { 1900280b571SJan Kiszka s = ioapics[i]; 1910280b571SJan Kiszka if (!s) { 1920280b571SJan Kiszka continue; 1930280b571SJan Kiszka } 1940280b571SJan Kiszka for (n = 0; n < IOAPIC_NUM_PINS; n++) { 1950280b571SJan Kiszka entry = s->ioredtbl[n]; 1961f5e71a8SJan Kiszka if ((entry & IOAPIC_LVT_REMOTE_IRR) 1971f5e71a8SJan Kiszka && (entry & IOAPIC_VECTOR_MASK) == vector) { 1980280b571SJan Kiszka s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; 1990280b571SJan Kiszka if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { 2000280b571SJan Kiszka ioapic_service(s); 2010280b571SJan Kiszka } 2020280b571SJan Kiszka } 2030280b571SJan Kiszka } 2040280b571SJan Kiszka } 2050280b571SJan Kiszka } 2060280b571SJan Kiszka 2076bde8fd6SPavel Butsykin void ioapic_dump_state(Monitor *mon, const QDict *qdict) 2086bde8fd6SPavel Butsykin { 2096bde8fd6SPavel Butsykin int i; 2106bde8fd6SPavel Butsykin 2116bde8fd6SPavel Butsykin for (i = 0; i < MAX_IOAPICS; i++) { 2126bde8fd6SPavel Butsykin if (ioapics[i] != 0) { 2136bde8fd6SPavel Butsykin ioapic_print_redtbl(mon, ioapics[i]); 2146bde8fd6SPavel Butsykin } 2156bde8fd6SPavel Butsykin } 2166bde8fd6SPavel Butsykin } 2176bde8fd6SPavel Butsykin 2184d5bf5f6SJan Kiszka static uint64_t 219a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) 220610626afSaliguori { 221244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 222610626afSaliguori int index; 223610626afSaliguori uint32_t val = 0; 224610626afSaliguori 2251f5e71a8SJan Kiszka switch (addr & 0xff) { 2261f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 227610626afSaliguori val = s->ioregsel; 2281f5e71a8SJan Kiszka break; 2291f5e71a8SJan Kiszka case IOAPIC_IOWIN: 2301a440963SJan Kiszka if (size != 4) { 2311a440963SJan Kiszka break; 2321a440963SJan Kiszka } 233610626afSaliguori switch (s->ioregsel) { 2341f5e71a8SJan Kiszka case IOAPIC_REG_ID: 2352f5a3b12SPaolo Bonzini case IOAPIC_REG_ARB: 2361f5e71a8SJan Kiszka val = s->id << IOAPIC_ID_SHIFT; 237610626afSaliguori break; 2381f5e71a8SJan Kiszka case IOAPIC_REG_VER: 2391f5e71a8SJan Kiszka val = IOAPIC_VERSION | 2401f5e71a8SJan Kiszka ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); 241610626afSaliguori break; 242610626afSaliguori default: 2431f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 244610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 2451f5e71a8SJan Kiszka if (s->ioregsel & 1) { 246610626afSaliguori val = s->ioredtbl[index] >> 32; 2471f5e71a8SJan Kiszka } else { 248610626afSaliguori val = s->ioredtbl[index] & 0xffffffff; 249610626afSaliguori } 250610626afSaliguori } 2511f5e71a8SJan Kiszka } 2529af9b330SBlue Swirl DPRINTF("read: %08x = %08x\n", s->ioregsel, val); 2531f5e71a8SJan Kiszka break; 254610626afSaliguori } 255610626afSaliguori return val; 256610626afSaliguori } 257610626afSaliguori 2581f5e71a8SJan Kiszka static void 259a8170e5eSAvi Kivity ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, 2604d5bf5f6SJan Kiszka unsigned int size) 261610626afSaliguori { 262244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 263610626afSaliguori int index; 264610626afSaliguori 2651f5e71a8SJan Kiszka switch (addr & 0xff) { 2661f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 267610626afSaliguori s->ioregsel = val; 2681f5e71a8SJan Kiszka break; 2691f5e71a8SJan Kiszka case IOAPIC_IOWIN: 2701a440963SJan Kiszka if (size != 4) { 2711a440963SJan Kiszka break; 2721a440963SJan Kiszka } 2730c1f781bSJason Wang DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val); 274610626afSaliguori switch (s->ioregsel) { 2751f5e71a8SJan Kiszka case IOAPIC_REG_ID: 2761f5e71a8SJan Kiszka s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK; 2771f5e71a8SJan Kiszka break; 2781f5e71a8SJan Kiszka case IOAPIC_REG_VER: 2791f5e71a8SJan Kiszka case IOAPIC_REG_ARB: 2801f5e71a8SJan Kiszka break; 281610626afSaliguori default: 2821f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 283610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 284*479c2a1cSPeter Xu uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS; 285610626afSaliguori if (s->ioregsel & 1) { 286610626afSaliguori s->ioredtbl[index] &= 0xffffffff; 287610626afSaliguori s->ioredtbl[index] |= (uint64_t)val << 32; 288610626afSaliguori } else { 289610626afSaliguori s->ioredtbl[index] &= ~0xffffffffULL; 290610626afSaliguori s->ioredtbl[index] |= val; 291610626afSaliguori } 292*479c2a1cSPeter Xu /* restore RO bits */ 293*479c2a1cSPeter Xu s->ioredtbl[index] &= IOAPIC_RW_BITS; 294*479c2a1cSPeter Xu s->ioredtbl[index] |= ro_bits; 295610626afSaliguori ioapic_service(s); 296610626afSaliguori } 297610626afSaliguori } 2981f5e71a8SJan Kiszka break; 299610626afSaliguori } 30015eafc2eSPaolo Bonzini 30115eafc2eSPaolo Bonzini ioapic_update_kvm_routes(s); 302610626afSaliguori } 303610626afSaliguori 3044d5bf5f6SJan Kiszka static const MemoryRegionOps ioapic_io_ops = { 3054d5bf5f6SJan Kiszka .read = ioapic_mem_read, 3064d5bf5f6SJan Kiszka .write = ioapic_mem_write, 3074d5bf5f6SJan Kiszka .endianness = DEVICE_NATIVE_ENDIAN, 308610626afSaliguori }; 309610626afSaliguori 310db0f8888Sxiaoqiang zhao static void ioapic_realize(DeviceState *dev, Error **errp) 311610626afSaliguori { 312db0f8888Sxiaoqiang zhao IOAPICCommonState *s = IOAPIC_COMMON(dev); 313f9771858Sxiaoqiang zhao 3141437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, 3151437c94bSPaolo Bonzini "ioapic", 0x1000); 316610626afSaliguori 317f9771858Sxiaoqiang zhao qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS); 318610626afSaliguori 319db0f8888Sxiaoqiang zhao ioapics[ioapic_no] = s; 320610626afSaliguori } 32196051119SBlue Swirl 322999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data) 323999e12bbSAnthony Liguori { 324999e12bbSAnthony Liguori IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); 32539bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 326999e12bbSAnthony Liguori 327db0f8888Sxiaoqiang zhao k->realize = ioapic_realize; 32839bffca2SAnthony Liguori dc->reset = ioapic_reset_common; 329999e12bbSAnthony Liguori } 330999e12bbSAnthony Liguori 3318c43a6f0SAndreas Färber static const TypeInfo ioapic_info = { 332999e12bbSAnthony Liguori .name = "ioapic", 33339bffca2SAnthony Liguori .parent = TYPE_IOAPIC_COMMON, 33439bffca2SAnthony Liguori .instance_size = sizeof(IOAPICCommonState), 335999e12bbSAnthony Liguori .class_init = ioapic_class_init, 33696051119SBlue Swirl }; 33796051119SBlue Swirl 33883f7d43aSAndreas Färber static void ioapic_register_types(void) 33996051119SBlue Swirl { 34039bffca2SAnthony Liguori type_register_static(&ioapic_info); 34196051119SBlue Swirl } 34296051119SBlue Swirl 34383f7d43aSAndreas Färber type_init(ioapic_register_types) 344