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 23*6bde8fd6SPavel Butsykin #include "monitor/monitor.h" 2483c9f4caSPaolo Bonzini #include "hw/hw.h" 250d09e41aSPaolo Bonzini #include "hw/i386/pc.h" 260d09e41aSPaolo Bonzini #include "hw/i386/ioapic.h" 270d09e41aSPaolo Bonzini #include "hw/i386/ioapic_internal.h" 28610626afSaliguori 29610626afSaliguori //#define DEBUG_IOAPIC 30610626afSaliguori 319af9b330SBlue Swirl #ifdef DEBUG_IOAPIC 329af9b330SBlue Swirl #define DPRINTF(fmt, ...) \ 339af9b330SBlue Swirl do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0) 349af9b330SBlue Swirl #else 359af9b330SBlue Swirl #define DPRINTF(fmt, ...) 369af9b330SBlue Swirl #endif 379af9b330SBlue Swirl 38244ac3afSJan Kiszka static IOAPICCommonState *ioapics[MAX_IOAPICS]; 390280b571SJan Kiszka 40db0f8888Sxiaoqiang zhao /* global variable from ioapic_common.c */ 41db0f8888Sxiaoqiang zhao extern int ioapic_no; 42db0f8888Sxiaoqiang zhao 43244ac3afSJan Kiszka static void ioapic_service(IOAPICCommonState *s) 44610626afSaliguori { 45610626afSaliguori uint8_t i; 46610626afSaliguori uint8_t trig_mode; 47610626afSaliguori uint8_t vector; 48610626afSaliguori uint8_t delivery_mode; 49610626afSaliguori uint32_t mask; 50610626afSaliguori uint64_t entry; 51610626afSaliguori uint8_t dest; 52610626afSaliguori uint8_t dest_mode; 53610626afSaliguori 54610626afSaliguori for (i = 0; i < IOAPIC_NUM_PINS; i++) { 55610626afSaliguori mask = 1 << i; 56610626afSaliguori if (s->irr & mask) { 57610626afSaliguori entry = s->ioredtbl[i]; 58610626afSaliguori if (!(entry & IOAPIC_LVT_MASKED)) { 591f5e71a8SJan Kiszka trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); 601f5e71a8SJan Kiszka dest = entry >> IOAPIC_LVT_DEST_SHIFT; 611f5e71a8SJan Kiszka dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; 621f5e71a8SJan Kiszka delivery_mode = 631f5e71a8SJan Kiszka (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; 640280b571SJan Kiszka if (trig_mode == IOAPIC_TRIGGER_EDGE) { 65610626afSaliguori s->irr &= ~mask; 660280b571SJan Kiszka } else { 670280b571SJan Kiszka s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; 680280b571SJan Kiszka } 691f5e71a8SJan Kiszka if (delivery_mode == IOAPIC_DM_EXTINT) { 70610626afSaliguori vector = pic_read_irq(isa_pic); 711f5e71a8SJan Kiszka } else { 721f5e71a8SJan Kiszka vector = entry & IOAPIC_VECTOR_MASK; 731f5e71a8SJan Kiszka } 74610626afSaliguori apic_deliver_irq(dest, dest_mode, delivery_mode, 751f6f408cSJan Kiszka vector, trig_mode); 76610626afSaliguori } 77610626afSaliguori } 78610626afSaliguori } 79610626afSaliguori } 80610626afSaliguori 817d0500c4SBlue Swirl static void ioapic_set_irq(void *opaque, int vector, int level) 82610626afSaliguori { 83244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 84610626afSaliguori 85610626afSaliguori /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps 86610626afSaliguori * to GSI 2. GSI maps to ioapic 1-1. This is not 87610626afSaliguori * the cleanest way of doing it but it should work. */ 88610626afSaliguori 899af9b330SBlue Swirl DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector); 901f5e71a8SJan Kiszka if (vector == 0) { 91610626afSaliguori vector = 2; 921f5e71a8SJan Kiszka } 93610626afSaliguori if (vector >= 0 && vector < IOAPIC_NUM_PINS) { 94610626afSaliguori uint32_t mask = 1 << vector; 95610626afSaliguori uint64_t entry = s->ioredtbl[vector]; 96610626afSaliguori 971f5e71a8SJan Kiszka if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == 981f5e71a8SJan Kiszka IOAPIC_TRIGGER_LEVEL) { 99610626afSaliguori /* level triggered */ 100610626afSaliguori if (level) { 101610626afSaliguori s->irr |= mask; 102c5955a56SPaolo Bonzini if (!(entry & IOAPIC_LVT_REMOTE_IRR)) { 103610626afSaliguori ioapic_service(s); 104c5955a56SPaolo Bonzini } 105610626afSaliguori } else { 106610626afSaliguori s->irr &= ~mask; 107610626afSaliguori } 108610626afSaliguori } else { 10947f7be39SJan Kiszka /* According to the 82093AA manual, we must ignore edge requests 11047f7be39SJan Kiszka * if the input pin is masked. */ 11147f7be39SJan Kiszka if (level && !(entry & IOAPIC_LVT_MASKED)) { 112610626afSaliguori s->irr |= mask; 113610626afSaliguori ioapic_service(s); 114610626afSaliguori } 115610626afSaliguori } 116610626afSaliguori } 117610626afSaliguori } 118610626afSaliguori 1190280b571SJan Kiszka void ioapic_eoi_broadcast(int vector) 1200280b571SJan Kiszka { 121244ac3afSJan Kiszka IOAPICCommonState *s; 1220280b571SJan Kiszka uint64_t entry; 1230280b571SJan Kiszka int i, n; 1240280b571SJan Kiszka 1250280b571SJan Kiszka for (i = 0; i < MAX_IOAPICS; i++) { 1260280b571SJan Kiszka s = ioapics[i]; 1270280b571SJan Kiszka if (!s) { 1280280b571SJan Kiszka continue; 1290280b571SJan Kiszka } 1300280b571SJan Kiszka for (n = 0; n < IOAPIC_NUM_PINS; n++) { 1310280b571SJan Kiszka entry = s->ioredtbl[n]; 1321f5e71a8SJan Kiszka if ((entry & IOAPIC_LVT_REMOTE_IRR) 1331f5e71a8SJan Kiszka && (entry & IOAPIC_VECTOR_MASK) == vector) { 1340280b571SJan Kiszka s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; 1350280b571SJan Kiszka if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { 1360280b571SJan Kiszka ioapic_service(s); 1370280b571SJan Kiszka } 1380280b571SJan Kiszka } 1390280b571SJan Kiszka } 1400280b571SJan Kiszka } 1410280b571SJan Kiszka } 1420280b571SJan Kiszka 143*6bde8fd6SPavel Butsykin void ioapic_dump_state(Monitor *mon, const QDict *qdict) 144*6bde8fd6SPavel Butsykin { 145*6bde8fd6SPavel Butsykin int i; 146*6bde8fd6SPavel Butsykin 147*6bde8fd6SPavel Butsykin for (i = 0; i < MAX_IOAPICS; i++) { 148*6bde8fd6SPavel Butsykin if (ioapics[i] != 0) { 149*6bde8fd6SPavel Butsykin ioapic_print_redtbl(mon, ioapics[i]); 150*6bde8fd6SPavel Butsykin } 151*6bde8fd6SPavel Butsykin } 152*6bde8fd6SPavel Butsykin } 153*6bde8fd6SPavel Butsykin 1544d5bf5f6SJan Kiszka static uint64_t 155a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) 156610626afSaliguori { 157244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 158610626afSaliguori int index; 159610626afSaliguori uint32_t val = 0; 160610626afSaliguori 1611f5e71a8SJan Kiszka switch (addr & 0xff) { 1621f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 163610626afSaliguori val = s->ioregsel; 1641f5e71a8SJan Kiszka break; 1651f5e71a8SJan Kiszka case IOAPIC_IOWIN: 1661a440963SJan Kiszka if (size != 4) { 1671a440963SJan Kiszka break; 1681a440963SJan Kiszka } 169610626afSaliguori switch (s->ioregsel) { 1701f5e71a8SJan Kiszka case IOAPIC_REG_ID: 1712f5a3b12SPaolo Bonzini case IOAPIC_REG_ARB: 1721f5e71a8SJan Kiszka val = s->id << IOAPIC_ID_SHIFT; 173610626afSaliguori break; 1741f5e71a8SJan Kiszka case IOAPIC_REG_VER: 1751f5e71a8SJan Kiszka val = IOAPIC_VERSION | 1761f5e71a8SJan Kiszka ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); 177610626afSaliguori break; 178610626afSaliguori default: 1791f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 180610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 1811f5e71a8SJan Kiszka if (s->ioregsel & 1) { 182610626afSaliguori val = s->ioredtbl[index] >> 32; 1831f5e71a8SJan Kiszka } else { 184610626afSaliguori val = s->ioredtbl[index] & 0xffffffff; 185610626afSaliguori } 186610626afSaliguori } 1871f5e71a8SJan Kiszka } 1889af9b330SBlue Swirl DPRINTF("read: %08x = %08x\n", s->ioregsel, val); 1891f5e71a8SJan Kiszka break; 190610626afSaliguori } 191610626afSaliguori return val; 192610626afSaliguori } 193610626afSaliguori 1941f5e71a8SJan Kiszka static void 195a8170e5eSAvi Kivity ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, 1964d5bf5f6SJan Kiszka unsigned int size) 197610626afSaliguori { 198244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 199610626afSaliguori int index; 200610626afSaliguori 2011f5e71a8SJan Kiszka switch (addr & 0xff) { 2021f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 203610626afSaliguori s->ioregsel = val; 2041f5e71a8SJan Kiszka break; 2051f5e71a8SJan Kiszka case IOAPIC_IOWIN: 2061a440963SJan Kiszka if (size != 4) { 2071a440963SJan Kiszka break; 2081a440963SJan Kiszka } 2090c1f781bSJason Wang DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val); 210610626afSaliguori switch (s->ioregsel) { 2111f5e71a8SJan Kiszka case IOAPIC_REG_ID: 2121f5e71a8SJan Kiszka s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK; 2131f5e71a8SJan Kiszka break; 2141f5e71a8SJan Kiszka case IOAPIC_REG_VER: 2151f5e71a8SJan Kiszka case IOAPIC_REG_ARB: 2161f5e71a8SJan Kiszka break; 217610626afSaliguori default: 2181f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 219610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 220610626afSaliguori if (s->ioregsel & 1) { 221610626afSaliguori s->ioredtbl[index] &= 0xffffffff; 222610626afSaliguori s->ioredtbl[index] |= (uint64_t)val << 32; 223610626afSaliguori } else { 224610626afSaliguori s->ioredtbl[index] &= ~0xffffffffULL; 225610626afSaliguori s->ioredtbl[index] |= val; 226610626afSaliguori } 227610626afSaliguori ioapic_service(s); 228610626afSaliguori } 229610626afSaliguori } 2301f5e71a8SJan Kiszka break; 231610626afSaliguori } 232610626afSaliguori } 233610626afSaliguori 2344d5bf5f6SJan Kiszka static const MemoryRegionOps ioapic_io_ops = { 2354d5bf5f6SJan Kiszka .read = ioapic_mem_read, 2364d5bf5f6SJan Kiszka .write = ioapic_mem_write, 2374d5bf5f6SJan Kiszka .endianness = DEVICE_NATIVE_ENDIAN, 238610626afSaliguori }; 239610626afSaliguori 240db0f8888Sxiaoqiang zhao static void ioapic_realize(DeviceState *dev, Error **errp) 241610626afSaliguori { 242db0f8888Sxiaoqiang zhao IOAPICCommonState *s = IOAPIC_COMMON(dev); 243f9771858Sxiaoqiang zhao 2441437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, 2451437c94bSPaolo Bonzini "ioapic", 0x1000); 246610626afSaliguori 247f9771858Sxiaoqiang zhao qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS); 248610626afSaliguori 249db0f8888Sxiaoqiang zhao ioapics[ioapic_no] = s; 250610626afSaliguori } 25196051119SBlue Swirl 252999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data) 253999e12bbSAnthony Liguori { 254999e12bbSAnthony Liguori IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); 25539bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 256999e12bbSAnthony Liguori 257db0f8888Sxiaoqiang zhao k->realize = ioapic_realize; 25839bffca2SAnthony Liguori dc->reset = ioapic_reset_common; 259999e12bbSAnthony Liguori } 260999e12bbSAnthony Liguori 2618c43a6f0SAndreas Färber static const TypeInfo ioapic_info = { 262999e12bbSAnthony Liguori .name = "ioapic", 26339bffca2SAnthony Liguori .parent = TYPE_IOAPIC_COMMON, 26439bffca2SAnthony Liguori .instance_size = sizeof(IOAPICCommonState), 265999e12bbSAnthony Liguori .class_init = ioapic_class_init, 26696051119SBlue Swirl }; 26796051119SBlue Swirl 26883f7d43aSAndreas Färber static void ioapic_register_types(void) 26996051119SBlue Swirl { 27039bffca2SAnthony Liguori type_register_static(&ioapic_info); 27196051119SBlue Swirl } 27296051119SBlue Swirl 27383f7d43aSAndreas Färber type_init(ioapic_register_types) 274