xref: /openbmc/qemu/hw/intc/apic_common.c (revision e05ee299)
17702e47cSPaolo Bonzini /*
27702e47cSPaolo Bonzini  *  APIC support - common bits of emulated and KVM kernel model
37702e47cSPaolo Bonzini  *
47702e47cSPaolo Bonzini  *  Copyright (c) 2004-2005 Fabrice Bellard
57702e47cSPaolo Bonzini  *  Copyright (c) 2011      Jan Kiszka, Siemens AG
67702e47cSPaolo Bonzini  *
77702e47cSPaolo Bonzini  * This library is free software; you can redistribute it and/or
87702e47cSPaolo Bonzini  * modify it under the terms of the GNU Lesser General Public
97702e47cSPaolo Bonzini  * License as published by the Free Software Foundation; either
1061f3c91aSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
117702e47cSPaolo Bonzini  *
127702e47cSPaolo Bonzini  * This library is distributed in the hope that it will be useful,
137702e47cSPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
147702e47cSPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
157702e47cSPaolo Bonzini  * Lesser General Public License for more details.
167702e47cSPaolo Bonzini  *
177702e47cSPaolo Bonzini  * You should have received a copy of the GNU Lesser General Public
187702e47cSPaolo Bonzini  * License along with this library; if not, see <http://www.gnu.org/licenses/>
197702e47cSPaolo Bonzini  */
200b8fa32fSMarkus Armbruster 
21b6a0aa05SPeter Maydell #include "qemu/osdep.h"
222f114315SRadim Krčmář #include "qemu/error-report.h"
230b8fa32fSMarkus Armbruster #include "qemu/module.h"
24da34e65cSMarkus Armbruster #include "qapi/error.h"
2533d7a288SIgor Mammedov #include "qapi/visitor.h"
267702e47cSPaolo Bonzini #include "hw/i386/apic.h"
277702e47cSPaolo Bonzini #include "hw/i386/apic_internal.h"
282b85e0cdSThomas Huth #include "hw/intc/kvm_irqcount.h"
297702e47cSPaolo Bonzini #include "trace.h"
3086378b29SPaolo Bonzini #include "hw/boards.h"
317702e47cSPaolo Bonzini #include "sysemu/kvm.h"
32a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
3353a89e26SIgor Mammedov #include "hw/sysbus.h"
34d6454270SMarkus Armbruster #include "migration/vmstate.h"
357702e47cSPaolo Bonzini 
367702e47cSPaolo Bonzini bool apic_report_tpr_access;
377702e47cSPaolo Bonzini 
cpu_set_apic_base(DeviceState * dev,uint64_t val)38774204cfSBui Quang Minh int cpu_set_apic_base(DeviceState *dev, uint64_t val)
397702e47cSPaolo Bonzini {
407702e47cSPaolo Bonzini     trace_cpu_set_apic_base(val);
417702e47cSPaolo Bonzini 
42d3b0c9e9Sxiaoqiang zhao     if (dev) {
43d3b0c9e9Sxiaoqiang zhao         APICCommonState *s = APIC_COMMON(dev);
447702e47cSPaolo Bonzini         APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
45774204cfSBui Quang Minh         /* Reset possibly modified xAPIC ID */
46facb07cdSIgor Mammedov         s->id = s->initial_apic_id;
47774204cfSBui Quang Minh         return info->set_base(s, val);
48facb07cdSIgor Mammedov     }
49774204cfSBui Quang Minh 
50774204cfSBui Quang Minh     return 0;
517702e47cSPaolo Bonzini }
527702e47cSPaolo Bonzini 
cpu_get_apic_base(DeviceState * dev)53d3b0c9e9Sxiaoqiang zhao uint64_t cpu_get_apic_base(DeviceState *dev)
547702e47cSPaolo Bonzini {
55d3b0c9e9Sxiaoqiang zhao     if (dev) {
56d3b0c9e9Sxiaoqiang zhao         APICCommonState *s = APIC_COMMON(dev);
577702e47cSPaolo Bonzini         trace_cpu_get_apic_base((uint64_t)s->apicbase);
587702e47cSPaolo Bonzini         return s->apicbase;
597702e47cSPaolo Bonzini     } else {
607702e47cSPaolo Bonzini         trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
617702e47cSPaolo Bonzini         return MSR_IA32_APICBASE_BSP;
627702e47cSPaolo Bonzini     }
637702e47cSPaolo Bonzini }
647702e47cSPaolo Bonzini 
cpu_is_apic_enabled(DeviceState * dev)65c2e6d7d8SBernhard Beschow bool cpu_is_apic_enabled(DeviceState *dev)
66c2e6d7d8SBernhard Beschow {
67c2e6d7d8SBernhard Beschow     APICCommonState *s;
68c2e6d7d8SBernhard Beschow 
69c2e6d7d8SBernhard Beschow     if (!dev) {
70c2e6d7d8SBernhard Beschow         return false;
71c2e6d7d8SBernhard Beschow     }
72c2e6d7d8SBernhard Beschow 
73c2e6d7d8SBernhard Beschow     s = APIC_COMMON(dev);
74c2e6d7d8SBernhard Beschow 
75c2e6d7d8SBernhard Beschow     return s->apicbase & MSR_IA32_APICBASE_ENABLE;
76c2e6d7d8SBernhard Beschow }
77c2e6d7d8SBernhard Beschow 
cpu_set_apic_tpr(DeviceState * dev,uint8_t val)78d3b0c9e9Sxiaoqiang zhao void cpu_set_apic_tpr(DeviceState *dev, uint8_t val)
797702e47cSPaolo Bonzini {
807702e47cSPaolo Bonzini     APICCommonState *s;
817702e47cSPaolo Bonzini     APICCommonClass *info;
827702e47cSPaolo Bonzini 
83d3b0c9e9Sxiaoqiang zhao     if (!dev) {
847702e47cSPaolo Bonzini         return;
857702e47cSPaolo Bonzini     }
867702e47cSPaolo Bonzini 
87d3b0c9e9Sxiaoqiang zhao     s = APIC_COMMON(dev);
887702e47cSPaolo Bonzini     info = APIC_COMMON_GET_CLASS(s);
897702e47cSPaolo Bonzini 
907702e47cSPaolo Bonzini     info->set_tpr(s, val);
917702e47cSPaolo Bonzini }
927702e47cSPaolo Bonzini 
cpu_get_apic_tpr(DeviceState * dev)93d3b0c9e9Sxiaoqiang zhao uint8_t cpu_get_apic_tpr(DeviceState *dev)
947702e47cSPaolo Bonzini {
957702e47cSPaolo Bonzini     APICCommonState *s;
967702e47cSPaolo Bonzini     APICCommonClass *info;
977702e47cSPaolo Bonzini 
98d3b0c9e9Sxiaoqiang zhao     if (!dev) {
997702e47cSPaolo Bonzini         return 0;
1007702e47cSPaolo Bonzini     }
1017702e47cSPaolo Bonzini 
102d3b0c9e9Sxiaoqiang zhao     s = APIC_COMMON(dev);
1037702e47cSPaolo Bonzini     info = APIC_COMMON_GET_CLASS(s);
1047702e47cSPaolo Bonzini 
1057702e47cSPaolo Bonzini     return info->get_tpr(s);
1067702e47cSPaolo Bonzini }
1077702e47cSPaolo Bonzini 
apic_enable_tpr_access_reporting(DeviceState * dev,bool enable)108d3b0c9e9Sxiaoqiang zhao void apic_enable_tpr_access_reporting(DeviceState *dev, bool enable)
1097702e47cSPaolo Bonzini {
110d3b0c9e9Sxiaoqiang zhao     APICCommonState *s = APIC_COMMON(dev);
1117702e47cSPaolo Bonzini     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
1127702e47cSPaolo Bonzini 
1137702e47cSPaolo Bonzini     apic_report_tpr_access = enable;
1147702e47cSPaolo Bonzini     if (info->enable_tpr_reporting) {
1157702e47cSPaolo Bonzini         info->enable_tpr_reporting(s, enable);
1167702e47cSPaolo Bonzini     }
1177702e47cSPaolo Bonzini }
1187702e47cSPaolo Bonzini 
apic_enable_vapic(DeviceState * dev,hwaddr paddr)119d3b0c9e9Sxiaoqiang zhao void apic_enable_vapic(DeviceState *dev, hwaddr paddr)
1207702e47cSPaolo Bonzini {
121d3b0c9e9Sxiaoqiang zhao     APICCommonState *s = APIC_COMMON(dev);
1227702e47cSPaolo Bonzini     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
1237702e47cSPaolo Bonzini 
1247702e47cSPaolo Bonzini     s->vapic_paddr = paddr;
1257702e47cSPaolo Bonzini     info->vapic_base_update(s);
1267702e47cSPaolo Bonzini }
1277702e47cSPaolo Bonzini 
apic_handle_tpr_access_report(DeviceState * dev,target_ulong ip,TPRAccess access)128d3b0c9e9Sxiaoqiang zhao void apic_handle_tpr_access_report(DeviceState *dev, target_ulong ip,
1297702e47cSPaolo Bonzini                                    TPRAccess access)
1307702e47cSPaolo Bonzini {
131d3b0c9e9Sxiaoqiang zhao     APICCommonState *s = APIC_COMMON(dev);
1327702e47cSPaolo Bonzini 
1337702e47cSPaolo Bonzini     vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
1347702e47cSPaolo Bonzini }
1357702e47cSPaolo Bonzini 
apic_deliver_nmi(DeviceState * dev)136d3b0c9e9Sxiaoqiang zhao void apic_deliver_nmi(DeviceState *dev)
1377702e47cSPaolo Bonzini {
138d3b0c9e9Sxiaoqiang zhao     APICCommonState *s = APIC_COMMON(dev);
1397702e47cSPaolo Bonzini     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
1407702e47cSPaolo Bonzini 
1417702e47cSPaolo Bonzini     info->external_nmi(s);
1427702e47cSPaolo Bonzini }
1437702e47cSPaolo Bonzini 
apic_next_timer(APICCommonState * s,int64_t current_time)1447702e47cSPaolo Bonzini bool apic_next_timer(APICCommonState *s, int64_t current_time)
1457702e47cSPaolo Bonzini {
1467702e47cSPaolo Bonzini     int64_t d;
1477702e47cSPaolo Bonzini 
1487702e47cSPaolo Bonzini     /* We need to store the timer state separately to support APIC
1497702e47cSPaolo Bonzini      * implementations that maintain a non-QEMU timer, e.g. inside the
1507702e47cSPaolo Bonzini      * host kernel. This open-coded state allows us to migrate between
1517702e47cSPaolo Bonzini      * both models. */
1527702e47cSPaolo Bonzini     s->timer_expiry = -1;
1537702e47cSPaolo Bonzini 
1547702e47cSPaolo Bonzini     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
1557702e47cSPaolo Bonzini         return false;
1567702e47cSPaolo Bonzini     }
1577702e47cSPaolo Bonzini 
1587702e47cSPaolo Bonzini     d = (current_time - s->initial_count_load_time) >> s->count_shift;
1597702e47cSPaolo Bonzini 
1607702e47cSPaolo Bonzini     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1617702e47cSPaolo Bonzini         if (!s->initial_count) {
1627702e47cSPaolo Bonzini             return false;
1637702e47cSPaolo Bonzini         }
1647702e47cSPaolo Bonzini         d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
1657702e47cSPaolo Bonzini             ((uint64_t)s->initial_count + 1);
1667702e47cSPaolo Bonzini     } else {
1677702e47cSPaolo Bonzini         if (d >= s->initial_count) {
1687702e47cSPaolo Bonzini             return false;
1697702e47cSPaolo Bonzini         }
1707702e47cSPaolo Bonzini         d = (uint64_t)s->initial_count + 1;
1717702e47cSPaolo Bonzini     }
1727702e47cSPaolo Bonzini     s->next_time = s->initial_count_load_time + (d << s->count_shift);
1737702e47cSPaolo Bonzini     s->timer_expiry = s->next_time;
1747702e47cSPaolo Bonzini     return true;
1757702e47cSPaolo Bonzini }
1767702e47cSPaolo Bonzini 
apic_get_current_count(APICCommonState * s)1776e083c0dSJan Kiszka uint32_t apic_get_current_count(APICCommonState *s)
1786e083c0dSJan Kiszka {
1796e083c0dSJan Kiszka     int64_t d;
1806e083c0dSJan Kiszka     uint32_t val;
1816e083c0dSJan Kiszka     d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >>
1826e083c0dSJan Kiszka         s->count_shift;
1836e083c0dSJan Kiszka     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
1846e083c0dSJan Kiszka         /* periodic */
1856e083c0dSJan Kiszka         val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
1866e083c0dSJan Kiszka     } else {
1876e083c0dSJan Kiszka         if (d >= s->initial_count) {
1886e083c0dSJan Kiszka             val = 0;
1896e083c0dSJan Kiszka         } else {
1906e083c0dSJan Kiszka             val = s->initial_count - d;
1916e083c0dSJan Kiszka         }
1926e083c0dSJan Kiszka     }
1936e083c0dSJan Kiszka     return val;
1946e083c0dSJan Kiszka }
1956e083c0dSJan Kiszka 
apic_init_reset(DeviceState * dev)196d3b0c9e9Sxiaoqiang zhao void apic_init_reset(DeviceState *dev)
1977702e47cSPaolo Bonzini {
198927411faSPaolo Bonzini     APICCommonState *s;
199927411faSPaolo Bonzini     APICCommonClass *info;
2007702e47cSPaolo Bonzini     int i;
2017702e47cSPaolo Bonzini 
202927411faSPaolo Bonzini     if (!dev) {
2037702e47cSPaolo Bonzini         return;
2047702e47cSPaolo Bonzini     }
205927411faSPaolo Bonzini     s = APIC_COMMON(dev);
2067702e47cSPaolo Bonzini     s->tpr = 0;
2077702e47cSPaolo Bonzini     s->spurious_vec = 0xff;
2087702e47cSPaolo Bonzini     s->log_dest = 0;
2097702e47cSPaolo Bonzini     s->dest_mode = 0xf;
2107702e47cSPaolo Bonzini     memset(s->isr, 0, sizeof(s->isr));
2117702e47cSPaolo Bonzini     memset(s->tmr, 0, sizeof(s->tmr));
2127702e47cSPaolo Bonzini     memset(s->irr, 0, sizeof(s->irr));
2137702e47cSPaolo Bonzini     for (i = 0; i < APIC_LVT_NB; i++) {
2147702e47cSPaolo Bonzini         s->lvt[i] = APIC_LVT_MASKED;
2157702e47cSPaolo Bonzini     }
2167702e47cSPaolo Bonzini     s->esr = 0;
2177702e47cSPaolo Bonzini     memset(s->icr, 0, sizeof(s->icr));
2187702e47cSPaolo Bonzini     s->divide_conf = 0;
2197702e47cSPaolo Bonzini     s->count_shift = 0;
2207702e47cSPaolo Bonzini     s->initial_count = 0;
2217702e47cSPaolo Bonzini     s->initial_count_load_time = 0;
2227702e47cSPaolo Bonzini     s->next_time = 0;
2237b4d915eSPaolo Bonzini     s->wait_for_sipi = !cpu_is_bsp(s->cpu);
2247702e47cSPaolo Bonzini 
2257702e47cSPaolo Bonzini     if (s->timer) {
226bc72ad67SAlex Bligh         timer_del(s->timer);
2277702e47cSPaolo Bonzini     }
2287702e47cSPaolo Bonzini     s->timer_expiry = -1;
229575a6f40SPaolo Bonzini 
230927411faSPaolo Bonzini     info = APIC_COMMON_GET_CLASS(s);
231575a6f40SPaolo Bonzini     if (info->reset) {
232575a6f40SPaolo Bonzini         info->reset(s);
233575a6f40SPaolo Bonzini     }
2347702e47cSPaolo Bonzini }
2357702e47cSPaolo Bonzini 
apic_designate_bsp(DeviceState * dev,bool bsp)2369cb11fd7SNadav Amit void apic_designate_bsp(DeviceState *dev, bool bsp)
2377702e47cSPaolo Bonzini {
238d3b0c9e9Sxiaoqiang zhao     if (dev == NULL) {
2397702e47cSPaolo Bonzini         return;
2407702e47cSPaolo Bonzini     }
2417702e47cSPaolo Bonzini 
242d3b0c9e9Sxiaoqiang zhao     APICCommonState *s = APIC_COMMON(dev);
2439cb11fd7SNadav Amit     if (bsp) {
2447702e47cSPaolo Bonzini         s->apicbase |= MSR_IA32_APICBASE_BSP;
2459cb11fd7SNadav Amit     } else {
2469cb11fd7SNadav Amit         s->apicbase &= ~MSR_IA32_APICBASE_BSP;
2479cb11fd7SNadav Amit     }
2487702e47cSPaolo Bonzini }
2497702e47cSPaolo Bonzini 
apic_reset_common(DeviceState * dev)250d3b0c9e9Sxiaoqiang zhao static void apic_reset_common(DeviceState *dev)
2517702e47cSPaolo Bonzini {
252d3b0c9e9Sxiaoqiang zhao     APICCommonState *s = APIC_COMMON(dev);
2537702e47cSPaolo Bonzini     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
25481329754SDenis V. Lunev     uint32_t bsp;
2557702e47cSPaolo Bonzini 
25681329754SDenis V. Lunev     bsp = s->apicbase & MSR_IA32_APICBASE_BSP;
25781329754SDenis V. Lunev     s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE;
2584c34897aSIgor Mammedov     s->id = s->initial_apic_id;
2597702e47cSPaolo Bonzini 
2602b85e0cdSThomas Huth     kvm_reset_irq_delivered();
261f65e8212SPavel Dovgalyuk 
2627702e47cSPaolo Bonzini     s->vapic_paddr = 0;
2637702e47cSPaolo Bonzini     info->vapic_base_update(s);
2647702e47cSPaolo Bonzini 
265d3b0c9e9Sxiaoqiang zhao     apic_init_reset(dev);
2667702e47cSPaolo Bonzini }
2677702e47cSPaolo Bonzini 
268f6e98444SIgor Mammedov static const VMStateDescription vmstate_apic_common;
269f6e98444SIgor Mammedov 
apic_common_realize(DeviceState * dev,Error ** errp)270494c2717Sxiaoqiang zhao static void apic_common_realize(DeviceState *dev, Error **errp)
2717702e47cSPaolo Bonzini {
2720459c141SPhilippe Mathieu-Daudé     ERRP_GUARD();
2737702e47cSPaolo Bonzini     APICCommonState *s = APIC_COMMON(dev);
2747702e47cSPaolo Bonzini     APICCommonClass *info;
2757702e47cSPaolo Bonzini     static DeviceState *vapic;
2760ab99486SPeter Xu     uint32_t instance_id = s->initial_apic_id;
2770ab99486SPeter Xu 
2780ab99486SPeter Xu     /* Normally initial APIC ID should be no more than hundreds */
2790ab99486SPeter Xu     assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
2807702e47cSPaolo Bonzini 
2817702e47cSPaolo Bonzini     info = APIC_COMMON_GET_CLASS(s);
282494c2717Sxiaoqiang zhao     info->realize(dev, errp);
2830459c141SPhilippe Mathieu-Daudé     if (*errp) {
2840459c141SPhilippe Mathieu-Daudé         return;
2850459c141SPhilippe Mathieu-Daudé     }
2867702e47cSPaolo Bonzini 
2877702e47cSPaolo Bonzini     /* Note: We need at least 1M to map the VAPIC option ROM */
2887702e47cSPaolo Bonzini     if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
289b91b0fc1SPhilippe Mathieu-Daudé             current_machine->ram_size >= 1024 * 1024) {
2907702e47cSPaolo Bonzini         vapic = sysbus_create_simple("kvmvapic", -1, NULL);
2917702e47cSPaolo Bonzini     }
2927702e47cSPaolo Bonzini     s->vapic = vapic;
2937702e47cSPaolo Bonzini     if (apic_report_tpr_access && info->enable_tpr_reporting) {
2947702e47cSPaolo Bonzini         info->enable_tpr_reporting(s, true);
2957702e47cSPaolo Bonzini     }
2967702e47cSPaolo Bonzini 
297f6e98444SIgor Mammedov     if (s->legacy_instance_id) {
2981df2c9a2SPeter Xu         instance_id = VMSTATE_INSTANCE_ID_ANY;
299f6e98444SIgor Mammedov     }
300f6e98444SIgor Mammedov     vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
301bc5c4f21SDr. David Alan Gilbert                                    s, -1, 0, NULL);
302b5ee0468SBui Quang Minh 
303b5ee0468SBui Quang Minh     /* APIC LDR in x2APIC mode */
304b5ee0468SBui Quang Minh     s->extended_log_dest = ((s->initial_apic_id >> 4) << 16) |
305b5ee0468SBui Quang Minh                             (1 << (s->initial_apic_id & 0xf));
3067702e47cSPaolo Bonzini }
3077702e47cSPaolo Bonzini 
apic_common_unrealize(DeviceState * dev)308b69c3c21SMarkus Armbruster static void apic_common_unrealize(DeviceState *dev)
3099c156f9dSIgor Mammedov {
3109c156f9dSIgor Mammedov     APICCommonState *s = APIC_COMMON(dev);
3119c156f9dSIgor Mammedov     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
3129c156f9dSIgor Mammedov 
313f6e98444SIgor Mammedov     vmstate_unregister(NULL, &vmstate_apic_common, s);
314b69c3c21SMarkus Armbruster     info->unrealize(dev);
3159c156f9dSIgor Mammedov 
3169c156f9dSIgor Mammedov     if (apic_report_tpr_access && info->enable_tpr_reporting) {
3179c156f9dSIgor Mammedov         info->enable_tpr_reporting(s, false);
3189c156f9dSIgor Mammedov     }
3199c156f9dSIgor Mammedov }
3209c156f9dSIgor Mammedov 
apic_pre_load(void * opaque)321c2c00148SPavel Dovgalyuk static int apic_pre_load(void *opaque)
322c2c00148SPavel Dovgalyuk {
323c2c00148SPavel Dovgalyuk     APICCommonState *s = APIC_COMMON(opaque);
324c2c00148SPavel Dovgalyuk 
325c2c00148SPavel Dovgalyuk     /* The default is !cpu_is_bsp(s->cpu), but the common value is 0
326c2c00148SPavel Dovgalyuk      * so that's what apic_common_sipi_needed checks for.  Reset to
327c2c00148SPavel Dovgalyuk      * the value that is assumed when the apic_sipi subsection is
328c2c00148SPavel Dovgalyuk      * absent.
329c2c00148SPavel Dovgalyuk      */
330c2c00148SPavel Dovgalyuk     s->wait_for_sipi = 0;
331c2c00148SPavel Dovgalyuk     return 0;
332c2c00148SPavel Dovgalyuk }
333c2c00148SPavel Dovgalyuk 
apic_dispatch_pre_save(void * opaque)33444b1ff31SDr. David Alan Gilbert static int apic_dispatch_pre_save(void *opaque)
3357702e47cSPaolo Bonzini {
3367702e47cSPaolo Bonzini     APICCommonState *s = APIC_COMMON(opaque);
3377702e47cSPaolo Bonzini     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
3387702e47cSPaolo Bonzini 
3397702e47cSPaolo Bonzini     if (info->pre_save) {
3407702e47cSPaolo Bonzini         info->pre_save(s);
3417702e47cSPaolo Bonzini     }
34244b1ff31SDr. David Alan Gilbert 
34344b1ff31SDr. David Alan Gilbert     return 0;
3447702e47cSPaolo Bonzini }
3457702e47cSPaolo Bonzini 
apic_dispatch_post_load(void * opaque,int version_id)3467702e47cSPaolo Bonzini static int apic_dispatch_post_load(void *opaque, int version_id)
3477702e47cSPaolo Bonzini {
3487702e47cSPaolo Bonzini     APICCommonState *s = APIC_COMMON(opaque);
3497702e47cSPaolo Bonzini     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
3507702e47cSPaolo Bonzini 
3517702e47cSPaolo Bonzini     if (info->post_load) {
3527702e47cSPaolo Bonzini         info->post_load(s);
3537702e47cSPaolo Bonzini     }
3547702e47cSPaolo Bonzini     return 0;
3557702e47cSPaolo Bonzini }
3567702e47cSPaolo Bonzini 
apic_common_sipi_needed(void * opaque)357c2c00148SPavel Dovgalyuk static bool apic_common_sipi_needed(void *opaque)
358c2c00148SPavel Dovgalyuk {
359c2c00148SPavel Dovgalyuk     APICCommonState *s = APIC_COMMON(opaque);
360c2c00148SPavel Dovgalyuk     return s->wait_for_sipi != 0;
361c2c00148SPavel Dovgalyuk }
362c2c00148SPavel Dovgalyuk 
363c2c00148SPavel Dovgalyuk static const VMStateDescription vmstate_apic_common_sipi = {
364c2c00148SPavel Dovgalyuk     .name = "apic_sipi",
365c2c00148SPavel Dovgalyuk     .version_id = 1,
366c2c00148SPavel Dovgalyuk     .minimum_version_id = 1,
3675cd8cadaSJuan Quintela     .needed = apic_common_sipi_needed,
36845b1f81dSRichard Henderson     .fields = (const VMStateField[]) {
369c2c00148SPavel Dovgalyuk         VMSTATE_INT32(sipi_vector, APICCommonState),
370c2c00148SPavel Dovgalyuk         VMSTATE_INT32(wait_for_sipi, APICCommonState),
371c2c00148SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
372c2c00148SPavel Dovgalyuk     }
373c2c00148SPavel Dovgalyuk };
374c2c00148SPavel Dovgalyuk 
3757702e47cSPaolo Bonzini static const VMStateDescription vmstate_apic_common = {
3767702e47cSPaolo Bonzini     .name = "apic",
3777702e47cSPaolo Bonzini     .version_id = 3,
3787702e47cSPaolo Bonzini     .minimum_version_id = 3,
379c2c00148SPavel Dovgalyuk     .pre_load = apic_pre_load,
3807702e47cSPaolo Bonzini     .pre_save = apic_dispatch_pre_save,
3817702e47cSPaolo Bonzini     .post_load = apic_dispatch_post_load,
38245b1f81dSRichard Henderson     .fields = (const VMStateField[]) {
3837702e47cSPaolo Bonzini         VMSTATE_UINT32(apicbase, APICCommonState),
3847702e47cSPaolo Bonzini         VMSTATE_UINT8(id, APICCommonState),
3857702e47cSPaolo Bonzini         VMSTATE_UINT8(arb_id, APICCommonState),
3867702e47cSPaolo Bonzini         VMSTATE_UINT8(tpr, APICCommonState),
3877702e47cSPaolo Bonzini         VMSTATE_UINT32(spurious_vec, APICCommonState),
3887702e47cSPaolo Bonzini         VMSTATE_UINT8(log_dest, APICCommonState),
3897702e47cSPaolo Bonzini         VMSTATE_UINT8(dest_mode, APICCommonState),
3907702e47cSPaolo Bonzini         VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
3917702e47cSPaolo Bonzini         VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
3927702e47cSPaolo Bonzini         VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
3937702e47cSPaolo Bonzini         VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
3947702e47cSPaolo Bonzini         VMSTATE_UINT32(esr, APICCommonState),
3957702e47cSPaolo Bonzini         VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
3967702e47cSPaolo Bonzini         VMSTATE_UINT32(divide_conf, APICCommonState),
3977702e47cSPaolo Bonzini         VMSTATE_INT32(count_shift, APICCommonState),
3987702e47cSPaolo Bonzini         VMSTATE_UINT32(initial_count, APICCommonState),
3997702e47cSPaolo Bonzini         VMSTATE_INT64(initial_count_load_time, APICCommonState),
4007702e47cSPaolo Bonzini         VMSTATE_INT64(next_time, APICCommonState),
4017702e47cSPaolo Bonzini         VMSTATE_INT64(timer_expiry,
4027702e47cSPaolo Bonzini                       APICCommonState), /* open-coded timer state */
4037702e47cSPaolo Bonzini         VMSTATE_END_OF_LIST()
404c2c00148SPavel Dovgalyuk     },
40545b1f81dSRichard Henderson     .subsections = (const VMStateDescription * const []) {
4065cd8cadaSJuan Quintela         &vmstate_apic_common_sipi,
4075cd8cadaSJuan Quintela         NULL
4087702e47cSPaolo Bonzini     }
4097702e47cSPaolo Bonzini };
4107702e47cSPaolo Bonzini 
4117702e47cSPaolo Bonzini static Property apic_properties_common[] = {
412aa93200bSGabriel L. Somlo     DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
4137702e47cSPaolo Bonzini     DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
4147702e47cSPaolo Bonzini                     true),
415f6e98444SIgor Mammedov     DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id,
416f6e98444SIgor Mammedov                      false),
4177702e47cSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
4187702e47cSPaolo Bonzini };
4197702e47cSPaolo Bonzini 
apic_common_get_id(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)42033d7a288SIgor Mammedov static void apic_common_get_id(Object *obj, Visitor *v, const char *name,
42133d7a288SIgor Mammedov                                void *opaque, Error **errp)
42233d7a288SIgor Mammedov {
42333d7a288SIgor Mammedov     APICCommonState *s = APIC_COMMON(obj);
424d528227dSMarc-André Lureau     uint32_t value;
42533d7a288SIgor Mammedov 
42633d7a288SIgor Mammedov     value = s->apicbase & MSR_IA32_APICBASE_EXTD ? s->initial_apic_id : s->id;
427d528227dSMarc-André Lureau     visit_type_uint32(v, name, &value, errp);
42833d7a288SIgor Mammedov }
42933d7a288SIgor Mammedov 
apic_common_set_id(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)43033d7a288SIgor Mammedov static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
43133d7a288SIgor Mammedov                                void *opaque, Error **errp)
43233d7a288SIgor Mammedov {
43333d7a288SIgor Mammedov     APICCommonState *s = APIC_COMMON(obj);
43433d7a288SIgor Mammedov     DeviceState *dev = DEVICE(obj);
435d528227dSMarc-André Lureau     uint32_t value;
436*e05ee299SZhao Liu     Error *local_err = NULL;
43733d7a288SIgor Mammedov 
43833d7a288SIgor Mammedov     if (dev->realized) {
43933d7a288SIgor Mammedov         qdev_prop_set_after_realize(dev, name, errp);
44033d7a288SIgor Mammedov         return;
44133d7a288SIgor Mammedov     }
44233d7a288SIgor Mammedov 
443668f62ecSMarkus Armbruster     if (!visit_type_uint32(v, name, &value, errp)) {
44433d7a288SIgor Mammedov         return;
44533d7a288SIgor Mammedov     }
44633d7a288SIgor Mammedov 
447b5ee0468SBui Quang Minh     if (value >= 255 && !cpu_has_x2apic_feature(&s->cpu->env)) {
448*e05ee299SZhao Liu         error_setg(&local_err,
449*e05ee299SZhao Liu                    "APIC ID %d requires x2APIC feature in CPU",
450*e05ee299SZhao Liu                    value);
451*e05ee299SZhao Liu         error_append_hint(&local_err, "Try x2apic=on in -cpu.\n");
452*e05ee299SZhao Liu         error_propagate(errp, local_err);
453b5ee0468SBui Quang Minh         return;
454b5ee0468SBui Quang Minh     }
455b5ee0468SBui Quang Minh 
45633d7a288SIgor Mammedov     s->initial_apic_id = value;
45733d7a288SIgor Mammedov     s->id = (uint8_t)value;
45833d7a288SIgor Mammedov }
45933d7a288SIgor Mammedov 
apic_common_initfn(Object * obj)46033d7a288SIgor Mammedov static void apic_common_initfn(Object *obj)
46133d7a288SIgor Mammedov {
46233d7a288SIgor Mammedov     APICCommonState *s = APIC_COMMON(obj);
46333d7a288SIgor Mammedov 
46433d7a288SIgor Mammedov     s->id = s->initial_apic_id = -1;
465d528227dSMarc-André Lureau     object_property_add(obj, "id", "uint32",
46633d7a288SIgor Mammedov                         apic_common_get_id,
467d2623129SMarkus Armbruster                         apic_common_set_id, NULL, NULL);
46833d7a288SIgor Mammedov }
46933d7a288SIgor Mammedov 
apic_common_class_init(ObjectClass * klass,void * data)4707702e47cSPaolo Bonzini static void apic_common_class_init(ObjectClass *klass, void *data)
4717702e47cSPaolo Bonzini {
4727702e47cSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
4737702e47cSPaolo Bonzini 
4747702e47cSPaolo Bonzini     dc->reset = apic_reset_common;
4754f67d30bSMarc-André Lureau     device_class_set_props(dc, apic_properties_common);
47646232aaaSChen Fan     dc->realize = apic_common_realize;
4779c156f9dSIgor Mammedov     dc->unrealize = apic_common_unrealize;
478f37a4374SMarkus Armbruster     /*
479f37a4374SMarkus Armbruster      * Reason: APIC and CPU need to be wired up by
480f37a4374SMarkus Armbruster      * x86_cpu_apic_create()
481f37a4374SMarkus Armbruster      */
482e90f2a8cSEduardo Habkost     dc->user_creatable = false;
4837702e47cSPaolo Bonzini }
4847702e47cSPaolo Bonzini 
4857702e47cSPaolo Bonzini static const TypeInfo apic_common_type = {
4867702e47cSPaolo Bonzini     .name = TYPE_APIC_COMMON,
48746232aaaSChen Fan     .parent = TYPE_DEVICE,
4887702e47cSPaolo Bonzini     .instance_size = sizeof(APICCommonState),
48933d7a288SIgor Mammedov     .instance_init = apic_common_initfn,
4907702e47cSPaolo Bonzini     .class_size = sizeof(APICCommonClass),
4917702e47cSPaolo Bonzini     .class_init = apic_common_class_init,
4927702e47cSPaolo Bonzini     .abstract = true,
4937702e47cSPaolo Bonzini };
4947702e47cSPaolo Bonzini 
apic_common_register_types(void)495d3b0c9e9Sxiaoqiang zhao static void apic_common_register_types(void)
4967702e47cSPaolo Bonzini {
4977702e47cSPaolo Bonzini     type_register_static(&apic_common_type);
4987702e47cSPaolo Bonzini }
4997702e47cSPaolo Bonzini 
500d3b0c9e9Sxiaoqiang zhao type_init(apic_common_register_types)
501