xref: /qemu/hw/intc/apic.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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"
2932cad1ffSPhilippe Mathieu-Daudé #include "system/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 
apic_set_max_apic_id(uint32_t max_apic_id)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 */
apic_fls_bit(uint32_t value)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 */
apic_ffs_bit(uint32_t value)72edf9735eSMichael S. Tsirkin static int apic_ffs_bit(uint32_t value)
73d3e9db93Sbellard {
74bb7e7293Saurel32     return ctz32(value);
75d3e9db93Sbellard }
76d3e9db93Sbellard 
apic_reset_bit(uint32_t * tab,int index)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 */
get_highest_priority_int(uint32_t * tab)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 
apic_sync_vapic(APICCommonState * s,int sync_type)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 
apic_vapic_base_update(APICCommonState * s)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 
apic_local_deliver(APICCommonState * s,int vector)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 
apic_deliver_pic_intr(DeviceState * dev,int level)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 
apic_external_nmi(APICCommonState * s)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 
apic_bus_deliver(const uint32_t * deliver_bitmask,uint8_t delivery_mode,uint8_t vector_num,uint8_t trigger_mode)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 
apic_deliver_irq(uint32_t dest,uint8_t dest_mode,uint8_t delivery_mode,uint8_t vector_num,uint8_t trigger_mode)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 {
294afd1af1cSPaolo Bonzini     g_autofree uint32_t *deliver_bitmask = g_new(uint32_t, max_apic_words);
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);
301610626afSaliguori }
302610626afSaliguori 
is_x2apic_mode(DeviceState * dev)303b2101358SBui Quang Minh bool is_x2apic_mode(DeviceState *dev)
304b2101358SBui Quang Minh {
305b2101358SBui Quang Minh     APICCommonState *s = APIC(dev);
306b2101358SBui Quang Minh 
307b2101358SBui Quang Minh     return s->apicbase & MSR_IA32_APICBASE_EXTD;
308b2101358SBui Quang Minh }
309b2101358SBui Quang Minh 
apic_set_base_check(APICCommonState * s,uint64_t val)310774204cfSBui Quang Minh static int apic_set_base_check(APICCommonState *s, uint64_t val)
311574bbf7bSbellard {
312774204cfSBui Quang Minh     /* Enable x2apic when x2apic is not supported by CPU */
313774204cfSBui Quang Minh     if (!cpu_has_x2apic_feature(&s->cpu->env) &&
314774204cfSBui Quang Minh         val & MSR_IA32_APICBASE_EXTD) {
315774204cfSBui Quang Minh         return -1;
316774204cfSBui Quang Minh     }
317774204cfSBui Quang Minh 
318774204cfSBui Quang Minh     /*
319774204cfSBui Quang Minh      * Transition into invalid state
320774204cfSBui Quang Minh      * (s->apicbase & MSR_IA32_APICBASE_ENABLE == 0) &&
321774204cfSBui Quang Minh      * (s->apicbase & MSR_IA32_APICBASE_EXTD) == 1
322774204cfSBui Quang Minh      */
323774204cfSBui Quang Minh     if (!(val & MSR_IA32_APICBASE_ENABLE) &&
324774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_EXTD)) {
325774204cfSBui Quang Minh         return -1;
326774204cfSBui Quang Minh     }
327774204cfSBui Quang Minh 
328774204cfSBui Quang Minh     /* Invalid transition from disabled mode to x2APIC */
329774204cfSBui Quang Minh     if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
330774204cfSBui Quang Minh         !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
331774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_ENABLE) &&
332774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_EXTD)) {
333774204cfSBui Quang Minh         return -1;
334774204cfSBui Quang Minh     }
335774204cfSBui Quang Minh 
336774204cfSBui Quang Minh     /* Invalid transition from x2APIC to xAPIC */
337774204cfSBui Quang Minh     if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
338774204cfSBui Quang Minh         (s->apicbase & MSR_IA32_APICBASE_EXTD) &&
339774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_ENABLE) &&
340774204cfSBui Quang Minh         !(val & MSR_IA32_APICBASE_EXTD)) {
341774204cfSBui Quang Minh         return -1;
342774204cfSBui Quang Minh     }
343774204cfSBui Quang Minh 
344774204cfSBui Quang Minh     return 0;
345774204cfSBui Quang Minh }
346774204cfSBui Quang Minh 
apic_set_base(APICCommonState * s,uint64_t val)347774204cfSBui Quang Minh static int apic_set_base(APICCommonState *s, uint64_t val)
348774204cfSBui Quang Minh {
349774204cfSBui Quang Minh     if (apic_set_base_check(s, val) < 0) {
350774204cfSBui Quang Minh         return -1;
351774204cfSBui Quang Minh     }
352774204cfSBui Quang Minh 
3531e71a9b1SPhil Dennis-Jordan     s->apicbase = (val & MSR_IA32_APICBASE_BASE) |
354574bbf7bSbellard         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
355574bbf7bSbellard     if (!(val & MSR_IA32_APICBASE_ENABLE)) {
356574bbf7bSbellard         s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
35760671e58SAndreas Färber         cpu_clear_apic_feature(&s->cpu->env);
358574bbf7bSbellard         s->spurious_vec &= ~APIC_SV_ENABLE;
359574bbf7bSbellard     }
360774204cfSBui Quang Minh 
361774204cfSBui Quang Minh     /* Transition from disabled mode to xAPIC */
362774204cfSBui Quang Minh     if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
363774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_ENABLE)) {
364774204cfSBui Quang Minh         s->apicbase |= MSR_IA32_APICBASE_ENABLE;
365774204cfSBui Quang Minh         cpu_set_apic_feature(&s->cpu->env);
366774204cfSBui Quang Minh     }
367774204cfSBui Quang Minh 
368774204cfSBui Quang Minh     /* Transition from xAPIC to x2APIC */
369774204cfSBui Quang Minh     if (cpu_has_x2apic_feature(&s->cpu->env) &&
370774204cfSBui Quang Minh         !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
371774204cfSBui Quang Minh         (val & MSR_IA32_APICBASE_EXTD)) {
372774204cfSBui Quang Minh         s->apicbase |= MSR_IA32_APICBASE_EXTD;
373774204cfSBui Quang Minh 
374774204cfSBui Quang Minh         s->log_dest = ((s->initial_apic_id & 0xffff0) << 16) |
375774204cfSBui Quang Minh                       (1 << (s->initial_apic_id & 0xf));
376774204cfSBui Quang Minh     }
377774204cfSBui Quang Minh 
378774204cfSBui Quang Minh     return 0;
379574bbf7bSbellard }
380574bbf7bSbellard 
apic_set_tpr(APICCommonState * s,uint8_t val)381dae01685SJan Kiszka static void apic_set_tpr(APICCommonState *s, uint8_t val)
382574bbf7bSbellard {
383e5ad936bSJan Kiszka     /* Updates from cr8 are ignored while the VAPIC is active */
384e5ad936bSJan Kiszka     if (!s->vapic_paddr) {
385e5ad936bSJan Kiszka         s->tpr = val << 4;
386d592d303Sbellard         apic_update_irq(s);
3879230e66eSbellard     }
388e5ad936bSJan Kiszka }
3899230e66eSbellard 
apic_get_highest_priority_irr(DeviceState * dev)3902cb9f06eSSergio Andres Gomez Del Real int apic_get_highest_priority_irr(DeviceState *dev)
3912cb9f06eSSergio Andres Gomez Del Real {
3922cb9f06eSSergio Andres Gomez Del Real     APICCommonState *s;
3932cb9f06eSSergio Andres Gomez Del Real 
3942cb9f06eSSergio Andres Gomez Del Real     if (!dev) {
3952cb9f06eSSergio Andres Gomez Del Real         /* no interrupts */
3962cb9f06eSSergio Andres Gomez Del Real         return -1;
3972cb9f06eSSergio Andres Gomez Del Real     }
3982cb9f06eSSergio Andres Gomez Del Real     s = APIC_COMMON(dev);
3992cb9f06eSSergio Andres Gomez Del Real     return get_highest_priority_int(s->irr);
4002cb9f06eSSergio Andres Gomez Del Real }
4012cb9f06eSSergio Andres Gomez Del Real 
apic_get_tpr(APICCommonState * s)402e5ad936bSJan Kiszka static uint8_t apic_get_tpr(APICCommonState *s)
403d592d303Sbellard {
404e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
405e5ad936bSJan Kiszka     return s->tpr >> 4;
406d592d303Sbellard }
407d592d303Sbellard 
apic_get_ppr(APICCommonState * s)40882a5e042SPavel Butsykin int apic_get_ppr(APICCommonState *s)
409574bbf7bSbellard {
410574bbf7bSbellard     int tpr, isrv, ppr;
411574bbf7bSbellard 
412574bbf7bSbellard     tpr = (s->tpr >> 4);
413574bbf7bSbellard     isrv = get_highest_priority_int(s->isr);
414574bbf7bSbellard     if (isrv < 0)
415574bbf7bSbellard         isrv = 0;
416574bbf7bSbellard     isrv >>= 4;
417574bbf7bSbellard     if (tpr >= isrv)
418574bbf7bSbellard         ppr = s->tpr;
419574bbf7bSbellard     else
420574bbf7bSbellard         ppr = isrv << 4;
421574bbf7bSbellard     return ppr;
422574bbf7bSbellard }
423574bbf7bSbellard 
apic_get_arb_pri(APICCommonState * s)424dae01685SJan Kiszka static int apic_get_arb_pri(APICCommonState *s)
425d592d303Sbellard {
426d592d303Sbellard     /* XXX: arbitration */
427d592d303Sbellard     return 0;
428d592d303Sbellard }
429d592d303Sbellard 
4300fbfbb59SGleb Natapov 
4310fbfbb59SGleb Natapov /*
4320fbfbb59SGleb Natapov  * <0 - low prio interrupt,
4330fbfbb59SGleb Natapov  * 0  - no interrupt,
4340fbfbb59SGleb Natapov  * >0 - interrupt number
4350fbfbb59SGleb Natapov  */
apic_irq_pending(APICCommonState * s)436dae01685SJan Kiszka static int apic_irq_pending(APICCommonState *s)
4370fbfbb59SGleb Natapov {
4380fbfbb59SGleb Natapov     int irrv, ppr;
43960e68042SPaolo Bonzini 
44060e68042SPaolo Bonzini     if (!(s->spurious_vec & APIC_SV_ENABLE)) {
44160e68042SPaolo Bonzini         return 0;
44260e68042SPaolo Bonzini     }
44360e68042SPaolo Bonzini 
4440fbfbb59SGleb Natapov     irrv = get_highest_priority_int(s->irr);
4450fbfbb59SGleb Natapov     if (irrv < 0) {
4460fbfbb59SGleb Natapov         return 0;
4470fbfbb59SGleb Natapov     }
4480fbfbb59SGleb Natapov     ppr = apic_get_ppr(s);
4490fbfbb59SGleb Natapov     if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
4500fbfbb59SGleb Natapov         return -1;
4510fbfbb59SGleb Natapov     }
4520fbfbb59SGleb Natapov 
4530fbfbb59SGleb Natapov     return irrv;
4540fbfbb59SGleb Natapov }
4550fbfbb59SGleb Natapov 
456574bbf7bSbellard /* signal the CPU if an irq is pending */
apic_update_irq(APICCommonState * s)457dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s)
458574bbf7bSbellard {
459c3affe56SAndreas Färber     CPUState *cpu;
460be9f8a08SZhu Guihua     DeviceState *dev = (DeviceState *)s;
46160e82579SAndreas Färber 
462c3affe56SAndreas Färber     cpu = CPU(s->cpu);
46360e82579SAndreas Färber     if (!qemu_cpu_is_self(cpu)) {
464c3affe56SAndreas Färber         cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
4655d62c43aSJan Kiszka     } else if (apic_irq_pending(s) > 0) {
466c3affe56SAndreas Färber         cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
467be9f8a08SZhu Guihua     } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
4688092cb71SPaolo Bonzini         cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
469574bbf7bSbellard     }
4700fbfbb59SGleb Natapov }
471574bbf7bSbellard 
apic_poll_irq(DeviceState * dev)472d3b0c9e9Sxiaoqiang zhao void apic_poll_irq(DeviceState *dev)
473e5ad936bSJan Kiszka {
474927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
475e5ad936bSJan Kiszka 
476e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
477e5ad936bSJan Kiszka     apic_update_irq(s);
478e5ad936bSJan Kiszka }
479e5ad936bSJan Kiszka 
apic_set_irq(APICCommonState * s,int vector_num,int trigger_mode)480dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
481574bbf7bSbellard {
4822b85e0cdSThomas Huth     kvm_report_irq_delivered(!apic_get_bit(s->irr, vector_num));
48373822ec8Saliguori 
484edf9735eSMichael S. Tsirkin     apic_set_bit(s->irr, vector_num);
485574bbf7bSbellard     if (trigger_mode)
486edf9735eSMichael S. Tsirkin         apic_set_bit(s->tmr, vector_num);
487574bbf7bSbellard     else
488edf9735eSMichael S. Tsirkin         apic_reset_bit(s->tmr, vector_num);
489e5ad936bSJan Kiszka     if (s->vapic_paddr) {
490e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
491e5ad936bSJan Kiszka         /*
492e5ad936bSJan Kiszka          * The vcpu thread needs to see the new IRR before we pull its current
493e5ad936bSJan Kiszka          * TPR value. That way, if we miss a lowering of the TRP, the guest
494e5ad936bSJan Kiszka          * has the chance to notice the new IRR and poll for IRQs on its own.
495e5ad936bSJan Kiszka          */
496e5ad936bSJan Kiszka         smp_wmb();
497e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_FROM_VAPIC);
498e5ad936bSJan Kiszka     }
499574bbf7bSbellard     apic_update_irq(s);
500574bbf7bSbellard }
501574bbf7bSbellard 
apic_eoi(APICCommonState * s)502dae01685SJan Kiszka static void apic_eoi(APICCommonState *s)
503574bbf7bSbellard {
504574bbf7bSbellard     int isrv;
505574bbf7bSbellard     isrv = get_highest_priority_int(s->isr);
506574bbf7bSbellard     if (isrv < 0)
507574bbf7bSbellard         return;
508edf9735eSMichael S. Tsirkin     apic_reset_bit(s->isr, isrv);
509edf9735eSMichael S. Tsirkin     if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) {
5100280b571SJan Kiszka         ioapic_eoi_broadcast(isrv);
5110280b571SJan Kiszka     }
512e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
513574bbf7bSbellard     apic_update_irq(s);
514574bbf7bSbellard }
515574bbf7bSbellard 
apic_match_dest(APICCommonState * apic,uint32_t dest)516b5ee0468SBui Quang Minh static bool apic_match_dest(APICCommonState *apic, uint32_t dest)
517678e12ccSGleb Natapov {
518b5ee0468SBui Quang Minh     if (is_x2apic_mode(&apic->parent_obj)) {
519b5ee0468SBui Quang Minh         return apic->initial_apic_id == dest;
520b5ee0468SBui Quang Minh     } else {
521b5ee0468SBui Quang Minh         return apic->id == (uint8_t)dest;
522b5ee0468SBui Quang Minh     }
523678e12ccSGleb Natapov }
524678e12ccSGleb Natapov 
apic_find_dest(uint32_t * deliver_bitmask,uint32_t dest)525b5ee0468SBui Quang Minh static void apic_find_dest(uint32_t *deliver_bitmask, uint32_t dest)
526b5ee0468SBui Quang Minh {
527b5ee0468SBui Quang Minh     APICCommonState *apic = NULL;
528b5ee0468SBui Quang Minh     int i;
529b5ee0468SBui Quang Minh 
530b5ee0468SBui Quang Minh     for (i = 0; i < max_apics; i++) {
531b5ee0468SBui Quang Minh         apic = local_apics[i];
532b5ee0468SBui Quang Minh         if (apic && apic_match_dest(apic, dest)) {
533b5ee0468SBui Quang Minh             apic_set_bit(deliver_bitmask, i);
534b5ee0468SBui Quang Minh         }
535b5ee0468SBui Quang Minh     }
536b5ee0468SBui Quang Minh }
537b5ee0468SBui Quang Minh 
538b5ee0468SBui Quang Minh /*
539b5ee0468SBui Quang Minh  * Deliver interrupt to x2APIC CPUs if it is x2APIC broadcast.
540b5ee0468SBui Quang Minh  * Otherwise, deliver interrupt to xAPIC CPUs if it is xAPIC
541b5ee0468SBui Quang Minh  * broadcast.
542b5ee0468SBui Quang Minh  */
apic_get_broadcast_bitmask(uint32_t * deliver_bitmask,bool is_x2apic_broadcast)543b5ee0468SBui Quang Minh static void apic_get_broadcast_bitmask(uint32_t *deliver_bitmask,
544b5ee0468SBui Quang Minh                                        bool is_x2apic_broadcast)
545b5ee0468SBui Quang Minh {
546b5ee0468SBui Quang Minh     int i;
547b5ee0468SBui Quang Minh     APICCommonState *apic_iter;
548b5ee0468SBui Quang Minh 
549b5ee0468SBui Quang Minh     for (i = 0; i < max_apics; i++) {
550b5ee0468SBui Quang Minh         apic_iter = local_apics[i];
551b5ee0468SBui Quang Minh         if (apic_iter) {
552b5ee0468SBui Quang Minh             bool apic_in_x2apic = is_x2apic_mode(&apic_iter->parent_obj);
553b5ee0468SBui Quang Minh 
554b5ee0468SBui Quang Minh             if (is_x2apic_broadcast && apic_in_x2apic) {
555b5ee0468SBui Quang Minh                 apic_set_bit(deliver_bitmask, i);
556b5ee0468SBui Quang Minh             } else if (!is_x2apic_broadcast && !apic_in_x2apic) {
557b5ee0468SBui Quang Minh                 apic_set_bit(deliver_bitmask, i);
558b5ee0468SBui Quang Minh             }
559b5ee0468SBui Quang Minh         }
560b5ee0468SBui Quang Minh     }
561678e12ccSGleb Natapov }
562678e12ccSGleb Natapov 
apic_get_delivery_bitmask(uint32_t * deliver_bitmask,uint32_t dest,uint8_t dest_mode)563d3e9db93Sbellard static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
564b5ee0468SBui Quang Minh                                       uint32_t dest, uint8_t dest_mode)
565d592d303Sbellard {
566b5ee0468SBui Quang Minh     APICCommonState *apic;
567d3e9db93Sbellard     int i;
568d592d303Sbellard 
569b5ee0468SBui Quang Minh     memset(deliver_bitmask, 0x00, max_apic_words * sizeof(uint32_t));
570b5ee0468SBui Quang Minh 
571b5ee0468SBui Quang Minh     /*
572b5ee0468SBui Quang Minh      * x2APIC broadcast is delivered to all x2APIC CPUs regardless of
573b5ee0468SBui Quang Minh      * destination mode. In case the destination mode is physical, it is
574b5ee0468SBui Quang Minh      * broadcasted to all xAPIC CPUs too. Otherwise, if the destination
575b5ee0468SBui Quang Minh      * mode is logical, we need to continue checking if xAPIC CPUs accepts
576b5ee0468SBui Quang Minh      * the interrupt.
577b5ee0468SBui Quang Minh      */
578b5ee0468SBui Quang Minh     if (dest == 0xffffffff) {
579b5ee0468SBui Quang Minh         if (dest_mode == APIC_DESTMODE_PHYSICAL) {
580b5ee0468SBui Quang Minh             memset(deliver_bitmask, 0xff, max_apic_words * sizeof(uint32_t));
581b5ee0468SBui Quang Minh             return;
582b5ee0468SBui Quang Minh         } else {
583b5ee0468SBui Quang Minh             apic_get_broadcast_bitmask(deliver_bitmask, true);
584b5ee0468SBui Quang Minh         }
585b5ee0468SBui Quang Minh     }
586b5ee0468SBui Quang Minh 
587b5ee0468SBui Quang Minh     if (dest_mode == APIC_DESTMODE_PHYSICAL) {
588b5ee0468SBui Quang Minh         apic_find_dest(deliver_bitmask, dest);
589b5ee0468SBui Quang Minh         /* Any APIC in xAPIC mode will interpret 0xFF as broadcast */
590d3e9db93Sbellard         if (dest == 0xff) {
591b5ee0468SBui Quang Minh             apic_get_broadcast_bitmask(deliver_bitmask, false);
592d3e9db93Sbellard         }
593d592d303Sbellard     } else {
594b5ee0468SBui Quang Minh         /* XXX: logical mode */
595b5ee0468SBui Quang Minh         for (i = 0; i < max_apics; i++) {
596b5ee0468SBui Quang Minh             apic = local_apics[i];
597b5ee0468SBui Quang Minh             if (apic) {
598b5ee0468SBui Quang Minh                 /* x2APIC logical mode */
599b5ee0468SBui Quang Minh                 if (apic->apicbase & MSR_IA32_APICBASE_EXTD) {
600b5ee0468SBui Quang Minh                     if ((dest >> 16) == (apic->extended_log_dest >> 16) &&
601b5ee0468SBui Quang Minh                         (dest & apic->extended_log_dest & 0xffff)) {
602edf9735eSMichael S. Tsirkin                         apic_set_bit(deliver_bitmask, i);
603b5ee0468SBui Quang Minh                     }
604b5ee0468SBui Quang Minh                     continue;
605b5ee0468SBui Quang Minh                 }
606b5ee0468SBui Quang Minh 
607b5ee0468SBui Quang Minh                 /* xAPIC logical mode */
608b5ee0468SBui Quang Minh                 dest = (uint8_t)dest;
609b5ee0468SBui Quang Minh                 if (apic->dest_mode == APIC_DESTMODE_LOGICAL_FLAT) {
610b5ee0468SBui Quang Minh                     if (dest & apic->log_dest) {
611b5ee0468SBui Quang Minh                         apic_set_bit(deliver_bitmask, i);
612b5ee0468SBui Quang Minh                     }
613b5ee0468SBui Quang Minh                 } else if (apic->dest_mode == APIC_DESTMODE_LOGICAL_CLUSTER) {
614b5ee0468SBui Quang Minh                     /*
615b5ee0468SBui Quang Minh                      * In cluster model of xAPIC logical mode IPI, 4 higher
616b5ee0468SBui Quang Minh                      * bits are used as cluster address, 4 lower bits are
617b5ee0468SBui Quang Minh                      * the bitmask for local APICs in the cluster. The IPI
618b5ee0468SBui Quang Minh                      * is delivered to an APIC if the cluster address
619b5ee0468SBui Quang Minh                      * matches and the APIC's address bit in the cluster is
620b5ee0468SBui Quang Minh                      * set in bitmask of destination ID in IPI.
621b5ee0468SBui Quang Minh                      *
622b5ee0468SBui Quang Minh                      * The cluster address ranges from 0 - 14, the cluster
623b5ee0468SBui Quang Minh                      * address 15 (0xf) is the broadcast address to all
624b5ee0468SBui Quang Minh                      * clusters.
625b5ee0468SBui Quang Minh                      */
626b5ee0468SBui Quang Minh                     if ((dest & 0xf0) == 0xf0 ||
627b5ee0468SBui Quang Minh                         (dest & 0xf0) == (apic->log_dest & 0xf0)) {
628b5ee0468SBui Quang Minh                         if (dest & apic->log_dest & 0x0f) {
629edf9735eSMichael S. Tsirkin                             apic_set_bit(deliver_bitmask, i);
630d592d303Sbellard                         }
631d592d303Sbellard                     }
632b5ee0468SBui Quang Minh                }
633d3e9db93Sbellard             }
634d3e9db93Sbellard         }
635d3e9db93Sbellard     }
636d592d303Sbellard }
637d592d303Sbellard 
apic_startup(APICCommonState * s,int vector_num)638dae01685SJan Kiszka static void apic_startup(APICCommonState *s, int vector_num)
639e0fd8781Sbellard {
640b09ea7d5SGleb Natapov     s->sipi_vector = vector_num;
641c3affe56SAndreas Färber     cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
642b09ea7d5SGleb Natapov }
643b09ea7d5SGleb Natapov 
apic_sipi(DeviceState * dev)644d3b0c9e9Sxiaoqiang zhao void apic_sipi(DeviceState *dev)
645b09ea7d5SGleb Natapov {
646927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
64792a16d7aSBlue Swirl 
648d8ed887bSAndreas Färber     cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
649b09ea7d5SGleb Natapov 
650b09ea7d5SGleb Natapov     if (!s->wait_for_sipi)
651e0fd8781Sbellard         return;
652e9f9d6b1SAndreas Färber     cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
653b09ea7d5SGleb Natapov     s->wait_for_sipi = 0;
654e0fd8781Sbellard }
655e0fd8781Sbellard 
apic_deliver(DeviceState * dev,uint32_t dest,uint8_t dest_mode,uint8_t delivery_mode,uint8_t vector_num,uint8_t trigger_mode,uint8_t dest_shorthand)656b5ee0468SBui Quang Minh static void apic_deliver(DeviceState *dev, uint32_t dest, uint8_t dest_mode,
657d592d303Sbellard                          uint8_t delivery_mode, uint8_t vector_num,
658b5ee0468SBui Quang Minh                          uint8_t trigger_mode, uint8_t dest_shorthand)
659d592d303Sbellard {
660927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
661dae01685SJan Kiszka     APICCommonState *apic_iter;
662b5ee0468SBui Quang Minh     uint32_t deliver_bitmask_size = max_apic_words * sizeof(uint32_t);
663afd1af1cSPaolo Bonzini     g_autofree uint32_t *deliver_bitmask = g_new(uint32_t, max_apic_words);
664b5ee0468SBui Quang Minh     uint32_t current_apic_id;
665b5ee0468SBui Quang Minh 
666b5ee0468SBui Quang Minh     if (is_x2apic_mode(dev)) {
667b5ee0468SBui Quang Minh         current_apic_id = s->initial_apic_id;
668b5ee0468SBui Quang Minh     } else {
669b5ee0468SBui Quang Minh         current_apic_id = s->id;
670b5ee0468SBui Quang Minh     }
671d592d303Sbellard 
672e0fd8781Sbellard     switch (dest_shorthand) {
673e0fd8781Sbellard     case 0:
674d3e9db93Sbellard         apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
675e0fd8781Sbellard         break;
676e0fd8781Sbellard     case 1:
677b5ee0468SBui Quang Minh         memset(deliver_bitmask, 0x00, deliver_bitmask_size);
678b5ee0468SBui Quang Minh         apic_set_bit(deliver_bitmask, current_apic_id);
679e0fd8781Sbellard         break;
680e0fd8781Sbellard     case 2:
681b5ee0468SBui Quang Minh         memset(deliver_bitmask, 0xff, deliver_bitmask_size);
682e0fd8781Sbellard         break;
683e0fd8781Sbellard     case 3:
684b5ee0468SBui Quang Minh         memset(deliver_bitmask, 0xff, deliver_bitmask_size);
685b5ee0468SBui Quang Minh         apic_reset_bit(deliver_bitmask, current_apic_id);
686e0fd8781Sbellard         break;
687e0fd8781Sbellard     }
688e0fd8781Sbellard 
689d592d303Sbellard     switch (delivery_mode) {
690d592d303Sbellard         case APIC_DM_INIT:
691d592d303Sbellard             {
692d592d303Sbellard                 int trig_mode = (s->icr[0] >> 15) & 1;
693d592d303Sbellard                 int level = (s->icr[0] >> 14) & 1;
694d592d303Sbellard                 if (level == 0 && trig_mode == 1) {
695d3e9db93Sbellard                     foreach_apic(apic_iter, deliver_bitmask,
696d3e9db93Sbellard                                  apic_iter->arb_id = apic_iter->id );
697d592d303Sbellard                     return;
698d592d303Sbellard                 }
699d592d303Sbellard             }
700d592d303Sbellard             break;
701d592d303Sbellard 
702d592d303Sbellard         case APIC_DM_SIPI:
703d3e9db93Sbellard             foreach_apic(apic_iter, deliver_bitmask,
704d3e9db93Sbellard                          apic_startup(apic_iter, vector_num) );
705d592d303Sbellard             return;
706d592d303Sbellard     }
707d592d303Sbellard 
7081f6f408cSJan Kiszka     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
709d592d303Sbellard }
710d592d303Sbellard 
apic_check_pic(APICCommonState * s)711a94820ddSJan Kiszka static bool apic_check_pic(APICCommonState *s)
712a94820ddSJan Kiszka {
713be9f8a08SZhu Guihua     DeviceState *dev = (DeviceState *)s;
714be9f8a08SZhu Guihua 
715be9f8a08SZhu Guihua     if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
716a94820ddSJan Kiszka         return false;
717a94820ddSJan Kiszka     }
718be9f8a08SZhu Guihua     apic_deliver_pic_intr(dev, 1);
719a94820ddSJan Kiszka     return true;
720a94820ddSJan Kiszka }
721a94820ddSJan Kiszka 
apic_get_interrupt(DeviceState * dev)722d3b0c9e9Sxiaoqiang zhao int apic_get_interrupt(DeviceState *dev)
723574bbf7bSbellard {
724927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
725574bbf7bSbellard     int intno;
726574bbf7bSbellard 
727574bbf7bSbellard     /* if the APIC is installed or enabled, we let the 8259 handle the
728574bbf7bSbellard        IRQs */
729574bbf7bSbellard     if (!s)
730574bbf7bSbellard         return -1;
731574bbf7bSbellard     if (!(s->spurious_vec & APIC_SV_ENABLE))
732574bbf7bSbellard         return -1;
733574bbf7bSbellard 
734e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
7350fbfbb59SGleb Natapov     intno = apic_irq_pending(s);
7360fbfbb59SGleb Natapov 
7375224c88dSPaolo Bonzini     /* if there is an interrupt from the 8259, let the caller handle
7385224c88dSPaolo Bonzini      * that first since ExtINT interrupts ignore the priority.
7395224c88dSPaolo Bonzini      */
7405224c88dSPaolo Bonzini     if (intno == 0 || apic_check_pic(s)) {
741e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_TO_VAPIC);
742574bbf7bSbellard         return -1;
7430fbfbb59SGleb Natapov     } else if (intno < 0) {
744e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_TO_VAPIC);
745d592d303Sbellard         return s->spurious_vec & 0xff;
7460fbfbb59SGleb Natapov     }
747edf9735eSMichael S. Tsirkin     apic_reset_bit(s->irr, intno);
748edf9735eSMichael S. Tsirkin     apic_set_bit(s->isr, intno);
749e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_TO_VAPIC);
7503db3659bSJan Kiszka 
751574bbf7bSbellard     apic_update_irq(s);
7523db3659bSJan Kiszka 
753574bbf7bSbellard     return intno;
754574bbf7bSbellard }
755574bbf7bSbellard 
apic_accept_pic_intr(DeviceState * dev)756d3b0c9e9Sxiaoqiang zhao int apic_accept_pic_intr(DeviceState *dev)
7570e21e12bSths {
758927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
7590e21e12bSths     uint32_t lvt0;
7600e21e12bSths 
7610e21e12bSths     if (!s)
7620e21e12bSths         return -1;
7630e21e12bSths 
7640e21e12bSths     lvt0 = s->lvt[APIC_LVT_LINT0];
7650e21e12bSths 
766a5b38b51Saurel32     if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
767a5b38b51Saurel32         (lvt0 & APIC_LVT_MASKED) == 0)
76878cafff8SSergio Lopez         return isa_pic != NULL;
7690e21e12bSths 
7700e21e12bSths     return 0;
7710e21e12bSths }
7720e21e12bSths 
apic_timer_update(APICCommonState * s,int64_t current_time)773dae01685SJan Kiszka static void apic_timer_update(APICCommonState *s, int64_t current_time)
774574bbf7bSbellard {
7757a380ca3SJan Kiszka     if (apic_next_timer(s, current_time)) {
776bc72ad67SAlex Bligh         timer_mod(s->timer, s->next_time);
777574bbf7bSbellard     } else {
778bc72ad67SAlex Bligh         timer_del(s->timer);
779574bbf7bSbellard     }
780574bbf7bSbellard }
781574bbf7bSbellard 
apic_timer(void * opaque)782574bbf7bSbellard static void apic_timer(void *opaque)
783574bbf7bSbellard {
784dae01685SJan Kiszka     APICCommonState *s = opaque;
785574bbf7bSbellard 
786cf6d64bfSBlue Swirl     apic_local_deliver(s, APIC_LVT_TIMER);
787574bbf7bSbellard     apic_timer_update(s, s->next_time);
788574bbf7bSbellard }
789574bbf7bSbellard 
apic_register_read(int index,uint64_t * value)790b2101358SBui Quang Minh static int apic_register_read(int index, uint64_t *value)
791574bbf7bSbellard {
792d3b0c9e9Sxiaoqiang zhao     DeviceState *dev;
793dae01685SJan Kiszka     APICCommonState *s;
794574bbf7bSbellard     uint32_t val;
795b2101358SBui Quang Minh     int ret = 0;
79621f80e8fSPeter Maydell 
797d3b0c9e9Sxiaoqiang zhao     dev = cpu_get_current_apic();
798d3b0c9e9Sxiaoqiang zhao     if (!dev) {
799b2101358SBui Quang Minh         return -1;
8000e26b7b8SBlue Swirl     }
801927d5a1dSWanpeng Li     s = APIC(dev);
802574bbf7bSbellard 
803574bbf7bSbellard     switch(index) {
804574bbf7bSbellard     case 0x02: /* id */
805b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
806b5ee0468SBui Quang Minh             val = s->initial_apic_id;
807b5ee0468SBui Quang Minh         } else {
808574bbf7bSbellard             val = s->id << 24;
809b5ee0468SBui Quang Minh         }
810574bbf7bSbellard         break;
811574bbf7bSbellard     case 0x03: /* version */
812aa93200bSGabriel L. Somlo         val = s->version | ((APIC_LVT_NB - 1) << 16);
813574bbf7bSbellard         break;
814574bbf7bSbellard     case 0x08:
815e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_FROM_VAPIC);
816e5ad936bSJan Kiszka         if (apic_report_tpr_access) {
81760671e58SAndreas Färber             cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
818e5ad936bSJan Kiszka         }
819574bbf7bSbellard         val = s->tpr;
820574bbf7bSbellard         break;
821d592d303Sbellard     case 0x09:
822d592d303Sbellard         val = apic_get_arb_pri(s);
823d592d303Sbellard         break;
824574bbf7bSbellard     case 0x0a:
825574bbf7bSbellard         /* ppr */
826574bbf7bSbellard         val = apic_get_ppr(s);
827574bbf7bSbellard         break;
828b237db36Saurel32     case 0x0b:
829b237db36Saurel32         val = 0;
830b237db36Saurel32         break;
831d592d303Sbellard     case 0x0d:
832b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
833b5ee0468SBui Quang Minh             val = s->extended_log_dest;
834b5ee0468SBui Quang Minh         } else {
835d592d303Sbellard             val = s->log_dest << 24;
836b5ee0468SBui Quang Minh         }
837d592d303Sbellard         break;
838d592d303Sbellard     case 0x0e:
839b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
840b5ee0468SBui Quang Minh             val = 0;
841b5ee0468SBui Quang Minh             ret = -1;
842b5ee0468SBui Quang Minh         } else {
843d6c140a7SJan Kiszka             val = (s->dest_mode << 28) | 0xfffffff;
844b5ee0468SBui Quang Minh         }
845d592d303Sbellard         break;
846574bbf7bSbellard     case 0x0f:
847574bbf7bSbellard         val = s->spurious_vec;
848574bbf7bSbellard         break;
849574bbf7bSbellard     case 0x10 ... 0x17:
850574bbf7bSbellard         val = s->isr[index & 7];
851574bbf7bSbellard         break;
852574bbf7bSbellard     case 0x18 ... 0x1f:
853574bbf7bSbellard         val = s->tmr[index & 7];
854574bbf7bSbellard         break;
855574bbf7bSbellard     case 0x20 ... 0x27:
856574bbf7bSbellard         val = s->irr[index & 7];
857574bbf7bSbellard         break;
858574bbf7bSbellard     case 0x28:
859574bbf7bSbellard         val = s->esr;
860574bbf7bSbellard         break;
861574bbf7bSbellard     case 0x30:
862574bbf7bSbellard     case 0x31:
863574bbf7bSbellard         val = s->icr[index & 1];
864574bbf7bSbellard         break;
865e0fd8781Sbellard     case 0x32 ... 0x37:
866e0fd8781Sbellard         val = s->lvt[index - 0x32];
867e0fd8781Sbellard         break;
868574bbf7bSbellard     case 0x38:
869574bbf7bSbellard         val = s->initial_count;
870574bbf7bSbellard         break;
871574bbf7bSbellard     case 0x39:
872574bbf7bSbellard         val = apic_get_current_count(s);
873574bbf7bSbellard         break;
874574bbf7bSbellard     case 0x3e:
875574bbf7bSbellard         val = s->divide_conf;
876574bbf7bSbellard         break;
877574bbf7bSbellard     default:
878a22bf99cSPavel Butsykin         s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
879574bbf7bSbellard         val = 0;
880b2101358SBui Quang Minh         ret = -1;
881574bbf7bSbellard         break;
882574bbf7bSbellard     }
883b2101358SBui Quang Minh 
884b2101358SBui Quang Minh     trace_apic_register_read(index, val);
885b2101358SBui Quang Minh     *value = val;
886b2101358SBui Quang Minh     return ret;
887b2101358SBui Quang Minh }
888b2101358SBui Quang Minh 
apic_mem_read(void * opaque,hwaddr addr,unsigned size)889b2101358SBui Quang Minh static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
890b2101358SBui Quang Minh {
891b2101358SBui Quang Minh     uint64_t val;
892b2101358SBui Quang Minh     int index;
893b2101358SBui Quang Minh 
894b2101358SBui Quang Minh     if (size < 4) {
895b2101358SBui Quang Minh         return 0;
896b2101358SBui Quang Minh     }
897b2101358SBui Quang Minh 
898b2101358SBui Quang Minh     index = (addr >> 4) & 0xff;
899b2101358SBui Quang Minh     apic_register_read(index, &val);
900b2101358SBui Quang Minh 
901574bbf7bSbellard     return val;
902574bbf7bSbellard }
903574bbf7bSbellard 
apic_msr_read(int index,uint64_t * val)904b2101358SBui Quang Minh int apic_msr_read(int index, uint64_t *val)
905b2101358SBui Quang Minh {
906b2101358SBui Quang Minh     DeviceState *dev;
907b2101358SBui Quang Minh 
908b2101358SBui Quang Minh     dev = cpu_get_current_apic();
909b2101358SBui Quang Minh     if (!dev) {
910b2101358SBui Quang Minh         return -1;
911b2101358SBui Quang Minh     }
912b2101358SBui Quang Minh 
913b2101358SBui Quang Minh     if (!is_x2apic_mode(dev)) {
914b2101358SBui Quang Minh         return -1;
915b2101358SBui Quang Minh     }
916b2101358SBui Quang Minh 
917b2101358SBui Quang Minh     return apic_register_read(index, val);
918b2101358SBui Quang Minh }
919b2101358SBui Quang Minh 
apic_send_msi(MSIMessage * msi)920267ee357SRadim Krčmář static void apic_send_msi(MSIMessage *msi)
92154c96da7SMichael S. Tsirkin {
922267ee357SRadim Krčmář     uint64_t addr = msi->address;
923267ee357SRadim Krčmář     uint32_t data = msi->data;
924b5ee0468SBui Quang Minh     uint32_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
925b5ee0468SBui Quang Minh     /*
926b5ee0468SBui Quang Minh      * The higher 3 bytes of destination id is stored in higher word of
927b5ee0468SBui Quang Minh      * msi address. See x86_iommu_irq_to_msi_message()
928b5ee0468SBui Quang Minh      */
929b5ee0468SBui Quang Minh     dest = dest | (addr >> 32);
93054c96da7SMichael S. Tsirkin     uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
93154c96da7SMichael S. Tsirkin     uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
93254c96da7SMichael S. Tsirkin     uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
93354c96da7SMichael S. Tsirkin     uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
93454c96da7SMichael S. Tsirkin     /* XXX: Ignore redirection hint. */
9351f6f408cSJan Kiszka     apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
93654c96da7SMichael S. Tsirkin }
93754c96da7SMichael S. Tsirkin 
apic_register_write(int index,uint64_t val)938b2101358SBui Quang Minh static int apic_register_write(int index, uint64_t val)
939574bbf7bSbellard {
940d3b0c9e9Sxiaoqiang zhao     DeviceState *dev;
941dae01685SJan Kiszka     APICCommonState *s;
942574bbf7bSbellard 
943d3b0c9e9Sxiaoqiang zhao     dev = cpu_get_current_apic();
944d3b0c9e9Sxiaoqiang zhao     if (!dev) {
945b2101358SBui Quang Minh         return -1;
9460e26b7b8SBlue Swirl     }
947927d5a1dSWanpeng Li     s = APIC(dev);
948574bbf7bSbellard 
949b2101358SBui Quang Minh     trace_apic_register_write(index, val);
950574bbf7bSbellard 
951574bbf7bSbellard     switch(index) {
952574bbf7bSbellard     case 0x02:
953b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
954b5ee0468SBui Quang Minh             return -1;
955b5ee0468SBui Quang Minh         }
956b5ee0468SBui Quang Minh 
957574bbf7bSbellard         s->id = (val >> 24);
958574bbf7bSbellard         break;
959e0fd8781Sbellard     case 0x03:
960e0fd8781Sbellard         break;
961574bbf7bSbellard     case 0x08:
962e5ad936bSJan Kiszka         if (apic_report_tpr_access) {
96360671e58SAndreas Färber             cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
964e5ad936bSJan Kiszka         }
965574bbf7bSbellard         s->tpr = val;
966e5ad936bSJan Kiszka         apic_sync_vapic(s, SYNC_TO_VAPIC);
967d592d303Sbellard         apic_update_irq(s);
968574bbf7bSbellard         break;
969e0fd8781Sbellard     case 0x09:
970e0fd8781Sbellard     case 0x0a:
971e0fd8781Sbellard         break;
972574bbf7bSbellard     case 0x0b: /* EOI */
973574bbf7bSbellard         apic_eoi(s);
974574bbf7bSbellard         break;
975d592d303Sbellard     case 0x0d:
976b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
977b5ee0468SBui Quang Minh             return -1;
978b5ee0468SBui Quang Minh         }
979b5ee0468SBui Quang Minh 
980d592d303Sbellard         s->log_dest = val >> 24;
981d592d303Sbellard         break;
982d592d303Sbellard     case 0x0e:
983b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
984b5ee0468SBui Quang Minh             return -1;
985b5ee0468SBui Quang Minh         }
986b5ee0468SBui Quang Minh 
987d592d303Sbellard         s->dest_mode = val >> 28;
988d592d303Sbellard         break;
989574bbf7bSbellard     case 0x0f:
990574bbf7bSbellard         s->spurious_vec = val & 0x1ff;
991d592d303Sbellard         apic_update_irq(s);
992574bbf7bSbellard         break;
993e0fd8781Sbellard     case 0x10 ... 0x17:
994e0fd8781Sbellard     case 0x18 ... 0x1f:
995e0fd8781Sbellard     case 0x20 ... 0x27:
996e0fd8781Sbellard     case 0x28:
997e0fd8781Sbellard         break;
998b5ee0468SBui Quang Minh     case 0x30: {
999b5ee0468SBui Quang Minh         uint32_t dest;
1000b5ee0468SBui Quang Minh 
1001d592d303Sbellard         s->icr[0] = val;
1002b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
1003b5ee0468SBui Quang Minh             s->icr[1] = val >> 32;
1004b5ee0468SBui Quang Minh             dest = s->icr[1];
1005b5ee0468SBui Quang Minh         } else {
1006b5ee0468SBui Quang Minh             dest = (s->icr[1] >> 24) & 0xff;
1007b5ee0468SBui Quang Minh         }
1008b5ee0468SBui Quang Minh 
1009b5ee0468SBui Quang Minh         apic_deliver(dev, dest, (s->icr[0] >> 11) & 1,
1010d592d303Sbellard                      (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1011b5ee0468SBui Quang Minh                      (s->icr[0] >> 15) & 1, (s->icr[0] >> 18) & 3);
1012d592d303Sbellard         break;
1013b5ee0468SBui Quang Minh     }
1014574bbf7bSbellard     case 0x31:
1015b5ee0468SBui Quang Minh         if (is_x2apic_mode(dev)) {
1016b5ee0468SBui Quang Minh             return -1;
1017b5ee0468SBui Quang Minh         }
1018b5ee0468SBui Quang Minh 
1019d592d303Sbellard         s->icr[1] = val;
1020574bbf7bSbellard         break;
1021574bbf7bSbellard     case 0x32 ... 0x37:
1022574bbf7bSbellard         {
1023574bbf7bSbellard             int n = index - 0x32;
1024574bbf7bSbellard             s->lvt[n] = val;
1025a94820ddSJan Kiszka             if (n == APIC_LVT_TIMER) {
1026bc72ad67SAlex Bligh                 apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
1027a94820ddSJan Kiszka             } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
1028a94820ddSJan Kiszka                 apic_update_irq(s);
1029a94820ddSJan Kiszka             }
1030574bbf7bSbellard         }
1031574bbf7bSbellard         break;
1032574bbf7bSbellard     case 0x38:
1033574bbf7bSbellard         s->initial_count = val;
1034bc72ad67SAlex Bligh         s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1035574bbf7bSbellard         apic_timer_update(s, s->initial_count_load_time);
1036574bbf7bSbellard         break;
1037e0fd8781Sbellard     case 0x39:
1038e0fd8781Sbellard         break;
1039574bbf7bSbellard     case 0x3e:
1040574bbf7bSbellard         {
1041574bbf7bSbellard             int v;
1042574bbf7bSbellard             s->divide_conf = val & 0xb;
1043574bbf7bSbellard             v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
1044574bbf7bSbellard             s->count_shift = (v + 1) & 7;
1045574bbf7bSbellard         }
1046574bbf7bSbellard         break;
1047b5ee0468SBui Quang Minh     case 0x3f: {
1048b5ee0468SBui Quang Minh         int vector = val & 0xff;
1049b5ee0468SBui Quang Minh 
1050b5ee0468SBui Quang Minh         if (!is_x2apic_mode(dev)) {
1051b5ee0468SBui Quang Minh             return -1;
1052b5ee0468SBui Quang Minh         }
1053b5ee0468SBui Quang Minh 
1054b5ee0468SBui Quang Minh         /*
1055b5ee0468SBui Quang Minh          * Self IPI is identical to IPI with
1056b5ee0468SBui Quang Minh          * - Destination shorthand: 1 (Self)
1057b5ee0468SBui Quang Minh          * - Trigger mode: 0 (Edge)
1058b5ee0468SBui Quang Minh          * - Delivery mode: 0 (Fixed)
1059b5ee0468SBui Quang Minh          */
1060b5ee0468SBui Quang Minh         apic_deliver(dev, 0, 0, APIC_DM_FIXED, vector, 0, 1);
1061b5ee0468SBui Quang Minh 
1062b5ee0468SBui Quang Minh         break;
1063b5ee0468SBui Quang Minh     }
1064574bbf7bSbellard     default:
1065a22bf99cSPavel Butsykin         s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
1066b2101358SBui Quang Minh         return -1;
1067574bbf7bSbellard     }
1068b2101358SBui Quang Minh 
1069b2101358SBui Quang Minh     return 0;
1070b2101358SBui Quang Minh }
1071b2101358SBui Quang Minh 
apic_mem_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)1072b2101358SBui Quang Minh static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
1073b2101358SBui Quang Minh                            unsigned size)
1074b2101358SBui Quang Minh {
1075b2101358SBui Quang Minh     int index = (addr >> 4) & 0xff;
1076b2101358SBui Quang Minh 
1077b2101358SBui Quang Minh     if (size < 4) {
1078b2101358SBui Quang Minh         return;
1079b2101358SBui Quang Minh     }
1080b2101358SBui Quang Minh 
1081b2101358SBui Quang Minh     if (addr > 0xfff || !index) {
1082b2101358SBui Quang Minh         /*
1083b2101358SBui Quang Minh          * MSI and MMIO APIC are at the same memory location,
1084b2101358SBui Quang Minh          * but actually not on the global bus: MSI is on PCI bus
1085b2101358SBui Quang Minh          * APIC is connected directly to the CPU.
1086b2101358SBui Quang Minh          * Mapping them on the global bus happens to work because
1087b2101358SBui Quang Minh          * MSI registers are reserved in APIC MMIO and vice versa.
1088b2101358SBui Quang Minh          */
1089b2101358SBui Quang Minh         MSIMessage msi = { .address = addr, .data = val };
1090b2101358SBui Quang Minh         apic_send_msi(&msi);
1091b2101358SBui Quang Minh         return;
1092b2101358SBui Quang Minh     }
1093b2101358SBui Quang Minh 
1094b2101358SBui Quang Minh     apic_register_write(index, val);
1095b2101358SBui Quang Minh }
1096b2101358SBui Quang Minh 
apic_msr_write(int index,uint64_t val)1097b2101358SBui Quang Minh int apic_msr_write(int index, uint64_t val)
1098b2101358SBui Quang Minh {
1099b2101358SBui Quang Minh     DeviceState *dev;
1100b2101358SBui Quang Minh 
1101b2101358SBui Quang Minh     dev = cpu_get_current_apic();
1102b2101358SBui Quang Minh     if (!dev) {
1103b2101358SBui Quang Minh         return -1;
1104b2101358SBui Quang Minh     }
1105b2101358SBui Quang Minh 
1106b2101358SBui Quang Minh     if (!is_x2apic_mode(dev)) {
1107b2101358SBui Quang Minh         return -1;
1108b2101358SBui Quang Minh     }
1109b2101358SBui Quang Minh 
1110b2101358SBui Quang Minh     return apic_register_write(index, val);
1111574bbf7bSbellard }
1112574bbf7bSbellard 
apic_pre_save(APICCommonState * s)1113e5ad936bSJan Kiszka static void apic_pre_save(APICCommonState *s)
1114e5ad936bSJan Kiszka {
1115e5ad936bSJan Kiszka     apic_sync_vapic(s, SYNC_FROM_VAPIC);
1116e5ad936bSJan Kiszka }
1117e5ad936bSJan Kiszka 
apic_post_load(APICCommonState * s)11187a380ca3SJan Kiszka static void apic_post_load(APICCommonState *s)
11197a380ca3SJan Kiszka {
11207a380ca3SJan Kiszka     if (s->timer_expiry != -1) {
1121bc72ad67SAlex Bligh         timer_mod(s->timer, s->timer_expiry);
11227a380ca3SJan Kiszka     } else {
1123bc72ad67SAlex Bligh         timer_del(s->timer);
11247a380ca3SJan Kiszka     }
11257a380ca3SJan Kiszka }
11267a380ca3SJan Kiszka 
1127312b4234SAvi Kivity static const MemoryRegionOps apic_io_ops = {
112821f80e8fSPeter Maydell     .read = apic_mem_read,
112921f80e8fSPeter Maydell     .write = apic_mem_write,
113021f80e8fSPeter Maydell     .impl.min_access_size = 1,
113121f80e8fSPeter Maydell     .impl.max_access_size = 4,
113221f80e8fSPeter Maydell     .valid.min_access_size = 1,
113321f80e8fSPeter Maydell     .valid.max_access_size = 4,
1134312b4234SAvi Kivity     .endianness = DEVICE_NATIVE_ENDIAN,
1135574bbf7bSbellard };
1136574bbf7bSbellard 
apic_realize(DeviceState * dev,Error ** errp)1137ff6986ceSxiaoqiang zhao static void apic_realize(DeviceState *dev, Error **errp)
11388546b099SBlue Swirl {
1139927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
1140889211b1SIgor Mammedov 
11412c933ac6SPaolo Bonzini     if (kvm_enabled()) {
11422c933ac6SPaolo Bonzini         warn_report("Userspace local APIC is deprecated for KVM.");
11432c933ac6SPaolo Bonzini         warn_report("Do not use kernel-irqchip except for the -M isapc machine type.");
11442c933ac6SPaolo Bonzini     }
11452c933ac6SPaolo Bonzini 
11461437c94bSPaolo Bonzini     memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
1147baaeda08SIgor Mammedov                           APIC_SPACE_SIZE);
11488546b099SBlue Swirl 
114950795ee0SAlexander Bulekov     /*
115050795ee0SAlexander Bulekov      * apic-msi's apic_mem_write can call into ioapic_eoi_broadcast, which can
115150795ee0SAlexander Bulekov      * write back to apic-msi. As such mark the apic-msi region re-entrancy
115250795ee0SAlexander Bulekov      * safe.
115350795ee0SAlexander Bulekov      */
115450795ee0SAlexander Bulekov     s->io_memory.disable_reentrancy_guard = true;
115550795ee0SAlexander Bulekov 
1156bc72ad67SAlex Bligh     s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
1157b5ee0468SBui Quang Minh 
1158b5ee0468SBui Quang Minh     /*
1159b5ee0468SBui Quang Minh      * The --machine none does not call apic_set_max_apic_id before creating
1160b5ee0468SBui Quang Minh      * apic, so we need to call it here and set it to 1 which is the max cpus
1161b5ee0468SBui Quang Minh      * in machine none.
1162b5ee0468SBui Quang Minh      */
1163b5ee0468SBui Quang Minh     if (!local_apics) {
1164b5ee0468SBui Quang Minh         apic_set_max_apic_id(1);
1165b5ee0468SBui Quang Minh     }
1166b5ee0468SBui Quang Minh     local_apics[s->initial_apic_id] = s;
116708a82ac0SJan Kiszka 
1168226419d6SMichael S. Tsirkin     msi_nonbroken = true;
11698546b099SBlue Swirl }
11708546b099SBlue Swirl 
apic_unrealize(DeviceState * dev)1171b69c3c21SMarkus Armbruster static void apic_unrealize(DeviceState *dev)
11729c156f9dSIgor Mammedov {
1173927d5a1dSWanpeng Li     APICCommonState *s = APIC(dev);
11749c156f9dSIgor Mammedov 
11759c156f9dSIgor Mammedov     timer_free(s->timer);
1176b5ee0468SBui Quang Minh     local_apics[s->initial_apic_id] = NULL;
11779c156f9dSIgor Mammedov }
11789c156f9dSIgor Mammedov 
apic_class_init(ObjectClass * klass,const void * data)1179*12d1a768SPhilippe Mathieu-Daudé static void apic_class_init(ObjectClass *klass, const void *data)
1180999e12bbSAnthony Liguori {
1181999e12bbSAnthony Liguori     APICCommonClass *k = APIC_COMMON_CLASS(klass);
1182999e12bbSAnthony Liguori 
1183ff6986ceSxiaoqiang zhao     k->realize = apic_realize;
11849c156f9dSIgor Mammedov     k->unrealize = apic_unrealize;
1185999e12bbSAnthony Liguori     k->set_base = apic_set_base;
1186999e12bbSAnthony Liguori     k->set_tpr = apic_set_tpr;
1187e5ad936bSJan Kiszka     k->get_tpr = apic_get_tpr;
1188e5ad936bSJan Kiszka     k->vapic_base_update = apic_vapic_base_update;
1189999e12bbSAnthony Liguori     k->external_nmi = apic_external_nmi;
1190e5ad936bSJan Kiszka     k->pre_save = apic_pre_save;
1191999e12bbSAnthony Liguori     k->post_load = apic_post_load;
1192267ee357SRadim Krčmář     k->send_msi = apic_send_msi;
1193999e12bbSAnthony Liguori }
1194999e12bbSAnthony Liguori 
11958c43a6f0SAndreas Färber static const TypeInfo apic_info = {
1196927d5a1dSWanpeng Li     .name          = TYPE_APIC,
119739bffca2SAnthony Liguori     .instance_size = sizeof(APICCommonState),
119839bffca2SAnthony Liguori     .parent        = TYPE_APIC_COMMON,
1199999e12bbSAnthony Liguori     .class_init    = apic_class_init,
12008546b099SBlue Swirl };
12018546b099SBlue Swirl 
apic_register_types(void)120283f7d43aSAndreas Färber static void apic_register_types(void)
12038546b099SBlue Swirl {
120439bffca2SAnthony Liguori     type_register_static(&apic_info);
12058546b099SBlue Swirl }
12068546b099SBlue Swirl 
120783f7d43aSAndreas Färber type_init(apic_register_types)
1208