xref: /qemu/hw/intc/ioapic.c (revision 479c2a1cb7fb82d23e66eab78b00fc5b0638439b)
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