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 39db0f8888Sxiaoqiang zhao /* global variable from ioapic_common.c */ 40db0f8888Sxiaoqiang zhao extern int ioapic_no; 41db0f8888Sxiaoqiang 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 961f5e71a8SJan Kiszka if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == 971f5e71a8SJan Kiszka IOAPIC_TRIGGER_LEVEL) { 98610626afSaliguori /* level triggered */ 99610626afSaliguori if (level) { 100610626afSaliguori s->irr |= mask; 101c5955a56SPaolo Bonzini if (!(entry & IOAPIC_LVT_REMOTE_IRR)) { 102610626afSaliguori ioapic_service(s); 103c5955a56SPaolo Bonzini } 104610626afSaliguori } else { 105610626afSaliguori s->irr &= ~mask; 106610626afSaliguori } 107610626afSaliguori } else { 10847f7be39SJan Kiszka /* According to the 82093AA manual, we must ignore edge requests 10947f7be39SJan Kiszka * if the input pin is masked. */ 11047f7be39SJan Kiszka if (level && !(entry & IOAPIC_LVT_MASKED)) { 111610626afSaliguori s->irr |= mask; 112610626afSaliguori ioapic_service(s); 113610626afSaliguori } 114610626afSaliguori } 115610626afSaliguori } 116610626afSaliguori } 117610626afSaliguori 1180280b571SJan Kiszka void ioapic_eoi_broadcast(int vector) 1190280b571SJan Kiszka { 120244ac3afSJan Kiszka IOAPICCommonState *s; 1210280b571SJan Kiszka uint64_t entry; 1220280b571SJan Kiszka int i, n; 1230280b571SJan Kiszka 1240280b571SJan Kiszka for (i = 0; i < MAX_IOAPICS; i++) { 1250280b571SJan Kiszka s = ioapics[i]; 1260280b571SJan Kiszka if (!s) { 1270280b571SJan Kiszka continue; 1280280b571SJan Kiszka } 1290280b571SJan Kiszka for (n = 0; n < IOAPIC_NUM_PINS; n++) { 1300280b571SJan Kiszka entry = s->ioredtbl[n]; 1311f5e71a8SJan Kiszka if ((entry & IOAPIC_LVT_REMOTE_IRR) 1321f5e71a8SJan Kiszka && (entry & IOAPIC_VECTOR_MASK) == vector) { 1330280b571SJan Kiszka s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; 1340280b571SJan Kiszka if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { 1350280b571SJan Kiszka ioapic_service(s); 1360280b571SJan Kiszka } 1370280b571SJan Kiszka } 1380280b571SJan Kiszka } 1390280b571SJan Kiszka } 1400280b571SJan Kiszka } 1410280b571SJan Kiszka 1424d5bf5f6SJan Kiszka static uint64_t 143a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) 144610626afSaliguori { 145244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 146610626afSaliguori int index; 147610626afSaliguori uint32_t val = 0; 148610626afSaliguori 1491f5e71a8SJan Kiszka switch (addr & 0xff) { 1501f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 151610626afSaliguori val = s->ioregsel; 1521f5e71a8SJan Kiszka break; 1531f5e71a8SJan Kiszka case IOAPIC_IOWIN: 1541a440963SJan Kiszka if (size != 4) { 1551a440963SJan Kiszka break; 1561a440963SJan Kiszka } 157610626afSaliguori switch (s->ioregsel) { 1581f5e71a8SJan Kiszka case IOAPIC_REG_ID: 159*2f5a3b12SPaolo Bonzini case IOAPIC_REG_ARB: 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; 166610626afSaliguori default: 1671f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 168610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 1691f5e71a8SJan Kiszka if (s->ioregsel & 1) { 170610626afSaliguori val = s->ioredtbl[index] >> 32; 1711f5e71a8SJan Kiszka } else { 172610626afSaliguori val = s->ioredtbl[index] & 0xffffffff; 173610626afSaliguori } 174610626afSaliguori } 1751f5e71a8SJan Kiszka } 1769af9b330SBlue Swirl DPRINTF("read: %08x = %08x\n", s->ioregsel, val); 1771f5e71a8SJan Kiszka break; 178610626afSaliguori } 179610626afSaliguori return val; 180610626afSaliguori } 181610626afSaliguori 1821f5e71a8SJan Kiszka static void 183a8170e5eSAvi Kivity ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, 1844d5bf5f6SJan Kiszka unsigned int size) 185610626afSaliguori { 186244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 187610626afSaliguori int index; 188610626afSaliguori 1891f5e71a8SJan Kiszka switch (addr & 0xff) { 1901f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 191610626afSaliguori s->ioregsel = val; 1921f5e71a8SJan Kiszka break; 1931f5e71a8SJan Kiszka case IOAPIC_IOWIN: 1941a440963SJan Kiszka if (size != 4) { 1951a440963SJan Kiszka break; 1961a440963SJan Kiszka } 1970c1f781bSJason Wang DPRINTF("write: %08x = %08" PRIx64 "\n", s->ioregsel, val); 198610626afSaliguori switch (s->ioregsel) { 1991f5e71a8SJan Kiszka case IOAPIC_REG_ID: 2001f5e71a8SJan Kiszka s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK; 2011f5e71a8SJan Kiszka break; 2021f5e71a8SJan Kiszka case IOAPIC_REG_VER: 2031f5e71a8SJan Kiszka case IOAPIC_REG_ARB: 2041f5e71a8SJan Kiszka break; 205610626afSaliguori default: 2061f5e71a8SJan Kiszka index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1; 207610626afSaliguori if (index >= 0 && index < IOAPIC_NUM_PINS) { 208610626afSaliguori if (s->ioregsel & 1) { 209610626afSaliguori s->ioredtbl[index] &= 0xffffffff; 210610626afSaliguori s->ioredtbl[index] |= (uint64_t)val << 32; 211610626afSaliguori } else { 212610626afSaliguori s->ioredtbl[index] &= ~0xffffffffULL; 213610626afSaliguori s->ioredtbl[index] |= val; 214610626afSaliguori } 215610626afSaliguori ioapic_service(s); 216610626afSaliguori } 217610626afSaliguori } 2181f5e71a8SJan Kiszka break; 219610626afSaliguori } 220610626afSaliguori } 221610626afSaliguori 2224d5bf5f6SJan Kiszka static const MemoryRegionOps ioapic_io_ops = { 2234d5bf5f6SJan Kiszka .read = ioapic_mem_read, 2244d5bf5f6SJan Kiszka .write = ioapic_mem_write, 2254d5bf5f6SJan Kiszka .endianness = DEVICE_NATIVE_ENDIAN, 226610626afSaliguori }; 227610626afSaliguori 228db0f8888Sxiaoqiang zhao static void ioapic_realize(DeviceState *dev, Error **errp) 229610626afSaliguori { 230db0f8888Sxiaoqiang zhao IOAPICCommonState *s = IOAPIC_COMMON(dev); 231f9771858Sxiaoqiang zhao 2321437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, 2331437c94bSPaolo Bonzini "ioapic", 0x1000); 234610626afSaliguori 235f9771858Sxiaoqiang zhao qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS); 236610626afSaliguori 237db0f8888Sxiaoqiang zhao ioapics[ioapic_no] = s; 238610626afSaliguori } 23996051119SBlue Swirl 240999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data) 241999e12bbSAnthony Liguori { 242999e12bbSAnthony Liguori IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); 24339bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 244999e12bbSAnthony Liguori 245db0f8888Sxiaoqiang zhao k->realize = ioapic_realize; 24639bffca2SAnthony Liguori dc->reset = ioapic_reset_common; 247999e12bbSAnthony Liguori } 248999e12bbSAnthony Liguori 2498c43a6f0SAndreas Färber static const TypeInfo ioapic_info = { 250999e12bbSAnthony Liguori .name = "ioapic", 25139bffca2SAnthony Liguori .parent = TYPE_IOAPIC_COMMON, 25239bffca2SAnthony Liguori .instance_size = sizeof(IOAPICCommonState), 253999e12bbSAnthony Liguori .class_init = ioapic_class_init, 25496051119SBlue Swirl }; 25596051119SBlue Swirl 25683f7d43aSAndreas Färber static void ioapic_register_types(void) 25796051119SBlue Swirl { 25839bffca2SAnthony Liguori type_register_static(&ioapic_info); 25996051119SBlue Swirl } 26096051119SBlue Swirl 26183f7d43aSAndreas Färber type_init(ioapic_register_types) 262