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 2383c9f4caSPaolo Bonzini #include "hw/hw.h" 240d09e41aSPaolo Bonzini #include "hw/i386/pc.h" 250d09e41aSPaolo Bonzini #include "hw/i386/ioapic.h" 260d09e41aSPaolo Bonzini #include "hw/i386/ioapic_internal.h" 27610626afSaliguori 28610626afSaliguori //#define DEBUG_IOAPIC 29610626afSaliguori 309af9b330SBlue Swirl #ifdef DEBUG_IOAPIC 319af9b330SBlue Swirl #define DPRINTF(fmt, ...) \ 329af9b330SBlue Swirl do { printf("ioapic: " fmt , ## __VA_ARGS__); } while (0) 339af9b330SBlue Swirl #else 349af9b330SBlue Swirl #define DPRINTF(fmt, ...) 359af9b330SBlue Swirl #endif 369af9b330SBlue Swirl 37244ac3afSJan Kiszka static IOAPICCommonState *ioapics[MAX_IOAPICS]; 380280b571SJan Kiszka 39*db0f8888Sxiaoqiang zhao /* global variable from ioapic_common.c */ 40*db0f8888Sxiaoqiang zhao extern int ioapic_no; 41*db0f8888Sxiaoqiang zhao 42244ac3afSJan Kiszka static void ioapic_service(IOAPICCommonState *s) 43610626afSaliguori { 44610626afSaliguori uint8_t i; 45610626afSaliguori uint8_t trig_mode; 46610626afSaliguori uint8_t vector; 47610626afSaliguori uint8_t delivery_mode; 48610626afSaliguori uint32_t mask; 49610626afSaliguori uint64_t entry; 50610626afSaliguori uint8_t dest; 51610626afSaliguori uint8_t dest_mode; 52610626afSaliguori 53610626afSaliguori for (i = 0; i < IOAPIC_NUM_PINS; i++) { 54610626afSaliguori mask = 1 << i; 55610626afSaliguori if (s->irr & mask) { 56610626afSaliguori entry = s->ioredtbl[i]; 57610626afSaliguori if (!(entry & IOAPIC_LVT_MASKED)) { 581f5e71a8SJan Kiszka trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); 591f5e71a8SJan Kiszka dest = entry >> IOAPIC_LVT_DEST_SHIFT; 601f5e71a8SJan Kiszka dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; 611f5e71a8SJan Kiszka delivery_mode = 621f5e71a8SJan Kiszka (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; 630280b571SJan Kiszka if (trig_mode == IOAPIC_TRIGGER_EDGE) { 64610626afSaliguori s->irr &= ~mask; 650280b571SJan Kiszka } else { 660280b571SJan Kiszka s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; 670280b571SJan Kiszka } 681f5e71a8SJan Kiszka if (delivery_mode == IOAPIC_DM_EXTINT) { 69610626afSaliguori vector = pic_read_irq(isa_pic); 701f5e71a8SJan Kiszka } else { 711f5e71a8SJan Kiszka vector = entry & IOAPIC_VECTOR_MASK; 721f5e71a8SJan Kiszka } 73610626afSaliguori apic_deliver_irq(dest, dest_mode, delivery_mode, 741f6f408cSJan Kiszka vector, trig_mode); 75610626afSaliguori } 76610626afSaliguori } 77610626afSaliguori } 78610626afSaliguori } 79610626afSaliguori 807d0500c4SBlue Swirl static void ioapic_set_irq(void *opaque, int vector, int level) 81610626afSaliguori { 82244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 83610626afSaliguori 84610626afSaliguori /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps 85610626afSaliguori * to GSI 2. GSI maps to ioapic 1-1. This is not 86610626afSaliguori * the cleanest way of doing it but it should work. */ 87610626afSaliguori 889af9b330SBlue Swirl DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector); 891f5e71a8SJan Kiszka if (vector == 0) { 90610626afSaliguori vector = 2; 911f5e71a8SJan Kiszka } 92610626afSaliguori if (vector >= 0 && vector < IOAPIC_NUM_PINS) { 93610626afSaliguori uint32_t mask = 1 << vector; 94610626afSaliguori uint64_t entry = s->ioredtbl[vector]; 95610626afSaliguori 960035e509SJan Kiszka if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) { 970035e509SJan Kiszka level = !level; 980035e509SJan Kiszka } 991f5e71a8SJan Kiszka if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == 1001f5e71a8SJan Kiszka IOAPIC_TRIGGER_LEVEL) { 101610626afSaliguori /* level triggered */ 102610626afSaliguori if (level) { 103610626afSaliguori s->irr |= mask; 104610626afSaliguori ioapic_service(s); 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 1434d5bf5f6SJan Kiszka static uint64_t 144a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) 145610626afSaliguori { 146244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 147610626afSaliguori int index; 148610626afSaliguori uint32_t val = 0; 149610626afSaliguori 1501f5e71a8SJan Kiszka switch (addr & 0xff) { 1511f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 152610626afSaliguori val = s->ioregsel; 1531f5e71a8SJan Kiszka break; 1541f5e71a8SJan Kiszka case IOAPIC_IOWIN: 1551a440963SJan Kiszka if (size != 4) { 1561a440963SJan Kiszka break; 1571a440963SJan Kiszka } 158610626afSaliguori switch (s->ioregsel) { 1591f5e71a8SJan Kiszka case IOAPIC_REG_ID: 1601f5e71a8SJan Kiszka val = s->id << IOAPIC_ID_SHIFT; 161610626afSaliguori break; 1621f5e71a8SJan Kiszka case IOAPIC_REG_VER: 1631f5e71a8SJan Kiszka val = IOAPIC_VERSION | 1641f5e71a8SJan Kiszka ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); 165610626afSaliguori break; 1661f5e71a8SJan Kiszka case IOAPIC_REG_ARB: 167610626afSaliguori val = 0; 168610626afSaliguori break; 169610626afSaliguori default: 1701f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 171610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 1721f5e71a8SJan Kiszka if (s->ioregsel & 1) { 173610626afSaliguori val = s->ioredtbl[index] >> 32; 1741f5e71a8SJan Kiszka } else { 175610626afSaliguori val = s->ioredtbl[index] & 0xffffffff; 176610626afSaliguori } 177610626afSaliguori } 1781f5e71a8SJan Kiszka } 1799af9b330SBlue Swirl DPRINTF("read: %08x = %08x\n", s->ioregsel, val); 1801f5e71a8SJan Kiszka break; 181610626afSaliguori } 182610626afSaliguori return val; 183610626afSaliguori } 184610626afSaliguori 1851f5e71a8SJan Kiszka static void 186a8170e5eSAvi Kivity ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, 1874d5bf5f6SJan Kiszka unsigned int size) 188610626afSaliguori { 189244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 190610626afSaliguori int index; 191610626afSaliguori 1921f5e71a8SJan Kiszka switch (addr & 0xff) { 1931f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 194610626afSaliguori s->ioregsel = val; 1951f5e71a8SJan Kiszka break; 1961f5e71a8SJan Kiszka case IOAPIC_IOWIN: 1971a440963SJan Kiszka if (size != 4) { 1981a440963SJan Kiszka break; 1991a440963SJan Kiszka } 2000c1f781bSJason Wang DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val); 201610626afSaliguori switch (s->ioregsel) { 2021f5e71a8SJan Kiszka case IOAPIC_REG_ID: 2031f5e71a8SJan Kiszka s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK; 2041f5e71a8SJan Kiszka break; 2051f5e71a8SJan Kiszka case IOAPIC_REG_VER: 2061f5e71a8SJan Kiszka case IOAPIC_REG_ARB: 2071f5e71a8SJan Kiszka break; 208610626afSaliguori default: 2091f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 210610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 211610626afSaliguori if (s->ioregsel & 1) { 212610626afSaliguori s->ioredtbl[index] &= 0xffffffff; 213610626afSaliguori s->ioredtbl[index] |= (uint64_t)val << 32; 214610626afSaliguori } else { 215610626afSaliguori s->ioredtbl[index] &= ~0xffffffffULL; 216610626afSaliguori s->ioredtbl[index] |= val; 217610626afSaliguori } 218610626afSaliguori ioapic_service(s); 219610626afSaliguori } 220610626afSaliguori } 2211f5e71a8SJan Kiszka break; 222610626afSaliguori } 223610626afSaliguori } 224610626afSaliguori 2254d5bf5f6SJan Kiszka static const MemoryRegionOps ioapic_io_ops = { 2264d5bf5f6SJan Kiszka .read = ioapic_mem_read, 2274d5bf5f6SJan Kiszka .write = ioapic_mem_write, 2284d5bf5f6SJan Kiszka .endianness = DEVICE_NATIVE_ENDIAN, 229610626afSaliguori }; 230610626afSaliguori 231*db0f8888Sxiaoqiang zhao static void ioapic_realize(DeviceState *dev, Error **errp) 232610626afSaliguori { 233*db0f8888Sxiaoqiang zhao IOAPICCommonState *s = IOAPIC_COMMON(dev); 234f9771858Sxiaoqiang zhao 2351437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, 2361437c94bSPaolo Bonzini "ioapic", 0x1000); 237610626afSaliguori 238f9771858Sxiaoqiang zhao qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS); 239610626afSaliguori 240*db0f8888Sxiaoqiang zhao ioapics[ioapic_no] = s; 241610626afSaliguori } 24296051119SBlue Swirl 243999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data) 244999e12bbSAnthony Liguori { 245999e12bbSAnthony Liguori IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); 24639bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 247999e12bbSAnthony Liguori 248*db0f8888Sxiaoqiang zhao k->realize = ioapic_realize; 24939bffca2SAnthony Liguori dc->reset = ioapic_reset_common; 250999e12bbSAnthony Liguori } 251999e12bbSAnthony Liguori 2528c43a6f0SAndreas Färber static const TypeInfo ioapic_info = { 253999e12bbSAnthony Liguori .name = "ioapic", 25439bffca2SAnthony Liguori .parent = TYPE_IOAPIC_COMMON, 25539bffca2SAnthony Liguori .instance_size = sizeof(IOAPICCommonState), 256999e12bbSAnthony Liguori .class_init = ioapic_class_init, 25796051119SBlue Swirl }; 25896051119SBlue Swirl 25983f7d43aSAndreas Färber static void ioapic_register_types(void) 26096051119SBlue Swirl { 26139bffca2SAnthony Liguori type_register_static(&ioapic_info); 26296051119SBlue Swirl } 26396051119SBlue Swirl 26483f7d43aSAndreas Färber type_init(ioapic_register_types) 265