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 39244ac3afSJan Kiszka static void ioapic_service(IOAPICCommonState *s) 40610626afSaliguori { 41610626afSaliguori uint8_t i; 42610626afSaliguori uint8_t trig_mode; 43610626afSaliguori uint8_t vector; 44610626afSaliguori uint8_t delivery_mode; 45610626afSaliguori uint32_t mask; 46610626afSaliguori uint64_t entry; 47610626afSaliguori uint8_t dest; 48610626afSaliguori uint8_t dest_mode; 49610626afSaliguori 50610626afSaliguori for (i = 0; i < IOAPIC_NUM_PINS; i++) { 51610626afSaliguori mask = 1 << i; 52610626afSaliguori if (s->irr & mask) { 53610626afSaliguori entry = s->ioredtbl[i]; 54610626afSaliguori if (!(entry & IOAPIC_LVT_MASKED)) { 551f5e71a8SJan Kiszka trig_mode = ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1); 561f5e71a8SJan Kiszka dest = entry >> IOAPIC_LVT_DEST_SHIFT; 571f5e71a8SJan Kiszka dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1; 581f5e71a8SJan Kiszka delivery_mode = 591f5e71a8SJan Kiszka (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) & IOAPIC_DM_MASK; 600280b571SJan Kiszka if (trig_mode == IOAPIC_TRIGGER_EDGE) { 61610626afSaliguori s->irr &= ~mask; 620280b571SJan Kiszka } else { 630280b571SJan Kiszka s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR; 640280b571SJan Kiszka } 651f5e71a8SJan Kiszka if (delivery_mode == IOAPIC_DM_EXTINT) { 66610626afSaliguori vector = pic_read_irq(isa_pic); 671f5e71a8SJan Kiszka } else { 681f5e71a8SJan Kiszka vector = entry & IOAPIC_VECTOR_MASK; 691f5e71a8SJan Kiszka } 70610626afSaliguori apic_deliver_irq(dest, dest_mode, delivery_mode, 711f6f408cSJan Kiszka vector, trig_mode); 72610626afSaliguori } 73610626afSaliguori } 74610626afSaliguori } 75610626afSaliguori } 76610626afSaliguori 777d0500c4SBlue Swirl static void ioapic_set_irq(void *opaque, int vector, int level) 78610626afSaliguori { 79244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 80610626afSaliguori 81610626afSaliguori /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps 82610626afSaliguori * to GSI 2. GSI maps to ioapic 1-1. This is not 83610626afSaliguori * the cleanest way of doing it but it should work. */ 84610626afSaliguori 859af9b330SBlue Swirl DPRINTF("%s: %s vec %x\n", __func__, level ? "raise" : "lower", vector); 861f5e71a8SJan Kiszka if (vector == 0) { 87610626afSaliguori vector = 2; 881f5e71a8SJan Kiszka } 89610626afSaliguori if (vector >= 0 && vector < IOAPIC_NUM_PINS) { 90610626afSaliguori uint32_t mask = 1 << vector; 91610626afSaliguori uint64_t entry = s->ioredtbl[vector]; 92610626afSaliguori 930035e509SJan Kiszka if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) { 940035e509SJan Kiszka level = !level; 950035e509SJan Kiszka } 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; 101610626afSaliguori ioapic_service(s); 102610626afSaliguori } else { 103610626afSaliguori s->irr &= ~mask; 104610626afSaliguori } 105610626afSaliguori } else { 10647f7be39SJan Kiszka /* According to the 82093AA manual, we must ignore edge requests 10747f7be39SJan Kiszka * if the input pin is masked. */ 10847f7be39SJan Kiszka if (level && !(entry & IOAPIC_LVT_MASKED)) { 109610626afSaliguori s->irr |= mask; 110610626afSaliguori ioapic_service(s); 111610626afSaliguori } 112610626afSaliguori } 113610626afSaliguori } 114610626afSaliguori } 115610626afSaliguori 1160280b571SJan Kiszka void ioapic_eoi_broadcast(int vector) 1170280b571SJan Kiszka { 118244ac3afSJan Kiszka IOAPICCommonState *s; 1190280b571SJan Kiszka uint64_t entry; 1200280b571SJan Kiszka int i, n; 1210280b571SJan Kiszka 1220280b571SJan Kiszka for (i = 0; i < MAX_IOAPICS; i++) { 1230280b571SJan Kiszka s = ioapics[i]; 1240280b571SJan Kiszka if (!s) { 1250280b571SJan Kiszka continue; 1260280b571SJan Kiszka } 1270280b571SJan Kiszka for (n = 0; n < IOAPIC_NUM_PINS; n++) { 1280280b571SJan Kiszka entry = s->ioredtbl[n]; 1291f5e71a8SJan Kiszka if ((entry & IOAPIC_LVT_REMOTE_IRR) 1301f5e71a8SJan Kiszka && (entry & IOAPIC_VECTOR_MASK) == vector) { 1310280b571SJan Kiszka s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR; 1320280b571SJan Kiszka if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) { 1330280b571SJan Kiszka ioapic_service(s); 1340280b571SJan Kiszka } 1350280b571SJan Kiszka } 1360280b571SJan Kiszka } 1370280b571SJan Kiszka } 1380280b571SJan Kiszka } 1390280b571SJan Kiszka 1404d5bf5f6SJan Kiszka static uint64_t 141a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) 142610626afSaliguori { 143244ac3afSJan Kiszka IOAPICCommonState *s = opaque; 144610626afSaliguori int index; 145610626afSaliguori uint32_t val = 0; 146610626afSaliguori 1471f5e71a8SJan Kiszka switch (addr & 0xff) { 1481f5e71a8SJan Kiszka case IOAPIC_IOREGSEL: 149610626afSaliguori val = s->ioregsel; 1501f5e71a8SJan Kiszka break; 1511f5e71a8SJan Kiszka case IOAPIC_IOWIN: 1521a440963SJan Kiszka if (size != 4) { 1531a440963SJan Kiszka break; 1541a440963SJan Kiszka } 155610626afSaliguori switch (s->ioregsel) { 1561f5e71a8SJan Kiszka case IOAPIC_REG_ID: 1571f5e71a8SJan Kiszka val = s->id << IOAPIC_ID_SHIFT; 158610626afSaliguori break; 1591f5e71a8SJan Kiszka case IOAPIC_REG_VER: 1601f5e71a8SJan Kiszka val = IOAPIC_VERSION | 1611f5e71a8SJan Kiszka ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT); 162610626afSaliguori break; 1631f5e71a8SJan Kiszka case IOAPIC_REG_ARB: 164610626afSaliguori val = 0; 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 228244ac3afSJan Kiszka static void ioapic_init(IOAPICCommonState *s, int instance_no) 229610626afSaliguori { 230*1437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s, 231*1437c94bSPaolo Bonzini "ioapic", 0x1000); 232610626afSaliguori 233244ac3afSJan Kiszka qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS); 234610626afSaliguori 235244ac3afSJan Kiszka ioapics[instance_no] = s; 236610626afSaliguori } 23796051119SBlue Swirl 238999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data) 239999e12bbSAnthony Liguori { 240999e12bbSAnthony Liguori IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); 24139bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 242999e12bbSAnthony Liguori 243999e12bbSAnthony Liguori k->init = ioapic_init; 24439bffca2SAnthony Liguori dc->reset = ioapic_reset_common; 245999e12bbSAnthony Liguori } 246999e12bbSAnthony Liguori 2478c43a6f0SAndreas Färber static const TypeInfo ioapic_info = { 248999e12bbSAnthony Liguori .name = "ioapic", 24939bffca2SAnthony Liguori .parent = TYPE_IOAPIC_COMMON, 25039bffca2SAnthony Liguori .instance_size = sizeof(IOAPICCommonState), 251999e12bbSAnthony Liguori .class_init = ioapic_class_init, 25296051119SBlue Swirl }; 25396051119SBlue Swirl 25483f7d43aSAndreas Färber static void ioapic_register_types(void) 25596051119SBlue Swirl { 25639bffca2SAnthony Liguori type_register_static(&ioapic_info); 25796051119SBlue Swirl } 25896051119SBlue Swirl 25983f7d43aSAndreas Färber type_init(ioapic_register_types) 260