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