17702e47cSPaolo Bonzini /*
27702e47cSPaolo Bonzini * APIC support
37702e47cSPaolo Bonzini *
47702e47cSPaolo Bonzini * Copyright (c) 2004-2005 Fabrice Bellard
57702e47cSPaolo Bonzini *
67702e47cSPaolo Bonzini * This library is free software; you can redistribute it and/or
77702e47cSPaolo Bonzini * modify it under the terms of the GNU Lesser General Public
87702e47cSPaolo Bonzini * License as published by the Free Software Foundation; either
961f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version.
107702e47cSPaolo Bonzini *
117702e47cSPaolo Bonzini * This library is distributed in the hope that it will be useful,
127702e47cSPaolo Bonzini * but WITHOUT ANY WARRANTY; without even the implied warranty of
137702e47cSPaolo Bonzini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
147702e47cSPaolo Bonzini * Lesser General Public License for more details.
157702e47cSPaolo Bonzini *
167702e47cSPaolo Bonzini * You should have received a copy of the GNU Lesser General Public
177702e47cSPaolo Bonzini * License along with this library; if not, see <http://www.gnu.org/licenses/>
187702e47cSPaolo Bonzini */
19b6a0aa05SPeter Maydell #include "qemu/osdep.h"
207702e47cSPaolo Bonzini #include "qemu/thread.h"
21cc37d98bSRichard Henderson #include "qemu/error-report.h"
227702e47cSPaolo Bonzini #include "hw/i386/apic_internal.h"
237702e47cSPaolo 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"
277702e47cSPaolo Bonzini #include "hw/pci/msi.h"
287702e47cSPaolo Bonzini #include "qemu/host-utils.h"
292c933ac6SPaolo Bonzini #include "sysemu/kvm.h"
307702e47cSPaolo Bonzini #include "trace.h"
317702e47cSPaolo Bonzini #include "hw/i386/apic-msidef.h"
32889211b1SIgor Mammedov #include "qapi/error.h"
33db1015e9SEduardo Habkost #include "qom/object.h"
347702e47cSPaolo Bonzini
357702e47cSPaolo Bonzini #define SYNC_FROM_VAPIC 0x1
367702e47cSPaolo Bonzini #define SYNC_TO_VAPIC 0x2
377702e47cSPaolo Bonzini #define SYNC_ISR_IRR_TO_VAPIC 0x4
387702e47cSPaolo Bonzini
39b5ee0468SBui Quang Minh static APICCommonState **local_apics;
40b5ee0468SBui Quang Minh static uint32_t max_apics;
41b5ee0468SBui Quang Minh static uint32_t max_apic_words;
427702e47cSPaolo Bonzini
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
487702e47cSPaolo Bonzini static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
497702e47cSPaolo Bonzini static void apic_update_irq(APICCommonState *s);
507702e47cSPaolo Bonzini 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
647702e47cSPaolo Bonzini
657702e47cSPaolo Bonzini /* Find first bit starting from msb */
apic_fls_bit(uint32_t value)66edf9735eSMichael S. Tsirkin static int apic_fls_bit(uint32_t value)
677702e47cSPaolo Bonzini {
687702e47cSPaolo Bonzini return 31 - clz32(value);
697702e47cSPaolo Bonzini }
707702e47cSPaolo Bonzini
717702e47cSPaolo Bonzini /* Find first bit starting from lsb */
apic_ffs_bit(uint32_t value)72edf9735eSMichael S. Tsirkin static int apic_ffs_bit(uint32_t value)
737702e47cSPaolo Bonzini {
747702e47cSPaolo Bonzini return ctz32(value);
757702e47cSPaolo Bonzini }
767702e47cSPaolo Bonzini
apic_reset_bit(uint32_t * tab,int index)77edf9735eSMichael S. Tsirkin static inline void apic_reset_bit(uint32_t *tab, int index)
787702e47cSPaolo Bonzini {
797702e47cSPaolo Bonzini int i, mask;
807702e47cSPaolo Bonzini i = index >> 5;
817702e47cSPaolo Bonzini mask = 1 << (index & 0x1f);
827702e47cSPaolo Bonzini tab[i] &= ~mask;
837702e47cSPaolo Bonzini }
847702e47cSPaolo Bonzini
857702e47cSPaolo Bonzini /* return -1 if no bit is set */
get_highest_priority_int(uint32_t * tab)867702e47cSPaolo Bonzini static int get_highest_priority_int(uint32_t *tab)
877702e47cSPaolo Bonzini {
887702e47cSPaolo Bonzini int i;
897702e47cSPaolo Bonzini for (i = 7; i >= 0; i--) {
907702e47cSPaolo Bonzini if (tab[i] != 0) {
91edf9735eSMichael S. Tsirkin return i * 32 + apic_fls_bit(tab[i]);
927702e47cSPaolo Bonzini }
937702e47cSPaolo Bonzini }
947702e47cSPaolo Bonzini return -1;
957702e47cSPaolo Bonzini }
967702e47cSPaolo Bonzini
apic_sync_vapic(APICCommonState * s,int sync_type)977702e47cSPaolo Bonzini static void apic_sync_vapic(APICCommonState *s, int sync_type)
987702e47cSPaolo Bonzini {
997702e47cSPaolo Bonzini VAPICState vapic_state;
1007702e47cSPaolo Bonzini size_t length;
1017702e47cSPaolo Bonzini off_t start;
1027702e47cSPaolo Bonzini int vector;
1037702e47cSPaolo Bonzini
1047702e47cSPaolo Bonzini if (!s->vapic_paddr) {
1057702e47cSPaolo Bonzini return;
1067702e47cSPaolo Bonzini }
1077702e47cSPaolo Bonzini if (sync_type & SYNC_FROM_VAPIC) {
108eb6282f2SStefan Weil cpu_physical_memory_read(s->vapic_paddr, &vapic_state,
109eb6282f2SStefan Weil sizeof(vapic_state));
1107702e47cSPaolo Bonzini s->tpr = vapic_state.tpr;
1117702e47cSPaolo Bonzini }
1127702e47cSPaolo Bonzini if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) {
1137702e47cSPaolo Bonzini start = offsetof(VAPICState, isr);
1147702e47cSPaolo Bonzini length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr);
1157702e47cSPaolo Bonzini
1167702e47cSPaolo Bonzini if (sync_type & SYNC_TO_VAPIC) {
1177702e47cSPaolo Bonzini assert(qemu_cpu_is_self(CPU(s->cpu)));
1187702e47cSPaolo Bonzini
1197702e47cSPaolo Bonzini vapic_state.tpr = s->tpr;
1207702e47cSPaolo Bonzini vapic_state.enabled = 1;
1217702e47cSPaolo Bonzini start = 0;
1227702e47cSPaolo Bonzini length = sizeof(VAPICState);
1237702e47cSPaolo Bonzini }
1247702e47cSPaolo Bonzini
1257702e47cSPaolo Bonzini vector = get_highest_priority_int(s->isr);
1267702e47cSPaolo Bonzini if (vector < 0) {
1277702e47cSPaolo Bonzini vector = 0;
1287702e47cSPaolo Bonzini }
1297702e47cSPaolo Bonzini vapic_state.isr = vector & 0xf0;
1307702e47cSPaolo Bonzini
1317702e47cSPaolo Bonzini vapic_state.zero = 0;
1327702e47cSPaolo Bonzini
1337702e47cSPaolo Bonzini vector = get_highest_priority_int(s->irr);
1347702e47cSPaolo Bonzini if (vector < 0) {
1357702e47cSPaolo Bonzini vector = 0;
1367702e47cSPaolo Bonzini }
1377702e47cSPaolo Bonzini vapic_state.irr = vector & 0xff;
1387702e47cSPaolo Bonzini
1393c8133f9SPeter Maydell address_space_write_rom(&address_space_memory,
1402a221651SEdgar E. Iglesias s->vapic_paddr + start,
1413c8133f9SPeter Maydell MEMTXATTRS_UNSPECIFIED,
1427702e47cSPaolo Bonzini ((void *)&vapic_state) + start, length);
1437702e47cSPaolo Bonzini }
1447702e47cSPaolo Bonzini }
1457702e47cSPaolo Bonzini
apic_vapic_base_update(APICCommonState * s)1467702e47cSPaolo Bonzini static void apic_vapic_base_update(APICCommonState *s)
1477702e47cSPaolo Bonzini {
1487702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_TO_VAPIC);
1497702e47cSPaolo Bonzini }
1507702e47cSPaolo Bonzini
apic_local_deliver(APICCommonState * s,int vector)1517702e47cSPaolo Bonzini static void apic_local_deliver(APICCommonState *s, int vector)
1527702e47cSPaolo Bonzini {
1537702e47cSPaolo Bonzini uint32_t lvt = s->lvt[vector];
1547702e47cSPaolo Bonzini int trigger_mode;
1557702e47cSPaolo Bonzini
1567702e47cSPaolo Bonzini trace_apic_local_deliver(vector, (lvt >> 8) & 7);
1577702e47cSPaolo Bonzini
1587702e47cSPaolo Bonzini if (lvt & APIC_LVT_MASKED)
1597702e47cSPaolo Bonzini return;
1607702e47cSPaolo Bonzini
1617702e47cSPaolo Bonzini switch ((lvt >> 8) & 7) {
1627702e47cSPaolo Bonzini case APIC_DM_SMI:
1637702e47cSPaolo Bonzini cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI);
1647702e47cSPaolo Bonzini break;
1657702e47cSPaolo Bonzini
1667702e47cSPaolo Bonzini case APIC_DM_NMI:
1677702e47cSPaolo Bonzini cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI);
1687702e47cSPaolo Bonzini break;
1697702e47cSPaolo Bonzini
1707702e47cSPaolo Bonzini case APIC_DM_EXTINT:
1717702e47cSPaolo Bonzini cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD);
1727702e47cSPaolo Bonzini break;
1737702e47cSPaolo Bonzini
1747702e47cSPaolo Bonzini case APIC_DM_FIXED:
1757702e47cSPaolo Bonzini trigger_mode = APIC_TRIGGER_EDGE;
1767702e47cSPaolo Bonzini if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) &&
1777702e47cSPaolo Bonzini (lvt & APIC_LVT_LEVEL_TRIGGER))
1787702e47cSPaolo Bonzini trigger_mode = APIC_TRIGGER_LEVEL;
1797702e47cSPaolo Bonzini apic_set_irq(s, lvt & 0xff, trigger_mode);
1807702e47cSPaolo Bonzini }
1817702e47cSPaolo Bonzini }
1827702e47cSPaolo Bonzini
apic_deliver_pic_intr(DeviceState * dev,int level)183d3b0c9e9Sxiaoqiang zhao void apic_deliver_pic_intr(DeviceState *dev, int level)
1847702e47cSPaolo Bonzini {
185927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
1867702e47cSPaolo Bonzini
1877702e47cSPaolo Bonzini if (level) {
1887702e47cSPaolo Bonzini apic_local_deliver(s, APIC_LVT_LINT0);
1897702e47cSPaolo Bonzini } else {
1907702e47cSPaolo Bonzini uint32_t lvt = s->lvt[APIC_LVT_LINT0];
1917702e47cSPaolo Bonzini
1927702e47cSPaolo Bonzini switch ((lvt >> 8) & 7) {
1937702e47cSPaolo Bonzini case APIC_DM_FIXED:
1947702e47cSPaolo Bonzini if (!(lvt & APIC_LVT_LEVEL_TRIGGER))
1957702e47cSPaolo Bonzini break;
196edf9735eSMichael S. Tsirkin apic_reset_bit(s->irr, lvt & 0xff);
1977702e47cSPaolo Bonzini /* fall through */
1987702e47cSPaolo Bonzini case APIC_DM_EXTINT:
1998092cb71SPaolo Bonzini apic_update_irq(s);
2007702e47cSPaolo Bonzini break;
2017702e47cSPaolo Bonzini }
2027702e47cSPaolo Bonzini }
2037702e47cSPaolo Bonzini }
2047702e47cSPaolo Bonzini
apic_external_nmi(APICCommonState * s)2057702e47cSPaolo Bonzini static void apic_external_nmi(APICCommonState *s)
2067702e47cSPaolo Bonzini {
2077702e47cSPaolo Bonzini apic_local_deliver(s, APIC_LVT_LINT1);
2087702e47cSPaolo Bonzini }
2097702e47cSPaolo Bonzini
2107702e47cSPaolo Bonzini #define foreach_apic(apic, deliver_bitmask, code) \
2117702e47cSPaolo Bonzini {\
2126d55574aSPeter Maydell int __i, __j;\
213b5ee0468SBui Quang Minh for (__i = 0; __i < max_apic_words; __i++) {\
2146d55574aSPeter Maydell uint32_t __mask = deliver_bitmask[__i];\
2157702e47cSPaolo Bonzini if (__mask) {\
2167702e47cSPaolo Bonzini for (__j = 0; __j < 32; __j++) {\
2176d55574aSPeter Maydell if (__mask & (1U << __j)) {\
2187702e47cSPaolo Bonzini apic = local_apics[__i * 32 + __j];\
2197702e47cSPaolo Bonzini if (apic) {\
2207702e47cSPaolo Bonzini code;\
2217702e47cSPaolo Bonzini }\
2227702e47cSPaolo Bonzini }\
2237702e47cSPaolo Bonzini }\
2247702e47cSPaolo Bonzini }\
2257702e47cSPaolo Bonzini }\
2267702e47cSPaolo Bonzini }
2277702e47cSPaolo Bonzini
apic_bus_deliver(const uint32_t * deliver_bitmask,uint8_t delivery_mode,uint8_t vector_num,uint8_t trigger_mode)2287702e47cSPaolo Bonzini static void apic_bus_deliver(const uint32_t *deliver_bitmask,
2297702e47cSPaolo Bonzini uint8_t delivery_mode, uint8_t vector_num,
2307702e47cSPaolo Bonzini uint8_t trigger_mode)
2317702e47cSPaolo Bonzini {
2327702e47cSPaolo Bonzini APICCommonState *apic_iter;
2337702e47cSPaolo Bonzini
2347702e47cSPaolo Bonzini switch (delivery_mode) {
2357702e47cSPaolo Bonzini case APIC_DM_LOWPRI:
2367702e47cSPaolo Bonzini /* XXX: search for focus processor, arbitration */
2377702e47cSPaolo Bonzini {
2387702e47cSPaolo Bonzini int i, d;
2397702e47cSPaolo Bonzini d = -1;
240b5ee0468SBui Quang Minh for (i = 0; i < max_apic_words; i++) {
2417702e47cSPaolo Bonzini if (deliver_bitmask[i]) {
242edf9735eSMichael S. Tsirkin d = i * 32 + apic_ffs_bit(deliver_bitmask[i]);
2437702e47cSPaolo Bonzini break;
2447702e47cSPaolo Bonzini }
2457702e47cSPaolo Bonzini }
2467702e47cSPaolo Bonzini if (d >= 0) {
2477702e47cSPaolo Bonzini apic_iter = local_apics[d];
2487702e47cSPaolo Bonzini if (apic_iter) {
2497702e47cSPaolo Bonzini apic_set_irq(apic_iter, vector_num, trigger_mode);
2507702e47cSPaolo Bonzini }
2517702e47cSPaolo Bonzini }
2527702e47cSPaolo Bonzini }
2537702e47cSPaolo Bonzini return;
2547702e47cSPaolo Bonzini
2557702e47cSPaolo Bonzini case APIC_DM_FIXED:
2567702e47cSPaolo Bonzini break;
2577702e47cSPaolo Bonzini
2587702e47cSPaolo Bonzini case APIC_DM_SMI:
2597702e47cSPaolo Bonzini foreach_apic(apic_iter, deliver_bitmask,
2607702e47cSPaolo Bonzini cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI)
2617702e47cSPaolo Bonzini );
2627702e47cSPaolo Bonzini return;
2637702e47cSPaolo Bonzini
2647702e47cSPaolo Bonzini case APIC_DM_NMI:
2657702e47cSPaolo Bonzini foreach_apic(apic_iter, deliver_bitmask,
2667702e47cSPaolo Bonzini cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI)
2677702e47cSPaolo Bonzini );
2687702e47cSPaolo Bonzini return;
2697702e47cSPaolo Bonzini
2707702e47cSPaolo Bonzini case APIC_DM_INIT:
2717702e47cSPaolo Bonzini /* normal INIT IPI sent to processors */
2727702e47cSPaolo Bonzini foreach_apic(apic_iter, deliver_bitmask,
2737702e47cSPaolo Bonzini cpu_interrupt(CPU(apic_iter->cpu),
2747702e47cSPaolo Bonzini CPU_INTERRUPT_INIT)
2757702e47cSPaolo Bonzini );
2767702e47cSPaolo Bonzini return;
2777702e47cSPaolo Bonzini
2787702e47cSPaolo Bonzini case APIC_DM_EXTINT:
2797702e47cSPaolo Bonzini /* handled in I/O APIC code */
2807702e47cSPaolo Bonzini break;
2817702e47cSPaolo Bonzini
2827702e47cSPaolo Bonzini default:
2837702e47cSPaolo Bonzini return;
2847702e47cSPaolo Bonzini }
2857702e47cSPaolo Bonzini
2867702e47cSPaolo Bonzini foreach_apic(apic_iter, deliver_bitmask,
2877702e47cSPaolo Bonzini apic_set_irq(apic_iter, vector_num, trigger_mode) );
2887702e47cSPaolo Bonzini }
2897702e47cSPaolo Bonzini
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)
2937702e47cSPaolo Bonzini {
294*0fad9095SPaolo Bonzini g_autofree uint32_t *deliver_bitmask = g_new(uint32_t, max_apic_words);
2957702e47cSPaolo Bonzini
2967702e47cSPaolo Bonzini trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num,
2977702e47cSPaolo Bonzini trigger_mode);
2987702e47cSPaolo Bonzini
2997702e47cSPaolo Bonzini apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
3007702e47cSPaolo Bonzini apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
3017702e47cSPaolo Bonzini }
3027702e47cSPaolo Bonzini
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)
3117702e47cSPaolo Bonzini {
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
3537702e47cSPaolo Bonzini s->apicbase = (val & 0xfffff000) |
3547702e47cSPaolo Bonzini (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
3557702e47cSPaolo Bonzini /* if disabled, cannot be enabled again */
3567702e47cSPaolo Bonzini if (!(val & MSR_IA32_APICBASE_ENABLE)) {
3577702e47cSPaolo Bonzini s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
3587702e47cSPaolo Bonzini cpu_clear_apic_feature(&s->cpu->env);
3597702e47cSPaolo Bonzini s->spurious_vec &= ~APIC_SV_ENABLE;
3607702e47cSPaolo Bonzini }
361774204cfSBui Quang Minh
362774204cfSBui Quang Minh /* Transition from disabled mode to xAPIC */
363774204cfSBui Quang Minh if (!(s->apicbase & MSR_IA32_APICBASE_ENABLE) &&
364774204cfSBui Quang Minh (val & MSR_IA32_APICBASE_ENABLE)) {
365774204cfSBui Quang Minh s->apicbase |= MSR_IA32_APICBASE_ENABLE;
366774204cfSBui Quang Minh cpu_set_apic_feature(&s->cpu->env);
367774204cfSBui Quang Minh }
368774204cfSBui Quang Minh
369774204cfSBui Quang Minh /* Transition from xAPIC to x2APIC */
370774204cfSBui Quang Minh if (cpu_has_x2apic_feature(&s->cpu->env) &&
371774204cfSBui Quang Minh !(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
372774204cfSBui Quang Minh (val & MSR_IA32_APICBASE_EXTD)) {
373774204cfSBui Quang Minh s->apicbase |= MSR_IA32_APICBASE_EXTD;
374774204cfSBui Quang Minh
375774204cfSBui Quang Minh s->log_dest = ((s->initial_apic_id & 0xffff0) << 16) |
376774204cfSBui Quang Minh (1 << (s->initial_apic_id & 0xf));
377774204cfSBui Quang Minh }
378774204cfSBui Quang Minh
379774204cfSBui Quang Minh return 0;
3807702e47cSPaolo Bonzini }
3817702e47cSPaolo Bonzini
apic_set_tpr(APICCommonState * s,uint8_t val)3827702e47cSPaolo Bonzini static void apic_set_tpr(APICCommonState *s, uint8_t val)
3837702e47cSPaolo Bonzini {
3847702e47cSPaolo Bonzini /* Updates from cr8 are ignored while the VAPIC is active */
3857702e47cSPaolo Bonzini if (!s->vapic_paddr) {
3867702e47cSPaolo Bonzini s->tpr = val << 4;
3877702e47cSPaolo Bonzini apic_update_irq(s);
3887702e47cSPaolo Bonzini }
3897702e47cSPaolo Bonzini }
3907702e47cSPaolo Bonzini
apic_get_highest_priority_irr(DeviceState * dev)3912cb9f06eSSergio Andres Gomez Del Real int apic_get_highest_priority_irr(DeviceState *dev)
3922cb9f06eSSergio Andres Gomez Del Real {
3932cb9f06eSSergio Andres Gomez Del Real APICCommonState *s;
3942cb9f06eSSergio Andres Gomez Del Real
3952cb9f06eSSergio Andres Gomez Del Real if (!dev) {
3962cb9f06eSSergio Andres Gomez Del Real /* no interrupts */
3972cb9f06eSSergio Andres Gomez Del Real return -1;
3982cb9f06eSSergio Andres Gomez Del Real }
3992cb9f06eSSergio Andres Gomez Del Real s = APIC_COMMON(dev);
4002cb9f06eSSergio Andres Gomez Del Real return get_highest_priority_int(s->irr);
4012cb9f06eSSergio Andres Gomez Del Real }
4022cb9f06eSSergio Andres Gomez Del Real
apic_get_tpr(APICCommonState * s)4037702e47cSPaolo Bonzini static uint8_t apic_get_tpr(APICCommonState *s)
4047702e47cSPaolo Bonzini {
4057702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC);
4067702e47cSPaolo Bonzini return s->tpr >> 4;
4077702e47cSPaolo Bonzini }
4087702e47cSPaolo Bonzini
apic_get_ppr(APICCommonState * s)40982a5e042SPavel Butsykin int apic_get_ppr(APICCommonState *s)
4107702e47cSPaolo Bonzini {
4117702e47cSPaolo Bonzini int tpr, isrv, ppr;
4127702e47cSPaolo Bonzini
4137702e47cSPaolo Bonzini tpr = (s->tpr >> 4);
4147702e47cSPaolo Bonzini isrv = get_highest_priority_int(s->isr);
4157702e47cSPaolo Bonzini if (isrv < 0)
4167702e47cSPaolo Bonzini isrv = 0;
4177702e47cSPaolo Bonzini isrv >>= 4;
4187702e47cSPaolo Bonzini if (tpr >= isrv)
4197702e47cSPaolo Bonzini ppr = s->tpr;
4207702e47cSPaolo Bonzini else
4217702e47cSPaolo Bonzini ppr = isrv << 4;
4227702e47cSPaolo Bonzini return ppr;
4237702e47cSPaolo Bonzini }
4247702e47cSPaolo Bonzini
apic_get_arb_pri(APICCommonState * s)4257702e47cSPaolo Bonzini static int apic_get_arb_pri(APICCommonState *s)
4267702e47cSPaolo Bonzini {
4277702e47cSPaolo Bonzini /* XXX: arbitration */
4287702e47cSPaolo Bonzini return 0;
4297702e47cSPaolo Bonzini }
4307702e47cSPaolo Bonzini
4317702e47cSPaolo Bonzini
4327702e47cSPaolo Bonzini /*
4337702e47cSPaolo Bonzini * <0 - low prio interrupt,
4347702e47cSPaolo Bonzini * 0 - no interrupt,
4357702e47cSPaolo Bonzini * >0 - interrupt number
4367702e47cSPaolo Bonzini */
apic_irq_pending(APICCommonState * s)4377702e47cSPaolo Bonzini static int apic_irq_pending(APICCommonState *s)
4387702e47cSPaolo Bonzini {
4397702e47cSPaolo Bonzini int irrv, ppr;
44060e68042SPaolo Bonzini
44160e68042SPaolo Bonzini if (!(s->spurious_vec & APIC_SV_ENABLE)) {
44260e68042SPaolo Bonzini return 0;
44360e68042SPaolo Bonzini }
44460e68042SPaolo Bonzini
4457702e47cSPaolo Bonzini irrv = get_highest_priority_int(s->irr);
4467702e47cSPaolo Bonzini if (irrv < 0) {
4477702e47cSPaolo Bonzini return 0;
4487702e47cSPaolo Bonzini }
4497702e47cSPaolo Bonzini ppr = apic_get_ppr(s);
4507702e47cSPaolo Bonzini if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
4517702e47cSPaolo Bonzini return -1;
4527702e47cSPaolo Bonzini }
4537702e47cSPaolo Bonzini
4547702e47cSPaolo Bonzini return irrv;
4557702e47cSPaolo Bonzini }
4567702e47cSPaolo Bonzini
4577702e47cSPaolo Bonzini /* signal the CPU if an irq is pending */
apic_update_irq(APICCommonState * s)4587702e47cSPaolo Bonzini static void apic_update_irq(APICCommonState *s)
4597702e47cSPaolo Bonzini {
4607702e47cSPaolo Bonzini CPUState *cpu;
461be9f8a08SZhu Guihua DeviceState *dev = (DeviceState *)s;
4627702e47cSPaolo Bonzini
4637702e47cSPaolo Bonzini cpu = CPU(s->cpu);
4647702e47cSPaolo Bonzini if (!qemu_cpu_is_self(cpu)) {
4657702e47cSPaolo Bonzini cpu_interrupt(cpu, CPU_INTERRUPT_POLL);
4667702e47cSPaolo Bonzini } else if (apic_irq_pending(s) > 0) {
4677702e47cSPaolo Bonzini cpu_interrupt(cpu, CPU_INTERRUPT_HARD);
468be9f8a08SZhu Guihua } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
4698092cb71SPaolo Bonzini cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD);
4707702e47cSPaolo Bonzini }
4717702e47cSPaolo Bonzini }
4727702e47cSPaolo Bonzini
apic_poll_irq(DeviceState * dev)473d3b0c9e9Sxiaoqiang zhao void apic_poll_irq(DeviceState *dev)
4747702e47cSPaolo Bonzini {
475927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
4767702e47cSPaolo Bonzini
4777702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC);
4787702e47cSPaolo Bonzini apic_update_irq(s);
4797702e47cSPaolo Bonzini }
4807702e47cSPaolo Bonzini
apic_set_irq(APICCommonState * s,int vector_num,int trigger_mode)4817702e47cSPaolo Bonzini static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
4827702e47cSPaolo Bonzini {
4832b85e0cdSThomas Huth kvm_report_irq_delivered(!apic_get_bit(s->irr, vector_num));
4847702e47cSPaolo Bonzini
485edf9735eSMichael S. Tsirkin apic_set_bit(s->irr, vector_num);
4867702e47cSPaolo Bonzini if (trigger_mode)
487edf9735eSMichael S. Tsirkin apic_set_bit(s->tmr, vector_num);
4887702e47cSPaolo Bonzini else
489edf9735eSMichael S. Tsirkin apic_reset_bit(s->tmr, vector_num);
4907702e47cSPaolo Bonzini if (s->vapic_paddr) {
4917702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC);
4927702e47cSPaolo Bonzini /*
4937702e47cSPaolo Bonzini * The vcpu thread needs to see the new IRR before we pull its current
4947702e47cSPaolo Bonzini * TPR value. That way, if we miss a lowering of the TRP, the guest
4957702e47cSPaolo Bonzini * has the chance to notice the new IRR and poll for IRQs on its own.
4967702e47cSPaolo Bonzini */
4977702e47cSPaolo Bonzini smp_wmb();
4987702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC);
4997702e47cSPaolo Bonzini }
5007702e47cSPaolo Bonzini apic_update_irq(s);
5017702e47cSPaolo Bonzini }
5027702e47cSPaolo Bonzini
apic_eoi(APICCommonState * s)5037702e47cSPaolo Bonzini static void apic_eoi(APICCommonState *s)
5047702e47cSPaolo Bonzini {
5057702e47cSPaolo Bonzini int isrv;
5067702e47cSPaolo Bonzini isrv = get_highest_priority_int(s->isr);
5077702e47cSPaolo Bonzini if (isrv < 0)
5087702e47cSPaolo Bonzini return;
509edf9735eSMichael S. Tsirkin apic_reset_bit(s->isr, isrv);
510edf9735eSMichael S. Tsirkin if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) {
5117702e47cSPaolo Bonzini ioapic_eoi_broadcast(isrv);
5127702e47cSPaolo Bonzini }
5137702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC);
5147702e47cSPaolo Bonzini apic_update_irq(s);
5157702e47cSPaolo Bonzini }
5167702e47cSPaolo Bonzini
apic_match_dest(APICCommonState * apic,uint32_t dest)517b5ee0468SBui Quang Minh static bool apic_match_dest(APICCommonState *apic, uint32_t dest)
5187702e47cSPaolo Bonzini {
519b5ee0468SBui Quang Minh if (is_x2apic_mode(&apic->parent_obj)) {
520b5ee0468SBui Quang Minh return apic->initial_apic_id == dest;
521b5ee0468SBui Quang Minh } else {
522b5ee0468SBui Quang Minh return apic->id == (uint8_t)dest;
523b5ee0468SBui Quang Minh }
5247702e47cSPaolo Bonzini }
5257702e47cSPaolo Bonzini
apic_find_dest(uint32_t * deliver_bitmask,uint32_t dest)526b5ee0468SBui Quang Minh static void apic_find_dest(uint32_t *deliver_bitmask, uint32_t dest)
527b5ee0468SBui Quang Minh {
528b5ee0468SBui Quang Minh APICCommonState *apic = NULL;
529b5ee0468SBui Quang Minh int i;
530b5ee0468SBui Quang Minh
531b5ee0468SBui Quang Minh for (i = 0; i < max_apics; i++) {
532b5ee0468SBui Quang Minh apic = local_apics[i];
533b5ee0468SBui Quang Minh if (apic && apic_match_dest(apic, dest)) {
534b5ee0468SBui Quang Minh apic_set_bit(deliver_bitmask, i);
535b5ee0468SBui Quang Minh }
536b5ee0468SBui Quang Minh }
537b5ee0468SBui Quang Minh }
538b5ee0468SBui Quang Minh
539b5ee0468SBui Quang Minh /*
540b5ee0468SBui Quang Minh * Deliver interrupt to x2APIC CPUs if it is x2APIC broadcast.
541b5ee0468SBui Quang Minh * Otherwise, deliver interrupt to xAPIC CPUs if it is xAPIC
542b5ee0468SBui Quang Minh * broadcast.
543b5ee0468SBui Quang Minh */
apic_get_broadcast_bitmask(uint32_t * deliver_bitmask,bool is_x2apic_broadcast)544b5ee0468SBui Quang Minh static void apic_get_broadcast_bitmask(uint32_t *deliver_bitmask,
545b5ee0468SBui Quang Minh bool is_x2apic_broadcast)
546b5ee0468SBui Quang Minh {
547b5ee0468SBui Quang Minh int i;
548b5ee0468SBui Quang Minh APICCommonState *apic_iter;
549b5ee0468SBui Quang Minh
550b5ee0468SBui Quang Minh for (i = 0; i < max_apics; i++) {
551b5ee0468SBui Quang Minh apic_iter = local_apics[i];
552b5ee0468SBui Quang Minh if (apic_iter) {
553b5ee0468SBui Quang Minh bool apic_in_x2apic = is_x2apic_mode(&apic_iter->parent_obj);
554b5ee0468SBui Quang Minh
555b5ee0468SBui Quang Minh if (is_x2apic_broadcast && apic_in_x2apic) {
556b5ee0468SBui Quang Minh apic_set_bit(deliver_bitmask, i);
557b5ee0468SBui Quang Minh } else if (!is_x2apic_broadcast && !apic_in_x2apic) {
558b5ee0468SBui Quang Minh apic_set_bit(deliver_bitmask, i);
559b5ee0468SBui Quang Minh }
560b5ee0468SBui Quang Minh }
561b5ee0468SBui Quang Minh }
5627702e47cSPaolo Bonzini }
5637702e47cSPaolo Bonzini
apic_get_delivery_bitmask(uint32_t * deliver_bitmask,uint32_t dest,uint8_t dest_mode)5647702e47cSPaolo Bonzini static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
565b5ee0468SBui Quang Minh uint32_t dest, uint8_t dest_mode)
5667702e47cSPaolo Bonzini {
567b5ee0468SBui Quang Minh APICCommonState *apic;
5687702e47cSPaolo Bonzini int i;
5697702e47cSPaolo Bonzini
570b5ee0468SBui Quang Minh memset(deliver_bitmask, 0x00, max_apic_words * sizeof(uint32_t));
571b5ee0468SBui Quang Minh
572b5ee0468SBui Quang Minh /*
573b5ee0468SBui Quang Minh * x2APIC broadcast is delivered to all x2APIC CPUs regardless of
574b5ee0468SBui Quang Minh * destination mode. In case the destination mode is physical, it is
575b5ee0468SBui Quang Minh * broadcasted to all xAPIC CPUs too. Otherwise, if the destination
576b5ee0468SBui Quang Minh * mode is logical, we need to continue checking if xAPIC CPUs accepts
577b5ee0468SBui Quang Minh * the interrupt.
578b5ee0468SBui Quang Minh */
579b5ee0468SBui Quang Minh if (dest == 0xffffffff) {
580b5ee0468SBui Quang Minh if (dest_mode == APIC_DESTMODE_PHYSICAL) {
581b5ee0468SBui Quang Minh memset(deliver_bitmask, 0xff, max_apic_words * sizeof(uint32_t));
582b5ee0468SBui Quang Minh return;
583b5ee0468SBui Quang Minh } else {
584b5ee0468SBui Quang Minh apic_get_broadcast_bitmask(deliver_bitmask, true);
585b5ee0468SBui Quang Minh }
586b5ee0468SBui Quang Minh }
587b5ee0468SBui Quang Minh
588b5ee0468SBui Quang Minh if (dest_mode == APIC_DESTMODE_PHYSICAL) {
589b5ee0468SBui Quang Minh apic_find_dest(deliver_bitmask, dest);
590b5ee0468SBui Quang Minh /* Any APIC in xAPIC mode will interpret 0xFF as broadcast */
5917702e47cSPaolo Bonzini if (dest == 0xff) {
592b5ee0468SBui Quang Minh apic_get_broadcast_bitmask(deliver_bitmask, false);
5937702e47cSPaolo Bonzini }
5947702e47cSPaolo Bonzini } else {
595b5ee0468SBui Quang Minh /* XXX: logical mode */
596b5ee0468SBui Quang Minh for (i = 0; i < max_apics; i++) {
597b5ee0468SBui Quang Minh apic = local_apics[i];
598b5ee0468SBui Quang Minh if (apic) {
599b5ee0468SBui Quang Minh /* x2APIC logical mode */
600b5ee0468SBui Quang Minh if (apic->apicbase & MSR_IA32_APICBASE_EXTD) {
601b5ee0468SBui Quang Minh if ((dest >> 16) == (apic->extended_log_dest >> 16) &&
602b5ee0468SBui Quang Minh (dest & apic->extended_log_dest & 0xffff)) {
603edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, i);
604b5ee0468SBui Quang Minh }
605b5ee0468SBui Quang Minh continue;
606b5ee0468SBui Quang Minh }
607b5ee0468SBui Quang Minh
608b5ee0468SBui Quang Minh /* xAPIC logical mode */
609b5ee0468SBui Quang Minh dest = (uint8_t)dest;
610b5ee0468SBui Quang Minh if (apic->dest_mode == APIC_DESTMODE_LOGICAL_FLAT) {
611b5ee0468SBui Quang Minh if (dest & apic->log_dest) {
612b5ee0468SBui Quang Minh apic_set_bit(deliver_bitmask, i);
613b5ee0468SBui Quang Minh }
614b5ee0468SBui Quang Minh } else if (apic->dest_mode == APIC_DESTMODE_LOGICAL_CLUSTER) {
615b5ee0468SBui Quang Minh /*
616b5ee0468SBui Quang Minh * In cluster model of xAPIC logical mode IPI, 4 higher
617b5ee0468SBui Quang Minh * bits are used as cluster address, 4 lower bits are
618b5ee0468SBui Quang Minh * the bitmask for local APICs in the cluster. The IPI
619b5ee0468SBui Quang Minh * is delivered to an APIC if the cluster address
620b5ee0468SBui Quang Minh * matches and the APIC's address bit in the cluster is
621b5ee0468SBui Quang Minh * set in bitmask of destination ID in IPI.
622b5ee0468SBui Quang Minh *
623b5ee0468SBui Quang Minh * The cluster address ranges from 0 - 14, the cluster
624b5ee0468SBui Quang Minh * address 15 (0xf) is the broadcast address to all
625b5ee0468SBui Quang Minh * clusters.
626b5ee0468SBui Quang Minh */
627b5ee0468SBui Quang Minh if ((dest & 0xf0) == 0xf0 ||
628b5ee0468SBui Quang Minh (dest & 0xf0) == (apic->log_dest & 0xf0)) {
629b5ee0468SBui Quang Minh if (dest & apic->log_dest & 0x0f) {
630edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, i);
6317702e47cSPaolo Bonzini }
6327702e47cSPaolo Bonzini }
633b5ee0468SBui Quang Minh }
6347702e47cSPaolo Bonzini }
6357702e47cSPaolo Bonzini }
6367702e47cSPaolo Bonzini }
6377702e47cSPaolo Bonzini }
6387702e47cSPaolo Bonzini
apic_startup(APICCommonState * s,int vector_num)6397702e47cSPaolo Bonzini static void apic_startup(APICCommonState *s, int vector_num)
6407702e47cSPaolo Bonzini {
6417702e47cSPaolo Bonzini s->sipi_vector = vector_num;
6427702e47cSPaolo Bonzini cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
6437702e47cSPaolo Bonzini }
6447702e47cSPaolo Bonzini
apic_sipi(DeviceState * dev)645d3b0c9e9Sxiaoqiang zhao void apic_sipi(DeviceState *dev)
6467702e47cSPaolo Bonzini {
647927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
6487702e47cSPaolo Bonzini
6497702e47cSPaolo Bonzini cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
6507702e47cSPaolo Bonzini
6517702e47cSPaolo Bonzini if (!s->wait_for_sipi)
6527702e47cSPaolo Bonzini return;
6537702e47cSPaolo Bonzini cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
6547702e47cSPaolo Bonzini s->wait_for_sipi = 0;
6557702e47cSPaolo Bonzini }
6567702e47cSPaolo Bonzini
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)657b5ee0468SBui Quang Minh static void apic_deliver(DeviceState *dev, uint32_t dest, uint8_t dest_mode,
6587702e47cSPaolo Bonzini uint8_t delivery_mode, uint8_t vector_num,
659b5ee0468SBui Quang Minh uint8_t trigger_mode, uint8_t dest_shorthand)
6607702e47cSPaolo Bonzini {
661927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
6627702e47cSPaolo Bonzini APICCommonState *apic_iter;
663b5ee0468SBui Quang Minh uint32_t deliver_bitmask_size = max_apic_words * sizeof(uint32_t);
664*0fad9095SPaolo Bonzini g_autofree uint32_t *deliver_bitmask = g_new(uint32_t, max_apic_words);
665b5ee0468SBui Quang Minh uint32_t current_apic_id;
666b5ee0468SBui Quang Minh
667b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
668b5ee0468SBui Quang Minh current_apic_id = s->initial_apic_id;
669b5ee0468SBui Quang Minh } else {
670b5ee0468SBui Quang Minh current_apic_id = s->id;
671b5ee0468SBui Quang Minh }
6727702e47cSPaolo Bonzini
6737702e47cSPaolo Bonzini switch (dest_shorthand) {
6747702e47cSPaolo Bonzini case 0:
6757702e47cSPaolo Bonzini apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
6767702e47cSPaolo Bonzini break;
6777702e47cSPaolo Bonzini case 1:
678b5ee0468SBui Quang Minh memset(deliver_bitmask, 0x00, deliver_bitmask_size);
679b5ee0468SBui Quang Minh apic_set_bit(deliver_bitmask, current_apic_id);
6807702e47cSPaolo Bonzini break;
6817702e47cSPaolo Bonzini case 2:
682b5ee0468SBui Quang Minh memset(deliver_bitmask, 0xff, deliver_bitmask_size);
6837702e47cSPaolo Bonzini break;
6847702e47cSPaolo Bonzini case 3:
685b5ee0468SBui Quang Minh memset(deliver_bitmask, 0xff, deliver_bitmask_size);
686b5ee0468SBui Quang Minh apic_reset_bit(deliver_bitmask, current_apic_id);
6877702e47cSPaolo Bonzini break;
6887702e47cSPaolo Bonzini }
6897702e47cSPaolo Bonzini
6907702e47cSPaolo Bonzini switch (delivery_mode) {
6917702e47cSPaolo Bonzini case APIC_DM_INIT:
6927702e47cSPaolo Bonzini {
6937702e47cSPaolo Bonzini int trig_mode = (s->icr[0] >> 15) & 1;
6947702e47cSPaolo Bonzini int level = (s->icr[0] >> 14) & 1;
6957702e47cSPaolo Bonzini if (level == 0 && trig_mode == 1) {
6967702e47cSPaolo Bonzini foreach_apic(apic_iter, deliver_bitmask,
6977702e47cSPaolo Bonzini apic_iter->arb_id = apic_iter->id );
6987702e47cSPaolo Bonzini return;
6997702e47cSPaolo Bonzini }
7007702e47cSPaolo Bonzini }
7017702e47cSPaolo Bonzini break;
7027702e47cSPaolo Bonzini
7037702e47cSPaolo Bonzini case APIC_DM_SIPI:
7047702e47cSPaolo Bonzini foreach_apic(apic_iter, deliver_bitmask,
7057702e47cSPaolo Bonzini apic_startup(apic_iter, vector_num) );
7067702e47cSPaolo Bonzini return;
7077702e47cSPaolo Bonzini }
7087702e47cSPaolo Bonzini
7097702e47cSPaolo Bonzini apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
7107702e47cSPaolo Bonzini }
7117702e47cSPaolo Bonzini
apic_check_pic(APICCommonState * s)7127702e47cSPaolo Bonzini static bool apic_check_pic(APICCommonState *s)
7137702e47cSPaolo Bonzini {
714be9f8a08SZhu Guihua DeviceState *dev = (DeviceState *)s;
715be9f8a08SZhu Guihua
716be9f8a08SZhu Guihua if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) {
7177702e47cSPaolo Bonzini return false;
7187702e47cSPaolo Bonzini }
719be9f8a08SZhu Guihua apic_deliver_pic_intr(dev, 1);
7207702e47cSPaolo Bonzini return true;
7217702e47cSPaolo Bonzini }
7227702e47cSPaolo Bonzini
apic_get_interrupt(DeviceState * dev)723d3b0c9e9Sxiaoqiang zhao int apic_get_interrupt(DeviceState *dev)
7247702e47cSPaolo Bonzini {
725927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
7267702e47cSPaolo Bonzini int intno;
7277702e47cSPaolo Bonzini
7287702e47cSPaolo Bonzini /* if the APIC is installed or enabled, we let the 8259 handle the
7297702e47cSPaolo Bonzini IRQs */
7307702e47cSPaolo Bonzini if (!s)
7317702e47cSPaolo Bonzini return -1;
7327702e47cSPaolo Bonzini if (!(s->spurious_vec & APIC_SV_ENABLE))
7337702e47cSPaolo Bonzini return -1;
7347702e47cSPaolo Bonzini
7357702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC);
7367702e47cSPaolo Bonzini intno = apic_irq_pending(s);
7377702e47cSPaolo Bonzini
7385224c88dSPaolo Bonzini /* if there is an interrupt from the 8259, let the caller handle
7395224c88dSPaolo Bonzini * that first since ExtINT interrupts ignore the priority.
7405224c88dSPaolo Bonzini */
7415224c88dSPaolo Bonzini if (intno == 0 || apic_check_pic(s)) {
7427702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_TO_VAPIC);
7437702e47cSPaolo Bonzini return -1;
7447702e47cSPaolo Bonzini } else if (intno < 0) {
7457702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_TO_VAPIC);
7467702e47cSPaolo Bonzini return s->spurious_vec & 0xff;
7477702e47cSPaolo Bonzini }
748edf9735eSMichael S. Tsirkin apic_reset_bit(s->irr, intno);
749edf9735eSMichael S. Tsirkin apic_set_bit(s->isr, intno);
7507702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_TO_VAPIC);
7517702e47cSPaolo Bonzini
7527702e47cSPaolo Bonzini apic_update_irq(s);
7537702e47cSPaolo Bonzini
7547702e47cSPaolo Bonzini return intno;
7557702e47cSPaolo Bonzini }
7567702e47cSPaolo Bonzini
apic_accept_pic_intr(DeviceState * dev)757d3b0c9e9Sxiaoqiang zhao int apic_accept_pic_intr(DeviceState *dev)
7587702e47cSPaolo Bonzini {
759927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
7607702e47cSPaolo Bonzini uint32_t lvt0;
7617702e47cSPaolo Bonzini
7627702e47cSPaolo Bonzini if (!s)
7637702e47cSPaolo Bonzini return -1;
7647702e47cSPaolo Bonzini
7657702e47cSPaolo Bonzini lvt0 = s->lvt[APIC_LVT_LINT0];
7667702e47cSPaolo Bonzini
7677702e47cSPaolo Bonzini if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 ||
7687702e47cSPaolo Bonzini (lvt0 & APIC_LVT_MASKED) == 0)
76978cafff8SSergio Lopez return isa_pic != NULL;
7707702e47cSPaolo Bonzini
7717702e47cSPaolo Bonzini return 0;
7727702e47cSPaolo Bonzini }
7737702e47cSPaolo Bonzini
apic_timer_update(APICCommonState * s,int64_t current_time)7747702e47cSPaolo Bonzini static void apic_timer_update(APICCommonState *s, int64_t current_time)
7757702e47cSPaolo Bonzini {
7767702e47cSPaolo Bonzini if (apic_next_timer(s, current_time)) {
777bc72ad67SAlex Bligh timer_mod(s->timer, s->next_time);
7787702e47cSPaolo Bonzini } else {
779bc72ad67SAlex Bligh timer_del(s->timer);
7807702e47cSPaolo Bonzini }
7817702e47cSPaolo Bonzini }
7827702e47cSPaolo Bonzini
apic_timer(void * opaque)7837702e47cSPaolo Bonzini static void apic_timer(void *opaque)
7847702e47cSPaolo Bonzini {
7857702e47cSPaolo Bonzini APICCommonState *s = opaque;
7867702e47cSPaolo Bonzini
7877702e47cSPaolo Bonzini apic_local_deliver(s, APIC_LVT_TIMER);
7887702e47cSPaolo Bonzini apic_timer_update(s, s->next_time);
7897702e47cSPaolo Bonzini }
7907702e47cSPaolo Bonzini
apic_register_read(int index,uint64_t * value)791b2101358SBui Quang Minh static int apic_register_read(int index, uint64_t *value)
7927702e47cSPaolo Bonzini {
793d3b0c9e9Sxiaoqiang zhao DeviceState *dev;
7947702e47cSPaolo Bonzini APICCommonState *s;
7957702e47cSPaolo Bonzini uint32_t val;
796b2101358SBui Quang Minh int ret = 0;
79721f80e8fSPeter Maydell
798d3b0c9e9Sxiaoqiang zhao dev = cpu_get_current_apic();
799d3b0c9e9Sxiaoqiang zhao if (!dev) {
800b2101358SBui Quang Minh return -1;
8017702e47cSPaolo Bonzini }
802927d5a1dSWanpeng Li s = APIC(dev);
8037702e47cSPaolo Bonzini
8047702e47cSPaolo Bonzini switch(index) {
8057702e47cSPaolo Bonzini case 0x02: /* id */
806b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
807b5ee0468SBui Quang Minh val = s->initial_apic_id;
808b5ee0468SBui Quang Minh } else {
8097702e47cSPaolo Bonzini val = s->id << 24;
810b5ee0468SBui Quang Minh }
8117702e47cSPaolo Bonzini break;
8127702e47cSPaolo Bonzini case 0x03: /* version */
813aa93200bSGabriel L. Somlo val = s->version | ((APIC_LVT_NB - 1) << 16);
8147702e47cSPaolo Bonzini break;
8157702e47cSPaolo Bonzini case 0x08:
8167702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC);
8177702e47cSPaolo Bonzini if (apic_report_tpr_access) {
8187702e47cSPaolo Bonzini cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ);
8197702e47cSPaolo Bonzini }
8207702e47cSPaolo Bonzini val = s->tpr;
8217702e47cSPaolo Bonzini break;
8227702e47cSPaolo Bonzini case 0x09:
8237702e47cSPaolo Bonzini val = apic_get_arb_pri(s);
8247702e47cSPaolo Bonzini break;
8257702e47cSPaolo Bonzini case 0x0a:
8267702e47cSPaolo Bonzini /* ppr */
8277702e47cSPaolo Bonzini val = apic_get_ppr(s);
8287702e47cSPaolo Bonzini break;
8297702e47cSPaolo Bonzini case 0x0b:
8307702e47cSPaolo Bonzini val = 0;
8317702e47cSPaolo Bonzini break;
8327702e47cSPaolo Bonzini case 0x0d:
833b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
834b5ee0468SBui Quang Minh val = s->extended_log_dest;
835b5ee0468SBui Quang Minh } else {
8367702e47cSPaolo Bonzini val = s->log_dest << 24;
837b5ee0468SBui Quang Minh }
8387702e47cSPaolo Bonzini break;
8397702e47cSPaolo Bonzini case 0x0e:
840b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
841b5ee0468SBui Quang Minh val = 0;
842b5ee0468SBui Quang Minh ret = -1;
843b5ee0468SBui Quang Minh } else {
844d6c140a7SJan Kiszka val = (s->dest_mode << 28) | 0xfffffff;
845b5ee0468SBui Quang Minh }
8467702e47cSPaolo Bonzini break;
8477702e47cSPaolo Bonzini case 0x0f:
8487702e47cSPaolo Bonzini val = s->spurious_vec;
8497702e47cSPaolo Bonzini break;
8507702e47cSPaolo Bonzini case 0x10 ... 0x17:
8517702e47cSPaolo Bonzini val = s->isr[index & 7];
8527702e47cSPaolo Bonzini break;
8537702e47cSPaolo Bonzini case 0x18 ... 0x1f:
8547702e47cSPaolo Bonzini val = s->tmr[index & 7];
8557702e47cSPaolo Bonzini break;
8567702e47cSPaolo Bonzini case 0x20 ... 0x27:
8577702e47cSPaolo Bonzini val = s->irr[index & 7];
8587702e47cSPaolo Bonzini break;
8597702e47cSPaolo Bonzini case 0x28:
8607702e47cSPaolo Bonzini val = s->esr;
8617702e47cSPaolo Bonzini break;
8627702e47cSPaolo Bonzini case 0x30:
8637702e47cSPaolo Bonzini case 0x31:
8647702e47cSPaolo Bonzini val = s->icr[index & 1];
8657702e47cSPaolo Bonzini break;
8667702e47cSPaolo Bonzini case 0x32 ... 0x37:
8677702e47cSPaolo Bonzini val = s->lvt[index - 0x32];
8687702e47cSPaolo Bonzini break;
8697702e47cSPaolo Bonzini case 0x38:
8707702e47cSPaolo Bonzini val = s->initial_count;
8717702e47cSPaolo Bonzini break;
8727702e47cSPaolo Bonzini case 0x39:
8737702e47cSPaolo Bonzini val = apic_get_current_count(s);
8747702e47cSPaolo Bonzini break;
8757702e47cSPaolo Bonzini case 0x3e:
8767702e47cSPaolo Bonzini val = s->divide_conf;
8777702e47cSPaolo Bonzini break;
8787702e47cSPaolo Bonzini default:
879a22bf99cSPavel Butsykin s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
8807702e47cSPaolo Bonzini val = 0;
881b2101358SBui Quang Minh ret = -1;
8827702e47cSPaolo Bonzini break;
8837702e47cSPaolo Bonzini }
884b2101358SBui Quang Minh
885b2101358SBui Quang Minh trace_apic_register_read(index, val);
886b2101358SBui Quang Minh *value = val;
887b2101358SBui Quang Minh return ret;
888b2101358SBui Quang Minh }
889b2101358SBui Quang Minh
apic_mem_read(void * opaque,hwaddr addr,unsigned size)890b2101358SBui Quang Minh static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size)
891b2101358SBui Quang Minh {
892b2101358SBui Quang Minh uint64_t val;
893b2101358SBui Quang Minh int index;
894b2101358SBui Quang Minh
895b2101358SBui Quang Minh if (size < 4) {
896b2101358SBui Quang Minh return 0;
897b2101358SBui Quang Minh }
898b2101358SBui Quang Minh
899b2101358SBui Quang Minh index = (addr >> 4) & 0xff;
900b2101358SBui Quang Minh apic_register_read(index, &val);
901b2101358SBui Quang Minh
9027702e47cSPaolo Bonzini return val;
9037702e47cSPaolo Bonzini }
9047702e47cSPaolo Bonzini
apic_msr_read(int index,uint64_t * val)905b2101358SBui Quang Minh int apic_msr_read(int index, uint64_t *val)
906b2101358SBui Quang Minh {
907b2101358SBui Quang Minh DeviceState *dev;
908b2101358SBui Quang Minh
909b2101358SBui Quang Minh dev = cpu_get_current_apic();
910b2101358SBui Quang Minh if (!dev) {
911b2101358SBui Quang Minh return -1;
912b2101358SBui Quang Minh }
913b2101358SBui Quang Minh
914b2101358SBui Quang Minh if (!is_x2apic_mode(dev)) {
915b2101358SBui Quang Minh return -1;
916b2101358SBui Quang Minh }
917b2101358SBui Quang Minh
918b2101358SBui Quang Minh return apic_register_read(index, val);
919b2101358SBui Quang Minh }
920b2101358SBui Quang Minh
apic_send_msi(MSIMessage * msi)921267ee357SRadim Krčmář static void apic_send_msi(MSIMessage *msi)
9227702e47cSPaolo Bonzini {
923267ee357SRadim Krčmář uint64_t addr = msi->address;
924267ee357SRadim Krčmář uint32_t data = msi->data;
925b5ee0468SBui Quang Minh uint32_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
926b5ee0468SBui Quang Minh /*
927b5ee0468SBui Quang Minh * The higher 3 bytes of destination id is stored in higher word of
928b5ee0468SBui Quang Minh * msi address. See x86_iommu_irq_to_msi_message()
929b5ee0468SBui Quang Minh */
930b5ee0468SBui Quang Minh dest = dest | (addr >> 32);
9317702e47cSPaolo Bonzini uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
9327702e47cSPaolo Bonzini uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
9337702e47cSPaolo Bonzini uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
9347702e47cSPaolo Bonzini uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
9357702e47cSPaolo Bonzini /* XXX: Ignore redirection hint. */
9367702e47cSPaolo Bonzini apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode);
9377702e47cSPaolo Bonzini }
9387702e47cSPaolo Bonzini
apic_register_write(int index,uint64_t val)939b2101358SBui Quang Minh static int apic_register_write(int index, uint64_t val)
9407702e47cSPaolo Bonzini {
941d3b0c9e9Sxiaoqiang zhao DeviceState *dev;
9427702e47cSPaolo Bonzini APICCommonState *s;
9437702e47cSPaolo Bonzini
944d3b0c9e9Sxiaoqiang zhao dev = cpu_get_current_apic();
945d3b0c9e9Sxiaoqiang zhao if (!dev) {
946b2101358SBui Quang Minh return -1;
9477702e47cSPaolo Bonzini }
948927d5a1dSWanpeng Li s = APIC(dev);
9497702e47cSPaolo Bonzini
950b2101358SBui Quang Minh trace_apic_register_write(index, val);
9517702e47cSPaolo Bonzini
9527702e47cSPaolo Bonzini switch(index) {
9537702e47cSPaolo Bonzini case 0x02:
954b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
955b5ee0468SBui Quang Minh return -1;
956b5ee0468SBui Quang Minh }
957b5ee0468SBui Quang Minh
9587702e47cSPaolo Bonzini s->id = (val >> 24);
9597702e47cSPaolo Bonzini break;
9607702e47cSPaolo Bonzini case 0x03:
9617702e47cSPaolo Bonzini break;
9627702e47cSPaolo Bonzini case 0x08:
9637702e47cSPaolo Bonzini if (apic_report_tpr_access) {
9647702e47cSPaolo Bonzini cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE);
9657702e47cSPaolo Bonzini }
9667702e47cSPaolo Bonzini s->tpr = val;
9677702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_TO_VAPIC);
9687702e47cSPaolo Bonzini apic_update_irq(s);
9697702e47cSPaolo Bonzini break;
9707702e47cSPaolo Bonzini case 0x09:
9717702e47cSPaolo Bonzini case 0x0a:
9727702e47cSPaolo Bonzini break;
9737702e47cSPaolo Bonzini case 0x0b: /* EOI */
9747702e47cSPaolo Bonzini apic_eoi(s);
9757702e47cSPaolo Bonzini break;
9767702e47cSPaolo Bonzini case 0x0d:
977b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
978b5ee0468SBui Quang Minh return -1;
979b5ee0468SBui Quang Minh }
980b5ee0468SBui Quang Minh
9817702e47cSPaolo Bonzini s->log_dest = val >> 24;
9827702e47cSPaolo Bonzini break;
9837702e47cSPaolo Bonzini case 0x0e:
984b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
985b5ee0468SBui Quang Minh return -1;
986b5ee0468SBui Quang Minh }
987b5ee0468SBui Quang Minh
9887702e47cSPaolo Bonzini s->dest_mode = val >> 28;
9897702e47cSPaolo Bonzini break;
9907702e47cSPaolo Bonzini case 0x0f:
9917702e47cSPaolo Bonzini s->spurious_vec = val & 0x1ff;
9927702e47cSPaolo Bonzini apic_update_irq(s);
9937702e47cSPaolo Bonzini break;
9947702e47cSPaolo Bonzini case 0x10 ... 0x17:
9957702e47cSPaolo Bonzini case 0x18 ... 0x1f:
9967702e47cSPaolo Bonzini case 0x20 ... 0x27:
9977702e47cSPaolo Bonzini case 0x28:
9987702e47cSPaolo Bonzini break;
999b5ee0468SBui Quang Minh case 0x30: {
1000b5ee0468SBui Quang Minh uint32_t dest;
1001b5ee0468SBui Quang Minh
10027702e47cSPaolo Bonzini s->icr[0] = val;
1003b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
1004b5ee0468SBui Quang Minh s->icr[1] = val >> 32;
1005b5ee0468SBui Quang Minh dest = s->icr[1];
1006b5ee0468SBui Quang Minh } else {
1007b5ee0468SBui Quang Minh dest = (s->icr[1] >> 24) & 0xff;
1008b5ee0468SBui Quang Minh }
1009b5ee0468SBui Quang Minh
1010b5ee0468SBui Quang Minh apic_deliver(dev, dest, (s->icr[0] >> 11) & 1,
10117702e47cSPaolo Bonzini (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
1012b5ee0468SBui Quang Minh (s->icr[0] >> 15) & 1, (s->icr[0] >> 18) & 3);
10137702e47cSPaolo Bonzini break;
1014b5ee0468SBui Quang Minh }
10157702e47cSPaolo Bonzini case 0x31:
1016b5ee0468SBui Quang Minh if (is_x2apic_mode(dev)) {
1017b5ee0468SBui Quang Minh return -1;
1018b5ee0468SBui Quang Minh }
1019b5ee0468SBui Quang Minh
10207702e47cSPaolo Bonzini s->icr[1] = val;
10217702e47cSPaolo Bonzini break;
10227702e47cSPaolo Bonzini case 0x32 ... 0x37:
10237702e47cSPaolo Bonzini {
10247702e47cSPaolo Bonzini int n = index - 0x32;
10257702e47cSPaolo Bonzini s->lvt[n] = val;
10267702e47cSPaolo Bonzini if (n == APIC_LVT_TIMER) {
1027bc72ad67SAlex Bligh apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
10287702e47cSPaolo Bonzini } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) {
10297702e47cSPaolo Bonzini apic_update_irq(s);
10307702e47cSPaolo Bonzini }
10317702e47cSPaolo Bonzini }
10327702e47cSPaolo Bonzini break;
10337702e47cSPaolo Bonzini case 0x38:
10347702e47cSPaolo Bonzini s->initial_count = val;
1035bc72ad67SAlex Bligh s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
10367702e47cSPaolo Bonzini apic_timer_update(s, s->initial_count_load_time);
10377702e47cSPaolo Bonzini break;
10387702e47cSPaolo Bonzini case 0x39:
10397702e47cSPaolo Bonzini break;
10407702e47cSPaolo Bonzini case 0x3e:
10417702e47cSPaolo Bonzini {
10427702e47cSPaolo Bonzini int v;
10437702e47cSPaolo Bonzini s->divide_conf = val & 0xb;
10447702e47cSPaolo Bonzini v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
10457702e47cSPaolo Bonzini s->count_shift = (v + 1) & 7;
10467702e47cSPaolo Bonzini }
10477702e47cSPaolo Bonzini break;
1048b5ee0468SBui Quang Minh case 0x3f: {
1049b5ee0468SBui Quang Minh int vector = val & 0xff;
1050b5ee0468SBui Quang Minh
1051b5ee0468SBui Quang Minh if (!is_x2apic_mode(dev)) {
1052b5ee0468SBui Quang Minh return -1;
1053b5ee0468SBui Quang Minh }
1054b5ee0468SBui Quang Minh
1055b5ee0468SBui Quang Minh /*
1056b5ee0468SBui Quang Minh * Self IPI is identical to IPI with
1057b5ee0468SBui Quang Minh * - Destination shorthand: 1 (Self)
1058b5ee0468SBui Quang Minh * - Trigger mode: 0 (Edge)
1059b5ee0468SBui Quang Minh * - Delivery mode: 0 (Fixed)
1060b5ee0468SBui Quang Minh */
1061b5ee0468SBui Quang Minh apic_deliver(dev, 0, 0, APIC_DM_FIXED, vector, 0, 1);
1062b5ee0468SBui Quang Minh
1063b5ee0468SBui Quang Minh break;
1064b5ee0468SBui Quang Minh }
10657702e47cSPaolo Bonzini default:
1066a22bf99cSPavel Butsykin s->esr |= APIC_ESR_ILLEGAL_ADDRESS;
1067b2101358SBui Quang Minh return -1;
10687702e47cSPaolo Bonzini }
1069b2101358SBui Quang Minh
1070b2101358SBui Quang Minh return 0;
1071b2101358SBui Quang Minh }
1072b2101358SBui Quang Minh
apic_mem_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)1073b2101358SBui Quang Minh static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val,
1074b2101358SBui Quang Minh unsigned size)
1075b2101358SBui Quang Minh {
1076b2101358SBui Quang Minh int index = (addr >> 4) & 0xff;
1077b2101358SBui Quang Minh
1078b2101358SBui Quang Minh if (size < 4) {
1079b2101358SBui Quang Minh return;
1080b2101358SBui Quang Minh }
1081b2101358SBui Quang Minh
1082b2101358SBui Quang Minh if (addr > 0xfff || !index) {
1083b2101358SBui Quang Minh /*
1084b2101358SBui Quang Minh * MSI and MMIO APIC are at the same memory location,
1085b2101358SBui Quang Minh * but actually not on the global bus: MSI is on PCI bus
1086b2101358SBui Quang Minh * APIC is connected directly to the CPU.
1087b2101358SBui Quang Minh * Mapping them on the global bus happens to work because
1088b2101358SBui Quang Minh * MSI registers are reserved in APIC MMIO and vice versa.
1089b2101358SBui Quang Minh */
1090b2101358SBui Quang Minh MSIMessage msi = { .address = addr, .data = val };
1091b2101358SBui Quang Minh apic_send_msi(&msi);
1092b2101358SBui Quang Minh return;
1093b2101358SBui Quang Minh }
1094b2101358SBui Quang Minh
1095b2101358SBui Quang Minh apic_register_write(index, val);
1096b2101358SBui Quang Minh }
1097b2101358SBui Quang Minh
apic_msr_write(int index,uint64_t val)1098b2101358SBui Quang Minh int apic_msr_write(int index, uint64_t val)
1099b2101358SBui Quang Minh {
1100b2101358SBui Quang Minh DeviceState *dev;
1101b2101358SBui Quang Minh
1102b2101358SBui Quang Minh dev = cpu_get_current_apic();
1103b2101358SBui Quang Minh if (!dev) {
1104b2101358SBui Quang Minh return -1;
1105b2101358SBui Quang Minh }
1106b2101358SBui Quang Minh
1107b2101358SBui Quang Minh if (!is_x2apic_mode(dev)) {
1108b2101358SBui Quang Minh return -1;
1109b2101358SBui Quang Minh }
1110b2101358SBui Quang Minh
1111b2101358SBui Quang Minh return apic_register_write(index, val);
11127702e47cSPaolo Bonzini }
11137702e47cSPaolo Bonzini
apic_pre_save(APICCommonState * s)11147702e47cSPaolo Bonzini static void apic_pre_save(APICCommonState *s)
11157702e47cSPaolo Bonzini {
11167702e47cSPaolo Bonzini apic_sync_vapic(s, SYNC_FROM_VAPIC);
11177702e47cSPaolo Bonzini }
11187702e47cSPaolo Bonzini
apic_post_load(APICCommonState * s)11197702e47cSPaolo Bonzini static void apic_post_load(APICCommonState *s)
11207702e47cSPaolo Bonzini {
11217702e47cSPaolo Bonzini if (s->timer_expiry != -1) {
1122bc72ad67SAlex Bligh timer_mod(s->timer, s->timer_expiry);
11237702e47cSPaolo Bonzini } else {
1124bc72ad67SAlex Bligh timer_del(s->timer);
11257702e47cSPaolo Bonzini }
11267702e47cSPaolo Bonzini }
11277702e47cSPaolo Bonzini
11287702e47cSPaolo Bonzini static const MemoryRegionOps apic_io_ops = {
112921f80e8fSPeter Maydell .read = apic_mem_read,
113021f80e8fSPeter Maydell .write = apic_mem_write,
113121f80e8fSPeter Maydell .impl.min_access_size = 1,
113221f80e8fSPeter Maydell .impl.max_access_size = 4,
113321f80e8fSPeter Maydell .valid.min_access_size = 1,
113421f80e8fSPeter Maydell .valid.max_access_size = 4,
11357702e47cSPaolo Bonzini .endianness = DEVICE_NATIVE_ENDIAN,
11367702e47cSPaolo Bonzini };
11377702e47cSPaolo Bonzini
apic_realize(DeviceState * dev,Error ** errp)1138ff6986ceSxiaoqiang zhao static void apic_realize(DeviceState *dev, Error **errp)
11397702e47cSPaolo Bonzini {
1140927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
1141889211b1SIgor Mammedov
11422c933ac6SPaolo Bonzini if (kvm_enabled()) {
11432c933ac6SPaolo Bonzini warn_report("Userspace local APIC is deprecated for KVM.");
11442c933ac6SPaolo Bonzini warn_report("Do not use kernel-irqchip except for the -M isapc machine type.");
11452c933ac6SPaolo Bonzini }
11462c933ac6SPaolo Bonzini
11471437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi",
1148baaeda08SIgor Mammedov APIC_SPACE_SIZE);
11497702e47cSPaolo Bonzini
115050795ee0SAlexander Bulekov /*
115150795ee0SAlexander Bulekov * apic-msi's apic_mem_write can call into ioapic_eoi_broadcast, which can
115250795ee0SAlexander Bulekov * write back to apic-msi. As such mark the apic-msi region re-entrancy
115350795ee0SAlexander Bulekov * safe.
115450795ee0SAlexander Bulekov */
115550795ee0SAlexander Bulekov s->io_memory.disable_reentrancy_guard = true;
115650795ee0SAlexander Bulekov
1157bc72ad67SAlex Bligh s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s);
1158b5ee0468SBui Quang Minh
1159b5ee0468SBui Quang Minh /*
1160b5ee0468SBui Quang Minh * The --machine none does not call apic_set_max_apic_id before creating
1161b5ee0468SBui Quang Minh * apic, so we need to call it here and set it to 1 which is the max cpus
1162b5ee0468SBui Quang Minh * in machine none.
1163b5ee0468SBui Quang Minh */
1164b5ee0468SBui Quang Minh if (!local_apics) {
1165b5ee0468SBui Quang Minh apic_set_max_apic_id(1);
1166b5ee0468SBui Quang Minh }
1167b5ee0468SBui Quang Minh local_apics[s->initial_apic_id] = s;
11687702e47cSPaolo Bonzini
1169226419d6SMichael S. Tsirkin msi_nonbroken = true;
11707702e47cSPaolo Bonzini }
11717702e47cSPaolo Bonzini
apic_unrealize(DeviceState * dev)1172b69c3c21SMarkus Armbruster static void apic_unrealize(DeviceState *dev)
11739c156f9dSIgor Mammedov {
1174927d5a1dSWanpeng Li APICCommonState *s = APIC(dev);
11759c156f9dSIgor Mammedov
11769c156f9dSIgor Mammedov timer_free(s->timer);
1177b5ee0468SBui Quang Minh local_apics[s->initial_apic_id] = NULL;
11789c156f9dSIgor Mammedov }
11799c156f9dSIgor Mammedov
apic_class_init(ObjectClass * klass,void * data)11807702e47cSPaolo Bonzini static void apic_class_init(ObjectClass *klass, void *data)
11817702e47cSPaolo Bonzini {
11827702e47cSPaolo Bonzini APICCommonClass *k = APIC_COMMON_CLASS(klass);
11837702e47cSPaolo Bonzini
1184ff6986ceSxiaoqiang zhao k->realize = apic_realize;
11859c156f9dSIgor Mammedov k->unrealize = apic_unrealize;
11867702e47cSPaolo Bonzini k->set_base = apic_set_base;
11877702e47cSPaolo Bonzini k->set_tpr = apic_set_tpr;
11887702e47cSPaolo Bonzini k->get_tpr = apic_get_tpr;
11897702e47cSPaolo Bonzini k->vapic_base_update = apic_vapic_base_update;
11907702e47cSPaolo Bonzini k->external_nmi = apic_external_nmi;
11917702e47cSPaolo Bonzini k->pre_save = apic_pre_save;
11927702e47cSPaolo Bonzini k->post_load = apic_post_load;
1193267ee357SRadim Krčmář k->send_msi = apic_send_msi;
11947702e47cSPaolo Bonzini }
11957702e47cSPaolo Bonzini
11967702e47cSPaolo Bonzini static const TypeInfo apic_info = {
1197927d5a1dSWanpeng Li .name = TYPE_APIC,
11987702e47cSPaolo Bonzini .instance_size = sizeof(APICCommonState),
11997702e47cSPaolo Bonzini .parent = TYPE_APIC_COMMON,
12007702e47cSPaolo Bonzini .class_init = apic_class_init,
12017702e47cSPaolo Bonzini };
12027702e47cSPaolo Bonzini
apic_register_types(void)12037702e47cSPaolo Bonzini static void apic_register_types(void)
12047702e47cSPaolo Bonzini {
12057702e47cSPaolo Bonzini type_register_static(&apic_info);
12067702e47cSPaolo Bonzini }
12077702e47cSPaolo Bonzini
12087702e47cSPaolo Bonzini type_init(apic_register_types)
1209