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 9574bbf7bSbellard * version 2 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" 2033c11879SPaolo Bonzini #include "cpu.h" 211de7afc9SPaolo Bonzini #include "qemu/thread.h" 220d09e41aSPaolo Bonzini #include "hw/i386/apic_internal.h" 230d09e41aSPaolo Bonzini #include "hw/i386/apic.h" 240d09e41aSPaolo Bonzini #include "hw/i386/ioapic.h" 25852c27e2SPaolo Bonzini #include "hw/intc/i8259.h" 2683c9f4caSPaolo Bonzini #include "hw/pci/msi.h" 271de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 28d8023f31SBlue Swirl #include "trace.h" 290d09e41aSPaolo Bonzini #include "hw/i386/apic-msidef.h" 30889211b1SIgor Mammedov #include "qapi/error.h" 31*db1015e9SEduardo Habkost #include "qom/object.h" 32574bbf7bSbellard 33889211b1SIgor Mammedov #define MAX_APICS 255 34d3e9db93Sbellard #define MAX_APIC_WORDS 8 35d3e9db93Sbellard 36e5ad936bSJan Kiszka #define SYNC_FROM_VAPIC 0x1 37e5ad936bSJan Kiszka #define SYNC_TO_VAPIC 0x2 38e5ad936bSJan Kiszka #define SYNC_ISR_IRR_TO_VAPIC 0x4 39e5ad936bSJan Kiszka 40dae01685SJan Kiszka static APICCommonState *local_apics[MAX_APICS + 1]; 4154c96da7SMichael S. Tsirkin 42927d5a1dSWanpeng Li #define TYPE_APIC "apic" 43927d5a1dSWanpeng Li #define APIC(obj) \ 44927d5a1dSWanpeng Li OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC) 45927d5a1dSWanpeng Li 46dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); 47dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s); 48610626afSaliguori static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, 49610626afSaliguori uint8_t dest, uint8_t dest_mode); 50d592d303Sbellard 513b63c04eSaurel32 /* Find first bit starting from msb */ 52edf9735eSMichael S. Tsirkin static int apic_fls_bit(uint32_t value) 533b63c04eSaurel32 { 543b63c04eSaurel32 return 31 - clz32(value); 553b63c04eSaurel32 } 563b63c04eSaurel32 57e95f5491Saurel32 /* Find first bit starting from lsb */ 58edf9735eSMichael S. Tsirkin static int apic_ffs_bit(uint32_t value) 59d3e9db93Sbellard { 60bb7e7293Saurel32 return ctz32(value); 61d3e9db93Sbellard } 62d3e9db93Sbellard 63edf9735eSMichael S. Tsirkin static inline void apic_reset_bit(uint32_t *tab, int index) 64d3e9db93Sbellard { 65d3e9db93Sbellard int i, mask; 66d3e9db93Sbellard i = index >> 5; 67d3e9db93Sbellard mask = 1 << (index & 0x1f); 68d3e9db93Sbellard tab[i] &= ~mask; 69d3e9db93Sbellard } 70d3e9db93Sbellard 71e5ad936bSJan Kiszka /* return -1 if no bit is set */ 72e5ad936bSJan Kiszka static int get_highest_priority_int(uint32_t *tab) 73e5ad936bSJan Kiszka { 74e5ad936bSJan Kiszka int i; 75e5ad936bSJan Kiszka for (i = 7; i >= 0; i--) { 76e5ad936bSJan Kiszka if (tab[i] != 0) { 77edf9735eSMichael S. Tsirkin return i * 32 + apic_fls_bit(tab[i]); 78e5ad936bSJan Kiszka } 79e5ad936bSJan Kiszka } 80e5ad936bSJan Kiszka return -1; 81e5ad936bSJan Kiszka } 82e5ad936bSJan Kiszka 83e5ad936bSJan Kiszka static void apic_sync_vapic(APICCommonState *s, int sync_type) 84e5ad936bSJan Kiszka { 85e5ad936bSJan Kiszka VAPICState vapic_state; 86e5ad936bSJan Kiszka size_t length; 87e5ad936bSJan Kiszka off_t start; 88e5ad936bSJan Kiszka int vector; 89e5ad936bSJan Kiszka 90e5ad936bSJan Kiszka if (!s->vapic_paddr) { 91e5ad936bSJan Kiszka return; 92e5ad936bSJan Kiszka } 93e5ad936bSJan Kiszka if (sync_type & SYNC_FROM_VAPIC) { 94eb6282f2SStefan Weil cpu_physical_memory_read(s->vapic_paddr, &vapic_state, 95eb6282f2SStefan Weil sizeof(vapic_state)); 96e5ad936bSJan Kiszka s->tpr = vapic_state.tpr; 97e5ad936bSJan Kiszka } 98e5ad936bSJan Kiszka if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) { 99e5ad936bSJan Kiszka start = offsetof(VAPICState, isr); 100e5ad936bSJan Kiszka length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr); 101e5ad936bSJan Kiszka 102e5ad936bSJan Kiszka if (sync_type & SYNC_TO_VAPIC) { 10360e82579SAndreas Färber assert(qemu_cpu_is_self(CPU(s->cpu))); 104e5ad936bSJan Kiszka 105e5ad936bSJan Kiszka vapic_state.tpr = s->tpr; 106e5ad936bSJan Kiszka vapic_state.enabled = 1; 107e5ad936bSJan Kiszka start = 0; 108e5ad936bSJan Kiszka length = sizeof(VAPICState); 109e5ad936bSJan Kiszka } 110e5ad936bSJan Kiszka 111e5ad936bSJan Kiszka vector = get_highest_priority_int(s->isr); 112e5ad936bSJan Kiszka if (vector < 0) { 113e5ad936bSJan Kiszka vector = 0; 114e5ad936bSJan Kiszka } 115e5ad936bSJan Kiszka vapic_state.isr = vector & 0xf0; 116e5ad936bSJan Kiszka 117e5ad936bSJan Kiszka vapic_state.zero = 0; 118e5ad936bSJan Kiszka 119e5ad936bSJan Kiszka vector = get_highest_priority_int(s->irr); 120e5ad936bSJan Kiszka if (vector < 0) { 121e5ad936bSJan Kiszka vector = 0; 122e5ad936bSJan Kiszka } 123e5ad936bSJan Kiszka vapic_state.irr = vector & 0xff; 124e5ad936bSJan Kiszka 1253c8133f9SPeter Maydell address_space_write_rom(&address_space_memory, 1262a221651SEdgar E. Iglesias s->vapic_paddr + start, 1273c8133f9SPeter Maydell MEMTXATTRS_UNSPECIFIED, 128e5ad936bSJan Kiszka ((void *)&vapic_state) + start, length); 129e5ad936bSJan Kiszka } 130e5ad936bSJan Kiszka } 131e5ad936bSJan Kiszka 132e5ad936bSJan Kiszka static void apic_vapic_base_update(APICCommonState *s) 133e5ad936bSJan Kiszka { 134e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 135e5ad936bSJan Kiszka } 136e5ad936bSJan Kiszka 137dae01685SJan Kiszka static void apic_local_deliver(APICCommonState *s, int vector) 138a5b38b51Saurel32 { 139a5b38b51Saurel32 uint32_t lvt = s->lvt[vector]; 140a5b38b51Saurel32 int trigger_mode; 141a5b38b51Saurel32 142d8023f31SBlue Swirl trace_apic_local_deliver(vector, (lvt >> 8) & 7); 143d8023f31SBlue Swirl 144a5b38b51Saurel32 if (lvt & APIC_LVT_MASKED) 145a5b38b51Saurel32 return; 146a5b38b51Saurel32 147a5b38b51Saurel32 switch ((lvt >> 8) & 7) { 148a5b38b51Saurel32 case APIC_DM_SMI: 149c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI); 150a5b38b51Saurel32 break; 151a5b38b51Saurel32 152a5b38b51Saurel32 case APIC_DM_NMI: 153c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI); 154a5b38b51Saurel32 break; 155a5b38b51Saurel32 156a5b38b51Saurel32 case APIC_DM_EXTINT: 157c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD); 158a5b38b51Saurel32 break; 159a5b38b51Saurel32 160a5b38b51Saurel32 case APIC_DM_FIXED: 161a5b38b51Saurel32 trigger_mode = APIC_TRIGGER_EDGE; 162a5b38b51Saurel32 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) && 163a5b38b51Saurel32 (lvt & APIC_LVT_LEVEL_TRIGGER)) 164a5b38b51Saurel32 trigger_mode = APIC_TRIGGER_LEVEL; 165a5b38b51Saurel32 apic_set_irq(s, lvt & 0xff, trigger_mode); 166a5b38b51Saurel32 } 167a5b38b51Saurel32 } 168a5b38b51Saurel32 169d3b0c9e9Sxiaoqiang zhao void apic_deliver_pic_intr(DeviceState *dev, int level) 1701a7de94aSaurel32 { 171927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 17292a16d7aSBlue Swirl 173cf6d64bfSBlue Swirl if (level) { 174cf6d64bfSBlue Swirl apic_local_deliver(s, APIC_LVT_LINT0); 175cf6d64bfSBlue Swirl } else { 1761a7de94aSaurel32 uint32_t lvt = s->lvt[APIC_LVT_LINT0]; 1771a7de94aSaurel32 1781a7de94aSaurel32 switch ((lvt >> 8) & 7) { 1791a7de94aSaurel32 case APIC_DM_FIXED: 1801a7de94aSaurel32 if (!(lvt & APIC_LVT_LEVEL_TRIGGER)) 1811a7de94aSaurel32 break; 182edf9735eSMichael S. Tsirkin apic_reset_bit(s->irr, lvt & 0xff); 1831a7de94aSaurel32 /* fall through */ 1841a7de94aSaurel32 case APIC_DM_EXTINT: 1858092cb71SPaolo Bonzini apic_update_irq(s); 1861a7de94aSaurel32 break; 1871a7de94aSaurel32 } 1881a7de94aSaurel32 } 1891a7de94aSaurel32 } 1901a7de94aSaurel32 191dae01685SJan Kiszka static void apic_external_nmi(APICCommonState *s) 19202c09195SJan Kiszka { 19302c09195SJan Kiszka apic_local_deliver(s, APIC_LVT_LINT1); 19402c09195SJan Kiszka } 19502c09195SJan Kiszka 196d3e9db93Sbellard #define foreach_apic(apic, deliver_bitmask, code) \ 197d3e9db93Sbellard {\ 1986d55574aSPeter Maydell int __i, __j;\ 199d3e9db93Sbellard for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\ 2006d55574aSPeter Maydell uint32_t __mask = deliver_bitmask[__i];\ 201d3e9db93Sbellard if (__mask) {\ 202d3e9db93Sbellard for(__j = 0; __j < 32; __j++) {\ 2036d55574aSPeter Maydell if (__mask & (1U << __j)) {\ 204d3e9db93Sbellard apic = local_apics[__i * 32 + __j];\ 205d3e9db93Sbellard if (apic) {\ 206d3e9db93Sbellard code;\ 207d3e9db93Sbellard }\ 208d3e9db93Sbellard }\ 209d3e9db93Sbellard }\ 210d3e9db93Sbellard }\ 211d3e9db93Sbellard }\ 212d3e9db93Sbellard } 213d3e9db93Sbellard 214d3e9db93Sbellard static void apic_bus_deliver(const uint32_t *deliver_bitmask, 2151f6f408cSJan Kiszka uint8_t delivery_mode, uint8_t vector_num, 216d592d303Sbellard uint8_t trigger_mode) 217d592d303Sbellard { 218dae01685SJan Kiszka APICCommonState *apic_iter; 219d592d303Sbellard 220d592d303Sbellard switch (delivery_mode) { 221d592d303Sbellard case APIC_DM_LOWPRI: 2228dd69b8fSbellard /* XXX: search for focus processor, arbitration */ 223d3e9db93Sbellard { 224d3e9db93Sbellard int i, d; 225d3e9db93Sbellard d = -1; 226d3e9db93Sbellard for(i = 0; i < MAX_APIC_WORDS; i++) { 227d3e9db93Sbellard if (deliver_bitmask[i]) { 228edf9735eSMichael S. Tsirkin d = i * 32 + apic_ffs_bit(deliver_bitmask[i]); 2298dd69b8fSbellard break; 230d3e9db93Sbellard } 231d3e9db93Sbellard } 232d3e9db93Sbellard if (d >= 0) { 233d3e9db93Sbellard apic_iter = local_apics[d]; 234d3e9db93Sbellard if (apic_iter) { 235d3e9db93Sbellard apic_set_irq(apic_iter, vector_num, trigger_mode); 236d3e9db93Sbellard } 237d3e9db93Sbellard } 238d3e9db93Sbellard } 239d3e9db93Sbellard return; 2408dd69b8fSbellard 241d592d303Sbellard case APIC_DM_FIXED: 242d592d303Sbellard break; 243d592d303Sbellard 244d592d303Sbellard case APIC_DM_SMI: 245e2eb9d3eSaurel32 foreach_apic(apic_iter, deliver_bitmask, 246c3affe56SAndreas Färber cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI) 24760671e58SAndreas Färber ); 248e2eb9d3eSaurel32 return; 249e2eb9d3eSaurel32 250d592d303Sbellard case APIC_DM_NMI: 251e2eb9d3eSaurel32 foreach_apic(apic_iter, deliver_bitmask, 252c3affe56SAndreas Färber cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI) 25360671e58SAndreas Färber ); 254e2eb9d3eSaurel32 return; 255d592d303Sbellard 256d592d303Sbellard case APIC_DM_INIT: 257d592d303Sbellard /* normal INIT IPI sent to processors */ 258d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 259c3affe56SAndreas Färber cpu_interrupt(CPU(apic_iter->cpu), 26060671e58SAndreas Färber CPU_INTERRUPT_INIT) 26160671e58SAndreas Färber ); 262d592d303Sbellard return; 263d592d303Sbellard 264d592d303Sbellard case APIC_DM_EXTINT: 265b1fc0348Sbellard /* handled in I/O APIC code */ 266d592d303Sbellard break; 267d592d303Sbellard 268d592d303Sbellard default: 269d592d303Sbellard return; 270d592d303Sbellard } 271d592d303Sbellard 272d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 273d3e9db93Sbellard apic_set_irq(apic_iter, vector_num, trigger_mode) ); 274d592d303Sbellard } 275574bbf7bSbellard 2761f6f408cSJan Kiszka void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, 2771f6f408cSJan Kiszka uint8_t vector_num, uint8_t trigger_mode) 278610626afSaliguori { 279610626afSaliguori uint32_t deliver_bitmask[MAX_APIC_WORDS]; 280610626afSaliguori 281d8023f31SBlue Swirl trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num, 2821f6f408cSJan Kiszka trigger_mode); 283d8023f31SBlue Swirl 284610626afSaliguori apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); 2851f6f408cSJan Kiszka apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); 286610626afSaliguori } 287610626afSaliguori 288dae01685SJan Kiszka static void apic_set_base(APICCommonState *s, uint64_t val) 289574bbf7bSbellard { 290574bbf7bSbellard s->apicbase = (val & 0xfffff000) | 291574bbf7bSbellard (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); 292574bbf7bSbellard /* if disabled, cannot be enabled again */ 293574bbf7bSbellard if (!(val & MSR_IA32_APICBASE_ENABLE)) { 294574bbf7bSbellard s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; 29560671e58SAndreas Färber cpu_clear_apic_feature(&s->cpu->env); 296574bbf7bSbellard s->spurious_vec &= ~APIC_SV_ENABLE; 297574bbf7bSbellard } 298574bbf7bSbellard } 299574bbf7bSbellard 300dae01685SJan Kiszka static void apic_set_tpr(APICCommonState *s, uint8_t val) 301574bbf7bSbellard { 302e5ad936bSJan Kiszka /* Updates from cr8 are ignored while the VAPIC is active */ 303e5ad936bSJan Kiszka if (!s->vapic_paddr) { 304e5ad936bSJan Kiszka s->tpr = val << 4; 305d592d303Sbellard apic_update_irq(s); 3069230e66eSbellard } 307e5ad936bSJan Kiszka } 3089230e66eSbellard 3092cb9f06eSSergio Andres Gomez Del Real int apic_get_highest_priority_irr(DeviceState *dev) 3102cb9f06eSSergio Andres Gomez Del Real { 3112cb9f06eSSergio Andres Gomez Del Real APICCommonState *s; 3122cb9f06eSSergio Andres Gomez Del Real 3132cb9f06eSSergio Andres Gomez Del Real if (!dev) { 3142cb9f06eSSergio Andres Gomez Del Real /* no interrupts */ 3152cb9f06eSSergio Andres Gomez Del Real return -1; 3162cb9f06eSSergio Andres Gomez Del Real } 3172cb9f06eSSergio Andres Gomez Del Real s = APIC_COMMON(dev); 3182cb9f06eSSergio Andres Gomez Del Real return get_highest_priority_int(s->irr); 3192cb9f06eSSergio Andres Gomez Del Real } 3202cb9f06eSSergio Andres Gomez Del Real 321e5ad936bSJan Kiszka static uint8_t apic_get_tpr(APICCommonState *s) 322d592d303Sbellard { 323e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 324e5ad936bSJan Kiszka return s->tpr >> 4; 325d592d303Sbellard } 326d592d303Sbellard 32782a5e042SPavel Butsykin int apic_get_ppr(APICCommonState *s) 328574bbf7bSbellard { 329574bbf7bSbellard int tpr, isrv, ppr; 330574bbf7bSbellard 331574bbf7bSbellard tpr = (s->tpr >> 4); 332574bbf7bSbellard isrv = get_highest_priority_int(s->isr); 333574bbf7bSbellard if (isrv < 0) 334574bbf7bSbellard isrv = 0; 335574bbf7bSbellard isrv >>= 4; 336574bbf7bSbellard if (tpr >= isrv) 337574bbf7bSbellard ppr = s->tpr; 338574bbf7bSbellard else 339574bbf7bSbellard ppr = isrv << 4; 340574bbf7bSbellard return ppr; 341574bbf7bSbellard } 342574bbf7bSbellard 343dae01685SJan Kiszka static int apic_get_arb_pri(APICCommonState *s) 344d592d303Sbellard { 345d592d303Sbellard /* XXX: arbitration */ 346d592d303Sbellard return 0; 347d592d303Sbellard } 348d592d303Sbellard 3490fbfbb59SGleb Natapov 3500fbfbb59SGleb Natapov /* 3510fbfbb59SGleb Natapov * <0 - low prio interrupt, 3520fbfbb59SGleb Natapov * 0 - no interrupt, 3530fbfbb59SGleb Natapov * >0 - interrupt number 3540fbfbb59SGleb Natapov */ 355dae01685SJan Kiszka static int apic_irq_pending(APICCommonState *s) 3560fbfbb59SGleb Natapov { 3570fbfbb59SGleb Natapov int irrv, ppr; 35860e68042SPaolo Bonzini 35960e68042SPaolo Bonzini if (!(s->spurious_vec & APIC_SV_ENABLE)) { 36060e68042SPaolo Bonzini return 0; 36160e68042SPaolo Bonzini } 36260e68042SPaolo Bonzini 3630fbfbb59SGleb Natapov irrv = get_highest_priority_int(s->irr); 3640fbfbb59SGleb Natapov if (irrv < 0) { 3650fbfbb59SGleb Natapov return 0; 3660fbfbb59SGleb Natapov } 3670fbfbb59SGleb Natapov ppr = apic_get_ppr(s); 3680fbfbb59SGleb Natapov if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) { 3690fbfbb59SGleb Natapov return -1; 3700fbfbb59SGleb Natapov } 3710fbfbb59SGleb Natapov 3720fbfbb59SGleb Natapov return irrv; 3730fbfbb59SGleb Natapov } 3740fbfbb59SGleb Natapov 375574bbf7bSbellard /* signal the CPU if an irq is pending */ 376dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s) 377574bbf7bSbellard { 378c3affe56SAndreas Färber CPUState *cpu; 379be9f8a08SZhu Guihua DeviceState *dev = (DeviceState *)s; 38060e82579SAndreas Färber 381c3affe56SAndreas Färber cpu = CPU(s->cpu); 38260e82579SAndreas Färber if (!qemu_cpu_is_self(cpu)) { 383c3affe56SAndreas Färber cpu_interrupt(cpu, CPU_INTERRUPT_POLL); 3845d62c43aSJan Kiszka } else if (apic_irq_pending(s) > 0) { 385c3affe56SAndreas Färber cpu_interrupt(cpu, CPU_INTERRUPT_HARD); 386be9f8a08SZhu Guihua } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) { 3878092cb71SPaolo Bonzini cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD); 388574bbf7bSbellard } 3890fbfbb59SGleb Natapov } 390574bbf7bSbellard 391d3b0c9e9Sxiaoqiang zhao void apic_poll_irq(DeviceState *dev) 392e5ad936bSJan Kiszka { 393927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 394e5ad936bSJan Kiszka 395e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 396e5ad936bSJan Kiszka apic_update_irq(s); 397e5ad936bSJan Kiszka } 398e5ad936bSJan Kiszka 399dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode) 400574bbf7bSbellard { 401edf9735eSMichael S. Tsirkin apic_report_irq_delivered(!apic_get_bit(s->irr, vector_num)); 40273822ec8Saliguori 403edf9735eSMichael S. Tsirkin apic_set_bit(s->irr, vector_num); 404574bbf7bSbellard if (trigger_mode) 405edf9735eSMichael S. Tsirkin apic_set_bit(s->tmr, vector_num); 406574bbf7bSbellard else 407edf9735eSMichael S. Tsirkin apic_reset_bit(s->tmr, vector_num); 408e5ad936bSJan Kiszka if (s->vapic_paddr) { 409e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC); 410e5ad936bSJan Kiszka /* 411e5ad936bSJan Kiszka * The vcpu thread needs to see the new IRR before we pull its current 412e5ad936bSJan Kiszka * TPR value. That way, if we miss a lowering of the TRP, the guest 413e5ad936bSJan Kiszka * has the chance to notice the new IRR and poll for IRQs on its own. 414e5ad936bSJan Kiszka */ 415e5ad936bSJan Kiszka smp_wmb(); 416e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 417e5ad936bSJan Kiszka } 418574bbf7bSbellard apic_update_irq(s); 419574bbf7bSbellard } 420574bbf7bSbellard 421dae01685SJan Kiszka static void apic_eoi(APICCommonState *s) 422574bbf7bSbellard { 423574bbf7bSbellard int isrv; 424574bbf7bSbellard isrv = get_highest_priority_int(s->isr); 425574bbf7bSbellard if (isrv < 0) 426574bbf7bSbellard return; 427edf9735eSMichael S. Tsirkin apic_reset_bit(s->isr, isrv); 428edf9735eSMichael S. Tsirkin if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) { 4290280b571SJan Kiszka ioapic_eoi_broadcast(isrv); 4300280b571SJan Kiszka } 431e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC); 432574bbf7bSbellard apic_update_irq(s); 433574bbf7bSbellard } 434574bbf7bSbellard 435678e12ccSGleb Natapov static int apic_find_dest(uint8_t dest) 436678e12ccSGleb Natapov { 437dae01685SJan Kiszka APICCommonState *apic = local_apics[dest]; 438678e12ccSGleb Natapov int i; 439678e12ccSGleb Natapov 440678e12ccSGleb Natapov if (apic && apic->id == dest) 4411dfe3282SIgor Mammedov return dest; /* shortcut in case apic->id == local_apics[dest]->id */ 442678e12ccSGleb Natapov 443678e12ccSGleb Natapov for (i = 0; i < MAX_APICS; i++) { 444678e12ccSGleb Natapov apic = local_apics[i]; 445678e12ccSGleb Natapov if (apic && apic->id == dest) 446678e12ccSGleb Natapov return i; 447b538e53eSAlex Williamson if (!apic) 448b538e53eSAlex Williamson break; 449678e12ccSGleb Natapov } 450678e12ccSGleb Natapov 451678e12ccSGleb Natapov return -1; 452678e12ccSGleb Natapov } 453678e12ccSGleb Natapov 454d3e9db93Sbellard static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, 455d3e9db93Sbellard uint8_t dest, uint8_t dest_mode) 456d592d303Sbellard { 457dae01685SJan Kiszka APICCommonState *apic_iter; 458d3e9db93Sbellard int i; 459d592d303Sbellard 460d592d303Sbellard if (dest_mode == 0) { 461d3e9db93Sbellard if (dest == 0xff) { 462d3e9db93Sbellard memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t)); 463d3e9db93Sbellard } else { 464678e12ccSGleb Natapov int idx = apic_find_dest(dest); 465d3e9db93Sbellard memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); 466678e12ccSGleb Natapov if (idx >= 0) 467edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, idx); 468d3e9db93Sbellard } 469d592d303Sbellard } else { 470d592d303Sbellard /* XXX: cluster mode */ 471d3e9db93Sbellard memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); 472d3e9db93Sbellard for(i = 0; i < MAX_APICS; i++) { 473d3e9db93Sbellard apic_iter = local_apics[i]; 474d3e9db93Sbellard if (apic_iter) { 475d3e9db93Sbellard if (apic_iter->dest_mode == 0xf) { 476d592d303Sbellard if (dest & apic_iter->log_dest) 477edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, i); 478d3e9db93Sbellard } else if (apic_iter->dest_mode == 0x0) { 479d3e9db93Sbellard if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && 480d3e9db93Sbellard (dest & apic_iter->log_dest & 0x0f)) { 481edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, i); 482d592d303Sbellard } 483d592d303Sbellard } 484b538e53eSAlex Williamson } else { 485b538e53eSAlex Williamson break; 486d3e9db93Sbellard } 487d3e9db93Sbellard } 488d3e9db93Sbellard } 489d592d303Sbellard } 490d592d303Sbellard 491dae01685SJan Kiszka static void apic_startup(APICCommonState *s, int vector_num) 492e0fd8781Sbellard { 493b09ea7d5SGleb Natapov s->sipi_vector = vector_num; 494c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); 495b09ea7d5SGleb Natapov } 496b09ea7d5SGleb Natapov 497d3b0c9e9Sxiaoqiang zhao void apic_sipi(DeviceState *dev) 498b09ea7d5SGleb Natapov { 499927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 50092a16d7aSBlue Swirl 501d8ed887bSAndreas Färber cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); 502b09ea7d5SGleb Natapov 503b09ea7d5SGleb Natapov if (!s->wait_for_sipi) 504e0fd8781Sbellard return; 505e9f9d6b1SAndreas Färber cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector); 506b09ea7d5SGleb Natapov s->wait_for_sipi = 0; 507e0fd8781Sbellard } 508e0fd8781Sbellard 509d3b0c9e9Sxiaoqiang zhao static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode, 510d592d303Sbellard uint8_t delivery_mode, uint8_t vector_num, 5111f6f408cSJan Kiszka uint8_t trigger_mode) 512d592d303Sbellard { 513927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 514d3e9db93Sbellard uint32_t deliver_bitmask[MAX_APIC_WORDS]; 515d592d303Sbellard int dest_shorthand = (s->icr[0] >> 18) & 3; 516dae01685SJan Kiszka APICCommonState *apic_iter; 517d592d303Sbellard 518e0fd8781Sbellard switch (dest_shorthand) { 519e0fd8781Sbellard case 0: 520d3e9db93Sbellard apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); 521e0fd8781Sbellard break; 522e0fd8781Sbellard case 1: 523d3e9db93Sbellard memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); 5241dfe3282SIgor Mammedov apic_set_bit(deliver_bitmask, s->id); 525e0fd8781Sbellard break; 526e0fd8781Sbellard case 2: 527d3e9db93Sbellard memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); 528e0fd8781Sbellard break; 529e0fd8781Sbellard case 3: 530d3e9db93Sbellard memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); 5311dfe3282SIgor Mammedov apic_reset_bit(deliver_bitmask, s->id); 532e0fd8781Sbellard break; 533e0fd8781Sbellard } 534e0fd8781Sbellard 535d592d303Sbellard switch (delivery_mode) { 536d592d303Sbellard case APIC_DM_INIT: 537d592d303Sbellard { 538d592d303Sbellard int trig_mode = (s->icr[0] >> 15) & 1; 539d592d303Sbellard int level = (s->icr[0] >> 14) & 1; 540d592d303Sbellard if (level == 0 && trig_mode == 1) { 541d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 542d3e9db93Sbellard apic_iter->arb_id = apic_iter->id ); 543d592d303Sbellard return; 544d592d303Sbellard } 545d592d303Sbellard } 546d592d303Sbellard break; 547d592d303Sbellard 548d592d303Sbellard case APIC_DM_SIPI: 549d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 550d3e9db93Sbellard apic_startup(apic_iter, vector_num) ); 551d592d303Sbellard return; 552d592d303Sbellard } 553d592d303Sbellard 5541f6f408cSJan Kiszka apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); 555d592d303Sbellard } 556d592d303Sbellard 557a94820ddSJan Kiszka static bool apic_check_pic(APICCommonState *s) 558a94820ddSJan Kiszka { 559be9f8a08SZhu Guihua DeviceState *dev = (DeviceState *)s; 560be9f8a08SZhu Guihua 561be9f8a08SZhu Guihua if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) { 562a94820ddSJan Kiszka return false; 563a94820ddSJan Kiszka } 564be9f8a08SZhu Guihua apic_deliver_pic_intr(dev, 1); 565a94820ddSJan Kiszka return true; 566a94820ddSJan Kiszka } 567a94820ddSJan Kiszka 568d3b0c9e9Sxiaoqiang zhao int apic_get_interrupt(DeviceState *dev) 569574bbf7bSbellard { 570927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 571574bbf7bSbellard int intno; 572574bbf7bSbellard 573574bbf7bSbellard /* if the APIC is installed or enabled, we let the 8259 handle the 574574bbf7bSbellard IRQs */ 575574bbf7bSbellard if (!s) 576574bbf7bSbellard return -1; 577574bbf7bSbellard if (!(s->spurious_vec & APIC_SV_ENABLE)) 578574bbf7bSbellard return -1; 579574bbf7bSbellard 580e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 5810fbfbb59SGleb Natapov intno = apic_irq_pending(s); 5820fbfbb59SGleb Natapov 5835224c88dSPaolo Bonzini /* if there is an interrupt from the 8259, let the caller handle 5845224c88dSPaolo Bonzini * that first since ExtINT interrupts ignore the priority. 5855224c88dSPaolo Bonzini */ 5865224c88dSPaolo Bonzini if (intno == 0 || apic_check_pic(s)) { 587e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 588574bbf7bSbellard return -1; 5890fbfbb59SGleb Natapov } else if (intno < 0) { 590e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 591d592d303Sbellard return s->spurious_vec & 0xff; 5920fbfbb59SGleb Natapov } 593edf9735eSMichael S. Tsirkin apic_reset_bit(s->irr, intno); 594edf9735eSMichael S. Tsirkin apic_set_bit(s->isr, intno); 595e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 5963db3659bSJan Kiszka 597574bbf7bSbellard apic_update_irq(s); 5983db3659bSJan Kiszka 599574bbf7bSbellard return intno; 600574bbf7bSbellard } 601574bbf7bSbellard 602d3b0c9e9Sxiaoqiang zhao int apic_accept_pic_intr(DeviceState *dev) 6030e21e12bSths { 604927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 6050e21e12bSths uint32_t lvt0; 6060e21e12bSths 6070e21e12bSths if (!s) 6080e21e12bSths return -1; 6090e21e12bSths 6100e21e12bSths lvt0 = s->lvt[APIC_LVT_LINT0]; 6110e21e12bSths 612a5b38b51Saurel32 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || 613a5b38b51Saurel32 (lvt0 & APIC_LVT_MASKED) == 0) 61478cafff8SSergio Lopez return isa_pic != NULL; 6150e21e12bSths 6160e21e12bSths return 0; 6170e21e12bSths } 6180e21e12bSths 619dae01685SJan Kiszka static void apic_timer_update(APICCommonState *s, int64_t current_time) 620574bbf7bSbellard { 6217a380ca3SJan Kiszka if (apic_next_timer(s, current_time)) { 622bc72ad67SAlex Bligh timer_mod(s->timer, s->next_time); 623574bbf7bSbellard } else { 624bc72ad67SAlex Bligh timer_del(s->timer); 625574bbf7bSbellard } 626574bbf7bSbellard } 627574bbf7bSbellard 628574bbf7bSbellard static void apic_timer(void *opaque) 629574bbf7bSbellard { 630dae01685SJan Kiszka APICCommonState *s = opaque; 631574bbf7bSbellard 632cf6d64bfSBlue Swirl apic_local_deliver(s, APIC_LVT_TIMER); 633574bbf7bSbellard apic_timer_update(s, s->next_time); 634574bbf7bSbellard } 635574bbf7bSbellard 63621f80e8fSPeter Maydell static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size) 637574bbf7bSbellard { 638d3b0c9e9Sxiaoqiang zhao DeviceState *dev; 639dae01685SJan Kiszka APICCommonState *s; 640574bbf7bSbellard uint32_t val; 641574bbf7bSbellard int index; 642574bbf7bSbellard 64321f80e8fSPeter Maydell if (size < 4) { 64421f80e8fSPeter Maydell return 0; 64521f80e8fSPeter Maydell } 64621f80e8fSPeter Maydell 647d3b0c9e9Sxiaoqiang zhao dev = cpu_get_current_apic(); 648d3b0c9e9Sxiaoqiang zhao if (!dev) { 649574bbf7bSbellard return 0; 6500e26b7b8SBlue Swirl } 651927d5a1dSWanpeng Li s = APIC(dev); 652574bbf7bSbellard 653574bbf7bSbellard index = (addr >> 4) & 0xff; 654574bbf7bSbellard switch(index) { 655574bbf7bSbellard case 0x02: /* id */ 656574bbf7bSbellard val = s->id << 24; 657574bbf7bSbellard break; 658574bbf7bSbellard case 0x03: /* version */ 659aa93200bSGabriel L. Somlo val = s->version | ((APIC_LVT_NB - 1) << 16); 660574bbf7bSbellard break; 661574bbf7bSbellard case 0x08: 662e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 663e5ad936bSJan Kiszka if (apic_report_tpr_access) { 66460671e58SAndreas Färber cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ); 665e5ad936bSJan Kiszka } 666574bbf7bSbellard val = s->tpr; 667574bbf7bSbellard break; 668d592d303Sbellard case 0x09: 669d592d303Sbellard val = apic_get_arb_pri(s); 670d592d303Sbellard break; 671574bbf7bSbellard case 0x0a: 672574bbf7bSbellard /* ppr */ 673574bbf7bSbellard val = apic_get_ppr(s); 674574bbf7bSbellard break; 675b237db36Saurel32 case 0x0b: 676b237db36Saurel32 val = 0; 677b237db36Saurel32 break; 678d592d303Sbellard case 0x0d: 679d592d303Sbellard val = s->log_dest << 24; 680d592d303Sbellard break; 681d592d303Sbellard case 0x0e: 682d6c140a7SJan Kiszka val = (s->dest_mode << 28) | 0xfffffff; 683d592d303Sbellard break; 684574bbf7bSbellard case 0x0f: 685574bbf7bSbellard val = s->spurious_vec; 686574bbf7bSbellard break; 687574bbf7bSbellard case 0x10 ... 0x17: 688574bbf7bSbellard val = s->isr[index & 7]; 689574bbf7bSbellard break; 690574bbf7bSbellard case 0x18 ... 0x1f: 691574bbf7bSbellard val = s->tmr[index & 7]; 692574bbf7bSbellard break; 693574bbf7bSbellard case 0x20 ... 0x27: 694574bbf7bSbellard val = s->irr[index & 7]; 695574bbf7bSbellard break; 696574bbf7bSbellard case 0x28: 697574bbf7bSbellard val = s->esr; 698574bbf7bSbellard break; 699574bbf7bSbellard case 0x30: 700574bbf7bSbellard case 0x31: 701574bbf7bSbellard val = s->icr[index & 1]; 702574bbf7bSbellard break; 703e0fd8781Sbellard case 0x32 ... 0x37: 704e0fd8781Sbellard val = s->lvt[index - 0x32]; 705e0fd8781Sbellard break; 706574bbf7bSbellard case 0x38: 707574bbf7bSbellard val = s->initial_count; 708574bbf7bSbellard break; 709574bbf7bSbellard case 0x39: 710574bbf7bSbellard val = apic_get_current_count(s); 711574bbf7bSbellard break; 712574bbf7bSbellard case 0x3e: 713574bbf7bSbellard val = s->divide_conf; 714574bbf7bSbellard break; 715574bbf7bSbellard default: 716a22bf99cSPavel Butsykin s->esr |= APIC_ESR_ILLEGAL_ADDRESS; 717574bbf7bSbellard val = 0; 718574bbf7bSbellard break; 719574bbf7bSbellard } 720d8023f31SBlue Swirl trace_apic_mem_readl(addr, val); 721574bbf7bSbellard return val; 722574bbf7bSbellard } 723574bbf7bSbellard 724267ee357SRadim Krčmář static void apic_send_msi(MSIMessage *msi) 72554c96da7SMichael S. Tsirkin { 726267ee357SRadim Krčmář uint64_t addr = msi->address; 727267ee357SRadim Krčmář uint32_t data = msi->data; 72854c96da7SMichael S. Tsirkin uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; 72954c96da7SMichael S. Tsirkin uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; 73054c96da7SMichael S. Tsirkin uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; 73154c96da7SMichael S. Tsirkin uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; 73254c96da7SMichael S. Tsirkin uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; 73354c96da7SMichael S. Tsirkin /* XXX: Ignore redirection hint. */ 7341f6f408cSJan Kiszka apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode); 73554c96da7SMichael S. Tsirkin } 73654c96da7SMichael S. Tsirkin 73721f80e8fSPeter Maydell static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val, 73821f80e8fSPeter Maydell unsigned size) 739574bbf7bSbellard { 740d3b0c9e9Sxiaoqiang zhao DeviceState *dev; 741dae01685SJan Kiszka APICCommonState *s; 74254c96da7SMichael S. Tsirkin int index = (addr >> 4) & 0xff; 74321f80e8fSPeter Maydell 74421f80e8fSPeter Maydell if (size < 4) { 74521f80e8fSPeter Maydell return; 74621f80e8fSPeter Maydell } 74721f80e8fSPeter Maydell 74854c96da7SMichael S. Tsirkin if (addr > 0xfff || !index) { 74954c96da7SMichael S. Tsirkin /* MSI and MMIO APIC are at the same memory location, 75054c96da7SMichael S. Tsirkin * but actually not on the global bus: MSI is on PCI bus 75154c96da7SMichael S. Tsirkin * APIC is connected directly to the CPU. 75254c96da7SMichael S. Tsirkin * Mapping them on the global bus happens to work because 75354c96da7SMichael S. Tsirkin * MSI registers are reserved in APIC MMIO and vice versa. */ 754267ee357SRadim Krčmář MSIMessage msi = { .address = addr, .data = val }; 755267ee357SRadim Krčmář apic_send_msi(&msi); 75654c96da7SMichael S. Tsirkin return; 75754c96da7SMichael S. Tsirkin } 758574bbf7bSbellard 759d3b0c9e9Sxiaoqiang zhao dev = cpu_get_current_apic(); 760d3b0c9e9Sxiaoqiang zhao if (!dev) { 761574bbf7bSbellard return; 7620e26b7b8SBlue Swirl } 763927d5a1dSWanpeng Li s = APIC(dev); 764574bbf7bSbellard 765d8023f31SBlue Swirl trace_apic_mem_writel(addr, val); 766574bbf7bSbellard 767574bbf7bSbellard switch(index) { 768574bbf7bSbellard case 0x02: 769574bbf7bSbellard s->id = (val >> 24); 770574bbf7bSbellard break; 771e0fd8781Sbellard case 0x03: 772e0fd8781Sbellard break; 773574bbf7bSbellard case 0x08: 774e5ad936bSJan Kiszka if (apic_report_tpr_access) { 77560671e58SAndreas Färber cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE); 776e5ad936bSJan Kiszka } 777574bbf7bSbellard s->tpr = val; 778e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 779d592d303Sbellard apic_update_irq(s); 780574bbf7bSbellard break; 781e0fd8781Sbellard case 0x09: 782e0fd8781Sbellard case 0x0a: 783e0fd8781Sbellard break; 784574bbf7bSbellard case 0x0b: /* EOI */ 785574bbf7bSbellard apic_eoi(s); 786574bbf7bSbellard break; 787d592d303Sbellard case 0x0d: 788d592d303Sbellard s->log_dest = val >> 24; 789d592d303Sbellard break; 790d592d303Sbellard case 0x0e: 791d592d303Sbellard s->dest_mode = val >> 28; 792d592d303Sbellard break; 793574bbf7bSbellard case 0x0f: 794574bbf7bSbellard s->spurious_vec = val & 0x1ff; 795d592d303Sbellard apic_update_irq(s); 796574bbf7bSbellard break; 797e0fd8781Sbellard case 0x10 ... 0x17: 798e0fd8781Sbellard case 0x18 ... 0x1f: 799e0fd8781Sbellard case 0x20 ... 0x27: 800e0fd8781Sbellard case 0x28: 801e0fd8781Sbellard break; 802574bbf7bSbellard case 0x30: 803d592d303Sbellard s->icr[0] = val; 804d3b0c9e9Sxiaoqiang zhao apic_deliver(dev, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, 805d592d303Sbellard (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff), 8061f6f408cSJan Kiszka (s->icr[0] >> 15) & 1); 807d592d303Sbellard break; 808574bbf7bSbellard case 0x31: 809d592d303Sbellard s->icr[1] = val; 810574bbf7bSbellard break; 811574bbf7bSbellard case 0x32 ... 0x37: 812574bbf7bSbellard { 813574bbf7bSbellard int n = index - 0x32; 814574bbf7bSbellard s->lvt[n] = val; 815a94820ddSJan Kiszka if (n == APIC_LVT_TIMER) { 816bc72ad67SAlex Bligh apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 817a94820ddSJan Kiszka } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) { 818a94820ddSJan Kiszka apic_update_irq(s); 819a94820ddSJan Kiszka } 820574bbf7bSbellard } 821574bbf7bSbellard break; 822574bbf7bSbellard case 0x38: 823574bbf7bSbellard s->initial_count = val; 824bc72ad67SAlex Bligh s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 825574bbf7bSbellard apic_timer_update(s, s->initial_count_load_time); 826574bbf7bSbellard break; 827e0fd8781Sbellard case 0x39: 828e0fd8781Sbellard break; 829574bbf7bSbellard case 0x3e: 830574bbf7bSbellard { 831574bbf7bSbellard int v; 832574bbf7bSbellard s->divide_conf = val & 0xb; 833574bbf7bSbellard v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); 834574bbf7bSbellard s->count_shift = (v + 1) & 7; 835574bbf7bSbellard } 836574bbf7bSbellard break; 837574bbf7bSbellard default: 838a22bf99cSPavel Butsykin s->esr |= APIC_ESR_ILLEGAL_ADDRESS; 839574bbf7bSbellard break; 840574bbf7bSbellard } 841574bbf7bSbellard } 842574bbf7bSbellard 843e5ad936bSJan Kiszka static void apic_pre_save(APICCommonState *s) 844e5ad936bSJan Kiszka { 845e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 846e5ad936bSJan Kiszka } 847e5ad936bSJan Kiszka 8487a380ca3SJan Kiszka static void apic_post_load(APICCommonState *s) 8497a380ca3SJan Kiszka { 8507a380ca3SJan Kiszka if (s->timer_expiry != -1) { 851bc72ad67SAlex Bligh timer_mod(s->timer, s->timer_expiry); 8527a380ca3SJan Kiszka } else { 853bc72ad67SAlex Bligh timer_del(s->timer); 8547a380ca3SJan Kiszka } 8557a380ca3SJan Kiszka } 8567a380ca3SJan Kiszka 857312b4234SAvi Kivity static const MemoryRegionOps apic_io_ops = { 85821f80e8fSPeter Maydell .read = apic_mem_read, 85921f80e8fSPeter Maydell .write = apic_mem_write, 86021f80e8fSPeter Maydell .impl.min_access_size = 1, 86121f80e8fSPeter Maydell .impl.max_access_size = 4, 86221f80e8fSPeter Maydell .valid.min_access_size = 1, 86321f80e8fSPeter Maydell .valid.max_access_size = 4, 864312b4234SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 865574bbf7bSbellard }; 866574bbf7bSbellard 867ff6986ceSxiaoqiang zhao static void apic_realize(DeviceState *dev, Error **errp) 8688546b099SBlue Swirl { 869927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 870889211b1SIgor Mammedov 8711dfe3282SIgor Mammedov if (s->id >= MAX_APICS) { 8721dfe3282SIgor Mammedov error_setg(errp, "%s initialization failed. APIC ID %d is invalid", 8731dfe3282SIgor Mammedov object_get_typename(OBJECT(dev)), s->id); 874889211b1SIgor Mammedov return; 875889211b1SIgor Mammedov } 876ff6986ceSxiaoqiang zhao 8771437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi", 878baaeda08SIgor Mammedov APIC_SPACE_SIZE); 8798546b099SBlue Swirl 880bc72ad67SAlex Bligh s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s); 8811dfe3282SIgor Mammedov local_apics[s->id] = s; 88208a82ac0SJan Kiszka 883226419d6SMichael S. Tsirkin msi_nonbroken = true; 8848546b099SBlue Swirl } 8858546b099SBlue Swirl 886b69c3c21SMarkus Armbruster static void apic_unrealize(DeviceState *dev) 8879c156f9dSIgor Mammedov { 888927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 8899c156f9dSIgor Mammedov 8909c156f9dSIgor Mammedov timer_del(s->timer); 8919c156f9dSIgor Mammedov timer_free(s->timer); 8929c156f9dSIgor Mammedov local_apics[s->id] = NULL; 8939c156f9dSIgor Mammedov } 8949c156f9dSIgor Mammedov 895999e12bbSAnthony Liguori static void apic_class_init(ObjectClass *klass, void *data) 896999e12bbSAnthony Liguori { 897999e12bbSAnthony Liguori APICCommonClass *k = APIC_COMMON_CLASS(klass); 898999e12bbSAnthony Liguori 899ff6986ceSxiaoqiang zhao k->realize = apic_realize; 9009c156f9dSIgor Mammedov k->unrealize = apic_unrealize; 901999e12bbSAnthony Liguori k->set_base = apic_set_base; 902999e12bbSAnthony Liguori k->set_tpr = apic_set_tpr; 903e5ad936bSJan Kiszka k->get_tpr = apic_get_tpr; 904e5ad936bSJan Kiszka k->vapic_base_update = apic_vapic_base_update; 905999e12bbSAnthony Liguori k->external_nmi = apic_external_nmi; 906e5ad936bSJan Kiszka k->pre_save = apic_pre_save; 907999e12bbSAnthony Liguori k->post_load = apic_post_load; 908267ee357SRadim Krčmář k->send_msi = apic_send_msi; 909999e12bbSAnthony Liguori } 910999e12bbSAnthony Liguori 9118c43a6f0SAndreas Färber static const TypeInfo apic_info = { 912927d5a1dSWanpeng Li .name = TYPE_APIC, 91339bffca2SAnthony Liguori .instance_size = sizeof(APICCommonState), 91439bffca2SAnthony Liguori .parent = TYPE_APIC_COMMON, 915999e12bbSAnthony Liguori .class_init = apic_class_init, 9168546b099SBlue Swirl }; 9178546b099SBlue Swirl 91883f7d43aSAndreas Färber static void apic_register_types(void) 9198546b099SBlue Swirl { 92039bffca2SAnthony Liguori type_register_static(&apic_info); 9218546b099SBlue Swirl } 9228546b099SBlue Swirl 92383f7d43aSAndreas Färber type_init(apic_register_types) 924