xref: /qemu/hw/intc/ioapic.c (revision e3d0814368d00e7985c31edf5d0cfce45972d4be)
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
1261f3c91aSChetan Pant  * version 2.1 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"
2411ab69d6SMarkus Armbruster #include "qapi/error.h"
256bde8fd6SPavel Butsykin #include "monitor/monitor.h"
26d613f8ccSPaolo Bonzini #include "hw/i386/apic.h"
27852c27e2SPaolo Bonzini #include "hw/i386/x86.h"
28852c27e2SPaolo Bonzini #include "hw/intc/i8259.h"
297f54640bSBernhard Beschow #include "hw/intc/ioapic.h"
307f54640bSBernhard Beschow #include "hw/intc/ioapic_internal.h"
31455e17a1SMichael S. Tsirkin #include "hw/pci/msi.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
3315eafc2eSPaolo Bonzini #include "sysemu/kvm.h"
3446517dd4SMarkus Armbruster #include "sysemu/sysemu.h"
35cb135f59SPeter Xu #include "hw/i386/apic-msidef.h"
36e3d9c925SPeter Xu #include "hw/i386/x86-iommu.h"
37e5074b38SPeter Xu #include "trace.h"
38610626afSaliguori 
3915eafc2eSPaolo Bonzini #define APIC_DELIVERY_MODE_SHIFT 8
4015eafc2eSPaolo Bonzini #define APIC_POLARITY_SHIFT 14
4115eafc2eSPaolo Bonzini #define APIC_TRIG_MODE_SHIFT 15
4215eafc2eSPaolo Bonzini 
43244ac3afSJan Kiszka static IOAPICCommonState *ioapics[MAX_IOAPICS];
440280b571SJan Kiszka 
45db0f8888Sxiaoqiang zhao /* global variable from ioapic_common.c */
46db0f8888Sxiaoqiang zhao extern int ioapic_no;
47db0f8888Sxiaoqiang zhao 
48c15fa0beSPeter Xu struct ioapic_entry_info {
49c15fa0beSPeter Xu     /* fields parsed from IOAPIC entries */
50c15fa0beSPeter Xu     uint8_t masked;
51c15fa0beSPeter Xu     uint8_t trig_mode;
52c15fa0beSPeter Xu     uint16_t dest_idx;
53c15fa0beSPeter Xu     uint8_t dest_mode;
54c15fa0beSPeter Xu     uint8_t delivery_mode;
55c15fa0beSPeter Xu     uint8_t vector;
56c15fa0beSPeter Xu 
57c15fa0beSPeter Xu     /* MSI message generated from above parsed fields */
58c15fa0beSPeter Xu     uint32_t addr;
59c15fa0beSPeter Xu     uint32_t data;
60c15fa0beSPeter Xu };
61c15fa0beSPeter Xu 
62c15fa0beSPeter Xu static void ioapic_entry_parse(uint64_t entry, struct ioapic_entry_info *info)
63c15fa0beSPeter Xu {
64c15fa0beSPeter Xu     memset(info, 0, sizeof(*info));
65c15fa0beSPeter Xu     info->masked = (entry >> IOAPIC_LVT_MASKED_SHIFT) & 1;
66c15fa0beSPeter Xu     info->trig_mode = (entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1;
67c15fa0beSPeter Xu     /*
68c15fa0beSPeter Xu      * By default, this would be dest_id[8] + reserved[8]. When IR
69c15fa0beSPeter Xu      * is enabled, this would be interrupt_index[15] +
70c15fa0beSPeter Xu      * interrupt_format[1]. This field never means anything, but
71c15fa0beSPeter Xu      * only used to generate corresponding MSI.
72c15fa0beSPeter Xu      */
73c15fa0beSPeter Xu     info->dest_idx = (entry >> IOAPIC_LVT_DEST_IDX_SHIFT) & 0xffff;
74c15fa0beSPeter Xu     info->dest_mode = (entry >> IOAPIC_LVT_DEST_MODE_SHIFT) & 1;
75c15fa0beSPeter Xu     info->delivery_mode = (entry >> IOAPIC_LVT_DELIV_MODE_SHIFT) \
76c15fa0beSPeter Xu         & IOAPIC_DM_MASK;
77c15fa0beSPeter Xu     if (info->delivery_mode == IOAPIC_DM_EXTINT) {
78c15fa0beSPeter Xu         info->vector = pic_read_irq(isa_pic);
79c15fa0beSPeter Xu     } else {
80c15fa0beSPeter Xu         info->vector = entry & IOAPIC_VECTOR_MASK;
81c15fa0beSPeter Xu     }
82c15fa0beSPeter Xu 
83c15fa0beSPeter Xu     info->addr = APIC_DEFAULT_ADDRESS | \
84c15fa0beSPeter Xu         (info->dest_idx << MSI_ADDR_DEST_IDX_SHIFT) | \
85c15fa0beSPeter Xu         (info->dest_mode << MSI_ADDR_DEST_MODE_SHIFT);
86c15fa0beSPeter Xu     info->data = (info->vector << MSI_DATA_VECTOR_SHIFT) | \
87c15fa0beSPeter Xu         (info->trig_mode << MSI_DATA_TRIGGER_SHIFT) | \
88c15fa0beSPeter Xu         (info->delivery_mode << MSI_DATA_DELIVERY_MODE_SHIFT);
89c15fa0beSPeter Xu }
90c15fa0beSPeter Xu 
91244ac3afSJan Kiszka static void ioapic_service(IOAPICCommonState *s)
92610626afSaliguori {
93f0bb276bSPaolo Bonzini     AddressSpace *ioapic_as = X86_MACHINE(qdev_get_machine())->ioapic_as;
94c15fa0beSPeter Xu     struct ioapic_entry_info info;
95610626afSaliguori     uint8_t i;
96610626afSaliguori     uint32_t mask;
97610626afSaliguori     uint64_t entry;
98610626afSaliguori 
99610626afSaliguori     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
100610626afSaliguori         mask = 1 << i;
101610626afSaliguori         if (s->irr & mask) {
10215eafc2eSPaolo Bonzini             int coalesce = 0;
10315eafc2eSPaolo Bonzini 
104610626afSaliguori             entry = s->ioredtbl[i];
105c15fa0beSPeter Xu             ioapic_entry_parse(entry, &info);
106c15fa0beSPeter Xu             if (!info.masked) {
107c15fa0beSPeter Xu                 if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
108610626afSaliguori                     s->irr &= ~mask;
1090280b571SJan Kiszka                 } else {
11015eafc2eSPaolo Bonzini                     coalesce = s->ioredtbl[i] & IOAPIC_LVT_REMOTE_IRR;
111e5074b38SPeter Xu                     trace_ioapic_set_remote_irr(i);
1120280b571SJan Kiszka                     s->ioredtbl[i] |= IOAPIC_LVT_REMOTE_IRR;
1130280b571SJan Kiszka                 }
114c15fa0beSPeter Xu 
115f99b86b9SPeter Xu                 if (coalesce) {
116f99b86b9SPeter Xu                     /* We are level triggered interrupts, and the
117f99b86b9SPeter Xu                      * guest should be still working on previous one,
118f99b86b9SPeter Xu                      * so skip it. */
119f99b86b9SPeter Xu                     continue;
120f99b86b9SPeter Xu                 }
121f99b86b9SPeter Xu 
12215eafc2eSPaolo Bonzini #ifdef CONFIG_KVM
12315eafc2eSPaolo Bonzini                 if (kvm_irqchip_is_split()) {
124c15fa0beSPeter Xu                     if (info.trig_mode == IOAPIC_TRIGGER_EDGE) {
12515eafc2eSPaolo Bonzini                         kvm_set_irq(kvm_state, i, 1);
12615eafc2eSPaolo Bonzini                         kvm_set_irq(kvm_state, i, 0);
12715eafc2eSPaolo Bonzini                     } else {
12815eafc2eSPaolo Bonzini                         kvm_set_irq(kvm_state, i, 1);
12915eafc2eSPaolo Bonzini                     }
13015eafc2eSPaolo Bonzini                     continue;
13115eafc2eSPaolo Bonzini                 }
13215eafc2eSPaolo Bonzini #endif
133f99b86b9SPeter Xu 
134cb135f59SPeter Xu                 /* No matter whether IR is enabled, we translate
135cb135f59SPeter Xu                  * the IOAPIC message into a MSI one, and its
136cb135f59SPeter Xu                  * address space will decide whether we need a
137cb135f59SPeter Xu                  * translation. */
138c15fa0beSPeter Xu                 stl_le_phys(ioapic_as, info.addr, info.data);
139610626afSaliguori             }
140610626afSaliguori         }
141610626afSaliguori     }
142610626afSaliguori }
143610626afSaliguori 
144958a01daSVitaly Kuznetsov #define SUCCESSIVE_IRQ_MAX_COUNT 10000
145958a01daSVitaly Kuznetsov 
146958a01daSVitaly Kuznetsov static void delayed_ioapic_service_cb(void *opaque)
147958a01daSVitaly Kuznetsov {
148958a01daSVitaly Kuznetsov     IOAPICCommonState *s = opaque;
149958a01daSVitaly Kuznetsov 
150958a01daSVitaly Kuznetsov     ioapic_service(s);
151958a01daSVitaly Kuznetsov }
152958a01daSVitaly Kuznetsov 
1537d0500c4SBlue Swirl static void ioapic_set_irq(void *opaque, int vector, int level)
154610626afSaliguori {
155244ac3afSJan Kiszka     IOAPICCommonState *s = opaque;
156610626afSaliguori 
157610626afSaliguori     /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
158610626afSaliguori      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
159610626afSaliguori      * the cleanest way of doing it but it should work. */
160610626afSaliguori 
161a2e6ffabSDr. David Alan Gilbert     trace_ioapic_set_irq(vector, level);
162cce5405eSPeter Xu     ioapic_stat_update_irq(s, vector, level);
1631f5e71a8SJan Kiszka     if (vector == 0) {
164610626afSaliguori         vector = 2;
1651f5e71a8SJan Kiszka     }
166960a479fSPaolo Bonzini     if (vector < IOAPIC_NUM_PINS) {
167610626afSaliguori         uint32_t mask = 1 << vector;
168610626afSaliguori         uint64_t entry = s->ioredtbl[vector];
169610626afSaliguori 
1701f5e71a8SJan Kiszka         if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) ==
1711f5e71a8SJan Kiszka             IOAPIC_TRIGGER_LEVEL) {
172610626afSaliguori             /* level triggered */
173610626afSaliguori             if (level) {
174610626afSaliguori                 s->irr |= mask;
175c5955a56SPaolo Bonzini                 if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
176610626afSaliguori                     ioapic_service(s);
177c5955a56SPaolo Bonzini                 }
178610626afSaliguori             } else {
179610626afSaliguori                 s->irr &= ~mask;
180610626afSaliguori             }
181610626afSaliguori         } else {
18247f7be39SJan Kiszka             /* According to the 82093AA manual, we must ignore edge requests
18347f7be39SJan Kiszka              * if the input pin is masked. */
18447f7be39SJan Kiszka             if (level && !(entry & IOAPIC_LVT_MASKED)) {
185610626afSaliguori                 s->irr |= mask;
186610626afSaliguori                 ioapic_service(s);
187610626afSaliguori             }
188610626afSaliguori         }
189610626afSaliguori     }
190610626afSaliguori }
191610626afSaliguori 
19215eafc2eSPaolo Bonzini static void ioapic_update_kvm_routes(IOAPICCommonState *s)
19315eafc2eSPaolo Bonzini {
19415eafc2eSPaolo Bonzini #ifdef CONFIG_KVM
19515eafc2eSPaolo Bonzini     int i;
19615eafc2eSPaolo Bonzini 
19715eafc2eSPaolo Bonzini     if (kvm_irqchip_is_split()) {
19815eafc2eSPaolo Bonzini         for (i = 0; i < IOAPIC_NUM_PINS; i++) {
19915eafc2eSPaolo Bonzini             MSIMessage msg;
200c15fa0beSPeter Xu             struct ioapic_entry_info info;
201c15fa0beSPeter Xu             ioapic_entry_parse(s->ioredtbl[i], &info);
202be1927c9SJan Kiszka             if (!info.masked) {
203c15fa0beSPeter Xu                 msg.address = info.addr;
204c15fa0beSPeter Xu                 msg.data = info.data;
20515eafc2eSPaolo Bonzini                 kvm_irqchip_update_msi_route(kvm_state, i, msg, NULL);
20615eafc2eSPaolo Bonzini             }
207be1927c9SJan Kiszka         }
20815eafc2eSPaolo Bonzini         kvm_irqchip_commit_routes(kvm_state);
20915eafc2eSPaolo Bonzini     }
21015eafc2eSPaolo Bonzini #endif
21115eafc2eSPaolo Bonzini }
21215eafc2eSPaolo Bonzini 
213e3d9c925SPeter Xu #ifdef CONFIG_KVM
214e3d9c925SPeter Xu static void ioapic_iec_notifier(void *private, bool global,
215e3d9c925SPeter Xu                                 uint32_t index, uint32_t mask)
216e3d9c925SPeter Xu {
217e3d9c925SPeter Xu     IOAPICCommonState *s = (IOAPICCommonState *)private;
218e3d9c925SPeter Xu     /* For simplicity, we just update all the routes */
219e3d9c925SPeter Xu     ioapic_update_kvm_routes(s);
220e3d9c925SPeter Xu }
221e3d9c925SPeter Xu #endif
222e3d9c925SPeter Xu 
2230280b571SJan Kiszka void ioapic_eoi_broadcast(int vector)
2240280b571SJan Kiszka {
225244ac3afSJan Kiszka     IOAPICCommonState *s;
2260280b571SJan Kiszka     uint64_t entry;
2270280b571SJan Kiszka     int i, n;
2280280b571SJan Kiszka 
229e5074b38SPeter Xu     trace_ioapic_eoi_broadcast(vector);
230e5074b38SPeter Xu 
2310280b571SJan Kiszka     for (i = 0; i < MAX_IOAPICS; i++) {
2320280b571SJan Kiszka         s = ioapics[i];
2330280b571SJan Kiszka         if (!s) {
2340280b571SJan Kiszka             continue;
2350280b571SJan Kiszka         }
2360280b571SJan Kiszka         for (n = 0; n < IOAPIC_NUM_PINS; n++) {
2370280b571SJan Kiszka             entry = s->ioredtbl[n];
238958a01daSVitaly Kuznetsov 
239958a01daSVitaly Kuznetsov             if ((entry & IOAPIC_VECTOR_MASK) != vector ||
240958a01daSVitaly Kuznetsov                 ((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) != IOAPIC_TRIGGER_LEVEL) {
241958a01daSVitaly Kuznetsov                 continue;
242958a01daSVitaly Kuznetsov             }
243958a01daSVitaly Kuznetsov 
244c82d9d43SPeter Xu #ifdef CONFIG_KVM
245c82d9d43SPeter Xu             /*
246c82d9d43SPeter Xu              * When IOAPIC is in the userspace while APIC is still in
247c82d9d43SPeter Xu              * the kernel (i.e., split irqchip), we have a trick to
248c82d9d43SPeter Xu              * kick the resamplefd logic for registered irqfds from
249c82d9d43SPeter Xu              * userspace to deactivate the IRQ.  When that happens, it
250c82d9d43SPeter Xu              * means the irq bypassed userspace IOAPIC (so the irr and
251c82d9d43SPeter Xu              * remote-irr of the table entry should be bypassed too
252c82d9d43SPeter Xu              * even if interrupt come).  Still kick the resamplefds if
253c82d9d43SPeter Xu              * they're bound to the IRQ, to make sure to EOI the
254c82d9d43SPeter Xu              * interrupt for the hardware correctly.
255c82d9d43SPeter Xu              *
256c82d9d43SPeter Xu              * Note: We still need to go through the irr & remote-irr
257c82d9d43SPeter Xu              * operations below because we don't know whether there're
258c82d9d43SPeter Xu              * emulated devices that are using/sharing the same IRQ.
259c82d9d43SPeter Xu              */
260c82d9d43SPeter Xu             kvm_resample_fd_notify(n);
261c82d9d43SPeter Xu #endif
262c82d9d43SPeter Xu 
263958a01daSVitaly Kuznetsov             if (!(entry & IOAPIC_LVT_REMOTE_IRR)) {
264958a01daSVitaly Kuznetsov                 continue;
265958a01daSVitaly Kuznetsov             }
266958a01daSVitaly Kuznetsov 
267e5074b38SPeter Xu             trace_ioapic_clear_remote_irr(n, vector);
2680280b571SJan Kiszka             s->ioredtbl[n] = entry & ~IOAPIC_LVT_REMOTE_IRR;
269958a01daSVitaly Kuznetsov 
2700280b571SJan Kiszka             if (!(entry & IOAPIC_LVT_MASKED) && (s->irr & (1 << n))) {
27103f990a5SLi Qiang                 ++s->irq_eoi[n];
27203f990a5SLi Qiang                 if (s->irq_eoi[n] >= SUCCESSIVE_IRQ_MAX_COUNT) {
273958a01daSVitaly Kuznetsov                     /*
274958a01daSVitaly Kuznetsov                      * Real hardware does not deliver the interrupt immediately
275958a01daSVitaly Kuznetsov                      * during eoi broadcast, and this lets a buggy guest make
276958a01daSVitaly Kuznetsov                      * slow progress even if it does not correctly handle a
277958a01daSVitaly Kuznetsov                      * level-triggered interrupt. Emulate this behavior if we
278958a01daSVitaly Kuznetsov                      * detect an interrupt storm.
279958a01daSVitaly Kuznetsov                      */
28003f990a5SLi Qiang                     s->irq_eoi[n] = 0;
281958a01daSVitaly Kuznetsov                     timer_mod_anticipate(s->delayed_ioapic_service_timer,
282958a01daSVitaly Kuznetsov                                          qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
283958a01daSVitaly Kuznetsov                                          NANOSECONDS_PER_SECOND / 100);
28403f990a5SLi Qiang                     trace_ioapic_eoi_delayed_reassert(n);
285958a01daSVitaly Kuznetsov                 } else {
2860280b571SJan Kiszka                     ioapic_service(s);
2870280b571SJan Kiszka                 }
288958a01daSVitaly Kuznetsov             } else {
28903f990a5SLi Qiang                 s->irq_eoi[n] = 0;
2900280b571SJan Kiszka             }
2910280b571SJan Kiszka         }
2920280b571SJan Kiszka     }
2930280b571SJan Kiszka }
2940280b571SJan Kiszka 
2954d5bf5f6SJan Kiszka static uint64_t
296a8170e5eSAvi Kivity ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
297610626afSaliguori {
298244ac3afSJan Kiszka     IOAPICCommonState *s = opaque;
299610626afSaliguori     int index;
300610626afSaliguori     uint32_t val = 0;
301610626afSaliguori 
302e5074b38SPeter Xu     addr &= 0xff;
303e5074b38SPeter Xu 
304e5074b38SPeter Xu     switch (addr) {
3051f5e71a8SJan Kiszka     case IOAPIC_IOREGSEL:
306610626afSaliguori         val = s->ioregsel;
3071f5e71a8SJan Kiszka         break;
3081f5e71a8SJan Kiszka     case IOAPIC_IOWIN:
3091a440963SJan Kiszka         if (size != 4) {
3101a440963SJan Kiszka             break;
3111a440963SJan Kiszka         }
312610626afSaliguori         switch (s->ioregsel) {
3131f5e71a8SJan Kiszka         case IOAPIC_REG_ID:
3142f5a3b12SPaolo Bonzini         case IOAPIC_REG_ARB:
3151f5e71a8SJan Kiszka             val = s->id << IOAPIC_ID_SHIFT;
316610626afSaliguori             break;
3171f5e71a8SJan Kiszka         case IOAPIC_REG_VER:
31820fd4b7bSPeter Xu             val = s->version |
3191f5e71a8SJan Kiszka                 ((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
320610626afSaliguori             break;
321610626afSaliguori         default:
3221f5e71a8SJan Kiszka             index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
323610626afSaliguori             if (index >= 0 && index < IOAPIC_NUM_PINS) {
3241f5e71a8SJan Kiszka                 if (s->ioregsel & 1) {
325610626afSaliguori                     val = s->ioredtbl[index] >> 32;
3261f5e71a8SJan Kiszka                 } else {
327610626afSaliguori                     val = s->ioredtbl[index] & 0xffffffff;
328610626afSaliguori                 }
329610626afSaliguori             }
3301f5e71a8SJan Kiszka         }
3311f5e71a8SJan Kiszka         break;
332610626afSaliguori     }
333e5074b38SPeter Xu 
334a2e6ffabSDr. David Alan Gilbert     trace_ioapic_mem_read(addr, s->ioregsel, size, val);
335e5074b38SPeter Xu 
336610626afSaliguori     return val;
337610626afSaliguori }
338610626afSaliguori 
339ed1263c3SPeter Xu /*
340ed1263c3SPeter Xu  * This is to satisfy the hack in Linux kernel. One hack of it is to
341ed1263c3SPeter Xu  * simulate clearing the Remote IRR bit of IOAPIC entry using the
342ed1263c3SPeter Xu  * following:
343ed1263c3SPeter Xu  *
344ed1263c3SPeter Xu  * "For IO-APIC's with EOI register, we use that to do an explicit EOI.
345ed1263c3SPeter Xu  * Otherwise, we simulate the EOI message manually by changing the trigger
346ed1263c3SPeter Xu  * mode to edge and then back to level, with RTE being masked during
347ed1263c3SPeter Xu  * this."
348ed1263c3SPeter Xu  *
349ed1263c3SPeter Xu  * (See linux kernel __eoi_ioapic_pin() comment in commit c0205701)
350ed1263c3SPeter Xu  *
351ed1263c3SPeter Xu  * This is based on the assumption that, Remote IRR bit will be
352ed1263c3SPeter Xu  * cleared by IOAPIC hardware when configured as edge-triggered
353ed1263c3SPeter Xu  * interrupts.
354ed1263c3SPeter Xu  *
355ed1263c3SPeter Xu  * Without this, level-triggered interrupts in IR mode might fail to
356ed1263c3SPeter Xu  * work correctly.
357ed1263c3SPeter Xu  */
358ed1263c3SPeter Xu static inline void
359ed1263c3SPeter Xu ioapic_fix_edge_remote_irr(uint64_t *entry)
360ed1263c3SPeter Xu {
361ed1263c3SPeter Xu     if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) {
362ed1263c3SPeter Xu         /* Edge-triggered interrupts, make sure remote IRR is zero */
363ed1263c3SPeter Xu         *entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR);
364ed1263c3SPeter Xu     }
365ed1263c3SPeter Xu }
366ed1263c3SPeter Xu 
3671f5e71a8SJan Kiszka static void
368a8170e5eSAvi Kivity ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
3694d5bf5f6SJan Kiszka                  unsigned int size)
370610626afSaliguori {
371244ac3afSJan Kiszka     IOAPICCommonState *s = opaque;
372610626afSaliguori     int index;
373610626afSaliguori 
374e5074b38SPeter Xu     addr &= 0xff;
375a2e6ffabSDr. David Alan Gilbert     trace_ioapic_mem_write(addr, s->ioregsel, size, val);
376e5074b38SPeter Xu 
377e5074b38SPeter Xu     switch (addr) {
3781f5e71a8SJan Kiszka     case IOAPIC_IOREGSEL:
379610626afSaliguori         s->ioregsel = val;
3801f5e71a8SJan Kiszka         break;
3811f5e71a8SJan Kiszka     case IOAPIC_IOWIN:
3821a440963SJan Kiszka         if (size != 4) {
3831a440963SJan Kiszka             break;
3841a440963SJan Kiszka         }
385610626afSaliguori         switch (s->ioregsel) {
3861f5e71a8SJan Kiszka         case IOAPIC_REG_ID:
3871f5e71a8SJan Kiszka             s->id = (val >> IOAPIC_ID_SHIFT) & IOAPIC_ID_MASK;
3881f5e71a8SJan Kiszka             break;
3891f5e71a8SJan Kiszka         case IOAPIC_REG_VER:
3901f5e71a8SJan Kiszka         case IOAPIC_REG_ARB:
3911f5e71a8SJan Kiszka             break;
392610626afSaliguori         default:
3931f5e71a8SJan Kiszka             index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
394610626afSaliguori             if (index >= 0 && index < IOAPIC_NUM_PINS) {
395479c2a1cSPeter Xu                 uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS;
396610626afSaliguori                 if (s->ioregsel & 1) {
397610626afSaliguori                     s->ioredtbl[index] &= 0xffffffff;
398610626afSaliguori                     s->ioredtbl[index] |= (uint64_t)val << 32;
399610626afSaliguori                 } else {
400610626afSaliguori                     s->ioredtbl[index] &= ~0xffffffffULL;
401610626afSaliguori                     s->ioredtbl[index] |= val;
402610626afSaliguori                 }
403479c2a1cSPeter Xu                 /* restore RO bits */
404479c2a1cSPeter Xu                 s->ioredtbl[index] &= IOAPIC_RW_BITS;
405479c2a1cSPeter Xu                 s->ioredtbl[index] |= ro_bits;
406d15d3d57SLi Qiang                 s->irq_eoi[index] = 0;
407ed1263c3SPeter Xu                 ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
40854ad31fbSDavid Woodhouse                 ioapic_update_kvm_routes(s);
409610626afSaliguori                 ioapic_service(s);
410610626afSaliguori             }
411610626afSaliguori         }
4121f5e71a8SJan Kiszka         break;
41320fd4b7bSPeter Xu     case IOAPIC_EOI:
41420fd4b7bSPeter Xu         /* Explicit EOI is only supported for IOAPIC version 0x20 */
41520fd4b7bSPeter Xu         if (size != 4 || s->version != 0x20) {
41620fd4b7bSPeter Xu             break;
41720fd4b7bSPeter Xu         }
41820fd4b7bSPeter Xu         ioapic_eoi_broadcast(val);
41920fd4b7bSPeter Xu         break;
420610626afSaliguori     }
421610626afSaliguori }
422610626afSaliguori 
4234d5bf5f6SJan Kiszka static const MemoryRegionOps ioapic_io_ops = {
4244d5bf5f6SJan Kiszka     .read = ioapic_mem_read,
4254d5bf5f6SJan Kiszka     .write = ioapic_mem_write,
4264d5bf5f6SJan Kiszka     .endianness = DEVICE_NATIVE_ENDIAN,
427610626afSaliguori };
428610626afSaliguori 
429e3d9c925SPeter Xu static void ioapic_machine_done_notify(Notifier *notifier, void *data)
430e3d9c925SPeter Xu {
431e3d9c925SPeter Xu #ifdef CONFIG_KVM
432e3d9c925SPeter Xu     IOAPICCommonState *s = container_of(notifier, IOAPICCommonState,
433e3d9c925SPeter Xu                                         machine_done);
434e3d9c925SPeter Xu 
435e3d9c925SPeter Xu     if (kvm_irqchip_is_split()) {
436e3d9c925SPeter Xu         X86IOMMUState *iommu = x86_iommu_get_default();
437e3d9c925SPeter Xu         if (iommu) {
438e3d9c925SPeter Xu             /* Register this IOAPIC with IOMMU IEC notifier, so that
439e3d9c925SPeter Xu              * when there are IR invalidates, we can be notified to
440e3d9c925SPeter Xu              * update kernel IR cache. */
441e3d9c925SPeter Xu             x86_iommu_iec_register_notifier(iommu, ioapic_iec_notifier, s);
442e3d9c925SPeter Xu         }
443e3d9c925SPeter Xu     }
444e3d9c925SPeter Xu #endif
445e3d9c925SPeter Xu }
446e3d9c925SPeter Xu 
4478d5516beSPeter Xu #define IOAPIC_VER_DEF 0x20
4488d5516beSPeter Xu 
449db0f8888Sxiaoqiang zhao static void ioapic_realize(DeviceState *dev, Error **errp)
450610626afSaliguori {
451db0f8888Sxiaoqiang zhao     IOAPICCommonState *s = IOAPIC_COMMON(dev);
452f9771858Sxiaoqiang zhao 
45320fd4b7bSPeter Xu     if (s->version != 0x11 && s->version != 0x20) {
45411ab69d6SMarkus Armbruster         error_setg(errp, "IOAPIC only supports version 0x11 or 0x20 "
4558d5516beSPeter Xu                    "(default: 0x%x).", IOAPIC_VER_DEF);
45611ab69d6SMarkus Armbruster         return;
45720fd4b7bSPeter Xu     }
45820fd4b7bSPeter Xu 
4591437c94bSPaolo Bonzini     memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
4601437c94bSPaolo Bonzini                           "ioapic", 0x1000);
461610626afSaliguori 
462958a01daSVitaly Kuznetsov     s->delayed_ioapic_service_timer =
463958a01daSVitaly Kuznetsov         timer_new_ns(QEMU_CLOCK_VIRTUAL, delayed_ioapic_service_cb, s);
464958a01daSVitaly Kuznetsov 
465f9771858Sxiaoqiang zhao     qdev_init_gpio_in(dev, ioapic_set_irq, IOAPIC_NUM_PINS);
466610626afSaliguori 
467db0f8888Sxiaoqiang zhao     ioapics[ioapic_no] = s;
468e3d9c925SPeter Xu     s->machine_done.notify = ioapic_machine_done_notify;
469e3d9c925SPeter Xu     qemu_add_machine_init_done_notifier(&s->machine_done);
470610626afSaliguori }
47196051119SBlue Swirl 
472b69c3c21SMarkus Armbruster static void ioapic_unrealize(DeviceState *dev)
473958a01daSVitaly Kuznetsov {
474958a01daSVitaly Kuznetsov     IOAPICCommonState *s = IOAPIC_COMMON(dev);
475958a01daSVitaly Kuznetsov 
476958a01daSVitaly Kuznetsov     timer_free(s->delayed_ioapic_service_timer);
477958a01daSVitaly Kuznetsov }
478958a01daSVitaly Kuznetsov 
47920fd4b7bSPeter Xu static Property ioapic_properties[] = {
4808d5516beSPeter Xu     DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF),
48120fd4b7bSPeter Xu     DEFINE_PROP_END_OF_LIST(),
48220fd4b7bSPeter Xu };
48320fd4b7bSPeter Xu 
484999e12bbSAnthony Liguori static void ioapic_class_init(ObjectClass *klass, void *data)
485999e12bbSAnthony Liguori {
486999e12bbSAnthony Liguori     IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
48739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
488999e12bbSAnthony Liguori 
489db0f8888Sxiaoqiang zhao     k->realize = ioapic_realize;
490958a01daSVitaly Kuznetsov     k->unrealize = ioapic_unrealize;
4910f254b1aSPeter Xu     /*
4920f254b1aSPeter Xu      * If APIC is in kernel, we need to update the kernel cache after
4930f254b1aSPeter Xu      * migration, otherwise first 24 gsi routes will be invalid.
4940f254b1aSPeter Xu      */
4950f254b1aSPeter Xu     k->post_load = ioapic_update_kvm_routes;
496*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, ioapic_reset_common);
4974f67d30bSMarc-André Lureau     device_class_set_props(dc, ioapic_properties);
498999e12bbSAnthony Liguori }
499999e12bbSAnthony Liguori 
5008c43a6f0SAndreas Färber static const TypeInfo ioapic_info = {
50134bec7a8SLi Qiang     .name          = TYPE_IOAPIC,
50239bffca2SAnthony Liguori     .parent        = TYPE_IOAPIC_COMMON,
50339bffca2SAnthony Liguori     .instance_size = sizeof(IOAPICCommonState),
504999e12bbSAnthony Liguori     .class_init    = ioapic_class_init,
50596051119SBlue Swirl };
50696051119SBlue Swirl 
50783f7d43aSAndreas Färber static void ioapic_register_types(void)
50896051119SBlue Swirl {
50939bffca2SAnthony Liguori     type_register_static(&ioapic_info);
51096051119SBlue Swirl }
51196051119SBlue Swirl 
51283f7d43aSAndreas Färber type_init(ioapic_register_types)
513