xref: /qemu/hw/intc/apic.c (revision 774204cf9874e58dc7fc13394a505452357750ad)
1574bbf7bSbellard /*
2574bbf7bSbellard  *  APIC support
3574bbf7bSbellard  *
4574bbf7bSbellard  *  Copyright (c) 2004-2005 Fabrice Bellard
5574bbf7bSbellard  *
6574bbf7bSbellard  * This library is free software; you can redistribute it and/or
7574bbf7bSbellard  * modify it under the terms of the GNU Lesser General Public
8574bbf7bSbellard  * License as published by the Free Software Foundation; either
961f3c91aSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10574bbf7bSbellard  *
11574bbf7bSbellard  * This library is distributed in the hope that it will be useful,
12574bbf7bSbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13574bbf7bSbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14574bbf7bSbellard  * Lesser General Public License for more details.
15574bbf7bSbellard  *
16574bbf7bSbellard  * You should have received a copy of the GNU Lesser General Public
178167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>
18574bbf7bSbellard  */
19b6a0aa05SPeter Maydell #include "qemu/osdep.h"
201de7afc9SPaolo Bonzini #include "qemu/thread.h"
21cc37d98bSRichard Henderson #include "qemu/error-report.h"
220d09e41aSPaolo Bonzini #include "hw/i386/apic_internal.h"
230d09e41aSPaolo Bonzini #include "hw/i386/apic.h"
247f54640bSBernhard Beschow #include "hw/intc/ioapic.h"
25852c27e2SPaolo Bonzini #include "hw/intc/i8259.h"
262b85e0cdSThomas Huth #include "hw/intc/kvm_irqcount.h"
2783c9f4caSPaolo Bonzini #include "hw/pci/msi.h"
281de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
292c933ac6SPaolo Bonzini #include "sysemu/kvm.h"
30d8023f31SBlue Swirl #include "trace.h"
310d09e41aSPaolo Bonzini #include "hw/i386/apic-msidef.h"
32889211b1SIgor Mammedov #include "qapi/error.h"
33db1015e9SEduardo Habkost #include "qom/object.h"
34574bbf7bSbellard 
35e5ad936bSJan Kiszka #define SYNC_FROM_VAPIC                 0x1
36e5ad936bSJan Kiszka #define SYNC_TO_VAPIC                   0x2
37e5ad936bSJan Kiszka #define SYNC_ISR_IRR_TO_VAPIC           0x4
38e5ad936bSJan Kiszka 
39b5ee0468SBui Quang Minh static APICCommonState **local_apics;
40b5ee0468SBui Quang Minh static uint32_t max_apics;
41b5ee0468SBui Quang Minh static uint32_t max_apic_words;
4254c96da7SMichael S. Tsirkin 
43927d5a1dSWanpeng Li #define TYPE_APIC "apic"
44fa34a3c5SEduardo Habkost /*This is reusing the APICCommonState typedef from APIC_COMMON */
45fa34a3c5SEduardo Habkost DECLARE_INSTANCE_CHECKER(APICCommonState, APIC,
46fa34a3c5SEduardo Habkost                          TYPE_APIC)
47927d5a1dSWanpeng Li 
48dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
49dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s);
50610626afSaliguori static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
51b5ee0468SBui Quang Minh                                       uint32_t dest, uint8_t dest_mode);
52b5ee0468SBui Quang Minh 
53b5ee0468SBui Quang Minh void apic_set_max_apic_id(uint32_t max_apic_id)
54b5ee0468SBui Quang Minh {
55b5ee0468SBui Quang Minh     int word_size = 32;
56b5ee0468SBui Quang Minh 
57b5ee0468SBui Quang Minh     /* round up the max apic id to next multiple of words */
58b5ee0468SBui Quang Minh     max_apics = (max_apic_id + word_size - 1) & ~(word_size - 1);
59b5ee0468SBui Quang Minh 
60b5ee0468SBui Quang Minh     local_apics = g_malloc0(sizeof(*local_apics) * max_apics);
61b5ee0468SBui Quang Minh     max_apic_words = max_apics >> 5;
62b5ee0468SBui Quang Minh }
63b5ee0468SBui Quang Minh 
64d592d303Sbellard 
653b63c04eSaurel32 /* Find first bit starting from msb */
66edf9735eSMichael S. Tsirkin static int apic_fls_bit(uint32_t value)
673b63c04eSaurel32 {
683b63c04eSaurel32     return 31 - clz32(value);
693b63c04eSaurel32 }
703b63c04eSaurel32 
71e95f5491Saurel32 /* Find first bit starting from lsb */
72edf9735eSMichael S. Tsirkin static int apic_ffs_bit(uint32_t value)
73d3e9db93Sbellard {
74bb7e7293Saurel32     return ctz32(value);
75d3e9db93Sbellard }
76d3e9db93Sbellard 
77edf9735eSMichael S. Tsirkin static inline void apic_reset_bit(uint32_t *tab, int index)
78d3e9db93Sbellard {
79d3e9db93Sbellard     int i, mask;
80d3e9db93Sbellard     i = index >> 5;
81d3e9db93Sbellard     mask = 1 << (index & 0x1f);
82d3e9db93Sbellard     tab[i] &= ~mask;
83d3e9db93Sbellard }
84d3e9db93Sbellard 
85e5ad936bSJan Kiszka /* return -1 if no bit is set */
86e5ad936bSJan Kiszka static int get_highest_priority_int(uint32_t *tab)
87e5ad936bSJan Kiszka {
88e5ad936bSJan Kiszka     int i;
89e5ad936bSJan Kiszka     for (i = 7; i >= 0; i--) {
90e5ad936bSJan Kiszka         if (tab[i] != 0) {
91edf9735eSMichael S. Tsirkin             return i * 32 + apic_fls_bit(tab[i]);
92e5ad936bSJan Kiszka         }
93e5ad936bSJan Kiszka     }
94e5ad936bSJan Kiszka     return -1;
95e5ad936bSJan Kiszka }
96e5ad936bSJan Kiszka 
97e5ad936bSJan Kiszka static void apic_sync_vapic(APICCommonState *s, int sync_type)
98e5ad936bSJan Kiszka {
99e5ad936bSJan Kiszka     VAPICState vapic_state;
100e5ad936bSJan Kiszka     size_t length;
101e5ad936bSJan Kiszka     off_t start;
102e5ad936bSJan Kiszka     int vector;
103e5ad936bSJan Kiszka 
104e5ad936bSJan Kiszka     if (!s->vapic_paddr) {
105e5ad936bSJan Kiszka         return;
106e5ad936bSJan Kiszka     }
107e5ad936bSJan Kiszka     if (sync_type & SYNC_FROM_VAPIC) {
108eb6282f2SStefan Weil         cpu_physical_memory_read(s->vapic_paddr, &vapic_state,
109eb6282f2SStefan Weil                                  sizeof(vapic_state));
110e5ad936bSJan Kiszka         s->tpr = vapic_state.tpr;
111e5ad936bSJan Kiszka     }
112e5ad936bSJan Kiszka     if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
113e5ad936bSJan Kiszka         start = offsetof(VAPICState, isr);
114e5ad936bSJan Kiszka         length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
115e5ad936bSJan Kiszka 
116e5ad936bSJan Kiszka         if (sync_type & SYNC_TO_VAPIC) {
11760e82579SAndreas Färber             assert(qemu_cpu_is_self(CPU(s->cpu)));
118e5ad936bSJan Kiszka 
119e5ad936bSJan Kiszka             vapic_state.tpr = s->tpr;
120e5ad936bSJan Kiszka             vapic_state.enabled = 1;
121e5ad936bSJan Kiszka             start = 0;
122e5ad936bSJan Kiszka             length = sizeof(VAPICState);
123e5ad936bSJan Kiszka         }
124e5ad936bSJan Kiszka 
125e5ad936bSJan Kiszka         vector = get_highest_priority_int(s->isr);
126e5ad936bSJan Kiszka         if (vector < 0) {
127e5ad936bSJan Kiszka             vector = 0;
128e5ad936bSJan Kiszka         }
129e5ad936bSJan Kiszka         vapic_state.isr = vector & 0xf0;
130e5ad936bSJan Kiszka 
131e5ad936bSJan Kiszka         vapic_state.zero = 0;
132e5ad936bSJan Kiszka 
133e5ad936bSJan Kiszka         vector = get_highest_priority_int(s->irr);
134e5ad936bSJan Kiszka         if (vector < 0) {
135e5ad936bSJan Kiszka             vector = 0;
136e5ad936bSJan Kiszka         }
137e5ad936bSJan Kiszka         vapic_state.irr = vector & 0xff;
138e5ad936bSJan Kiszka 
1393c8133f9SPeter Maydell         address_space_write_rom(&address_space_memory,
1402a221651SEdgar E. Iglesias                                 s->vapic_paddr + start,
1413c8133f9SPeter Maydell                                 MEMTXATTRS_UNSPECIFIED,
142e5ad936bSJan Kiszka                                 ((void *)&vapic_state) + start, length);
143e5ad936bSJan Kiszka     }
144e5ad936bSJan Kiszka }
145e5ad936bSJan Kiszka 
146e5ad936bSJan Kiszka static void apic_vapic_base_update(APICCommonState *s)
147e5ad936bSJan Kiszka {
148e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_TO_VAPIC);
149e5ad936bSJan Kiszka }
150e5ad936bSJan Kiszka 
151dae01685SJan Kiszka static void apic_local_deliver(APICCommonState *s, int vector)
152a5b38b51Saurel32 {
153a5b38b51Saurel32     uint32_t lvt = s->lvt[vector];
154a5b38b51Saurel32     int trigger_mode;
155a5b38b51Saurel32 
156d8023f31SBlue Swirl     trace_apic_local_deliver(vector, (lvt >> 8) & 7);
157d8023f31SBlue Swirl 
158a5b38b51Saurel32     if (lvt & APIC_LVT_MASKED)
159a5b38b51Saurel32         return;
160a5b38b51Saurel32 
161a5b38b51Saurel32     switch ((lvt >> 8) & 7) {
162a5b38b51Saurel32     case APIC_DM_SMI:
163c3affe56SAndreas Färber         cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
164a5b38b51Saurel32         break;
165a5b38b51Saurel32 
166a5b38b51Saurel32     case APIC_DM_NMI:
167c3affe56SAndreas Färber         cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
168a5b38b51Saurel32         break;
169a5b38b51Saurel32 
170a5b38b51Saurel32     case APIC_DM_EXTINT:
171c3affe56SAndreas Färber         cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
172a5b38b51Saurel32         break;
173a5b38b51Saurel32 
174a5b38b51Saurel32     case APIC_DM_FIXED:
175a5b38b51Saurel32         trigger_mode = APIC_TRIGGER_EDGE;
176a5b38b51Saurel32         if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
177a5b38b51Saurel32             (lvt & APIC_LVT_LEVEL_TRIGGER))
178a5b38b51Saurel32             trigger_mode = APIC_TRIGGER_LEVEL;
179a5b38b51Saurel32         apic_set_irq(s, lvt & 0xff, trigger_mode);
180a5b38b51Saurel32     }
181a5b38b51Saurel32 }
182a5b38b51Saurel32 
183d3b0c9e9Sxiaoqiang zhao void apic_deliver_pic_intr(DeviceState *dev, int level)
1841a7de94aSaurel32 {
185927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
18692a16d7aSBlue Swirl 
187cf6d64bfSBlue Swirl     if (level) {
188cf6d64bfSBlue Swirl         apic_local_deliver(s, APIC_LVT_LINT0);
189cf6d64bfSBlue Swirl     } else {
1901a7de94aSaurel32         uint32_t lvt = s->lvt[APIC_LVT_LINT0];
1911a7de94aSaurel32 
1921a7de94aSaurel32         switch ((lvt >> 8) & 7) {
1931a7de94aSaurel32         case APIC_DM_FIXED:
1941a7de94aSaurel32             if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
1951a7de94aSaurel32                 break;
196edf9735eSMichael S. Tsirkin             apic_reset_bit(s->irr, lvt & 0xff);
1971a7de94aSaurel32             /* fall through */
1981a7de94aSaurel32         case APIC_DM_EXTINT:
1998092cb71SPaolo Bonzini             apic_update_irq(s);
2001a7de94aSaurel32             break;
2011a7de94aSaurel32         }
2021a7de94aSaurel32     }
2031a7de94aSaurel32 }
2041a7de94aSaurel32 
205dae01685SJan Kiszka static void apic_external_nmi(APICCommonState *s)
20602c09195SJan Kiszka {
20702c09195SJan Kiszka     apic_local_deliver(s, APIC_LVT_LINT1);
20802c09195SJan Kiszka }
20902c09195SJan Kiszka 
210d3e9db93Sbellard #define foreach_apic(apic, deliver_bitmask, code) \
211d3e9db93Sbellard {\
2126d55574aSPeter Maydell     int __i, __j;\
213b5ee0468SBui Quang Minh     for (__i = 0; __i < max_apic_words; __i++) {\
2146d55574aSPeter Maydell         uint32_t __mask = deliver_bitmask[__i];\
215d3e9db93Sbellard         if (__mask) {\
216d3e9db93Sbellard             for (__j = 0; __j < 32; __j++) {\
2176d55574aSPeter Maydell                 if (__mask & (1U << __j)) {\
218d3e9db93Sbellard                     apic = local_apics[__i * 32 + __j];\
219d3e9db93Sbellard                     if (apic) {\
220d3e9db93Sbellard                         code;\
221d3e9db93Sbellard                     }\
222d3e9db93Sbellard                 }\
223d3e9db93Sbellard             }\
224d3e9db93Sbellard         }\
225d3e9db93Sbellard     }\
226d3e9db93Sbellard }
227d3e9db93Sbellard 
228d3e9db93Sbellard static void apic_bus_deliver(const uint32_t *deliver_bitmask,
2291f6f408cSJan Kiszka                              uint8_t delivery_mode, uint8_t vector_num,
230d592d303Sbellard                              uint8_t trigger_mode)
231d592d303Sbellard {
232dae01685SJan Kiszka     APICCommonState *apic_iter;
233d592d303Sbellard 
234d592d303Sbellard     switch (delivery_mode) {
235d592d303Sbellard         case APIC_DM_LOWPRI:
2368dd69b8fSbellard             /* XXX: search for focus processor, arbitration */
237d3e9db93Sbellard             {
238d3e9db93Sbellard                 int i, d;
239d3e9db93Sbellard                 d = -1;
240b5ee0468SBui Quang Minh                 for (i = 0; i < max_apic_words; i++) {
241d3e9db93Sbellard                     if (deliver_bitmask[i]) {
242edf9735eSMichael S. Tsirkin                         d = i * 32 + apic_ffs_bit(deliver_bitmask[i]);
2438dd69b8fSbellard                         break;
244d3e9db93Sbellard                     }
245d3e9db93Sbellard                 }
246d3e9db93Sbellard                 if (d >= 0) {
247d3e9db93Sbellard                     apic_iter = local_apics[d];
248d3e9db93Sbellard                     if (apic_iter) {
249d3e9db93Sbellard                         apic_set_irq(apic_iter, vector_num, trigger_mode);
250d3e9db93Sbellard                     }
251d3e9db93Sbellard                 }
252d3e9db93Sbellard             }
253d3e9db93Sbellard             return;
2548dd69b8fSbellard 
255d592d303Sbellard         case APIC_DM_FIXED:
256d592d303Sbellard             break;
257d592d303Sbellard 
258d592d303Sbellard         case APIC_DM_SMI:
259e2eb9d3eSaurel32             foreach_apic(apic_iter, deliver_bitmask,
260c3affe56SAndreas Färber                 cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
26160671e58SAndreas Färber             );
262e2eb9d3eSaurel32             return;
263e2eb9d3eSaurel32 
264d592d303Sbellard         case APIC_DM_NMI:
265e2eb9d3eSaurel32             foreach_apic(apic_iter, deliver_bitmask,
266c3affe56SAndreas Färber                 cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
26760671e58SAndreas Färber             );
268e2eb9d3eSaurel32             return;
269d592d303Sbellard 
270d592d303Sbellard         case APIC_DM_INIT:
271d592d303Sbellard             /* normal INIT IPI sent to processors */
272d3e9db93Sbellard             foreach_apic(apic_iter, deliver_bitmask,
273c3affe56SAndreas Färber                          cpu_interrupt(CPU(apic_iter->cpu),
27460671e58SAndreas Färber                                        CPU_INTERRUPT_INIT)
27560671e58SAndreas Färber             );
276d592d303Sbellard             return;
277d592d303Sbellard 
278d592d303Sbellard         case APIC_DM_EXTINT:
279b1fc0348Sbellard             /* handled in I/O APIC code */
280d592d303Sbellard             break;
281d592d303Sbellard 
282d592d303Sbellard         default:
283d592d303Sbellard             return;
284d592d303Sbellard     }
285d592d303Sbellard 
286d3e9db93Sbellard     foreach_apic(apic_iter, deliver_bitmask,
287d3e9db93Sbellard                  apic_set_irq(apic_iter, vector_num, trigger_mode) );
288d592d303Sbellard }
289574bbf7bSbellard 
290b5ee0468SBui Quang Minh static void apic_deliver_irq(uint32_t dest, uint8_t dest_mode,
291b5ee0468SBui Quang Minh                              uint8_t delivery_mode, uint8_t vector_num,
292b5ee0468SBui Quang Minh                              uint8_t trigger_mode)
293610626afSaliguori {
294b5ee0468SBui Quang Minh     uint32_t *deliver_bitmask = g_malloc(max_apic_words * sizeof(uint32_t));
295610626afSaliguori 
296d8023f31SBlue Swirl     trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
2971f6f408cSJan Kiszka                            trigger_mode);
298d8023f31SBlue Swirl 
299610626afSaliguori     apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
3001f6f408cSJan Kiszka     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
301b5ee0468SBui Quang Minh     g_free(deliver_bitmask);
302610626afSaliguori }
303610626afSaliguori 
304b2101358SBui Quang Minh bool is_x2apic_mode(DeviceState *dev)
305b2101358SBui Quang Minh {
306b2101358SBui Quang Minh     APICCommonState *s = APIC(dev);
307b2101358SBui Quang Minh 
308b2101358SBui Quang Minh     return s->apicbase & MSR_IA32_APICBASE_EXTD;
309b2101358SBui Quang Minh }
310b2101358SBui Quang Minh 
311*774204cfSBui Quang Minh static int apic_set_base_check(APICCommonState *s, uint64_t val)
312574bbf7bSbellard {
313*774204cfSBui Quang Minh     /* Enable x2apic when x2apic is not supported by CPU */
314*774204cfSBui Quang Minh     if (!cpu_has_x2apic_feature(&s->cpu->env) &&
315*774204cfSBui Quang Minh         val & MSR_IA32_APICBASE_EXTD) {
316*774204cfSBui Quang Minh         return -1;
317*774204cfSBui Quang Minh     }
318*774204cfSBui Quang Minh 
319*774204cfSBui Quang Minh     /*
320*774204cfSBui Quang Minh      * Transition into invalid state
321*774204cfSBui Quang Minh      * (s->apicbase & MSR_IA32_APICBASE_ENABLE == 0) &&
322*774204cfSBui Quang Minh      * (s->apicbase & MSR_IA32_APICBASE_EXTD) == 1
323*774204cfSBui Quang Minh      */
324*774204cfSBui Quang Minh     if (!(val & MSR_IA32_APICBASE_ENABLE) &&
325*774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_EXTD)) {
326*774204cfSBui Quang Minh         return -1;
327*774204cfSBui Quang Minh     }
328*774204cfSBui Quang Minh 
329*774204cfSBui Quang Minh     /* Invalid transition from disabled mode to x2APIC */
330*774204cfSBui Quang Minh     if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
331*774204cfSBui Quang Minh         !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
332*774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_ENABLE) &&
333*774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_EXTD)) {
334*774204cfSBui Quang Minh         return -1;
335*774204cfSBui Quang Minh     }
336*774204cfSBui Quang Minh 
337*774204cfSBui Quang Minh     /* Invalid transition from x2APIC to xAPIC */
338*774204cfSBui Quang Minh     if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
339*774204cfSBui Quang Minh         (s->apicbase & MSR_IA32_APICBASE_EXTD) &&
340*774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_ENABLE) &&
341*774204cfSBui Quang Minh         !(val & MSR_IA32_APICBASE_EXTD)) {
342*774204cfSBui Quang Minh         return -1;
343*774204cfSBui Quang Minh     }
344*774204cfSBui Quang Minh 
345*774204cfSBui Quang Minh     return 0;
346*774204cfSBui Quang Minh }
347*774204cfSBui Quang Minh 
348*774204cfSBui Quang Minh static int apic_set_base(APICCommonState *s, uint64_t val)
349*774204cfSBui Quang Minh {
350*774204cfSBui Quang Minh     if (apic_set_base_check(s, val) < 0) {
351*774204cfSBui Quang Minh         return -1;
352*774204cfSBui Quang Minh     }
353*774204cfSBui Quang Minh 
354574bbf7bSbellard     s->apicbase = (val & 0xfffff000) |
355574bbf7bSbellard         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
356574bbf7bSbellard     /* if disabled, cannot be enabled again */
357574bbf7bSbellard     if (!(val & MSR_IA32_APICBASE_ENABLE)) {
358574bbf7bSbellard         s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
35960671e58SAndreas Färber         cpu_clear_apic_feature(&s->cpu->env);
360574bbf7bSbellard         s->spurious_vec &= ~APIC_SV_ENABLE;
361574bbf7bSbellard     }
362*774204cfSBui Quang Minh 
363*774204cfSBui Quang Minh     /* Transition from disabled mode to xAPIC */
364*774204cfSBui Quang Minh     if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
365*774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_ENABLE)) {
366*774204cfSBui Quang Minh         s->apicbase |= MSR_IA32_APICBASE_ENABLE;
367*774204cfSBui Quang Minh         cpu_set_apic_feature(&s->cpu->env);
368*774204cfSBui Quang Minh     }
369*774204cfSBui Quang Minh 
370*774204cfSBui Quang Minh     /* Transition from xAPIC to x2APIC */
371*774204cfSBui Quang Minh     if (cpu_has_x2apic_feature(&s->cpu->env) &&
372*774204cfSBui Quang Minh         !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
373*774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_EXTD)) {
374*774204cfSBui Quang Minh         s->apicbase |= MSR_IA32_APICBASE_EXTD;
375*774204cfSBui Quang Minh 
376*774204cfSBui Quang Minh         s->log_dest = ((s->initial_apic_id & 0xffff0) << 16) |
377*774204cfSBui Quang Minh                       (1 << (s->initial_apic_id & 0xf));
378*774204cfSBui Quang Minh     }
379*774204cfSBui Quang Minh 
380*774204cfSBui Quang Minh     return 0;
381574bbf7bSbellard }
382574bbf7bSbellard 
383dae01685SJan Kiszka static void apic_set_tpr(APICCommonState *s, uint8_t val)
384574bbf7bSbellard {
385e5ad936bSJan Kiszka     /* Updates from cr8 are ignored while the VAPIC is active */
386e5ad936bSJan Kiszka     if (!s->vapic_paddr) {
387e5ad936bSJan Kiszka         s->tpr = val << 4;
388d592d303Sbellard         apic_update_irq(s);
3899230e66eSbellard     }
390e5ad936bSJan Kiszka }
3919230e66eSbellard 
3922cb9f06eSSergio Andres Gomez Del Real int apic_get_highest_priority_irr(DeviceState *dev)
3932cb9f06eSSergio Andres Gomez Del Real {
3942cb9f06eSSergio Andres Gomez Del Real     APICCommonState *s;
3952cb9f06eSSergio Andres Gomez Del Real 
3962cb9f06eSSergio Andres Gomez Del Real     if (!dev) {
3972cb9f06eSSergio Andres Gomez Del Real         /* no interrupts */
3982cb9f06eSSergio Andres Gomez Del Real         return -1;
3992cb9f06eSSergio Andres Gomez Del Real     }
4002cb9f06eSSergio Andres Gomez Del Real     s = APIC_COMMON(dev);
4012cb9f06eSSergio Andres Gomez Del Real     return get_highest_priority_int(s->irr);
4022cb9f06eSSergio Andres Gomez Del Real }
4032cb9f06eSSergio Andres Gomez Del Real 
404e5ad936bSJan Kiszka static uint8_t apic_get_tpr(APICCommonState *s)
405d592d303Sbellard {
406e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
407e5ad936bSJan Kiszka     return s->tpr >> 4;
408d592d303Sbellard }
409d592d303Sbellard 
41082a5e042SPavel Butsykin int apic_get_ppr(APICCommonState *s)
411574bbf7bSbellard {
412574bbf7bSbellard     int tpr, isrv, ppr;
413574bbf7bSbellard 
414574bbf7bSbellard     tpr = (s->tpr >> 4);
415574bbf7bSbellard     isrv = get_highest_priority_int(s->isr);
416574bbf7bSbellard     if (isrv < 0)
417574bbf7bSbellard         isrv = 0;
418574bbf7bSbellard     isrv >>= 4;
419574bbf7bSbellard     if (tpr >= isrv)
420574bbf7bSbellard         ppr = s->tpr;
421574bbf7bSbellard     else
422574bbf7bSbellard         ppr = isrv << 4;
423574bbf7bSbellard     return ppr;
424574bbf7bSbellard }
425574bbf7bSbellard 
426dae01685SJan Kiszka static int apic_get_arb_pri(APICCommonState *s)
427d592d303Sbellard {
428d592d303Sbellard     /* XXX: arbitration */
429d592d303Sbellard     return 0;
430d592d303Sbellard }
431d592d303Sbellard 
4320fbfbb59SGleb Natapov 
4330fbfbb59SGleb Natapov /*
4340fbfbb59SGleb Natapov  * <0 - low prio interrupt,
4350fbfbb59SGleb Natapov  * 0  - no interrupt,
4360fbfbb59SGleb Natapov  * >0 - interrupt number
4370fbfbb59SGleb Natapov  */
438dae01685SJan Kiszka static int apic_irq_pending(APICCommonState *s)
4390fbfbb59SGleb Natapov {
4400fbfbb59SGleb Natapov     int irrv, ppr;
44160e68042SPaolo Bonzini 
44260e68042SPaolo Bonzini     if (!(s->spurious_vec & APIC_SV_ENABLE)) {
44360e68042SPaolo Bonzini         return 0;
44460e68042SPaolo Bonzini     }
44560e68042SPaolo Bonzini 
4460fbfbb59SGleb Natapov     irrv = get_highest_priority_int(s->irr);
4470fbfbb59SGleb Natapov     if (irrv < 0) {
4480fbfbb59SGleb Natapov         return 0;
4490fbfbb59SGleb Natapov     }
4500fbfbb59SGleb Natapov     ppr = apic_get_ppr(s);
4510fbfbb59SGleb Natapov     if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
4520fbfbb59SGleb Natapov         return -1;
4530fbfbb59SGleb Natapov     }
4540fbfbb59SGleb Natapov 
4550fbfbb59SGleb Natapov     return irrv;
4560fbfbb59SGleb Natapov }
4570fbfbb59SGleb Natapov 
458574bbf7bSbellard /* signal the CPU if an irq is pending */
459dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s)
460574bbf7bSbellard {
461c3affe56SAndreas Färber     CPUState *cpu;
462be9f8a08SZhu Guihua     DeviceState *dev = (DeviceState *)s;
46360e82579SAndreas Färber 
464c3affe56SAndreas Färber     cpu = CPU(s->cpu);
46560e82579SAndreas Färber     if (!qemu_cpu_is_self(cpu)) {
466c3affe56SAndreas Färber         cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
4675d62c43aSJan Kiszka     } else if (apic_irq_pending(s) > 0) {
468c3affe56SAndreas Färber         cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
469be9f8a08SZhu Guihua     } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
4708092cb71SPaolo Bonzini         cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
471574bbf7bSbellard     }
4720fbfbb59SGleb Natapov }
473574bbf7bSbellard 
474d3b0c9e9Sxiaoqiang zhao void apic_poll_irq(DeviceState *dev)
475e5ad936bSJan Kiszka {
476927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
477e5ad936bSJan Kiszka 
478e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
479e5ad936bSJan Kiszka     apic_update_irq(s);
480e5ad936bSJan Kiszka }
481e5ad936bSJan Kiszka 
482dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
483574bbf7bSbellard {
4842b85e0cdSThomas Huth     kvm_report_irq_delivered(!apic_get_bit(s->irr, vector_num));
48573822ec8Saliguori 
486edf9735eSMichael S. Tsirkin     apic_set_bit(s->irr, vector_num);
487574bbf7bSbellard     if (trigger_mode)
488edf9735eSMichael S. Tsirkin         apic_set_bit(s->tmr, vector_num);
489574bbf7bSbellard     else
490edf9735eSMichael S. Tsirkin         apic_reset_bit(s->tmr, vector_num);
491e5ad936bSJan Kiszka     if (s->vapic_paddr) {
492e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
493e5ad936bSJan Kiszka         /*
494e5ad936bSJan Kiszka          * The vcpu thread needs to see the new IRR before we pull its current
495e5ad936bSJan Kiszka          * TPR value. That way, if we miss a lowering of the TRP, the guest
496e5ad936bSJan Kiszka          * has the chance to notice the new IRR and poll for IRQs on its own.
497e5ad936bSJan Kiszka          */
498e5ad936bSJan Kiszka         smp_wmb();
499e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_FROM_VAPIC);
500e5ad936bSJan Kiszka     }
501574bbf7bSbellard     apic_update_irq(s);
502574bbf7bSbellard }
503574bbf7bSbellard 
504dae01685SJan Kiszka static void apic_eoi(APICCommonState *s)
505574bbf7bSbellard {
506574bbf7bSbellard     int isrv;
507574bbf7bSbellard     isrv = get_highest_priority_int(s->isr);
508574bbf7bSbellard     if (isrv < 0)
509574bbf7bSbellard         return;
510edf9735eSMichael S. Tsirkin     apic_reset_bit(s->isr, isrv);
511edf9735eSMichael S. Tsirkin     if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) {
5120280b571SJan Kiszka         ioapic_eoi_broadcast(isrv);
5130280b571SJan Kiszka     }
514e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
515574bbf7bSbellard     apic_update_irq(s);
516574bbf7bSbellard }
517574bbf7bSbellard 
518b5ee0468SBui Quang Minh static bool apic_match_dest(APICCommonState *apic, uint32_t dest)
519678e12ccSGleb Natapov {
520b5ee0468SBui Quang Minh     if (is_x2apic_mode(&apic->parent_obj)) {
521b5ee0468SBui Quang Minh         return apic->initial_apic_id == dest;
522b5ee0468SBui Quang Minh     } else {
523b5ee0468SBui Quang Minh         return apic->id == (uint8_t)dest;
524b5ee0468SBui Quang Minh     }
525678e12ccSGleb Natapov }
526678e12ccSGleb Natapov 
527b5ee0468SBui Quang Minh static void apic_find_dest(uint32_t *deliver_bitmask, uint32_t dest)
528b5ee0468SBui Quang Minh {
529b5ee0468SBui Quang Minh     APICCommonState *apic = NULL;
530b5ee0468SBui Quang Minh     int i;
531b5ee0468SBui Quang Minh 
532b5ee0468SBui Quang Minh     for (i = 0; i < max_apics; i++) {
533b5ee0468SBui Quang Minh         apic = local_apics[i];
534b5ee0468SBui Quang Minh         if (apic && apic_match_dest(apic, dest)) {
535b5ee0468SBui Quang Minh             apic_set_bit(deliver_bitmask, i);
536b5ee0468SBui Quang Minh         }
537b5ee0468SBui Quang Minh     }
538b5ee0468SBui Quang Minh }
539b5ee0468SBui Quang Minh 
540b5ee0468SBui Quang Minh /*
541b5ee0468SBui Quang Minh  * Deliver interrupt to x2APIC CPUs if it is x2APIC broadcast.
542b5ee0468SBui Quang Minh  * Otherwise, deliver interrupt to xAPIC CPUs if it is xAPIC
543b5ee0468SBui Quang Minh  * broadcast.
544b5ee0468SBui Quang Minh  */
545b5ee0468SBui Quang Minh static void apic_get_broadcast_bitmask(uint32_t *deliver_bitmask,
546b5ee0468SBui Quang Minh                                        bool is_x2apic_broadcast)
547b5ee0468SBui Quang Minh {
548b5ee0468SBui Quang Minh     int i;
549b5ee0468SBui Quang Minh     APICCommonState *apic_iter;
550b5ee0468SBui Quang Minh 
551b5ee0468SBui Quang Minh     for (i = 0; i < max_apics; i++) {
552b5ee0468SBui Quang Minh         apic_iter = local_apics[i];
553b5ee0468SBui Quang Minh         if (apic_iter) {
554b5ee0468SBui Quang Minh             bool apic_in_x2apic = is_x2apic_mode(&apic_iter->parent_obj);
555b5ee0468SBui Quang Minh 
556b5ee0468SBui Quang Minh             if (is_x2apic_broadcast && apic_in_x2apic) {
557b5ee0468SBui Quang Minh                 apic_set_bit(deliver_bitmask, i);
558b5ee0468SBui Quang Minh             } else if (!is_x2apic_broadcast && !apic_in_x2apic) {
559b5ee0468SBui Quang Minh                 apic_set_bit(deliver_bitmask, i);
560b5ee0468SBui Quang Minh             }
561b5ee0468SBui Quang Minh         }
562b5ee0468SBui Quang Minh     }
563678e12ccSGleb Natapov }
564678e12ccSGleb Natapov 
565d3e9db93Sbellard static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
566b5ee0468SBui Quang Minh                                       uint32_t dest, uint8_t dest_mode)
567d592d303Sbellard {
568b5ee0468SBui Quang Minh     APICCommonState *apic;
569d3e9db93Sbellard     int i;
570d592d303Sbellard 
571b5ee0468SBui Quang Minh     memset(deliver_bitmask, 0x00, max_apic_words * sizeof(uint32_t));
572b5ee0468SBui Quang Minh 
573b5ee0468SBui Quang Minh     /*
574b5ee0468SBui Quang Minh      * x2APIC broadcast is delivered to all x2APIC CPUs regardless of
575b5ee0468SBui Quang Minh      * destination mode. In case the destination mode is physical, it is
576b5ee0468SBui Quang Minh      * broadcasted to all xAPIC CPUs too. Otherwise, if the destination
577b5ee0468SBui Quang Minh      * mode is logical, we need to continue checking if xAPIC CPUs accepts
578b5ee0468SBui Quang Minh      * the interrupt.
579b5ee0468SBui Quang Minh      */
580b5ee0468SBui Quang Minh     if (dest == 0xffffffff) {
581b5ee0468SBui Quang Minh         if (dest_mode == APIC_DESTMODE_PHYSICAL) {
582b5ee0468SBui Quang Minh             memset(deliver_bitmask, 0xff, max_apic_words * sizeof(uint32_t));
583b5ee0468SBui Quang Minh             return;
584b5ee0468SBui Quang Minh         } else {
585b5ee0468SBui Quang Minh             apic_get_broadcast_bitmask(deliver_bitmask, true);
586b5ee0468SBui Quang Minh         }
587b5ee0468SBui Quang Minh     }
588b5ee0468SBui Quang Minh 
589b5ee0468SBui Quang Minh     if (dest_mode == APIC_DESTMODE_PHYSICAL) {
590b5ee0468SBui Quang Minh         apic_find_dest(deliver_bitmask, dest);
591b5ee0468SBui Quang Minh         /* Any APIC in xAPIC mode will interpret 0xFF as broadcast */
592d3e9db93Sbellard         if (dest == 0xff) {
593b5ee0468SBui Quang Minh             apic_get_broadcast_bitmask(deliver_bitmask, false);
594d3e9db93Sbellard         }
595d592d303Sbellard     } else {
596b5ee0468SBui Quang Minh         /* XXX: logical mode */
597b5ee0468SBui Quang Minh         for (i = 0; i < max_apics; i++) {
598b5ee0468SBui Quang Minh             apic = local_apics[i];
599b5ee0468SBui Quang Minh             if (apic) {
600b5ee0468SBui Quang Minh                 /* x2APIC logical mode */
601b5ee0468SBui Quang Minh                 if (apic->apicbase & MSR_IA32_APICBASE_EXTD) {
602b5ee0468SBui Quang Minh                     if ((dest >> 16) == (apic->extended_log_dest >> 16) &&
603b5ee0468SBui Quang Minh                         (dest & apic->extended_log_dest & 0xffff)) {
604edf9735eSMichael S. Tsirkin                         apic_set_bit(deliver_bitmask, i);
605b5ee0468SBui Quang Minh                     }
606b5ee0468SBui Quang Minh                     continue;
607b5ee0468SBui Quang Minh                 }
608b5ee0468SBui Quang Minh 
609b5ee0468SBui Quang Minh                 /* xAPIC logical mode */
610b5ee0468SBui Quang Minh                 dest = (uint8_t)dest;
611b5ee0468SBui Quang Minh                 if (apic->dest_mode == APIC_DESTMODE_LOGICAL_FLAT) {
612b5ee0468SBui Quang Minh                     if (dest & apic->log_dest) {
613b5ee0468SBui Quang Minh                         apic_set_bit(deliver_bitmask, i);
614b5ee0468SBui Quang Minh                     }
615b5ee0468SBui Quang Minh                 } else if (apic->dest_mode == APIC_DESTMODE_LOGICAL_CLUSTER) {
616b5ee0468SBui Quang Minh                     /*
617b5ee0468SBui Quang Minh                      * In cluster model of xAPIC logical mode IPI, 4 higher
618b5ee0468SBui Quang Minh                      * bits are used as cluster address, 4 lower bits are
619b5ee0468SBui Quang Minh                      * the bitmask for local APICs in the cluster. The IPI
620b5ee0468SBui Quang Minh                      * is delivered to an APIC if the cluster address
621b5ee0468SBui Quang Minh                      * matches and the APIC's address bit in the cluster is
622b5ee0468SBui Quang Minh                      * set in bitmask of destination ID in IPI.
623b5ee0468SBui Quang Minh                      *
624b5ee0468SBui Quang Minh                      * The cluster address ranges from 0 - 14, the cluster
625b5ee0468SBui Quang Minh                      * address 15 (0xf) is the broadcast address to all
626b5ee0468SBui Quang Minh                      * clusters.
627b5ee0468SBui Quang Minh                      */
628b5ee0468SBui Quang Minh                     if ((dest & 0xf0) == 0xf0 ||
629b5ee0468SBui Quang Minh                         (dest & 0xf0) == (apic->log_dest & 0xf0)) {
630b5ee0468SBui Quang Minh                         if (dest & apic->log_dest & 0x0f) {
631edf9735eSMichael S. Tsirkin                             apic_set_bit(deliver_bitmask, i);
632d592d303Sbellard                         }
633d592d303Sbellard                     }
634b5ee0468SBui Quang Minh                }
635d3e9db93Sbellard             }
636d3e9db93Sbellard         }
637d3e9db93Sbellard     }
638d592d303Sbellard }
639d592d303Sbellard 
640dae01685SJan Kiszka static void apic_startup(APICCommonState *s, int vector_num)
641e0fd8781Sbellard {
642b09ea7d5SGleb Natapov     s->sipi_vector = vector_num;
643c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
644b09ea7d5SGleb Natapov }
645b09ea7d5SGleb Natapov 
646d3b0c9e9Sxiaoqiang zhao void apic_sipi(DeviceState *dev)
647b09ea7d5SGleb Natapov {
648927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
64992a16d7aSBlue Swirl 
650d8ed887bSAndreas Färber     cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
651b09ea7d5SGleb Natapov 
652b09ea7d5SGleb Natapov     if (!s->wait_for_sipi)
653e0fd8781Sbellard         return;
654e9f9d6b1SAndreas Färber     cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
655b09ea7d5SGleb Natapov     s->wait_for_sipi = 0;
656e0fd8781Sbellard }
657e0fd8781Sbellard 
658b5ee0468SBui Quang Minh static void apic_deliver(DeviceState *dev, uint32_t dest, uint8_t dest_mode,
659d592d303Sbellard                          uint8_t delivery_mode, uint8_t vector_num,
660b5ee0468SBui Quang Minh                          uint8_t trigger_mode, uint8_t dest_shorthand)
661d592d303Sbellard {
662927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
663dae01685SJan Kiszka     APICCommonState *apic_iter;
664b5ee0468SBui Quang Minh     uint32_t deliver_bitmask_size = max_apic_words * sizeof(uint32_t);
665b5ee0468SBui Quang Minh     uint32_t *deliver_bitmask = g_malloc(deliver_bitmask_size);
666b5ee0468SBui Quang Minh     uint32_t current_apic_id;
667b5ee0468SBui Quang Minh 
668b5ee0468SBui Quang Minh     if (is_x2apic_mode(dev)) {
669b5ee0468SBui Quang Minh         current_apic_id = s->initial_apic_id;
670b5ee0468SBui Quang Minh     } else {
671b5ee0468SBui Quang Minh         current_apic_id = s->id;
672b5ee0468SBui Quang Minh     }
673d592d303Sbellard 
674e0fd8781Sbellard     switch (dest_shorthand) {
675e0fd8781Sbellard     case 0:
676d3e9db93Sbellard         apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
677e0fd8781Sbellard         break;
678e0fd8781Sbellard     case 1:
679b5ee0468SBui Quang Minh         memset(deliver_bitmask, 0x00, deliver_bitmask_size);
680b5ee0468SBui Quang Minh         apic_set_bit(deliver_bitmask, current_apic_id);
681e0fd8781Sbellard         break;
682e0fd8781Sbellard     case 2:
683b5ee0468SBui Quang Minh         memset(deliver_bitmask, 0xff, deliver_bitmask_size);
684e0fd8781Sbellard         break;
685e0fd8781Sbellard     case 3:
686b5ee0468SBui Quang Minh         memset(deliver_bitmask, 0xff, deliver_bitmask_size);
687b5ee0468SBui Quang Minh         apic_reset_bit(deliver_bitmask, current_apic_id);
688e0fd8781Sbellard         break;
689e0fd8781Sbellard     }
690e0fd8781Sbellard 
691d592d303Sbellard     switch (delivery_mode) {
692d592d303Sbellard         case APIC_DM_INIT:
693d592d303Sbellard             {
694d592d303Sbellard                 int trig_mode = (s->icr[0] >> 15) & 1;
695d592d303Sbellard                 int level = (s->icr[0] >> 14) & 1;
696d592d303Sbellard                 if (level == 0 && trig_mode == 1) {
697d3e9db93Sbellard                     foreach_apic(apic_iter, deliver_bitmask,
698d3e9db93Sbellard                                  apic_iter->arb_id = apic_iter->id );
699d592d303Sbellard                     return;
700d592d303Sbellard                 }
701d592d303Sbellard             }
702d592d303Sbellard             break;
703d592d303Sbellard 
704d592d303Sbellard         case APIC_DM_SIPI:
705d3e9db93Sbellard             foreach_apic(apic_iter, deliver_bitmask,
706d3e9db93Sbellard                          apic_startup(apic_iter, vector_num) );
707d592d303Sbellard             return;
708d592d303Sbellard     }
709d592d303Sbellard 
7101f6f408cSJan Kiszka     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
711b5ee0468SBui Quang Minh     g_free(deliver_bitmask);
712d592d303Sbellard }
713d592d303Sbellard 
714a94820ddSJan Kiszka static bool apic_check_pic(APICCommonState *s)
715a94820ddSJan Kiszka {
716be9f8a08SZhu Guihua     DeviceState *dev = (DeviceState *)s;
717be9f8a08SZhu Guihua 
718be9f8a08SZhu Guihua     if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
719a94820ddSJan Kiszka         return false;
720a94820ddSJan Kiszka     }
721be9f8a08SZhu Guihua     apic_deliver_pic_intr(dev, 1);
722a94820ddSJan Kiszka     return true;
723a94820ddSJan Kiszka }
724a94820ddSJan Kiszka 
725d3b0c9e9Sxiaoqiang zhao int apic_get_interrupt(DeviceState *dev)
726574bbf7bSbellard {
727927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
728574bbf7bSbellard     int intno;
729574bbf7bSbellard 
730574bbf7bSbellard     /* if the APIC is installed or enabled, we let the 8259 handle the
731574bbf7bSbellard        IRQs */
732574bbf7bSbellard     if (!s)
733574bbf7bSbellard         return -1;
734574bbf7bSbellard     if (!(s->spurious_vec & APIC_SV_ENABLE))
735574bbf7bSbellard         return -1;
736574bbf7bSbellard 
737e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
7380fbfbb59SGleb Natapov     intno = apic_irq_pending(s);
7390fbfbb59SGleb Natapov 
7405224c88dSPaolo Bonzini     /* if there is an interrupt from the 8259, let the caller handle
7415224c88dSPaolo Bonzini      * that first since ExtINT interrupts ignore the priority.
7425224c88dSPaolo Bonzini      */
7435224c88dSPaolo Bonzini     if (intno == 0 || apic_check_pic(s)) {
744e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_TO_VAPIC);
745574bbf7bSbellard         return -1;
7460fbfbb59SGleb Natapov     } else if (intno < 0) {
747e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_TO_VAPIC);
748d592d303Sbellard         return s->spurious_vec & 0xff;
7490fbfbb59SGleb Natapov     }
750edf9735eSMichael S. Tsirkin     apic_reset_bit(s->irr, intno);
751edf9735eSMichael S. Tsirkin     apic_set_bit(s->isr, intno);
752e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_TO_VAPIC);
7533db3659bSJan Kiszka 
754574bbf7bSbellard     apic_update_irq(s);
7553db3659bSJan Kiszka 
756574bbf7bSbellard     return intno;
757574bbf7bSbellard }
758574bbf7bSbellard 
759d3b0c9e9Sxiaoqiang zhao int apic_accept_pic_intr(DeviceState *dev)
7600e21e12bSths {
761927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
7620e21e12bSths     uint32_t lvt0;
7630e21e12bSths 
7640e21e12bSths     if (!s)
7650e21e12bSths         return -1;
7660e21e12bSths 
7670e21e12bSths     lvt0 = s->lvt[APIC_LVT_LINT0];
7680e21e12bSths 
769a5b38b51Saurel32     if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
770a5b38b51Saurel32         (lvt0 & APIC_LVT_MASKED) == 0)
77178cafff8SSergio Lopez         return isa_pic != NULL;
7720e21e12bSths 
7730e21e12bSths     return 0;
7740e21e12bSths }
7750e21e12bSths 
776dae01685SJan Kiszka static void apic_timer_update(APICCommonState *s, int64_t current_time)
777574bbf7bSbellard {
7787a380ca3SJan Kiszka     if (apic_next_timer(s, current_time)) {
779bc72ad67SAlex Bligh         timer_mod(s->timer, s->next_time);
780574bbf7bSbellard     } else {
781bc72ad67SAlex Bligh         timer_del(s->timer);
782574bbf7bSbellard     }
783574bbf7bSbellard }
784574bbf7bSbellard 
785574bbf7bSbellard static void apic_timer(void *opaque)
786574bbf7bSbellard {
787dae01685SJan Kiszka     APICCommonState *s = opaque;
788574bbf7bSbellard 
789cf6d64bfSBlue Swirl     apic_local_deliver(s, APIC_LVT_TIMER);
790574bbf7bSbellard     apic_timer_update(s, s->next_time);
791574bbf7bSbellard }
792574bbf7bSbellard 
793b2101358SBui Quang Minh static int apic_register_read(int index, uint64_t *value)
794574bbf7bSbellard {
795d3b0c9e9Sxiaoqiang zhao     DeviceState *dev;
796dae01685SJan Kiszka     APICCommonState *s;
797574bbf7bSbellard     uint32_t val;
798b2101358SBui Quang Minh     int ret = 0;
79921f80e8fSPeter Maydell 
800d3b0c9e9Sxiaoqiang zhao     dev = cpu_get_current_apic();
801d3b0c9e9Sxiaoqiang zhao     if (!dev) {
802b2101358SBui Quang Minh         return -1;
8030e26b7b8SBlue Swirl     }
804927d5a1dSWanpeng Li     s = APIC(dev);
805574bbf7bSbellard 
806574bbf7bSbellard     switch(index) {
807574bbf7bSbellard     case 0x02: /* id */
808b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
809b5ee0468SBui Quang Minh             val = s->initial_apic_id;
810b5ee0468SBui Quang Minh         } else {
811574bbf7bSbellard             val = s->id << 24;
812b5ee0468SBui Quang Minh         }
813574bbf7bSbellard         break;
814574bbf7bSbellard     case 0x03: /* version */
815aa93200bSGabriel L. Somlo         val = s->version | ((APIC_LVT_NB - 1) << 16);
816574bbf7bSbellard         break;
817574bbf7bSbellard     case 0x08:
818e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_FROM_VAPIC);
819e5ad936bSJan Kiszka         if (apic_report_tpr_access) {
82060671e58SAndreas Färber             cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
821e5ad936bSJan Kiszka         }
822574bbf7bSbellard         val = s->tpr;
823574bbf7bSbellard         break;
824d592d303Sbellard     case 0x09:
825d592d303Sbellard         val = apic_get_arb_pri(s);
826d592d303Sbellard         break;
827574bbf7bSbellard     case 0x0a:
828574bbf7bSbellard         /* ppr */
829574bbf7bSbellard         val = apic_get_ppr(s);
830574bbf7bSbellard         break;
831b237db36Saurel32     case 0x0b:
832b237db36Saurel32         val = 0;
833b237db36Saurel32         break;
834d592d303Sbellard     case 0x0d:
835b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
836b5ee0468SBui Quang Minh             val = s->extended_log_dest;
837b5ee0468SBui Quang Minh         } else {
838d592d303Sbellard             val = s->log_dest << 24;
839b5ee0468SBui Quang Minh         }
840d592d303Sbellard         break;
841d592d303Sbellard     case 0x0e:
842b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
843b5ee0468SBui Quang Minh             val = 0;
844b5ee0468SBui Quang Minh             ret = -1;
845b5ee0468SBui Quang Minh         } else {
846d6c140a7SJan Kiszka             val = (s->dest_mode << 28) | 0xfffffff;
847b5ee0468SBui Quang Minh         }
848d592d303Sbellard         break;
849574bbf7bSbellard     case 0x0f:
850574bbf7bSbellard         val = s->spurious_vec;
851574bbf7bSbellard         break;
852574bbf7bSbellard     case 0x10 ... 0x17:
853574bbf7bSbellard         val = s->isr[index & 7];
854574bbf7bSbellard         break;
855574bbf7bSbellard     case 0x18 ... 0x1f:
856574bbf7bSbellard         val = s->tmr[index & 7];
857574bbf7bSbellard         break;
858574bbf7bSbellard     case 0x20 ... 0x27:
859574bbf7bSbellard         val = s->irr[index & 7];
860574bbf7bSbellard         break;
861574bbf7bSbellard     case 0x28:
862574bbf7bSbellard         val = s->esr;
863574bbf7bSbellard         break;
864574bbf7bSbellard     case 0x30:
865574bbf7bSbellard     case 0x31:
866574bbf7bSbellard         val = s->icr[index & 1];
867574bbf7bSbellard         break;
868e0fd8781Sbellard     case 0x32 ... 0x37:
869e0fd8781Sbellard         val = s->lvt[index - 0x32];
870e0fd8781Sbellard         break;
871574bbf7bSbellard     case 0x38:
872574bbf7bSbellard         val = s->initial_count;
873574bbf7bSbellard         break;
874574bbf7bSbellard     case 0x39:
875574bbf7bSbellard         val = apic_get_current_count(s);
876574bbf7bSbellard         break;
877574bbf7bSbellard     case 0x3e:
878574bbf7bSbellard         val = s->divide_conf;
879574bbf7bSbellard         break;
880574bbf7bSbellard     default:
881a22bf99cSPavel Butsykin         s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
882574bbf7bSbellard         val = 0;
883b2101358SBui Quang Minh         ret = -1;
884574bbf7bSbellard         break;
885574bbf7bSbellard     }
886b2101358SBui Quang Minh 
887b2101358SBui Quang Minh     trace_apic_register_read(index, val);
888b2101358SBui Quang Minh     *value = val;
889b2101358SBui Quang Minh     return ret;
890b2101358SBui Quang Minh }
891b2101358SBui Quang Minh 
892b2101358SBui Quang Minh static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
893b2101358SBui Quang Minh {
894b2101358SBui Quang Minh     uint64_t val;
895b2101358SBui Quang Minh     int index;
896b2101358SBui Quang Minh 
897b2101358SBui Quang Minh     if (size < 4) {
898b2101358SBui Quang Minh         return 0;
899b2101358SBui Quang Minh     }
900b2101358SBui Quang Minh 
901b2101358SBui Quang Minh     index = (addr >> 4) & 0xff;
902b2101358SBui Quang Minh     apic_register_read(index, &val);
903b2101358SBui Quang Minh 
904574bbf7bSbellard     return val;
905574bbf7bSbellard }
906574bbf7bSbellard 
907b2101358SBui Quang Minh int apic_msr_read(int index, uint64_t *val)
908b2101358SBui Quang Minh {
909b2101358SBui Quang Minh     DeviceState *dev;
910b2101358SBui Quang Minh 
911b2101358SBui Quang Minh     dev = cpu_get_current_apic();
912b2101358SBui Quang Minh     if (!dev) {
913b2101358SBui Quang Minh         return -1;
914b2101358SBui Quang Minh     }
915b2101358SBui Quang Minh 
916b2101358SBui Quang Minh     if (!is_x2apic_mode(dev)) {
917b2101358SBui Quang Minh         return -1;
918b2101358SBui Quang Minh     }
919b2101358SBui Quang Minh 
920b2101358SBui Quang Minh     return apic_register_read(index, val);
921b2101358SBui Quang Minh }
922b2101358SBui Quang Minh 
923267ee357SRadim Krčmář static void apic_send_msi(MSIMessage *msi)
92454c96da7SMichael S. Tsirkin {
925267ee357SRadim Krčmář     uint64_t addr = msi->address;
926267ee357SRadim Krčmář     uint32_t data = msi->data;
927b5ee0468SBui Quang Minh     uint32_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
928b5ee0468SBui Quang Minh     /*
929b5ee0468SBui Quang Minh      * The higher 3 bytes of destination id is stored in higher word of
930b5ee0468SBui Quang Minh      * msi address. See x86_iommu_irq_to_msi_message()
931b5ee0468SBui Quang Minh      */
932b5ee0468SBui Quang Minh     dest = dest | (addr >> 32);
93354c96da7SMichael S. Tsirkin     uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
93454c96da7SMichael S. Tsirkin     uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
93554c96da7SMichael S. Tsirkin     uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
93654c96da7SMichael S. Tsirkin     uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
93754c96da7SMichael S. Tsirkin     /* XXX: Ignore redirection hint. */
9381f6f408cSJan Kiszka     apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
93954c96da7SMichael S. Tsirkin }
94054c96da7SMichael S. Tsirkin 
941b2101358SBui Quang Minh static int apic_register_write(int index, uint64_t val)
942574bbf7bSbellard {
943d3b0c9e9Sxiaoqiang zhao     DeviceState *dev;
944dae01685SJan Kiszka     APICCommonState *s;
945574bbf7bSbellard 
946d3b0c9e9Sxiaoqiang zhao     dev = cpu_get_current_apic();
947d3b0c9e9Sxiaoqiang zhao     if (!dev) {
948b2101358SBui Quang Minh         return -1;
9490e26b7b8SBlue Swirl     }
950927d5a1dSWanpeng Li     s = APIC(dev);
951574bbf7bSbellard 
952b2101358SBui Quang Minh     trace_apic_register_write(index, val);
953574bbf7bSbellard 
954574bbf7bSbellard     switch(index) {
955574bbf7bSbellard     case 0x02:
956b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
957b5ee0468SBui Quang Minh             return -1;
958b5ee0468SBui Quang Minh         }
959b5ee0468SBui Quang Minh 
960574bbf7bSbellard         s->id = (val >> 24);
961574bbf7bSbellard         break;
962e0fd8781Sbellard     case 0x03:
963e0fd8781Sbellard         break;
964574bbf7bSbellard     case 0x08:
965e5ad936bSJan Kiszka         if (apic_report_tpr_access) {
96660671e58SAndreas Färber             cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
967e5ad936bSJan Kiszka         }
968574bbf7bSbellard         s->tpr = val;
969e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_TO_VAPIC);
970d592d303Sbellard         apic_update_irq(s);
971574bbf7bSbellard         break;
972e0fd8781Sbellard     case 0x09:
973e0fd8781Sbellard     case 0x0a:
974e0fd8781Sbellard         break;
975574bbf7bSbellard     case 0x0b: /* EOI */
976574bbf7bSbellard         apic_eoi(s);
977574bbf7bSbellard         break;
978d592d303Sbellard     case 0x0d:
979b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
980b5ee0468SBui Quang Minh             return -1;
981b5ee0468SBui Quang Minh         }
982b5ee0468SBui Quang Minh 
983d592d303Sbellard         s->log_dest = val >> 24;
984d592d303Sbellard         break;
985d592d303Sbellard     case 0x0e:
986b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
987b5ee0468SBui Quang Minh             return -1;
988b5ee0468SBui Quang Minh         }
989b5ee0468SBui Quang Minh 
990d592d303Sbellard         s->dest_mode = val >> 28;
991d592d303Sbellard         break;
992574bbf7bSbellard     case 0x0f:
993574bbf7bSbellard         s->spurious_vec = val & 0x1ff;
994d592d303Sbellard         apic_update_irq(s);
995574bbf7bSbellard         break;
996e0fd8781Sbellard     case 0x10 ... 0x17:
997e0fd8781Sbellard     case 0x18 ... 0x1f:
998e0fd8781Sbellard     case 0x20 ... 0x27:
999e0fd8781Sbellard     case 0x28:
1000e0fd8781Sbellard         break;
1001b5ee0468SBui Quang Minh     case 0x30: {
1002b5ee0468SBui Quang Minh         uint32_t dest;
1003b5ee0468SBui Quang Minh 
1004d592d303Sbellard         s->icr[0] = val;
1005b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
1006b5ee0468SBui Quang Minh             s->icr[1] = val >> 32;
1007b5ee0468SBui Quang Minh             dest = s->icr[1];
1008b5ee0468SBui Quang Minh         } else {
1009b5ee0468SBui Quang Minh             dest = (s->icr[1] >> 24) & 0xff;
1010b5ee0468SBui Quang Minh         }
1011b5ee0468SBui Quang Minh 
1012b5ee0468SBui Quang Minh         apic_deliver(dev, dest, (s->icr[0] >> 11) & 1,
1013d592d303Sbellard                      (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1014b5ee0468SBui Quang Minh                      (s->icr[0] >> 15) & 1, (s->icr[0] >> 18) & 3);
1015d592d303Sbellard         break;
1016b5ee0468SBui Quang Minh     }
1017574bbf7bSbellard     case 0x31:
1018b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
1019b5ee0468SBui Quang Minh             return -1;
1020b5ee0468SBui Quang Minh         }
1021b5ee0468SBui Quang Minh 
1022d592d303Sbellard         s->icr[1] = val;
1023574bbf7bSbellard         break;
1024574bbf7bSbellard     case 0x32 ... 0x37:
1025574bbf7bSbellard         {
1026574bbf7bSbellard             int n = index - 0x32;
1027574bbf7bSbellard             s->lvt[n] = val;
1028a94820ddSJan Kiszka             if (n == APIC_LVT_TIMER) {
1029bc72ad67SAlex Bligh                 apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
1030a94820ddSJan Kiszka             } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
1031a94820ddSJan Kiszka                 apic_update_irq(s);
1032a94820ddSJan Kiszka             }
1033574bbf7bSbellard         }
1034574bbf7bSbellard         break;
1035574bbf7bSbellard     case 0x38:
1036574bbf7bSbellard         s->initial_count = val;
1037bc72ad67SAlex Bligh         s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1038574bbf7bSbellard         apic_timer_update(s, s->initial_count_load_time);
1039574bbf7bSbellard         break;
1040e0fd8781Sbellard     case 0x39:
1041e0fd8781Sbellard         break;
1042574bbf7bSbellard     case 0x3e:
1043574bbf7bSbellard         {
1044574bbf7bSbellard             int v;
1045574bbf7bSbellard             s->divide_conf = val & 0xb;
1046574bbf7bSbellard             v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
1047574bbf7bSbellard             s->count_shift = (v + 1) & 7;
1048574bbf7bSbellard         }
1049574bbf7bSbellard         break;
1050b5ee0468SBui Quang Minh     case 0x3f: {
1051b5ee0468SBui Quang Minh         int vector = val & 0xff;
1052b5ee0468SBui Quang Minh 
1053b5ee0468SBui Quang Minh         if (!is_x2apic_mode(dev)) {
1054b5ee0468SBui Quang Minh             return -1;
1055b5ee0468SBui Quang Minh         }
1056b5ee0468SBui Quang Minh 
1057b5ee0468SBui Quang Minh         /*
1058b5ee0468SBui Quang Minh          * Self IPI is identical to IPI with
1059b5ee0468SBui Quang Minh          * - Destination shorthand: 1 (Self)
1060b5ee0468SBui Quang Minh          * - Trigger mode: 0 (Edge)
1061b5ee0468SBui Quang Minh          * - Delivery mode: 0 (Fixed)
1062b5ee0468SBui Quang Minh          */
1063b5ee0468SBui Quang Minh         apic_deliver(dev, 0, 0, APIC_DM_FIXED, vector, 0, 1);
1064b5ee0468SBui Quang Minh 
1065b5ee0468SBui Quang Minh         break;
1066b5ee0468SBui Quang Minh     }
1067574bbf7bSbellard     default:
1068a22bf99cSPavel Butsykin         s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
1069b2101358SBui Quang Minh         return -1;
1070574bbf7bSbellard     }
1071b2101358SBui Quang Minh 
1072b2101358SBui Quang Minh     return 0;
1073b2101358SBui Quang Minh }
1074b2101358SBui Quang Minh 
1075b2101358SBui Quang Minh static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
1076b2101358SBui Quang Minh                            unsigned size)
1077b2101358SBui Quang Minh {
1078b2101358SBui Quang Minh     int index = (addr >> 4) & 0xff;
1079b2101358SBui Quang Minh 
1080b2101358SBui Quang Minh     if (size < 4) {
1081b2101358SBui Quang Minh         return;
1082b2101358SBui Quang Minh     }
1083b2101358SBui Quang Minh 
1084b2101358SBui Quang Minh     if (addr > 0xfff || !index) {
1085b2101358SBui Quang Minh         /*
1086b2101358SBui Quang Minh          * MSI and MMIO APIC are at the same memory location,
1087b2101358SBui Quang Minh          * but actually not on the global bus: MSI is on PCI bus
1088b2101358SBui Quang Minh          * APIC is connected directly to the CPU.
1089b2101358SBui Quang Minh          * Mapping them on the global bus happens to work because
1090b2101358SBui Quang Minh          * MSI registers are reserved in APIC MMIO and vice versa.
1091b2101358SBui Quang Minh          */
1092b2101358SBui Quang Minh         MSIMessage msi = { .address = addr, .data = val };
1093b2101358SBui Quang Minh         apic_send_msi(&msi);
1094b2101358SBui Quang Minh         return;
1095b2101358SBui Quang Minh     }
1096b2101358SBui Quang Minh 
1097b2101358SBui Quang Minh     apic_register_write(index, val);
1098b2101358SBui Quang Minh }
1099b2101358SBui Quang Minh 
1100b2101358SBui Quang Minh int apic_msr_write(int index, uint64_t val)
1101b2101358SBui Quang Minh {
1102b2101358SBui Quang Minh     DeviceState *dev;
1103b2101358SBui Quang Minh 
1104b2101358SBui Quang Minh     dev = cpu_get_current_apic();
1105b2101358SBui Quang Minh     if (!dev) {
1106b2101358SBui Quang Minh         return -1;
1107b2101358SBui Quang Minh     }
1108b2101358SBui Quang Minh 
1109b2101358SBui Quang Minh     if (!is_x2apic_mode(dev)) {
1110b2101358SBui Quang Minh         return -1;
1111b2101358SBui Quang Minh     }
1112b2101358SBui Quang Minh 
1113b2101358SBui Quang Minh     return apic_register_write(index, val);
1114574bbf7bSbellard }
1115574bbf7bSbellard 
1116e5ad936bSJan Kiszka static void apic_pre_save(APICCommonState *s)
1117e5ad936bSJan Kiszka {
1118e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
1119e5ad936bSJan Kiszka }
1120e5ad936bSJan Kiszka 
11217a380ca3SJan Kiszka static void apic_post_load(APICCommonState *s)
11227a380ca3SJan Kiszka {
11237a380ca3SJan Kiszka     if (s->timer_expiry != -1) {
1124bc72ad67SAlex Bligh         timer_mod(s->timer, s->timer_expiry);
11257a380ca3SJan Kiszka     } else {
1126bc72ad67SAlex Bligh         timer_del(s->timer);
11277a380ca3SJan Kiszka     }
11287a380ca3SJan Kiszka }
11297a380ca3SJan Kiszka 
1130312b4234SAvi Kivity static const MemoryRegionOps apic_io_ops = {
113121f80e8fSPeter Maydell     .read = apic_mem_read,
113221f80e8fSPeter Maydell     .write = apic_mem_write,
113321f80e8fSPeter Maydell     .impl.min_access_size = 1,
113421f80e8fSPeter Maydell     .impl.max_access_size = 4,
113521f80e8fSPeter Maydell     .valid.min_access_size = 1,
113621f80e8fSPeter Maydell     .valid.max_access_size = 4,
1137312b4234SAvi Kivity     .endianness = DEVICE_NATIVE_ENDIAN,
1138574bbf7bSbellard };
1139574bbf7bSbellard 
1140ff6986ceSxiaoqiang zhao static void apic_realize(DeviceState *dev, Error **errp)
11418546b099SBlue Swirl {
1142927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
1143889211b1SIgor Mammedov 
11442c933ac6SPaolo Bonzini     if (kvm_enabled()) {
11452c933ac6SPaolo Bonzini         warn_report("Userspace local APIC is deprecated for KVM.");
11462c933ac6SPaolo Bonzini         warn_report("Do not use kernel-irqchip except for the -M isapc machine type.");
11472c933ac6SPaolo Bonzini     }
11482c933ac6SPaolo Bonzini 
11491437c94bSPaolo Bonzini     memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
1150baaeda08SIgor Mammedov                           APIC_SPACE_SIZE);
11518546b099SBlue Swirl 
115250795ee0SAlexander Bulekov     /*
115350795ee0SAlexander Bulekov      * apic-msi's apic_mem_write can call into ioapic_eoi_broadcast, which can
115450795ee0SAlexander Bulekov      * write back to apic-msi. As such mark the apic-msi region re-entrancy
115550795ee0SAlexander Bulekov      * safe.
115650795ee0SAlexander Bulekov      */
115750795ee0SAlexander Bulekov     s->io_memory.disable_reentrancy_guard = true;
115850795ee0SAlexander Bulekov 
1159bc72ad67SAlex Bligh     s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
1160b5ee0468SBui Quang Minh 
1161b5ee0468SBui Quang Minh     /*
1162b5ee0468SBui Quang Minh      * The --machine none does not call apic_set_max_apic_id before creating
1163b5ee0468SBui Quang Minh      * apic, so we need to call it here and set it to 1 which is the max cpus
1164b5ee0468SBui Quang Minh      * in machine none.
1165b5ee0468SBui Quang Minh      */
1166b5ee0468SBui Quang Minh     if (!local_apics) {
1167b5ee0468SBui Quang Minh         apic_set_max_apic_id(1);
1168b5ee0468SBui Quang Minh     }
1169b5ee0468SBui Quang Minh     local_apics[s->initial_apic_id] = s;
117008a82ac0SJan Kiszka 
1171226419d6SMichael S. Tsirkin     msi_nonbroken = true;
11728546b099SBlue Swirl }
11738546b099SBlue Swirl 
1174b69c3c21SMarkus Armbruster static void apic_unrealize(DeviceState *dev)
11759c156f9dSIgor Mammedov {
1176927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
11779c156f9dSIgor Mammedov 
11789c156f9dSIgor Mammedov     timer_free(s->timer);
1179b5ee0468SBui Quang Minh     local_apics[s->initial_apic_id] = NULL;
11809c156f9dSIgor Mammedov }
11819c156f9dSIgor Mammedov 
1182999e12bbSAnthony Liguori static void apic_class_init(ObjectClass *klass, void *data)
1183999e12bbSAnthony Liguori {
1184999e12bbSAnthony Liguori     APICCommonClass *k = APIC_COMMON_CLASS(klass);
1185999e12bbSAnthony Liguori 
1186ff6986ceSxiaoqiang zhao     k->realize = apic_realize;
11879c156f9dSIgor Mammedov     k->unrealize = apic_unrealize;
1188999e12bbSAnthony Liguori     k->set_base = apic_set_base;
1189999e12bbSAnthony Liguori     k->set_tpr = apic_set_tpr;
1190e5ad936bSJan Kiszka     k->get_tpr = apic_get_tpr;
1191e5ad936bSJan Kiszka     k->vapic_base_update = apic_vapic_base_update;
1192999e12bbSAnthony Liguori     k->external_nmi = apic_external_nmi;
1193e5ad936bSJan Kiszka     k->pre_save = apic_pre_save;
1194999e12bbSAnthony Liguori     k->post_load = apic_post_load;
1195267ee357SRadim Krčmář     k->send_msi = apic_send_msi;
1196999e12bbSAnthony Liguori }
1197999e12bbSAnthony Liguori 
11988c43a6f0SAndreas Färber static const TypeInfo apic_info = {
1199927d5a1dSWanpeng Li     .name          = TYPE_APIC,
120039bffca2SAnthony Liguori     .instance_size = sizeof(APICCommonState),
120139bffca2SAnthony Liguori     .parent        = TYPE_APIC_COMMON,
1202999e12bbSAnthony Liguori     .class_init    = apic_class_init,
12038546b099SBlue Swirl };
12048546b099SBlue Swirl 
120583f7d43aSAndreas Färber static void apic_register_types(void)
12068546b099SBlue Swirl {
120739bffca2SAnthony Liguori     type_register_static(&apic_info);
12088546b099SBlue Swirl }
12098546b099SBlue Swirl 
121083f7d43aSAndreas Färber type_init(apic_register_types)
1211