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" 25*852c27e2SPaolo 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" 31574bbf7bSbellard 32889211b1SIgor Mammedov #define MAX_APICS 255 33d3e9db93Sbellard #define MAX_APIC_WORDS 8 34d3e9db93Sbellard 35e5ad936bSJan Kiszka #define SYNC_FROM_VAPIC 0x1 36e5ad936bSJan Kiszka #define SYNC_TO_VAPIC 0x2 37e5ad936bSJan Kiszka #define SYNC_ISR_IRR_TO_VAPIC 0x4 38e5ad936bSJan Kiszka 39dae01685SJan Kiszka static APICCommonState *local_apics[MAX_APICS + 1]; 4054c96da7SMichael S. Tsirkin 41927d5a1dSWanpeng Li #define TYPE_APIC "apic" 42927d5a1dSWanpeng Li #define APIC(obj) \ 43927d5a1dSWanpeng Li OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC) 44927d5a1dSWanpeng Li 45dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode); 46dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s); 47610626afSaliguori static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, 48610626afSaliguori uint8_t dest, uint8_t dest_mode); 49d592d303Sbellard 503b63c04eSaurel32 /* Find first bit starting from msb */ 51edf9735eSMichael S. Tsirkin static int apic_fls_bit(uint32_t value) 523b63c04eSaurel32 { 533b63c04eSaurel32 return 31 - clz32(value); 543b63c04eSaurel32 } 553b63c04eSaurel32 56e95f5491Saurel32 /* Find first bit starting from lsb */ 57edf9735eSMichael S. Tsirkin static int apic_ffs_bit(uint32_t value) 58d3e9db93Sbellard { 59bb7e7293Saurel32 return ctz32(value); 60d3e9db93Sbellard } 61d3e9db93Sbellard 62edf9735eSMichael S. Tsirkin static inline void apic_reset_bit(uint32_t *tab, int index) 63d3e9db93Sbellard { 64d3e9db93Sbellard int i, mask; 65d3e9db93Sbellard i = index >> 5; 66d3e9db93Sbellard mask = 1 << (index & 0x1f); 67d3e9db93Sbellard tab[i] &= ~mask; 68d3e9db93Sbellard } 69d3e9db93Sbellard 70e5ad936bSJan Kiszka /* return -1 if no bit is set */ 71e5ad936bSJan Kiszka static int get_highest_priority_int(uint32_t *tab) 72e5ad936bSJan Kiszka { 73e5ad936bSJan Kiszka int i; 74e5ad936bSJan Kiszka for (i = 7; i >= 0; i--) { 75e5ad936bSJan Kiszka if (tab[i] != 0) { 76edf9735eSMichael S. Tsirkin return i * 32 + apic_fls_bit(tab[i]); 77e5ad936bSJan Kiszka } 78e5ad936bSJan Kiszka } 79e5ad936bSJan Kiszka return -1; 80e5ad936bSJan Kiszka } 81e5ad936bSJan Kiszka 82e5ad936bSJan Kiszka static void apic_sync_vapic(APICCommonState *s, int sync_type) 83e5ad936bSJan Kiszka { 84e5ad936bSJan Kiszka VAPICState vapic_state; 85e5ad936bSJan Kiszka size_t length; 86e5ad936bSJan Kiszka off_t start; 87e5ad936bSJan Kiszka int vector; 88e5ad936bSJan Kiszka 89e5ad936bSJan Kiszka if (!s->vapic_paddr) { 90e5ad936bSJan Kiszka return; 91e5ad936bSJan Kiszka } 92e5ad936bSJan Kiszka if (sync_type & SYNC_FROM_VAPIC) { 93eb6282f2SStefan Weil cpu_physical_memory_read(s->vapic_paddr, &vapic_state, 94eb6282f2SStefan Weil sizeof(vapic_state)); 95e5ad936bSJan Kiszka s->tpr = vapic_state.tpr; 96e5ad936bSJan Kiszka } 97e5ad936bSJan Kiszka if (sync_type & (SYNC_TO_VAPIC | SYNC_ISR_IRR_TO_VAPIC)) { 98e5ad936bSJan Kiszka start = offsetof(VAPICState, isr); 99e5ad936bSJan Kiszka length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr); 100e5ad936bSJan Kiszka 101e5ad936bSJan Kiszka if (sync_type & SYNC_TO_VAPIC) { 10260e82579SAndreas Färber assert(qemu_cpu_is_self(CPU(s->cpu))); 103e5ad936bSJan Kiszka 104e5ad936bSJan Kiszka vapic_state.tpr = s->tpr; 105e5ad936bSJan Kiszka vapic_state.enabled = 1; 106e5ad936bSJan Kiszka start = 0; 107e5ad936bSJan Kiszka length = sizeof(VAPICState); 108e5ad936bSJan Kiszka } 109e5ad936bSJan Kiszka 110e5ad936bSJan Kiszka vector = get_highest_priority_int(s->isr); 111e5ad936bSJan Kiszka if (vector < 0) { 112e5ad936bSJan Kiszka vector = 0; 113e5ad936bSJan Kiszka } 114e5ad936bSJan Kiszka vapic_state.isr = vector & 0xf0; 115e5ad936bSJan Kiszka 116e5ad936bSJan Kiszka vapic_state.zero = 0; 117e5ad936bSJan Kiszka 118e5ad936bSJan Kiszka vector = get_highest_priority_int(s->irr); 119e5ad936bSJan Kiszka if (vector < 0) { 120e5ad936bSJan Kiszka vector = 0; 121e5ad936bSJan Kiszka } 122e5ad936bSJan Kiszka vapic_state.irr = vector & 0xff; 123e5ad936bSJan Kiszka 1243c8133f9SPeter Maydell address_space_write_rom(&address_space_memory, 1252a221651SEdgar E. Iglesias s->vapic_paddr + start, 1263c8133f9SPeter Maydell MEMTXATTRS_UNSPECIFIED, 127e5ad936bSJan Kiszka ((void *)&vapic_state) + start, length); 128e5ad936bSJan Kiszka } 129e5ad936bSJan Kiszka } 130e5ad936bSJan Kiszka 131e5ad936bSJan Kiszka static void apic_vapic_base_update(APICCommonState *s) 132e5ad936bSJan Kiszka { 133e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 134e5ad936bSJan Kiszka } 135e5ad936bSJan Kiszka 136dae01685SJan Kiszka static void apic_local_deliver(APICCommonState *s, int vector) 137a5b38b51Saurel32 { 138a5b38b51Saurel32 uint32_t lvt = s->lvt[vector]; 139a5b38b51Saurel32 int trigger_mode; 140a5b38b51Saurel32 141d8023f31SBlue Swirl trace_apic_local_deliver(vector, (lvt >> 8) & 7); 142d8023f31SBlue Swirl 143a5b38b51Saurel32 if (lvt & APIC_LVT_MASKED) 144a5b38b51Saurel32 return; 145a5b38b51Saurel32 146a5b38b51Saurel32 switch ((lvt >> 8) & 7) { 147a5b38b51Saurel32 case APIC_DM_SMI: 148c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SMI); 149a5b38b51Saurel32 break; 150a5b38b51Saurel32 151a5b38b51Saurel32 case APIC_DM_NMI: 152c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_NMI); 153a5b38b51Saurel32 break; 154a5b38b51Saurel32 155a5b38b51Saurel32 case APIC_DM_EXTINT: 156c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_HARD); 157a5b38b51Saurel32 break; 158a5b38b51Saurel32 159a5b38b51Saurel32 case APIC_DM_FIXED: 160a5b38b51Saurel32 trigger_mode = APIC_TRIGGER_EDGE; 161a5b38b51Saurel32 if ((vector == APIC_LVT_LINT0 || vector == APIC_LVT_LINT1) && 162a5b38b51Saurel32 (lvt & APIC_LVT_LEVEL_TRIGGER)) 163a5b38b51Saurel32 trigger_mode = APIC_TRIGGER_LEVEL; 164a5b38b51Saurel32 apic_set_irq(s, lvt & 0xff, trigger_mode); 165a5b38b51Saurel32 } 166a5b38b51Saurel32 } 167a5b38b51Saurel32 168d3b0c9e9Sxiaoqiang zhao void apic_deliver_pic_intr(DeviceState *dev, int level) 1691a7de94aSaurel32 { 170927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 17192a16d7aSBlue Swirl 172cf6d64bfSBlue Swirl if (level) { 173cf6d64bfSBlue Swirl apic_local_deliver(s, APIC_LVT_LINT0); 174cf6d64bfSBlue Swirl } else { 1751a7de94aSaurel32 uint32_t lvt = s->lvt[APIC_LVT_LINT0]; 1761a7de94aSaurel32 1771a7de94aSaurel32 switch ((lvt >> 8) & 7) { 1781a7de94aSaurel32 case APIC_DM_FIXED: 1791a7de94aSaurel32 if (!(lvt & APIC_LVT_LEVEL_TRIGGER)) 1801a7de94aSaurel32 break; 181edf9735eSMichael S. Tsirkin apic_reset_bit(s->irr, lvt & 0xff); 1821a7de94aSaurel32 /* fall through */ 1831a7de94aSaurel32 case APIC_DM_EXTINT: 1848092cb71SPaolo Bonzini apic_update_irq(s); 1851a7de94aSaurel32 break; 1861a7de94aSaurel32 } 1871a7de94aSaurel32 } 1881a7de94aSaurel32 } 1891a7de94aSaurel32 190dae01685SJan Kiszka static void apic_external_nmi(APICCommonState *s) 19102c09195SJan Kiszka { 19202c09195SJan Kiszka apic_local_deliver(s, APIC_LVT_LINT1); 19302c09195SJan Kiszka } 19402c09195SJan Kiszka 195d3e9db93Sbellard #define foreach_apic(apic, deliver_bitmask, code) \ 196d3e9db93Sbellard {\ 1976d55574aSPeter Maydell int __i, __j;\ 198d3e9db93Sbellard for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\ 1996d55574aSPeter Maydell uint32_t __mask = deliver_bitmask[__i];\ 200d3e9db93Sbellard if (__mask) {\ 201d3e9db93Sbellard for(__j = 0; __j < 32; __j++) {\ 2026d55574aSPeter Maydell if (__mask & (1U << __j)) {\ 203d3e9db93Sbellard apic = local_apics[__i * 32 + __j];\ 204d3e9db93Sbellard if (apic) {\ 205d3e9db93Sbellard code;\ 206d3e9db93Sbellard }\ 207d3e9db93Sbellard }\ 208d3e9db93Sbellard }\ 209d3e9db93Sbellard }\ 210d3e9db93Sbellard }\ 211d3e9db93Sbellard } 212d3e9db93Sbellard 213d3e9db93Sbellard static void apic_bus_deliver(const uint32_t *deliver_bitmask, 2141f6f408cSJan Kiszka uint8_t delivery_mode, uint8_t vector_num, 215d592d303Sbellard uint8_t trigger_mode) 216d592d303Sbellard { 217dae01685SJan Kiszka APICCommonState *apic_iter; 218d592d303Sbellard 219d592d303Sbellard switch (delivery_mode) { 220d592d303Sbellard case APIC_DM_LOWPRI: 2218dd69b8fSbellard /* XXX: search for focus processor, arbitration */ 222d3e9db93Sbellard { 223d3e9db93Sbellard int i, d; 224d3e9db93Sbellard d = -1; 225d3e9db93Sbellard for(i = 0; i < MAX_APIC_WORDS; i++) { 226d3e9db93Sbellard if (deliver_bitmask[i]) { 227edf9735eSMichael S. Tsirkin d = i * 32 + apic_ffs_bit(deliver_bitmask[i]); 2288dd69b8fSbellard break; 229d3e9db93Sbellard } 230d3e9db93Sbellard } 231d3e9db93Sbellard if (d >= 0) { 232d3e9db93Sbellard apic_iter = local_apics[d]; 233d3e9db93Sbellard if (apic_iter) { 234d3e9db93Sbellard apic_set_irq(apic_iter, vector_num, trigger_mode); 235d3e9db93Sbellard } 236d3e9db93Sbellard } 237d3e9db93Sbellard } 238d3e9db93Sbellard return; 2398dd69b8fSbellard 240d592d303Sbellard case APIC_DM_FIXED: 241d592d303Sbellard break; 242d592d303Sbellard 243d592d303Sbellard case APIC_DM_SMI: 244e2eb9d3eSaurel32 foreach_apic(apic_iter, deliver_bitmask, 245c3affe56SAndreas Färber cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_SMI) 24660671e58SAndreas Färber ); 247e2eb9d3eSaurel32 return; 248e2eb9d3eSaurel32 249d592d303Sbellard case APIC_DM_NMI: 250e2eb9d3eSaurel32 foreach_apic(apic_iter, deliver_bitmask, 251c3affe56SAndreas Färber cpu_interrupt(CPU(apic_iter->cpu), CPU_INTERRUPT_NMI) 25260671e58SAndreas Färber ); 253e2eb9d3eSaurel32 return; 254d592d303Sbellard 255d592d303Sbellard case APIC_DM_INIT: 256d592d303Sbellard /* normal INIT IPI sent to processors */ 257d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 258c3affe56SAndreas Färber cpu_interrupt(CPU(apic_iter->cpu), 25960671e58SAndreas Färber CPU_INTERRUPT_INIT) 26060671e58SAndreas Färber ); 261d592d303Sbellard return; 262d592d303Sbellard 263d592d303Sbellard case APIC_DM_EXTINT: 264b1fc0348Sbellard /* handled in I/O APIC code */ 265d592d303Sbellard break; 266d592d303Sbellard 267d592d303Sbellard default: 268d592d303Sbellard return; 269d592d303Sbellard } 270d592d303Sbellard 271d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 272d3e9db93Sbellard apic_set_irq(apic_iter, vector_num, trigger_mode) ); 273d592d303Sbellard } 274574bbf7bSbellard 2751f6f408cSJan Kiszka void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode, 2761f6f408cSJan Kiszka uint8_t vector_num, uint8_t trigger_mode) 277610626afSaliguori { 278610626afSaliguori uint32_t deliver_bitmask[MAX_APIC_WORDS]; 279610626afSaliguori 280d8023f31SBlue Swirl trace_apic_deliver_irq(dest, dest_mode, delivery_mode, vector_num, 2811f6f408cSJan Kiszka trigger_mode); 282d8023f31SBlue Swirl 283610626afSaliguori apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); 2841f6f408cSJan Kiszka apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); 285610626afSaliguori } 286610626afSaliguori 287dae01685SJan Kiszka static void apic_set_base(APICCommonState *s, uint64_t val) 288574bbf7bSbellard { 289574bbf7bSbellard s->apicbase = (val & 0xfffff000) | 290574bbf7bSbellard (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); 291574bbf7bSbellard /* if disabled, cannot be enabled again */ 292574bbf7bSbellard if (!(val & MSR_IA32_APICBASE_ENABLE)) { 293574bbf7bSbellard s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; 29460671e58SAndreas Färber cpu_clear_apic_feature(&s->cpu->env); 295574bbf7bSbellard s->spurious_vec &= ~APIC_SV_ENABLE; 296574bbf7bSbellard } 297574bbf7bSbellard } 298574bbf7bSbellard 299dae01685SJan Kiszka static void apic_set_tpr(APICCommonState *s, uint8_t val) 300574bbf7bSbellard { 301e5ad936bSJan Kiszka /* Updates from cr8 are ignored while the VAPIC is active */ 302e5ad936bSJan Kiszka if (!s->vapic_paddr) { 303e5ad936bSJan Kiszka s->tpr = val << 4; 304d592d303Sbellard apic_update_irq(s); 3059230e66eSbellard } 306e5ad936bSJan Kiszka } 3079230e66eSbellard 3082cb9f06eSSergio Andres Gomez Del Real int apic_get_highest_priority_irr(DeviceState *dev) 3092cb9f06eSSergio Andres Gomez Del Real { 3102cb9f06eSSergio Andres Gomez Del Real APICCommonState *s; 3112cb9f06eSSergio Andres Gomez Del Real 3122cb9f06eSSergio Andres Gomez Del Real if (!dev) { 3132cb9f06eSSergio Andres Gomez Del Real /* no interrupts */ 3142cb9f06eSSergio Andres Gomez Del Real return -1; 3152cb9f06eSSergio Andres Gomez Del Real } 3162cb9f06eSSergio Andres Gomez Del Real s = APIC_COMMON(dev); 3172cb9f06eSSergio Andres Gomez Del Real return get_highest_priority_int(s->irr); 3182cb9f06eSSergio Andres Gomez Del Real } 3192cb9f06eSSergio Andres Gomez Del Real 320e5ad936bSJan Kiszka static uint8_t apic_get_tpr(APICCommonState *s) 321d592d303Sbellard { 322e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 323e5ad936bSJan Kiszka return s->tpr >> 4; 324d592d303Sbellard } 325d592d303Sbellard 32682a5e042SPavel Butsykin int apic_get_ppr(APICCommonState *s) 327574bbf7bSbellard { 328574bbf7bSbellard int tpr, isrv, ppr; 329574bbf7bSbellard 330574bbf7bSbellard tpr = (s->tpr >> 4); 331574bbf7bSbellard isrv = get_highest_priority_int(s->isr); 332574bbf7bSbellard if (isrv < 0) 333574bbf7bSbellard isrv = 0; 334574bbf7bSbellard isrv >>= 4; 335574bbf7bSbellard if (tpr >= isrv) 336574bbf7bSbellard ppr = s->tpr; 337574bbf7bSbellard else 338574bbf7bSbellard ppr = isrv << 4; 339574bbf7bSbellard return ppr; 340574bbf7bSbellard } 341574bbf7bSbellard 342dae01685SJan Kiszka static int apic_get_arb_pri(APICCommonState *s) 343d592d303Sbellard { 344d592d303Sbellard /* XXX: arbitration */ 345d592d303Sbellard return 0; 346d592d303Sbellard } 347d592d303Sbellard 3480fbfbb59SGleb Natapov 3490fbfbb59SGleb Natapov /* 3500fbfbb59SGleb Natapov * <0 - low prio interrupt, 3510fbfbb59SGleb Natapov * 0 - no interrupt, 3520fbfbb59SGleb Natapov * >0 - interrupt number 3530fbfbb59SGleb Natapov */ 354dae01685SJan Kiszka static int apic_irq_pending(APICCommonState *s) 3550fbfbb59SGleb Natapov { 3560fbfbb59SGleb Natapov int irrv, ppr; 35760e68042SPaolo Bonzini 35860e68042SPaolo Bonzini if (!(s->spurious_vec & APIC_SV_ENABLE)) { 35960e68042SPaolo Bonzini return 0; 36060e68042SPaolo Bonzini } 36160e68042SPaolo Bonzini 3620fbfbb59SGleb Natapov irrv = get_highest_priority_int(s->irr); 3630fbfbb59SGleb Natapov if (irrv < 0) { 3640fbfbb59SGleb Natapov return 0; 3650fbfbb59SGleb Natapov } 3660fbfbb59SGleb Natapov ppr = apic_get_ppr(s); 3670fbfbb59SGleb Natapov if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) { 3680fbfbb59SGleb Natapov return -1; 3690fbfbb59SGleb Natapov } 3700fbfbb59SGleb Natapov 3710fbfbb59SGleb Natapov return irrv; 3720fbfbb59SGleb Natapov } 3730fbfbb59SGleb Natapov 374574bbf7bSbellard /* signal the CPU if an irq is pending */ 375dae01685SJan Kiszka static void apic_update_irq(APICCommonState *s) 376574bbf7bSbellard { 377c3affe56SAndreas Färber CPUState *cpu; 378be9f8a08SZhu Guihua DeviceState *dev = (DeviceState *)s; 37960e82579SAndreas Färber 380c3affe56SAndreas Färber cpu = CPU(s->cpu); 38160e82579SAndreas Färber if (!qemu_cpu_is_self(cpu)) { 382c3affe56SAndreas Färber cpu_interrupt(cpu, CPU_INTERRUPT_POLL); 3835d62c43aSJan Kiszka } else if (apic_irq_pending(s) > 0) { 384c3affe56SAndreas Färber cpu_interrupt(cpu, CPU_INTERRUPT_HARD); 385be9f8a08SZhu Guihua } else if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) { 3868092cb71SPaolo Bonzini cpu_reset_interrupt(cpu, CPU_INTERRUPT_HARD); 387574bbf7bSbellard } 3880fbfbb59SGleb Natapov } 389574bbf7bSbellard 390d3b0c9e9Sxiaoqiang zhao void apic_poll_irq(DeviceState *dev) 391e5ad936bSJan Kiszka { 392927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 393e5ad936bSJan Kiszka 394e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 395e5ad936bSJan Kiszka apic_update_irq(s); 396e5ad936bSJan Kiszka } 397e5ad936bSJan Kiszka 398dae01685SJan Kiszka static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode) 399574bbf7bSbellard { 400edf9735eSMichael S. Tsirkin apic_report_irq_delivered(!apic_get_bit(s->irr, vector_num)); 40173822ec8Saliguori 402edf9735eSMichael S. Tsirkin apic_set_bit(s->irr, vector_num); 403574bbf7bSbellard if (trigger_mode) 404edf9735eSMichael S. Tsirkin apic_set_bit(s->tmr, vector_num); 405574bbf7bSbellard else 406edf9735eSMichael S. Tsirkin apic_reset_bit(s->tmr, vector_num); 407e5ad936bSJan Kiszka if (s->vapic_paddr) { 408e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_ISR_IRR_TO_VAPIC); 409e5ad936bSJan Kiszka /* 410e5ad936bSJan Kiszka * The vcpu thread needs to see the new IRR before we pull its current 411e5ad936bSJan Kiszka * TPR value. That way, if we miss a lowering of the TRP, the guest 412e5ad936bSJan Kiszka * has the chance to notice the new IRR and poll for IRQs on its own. 413e5ad936bSJan Kiszka */ 414e5ad936bSJan Kiszka smp_wmb(); 415e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 416e5ad936bSJan Kiszka } 417574bbf7bSbellard apic_update_irq(s); 418574bbf7bSbellard } 419574bbf7bSbellard 420dae01685SJan Kiszka static void apic_eoi(APICCommonState *s) 421574bbf7bSbellard { 422574bbf7bSbellard int isrv; 423574bbf7bSbellard isrv = get_highest_priority_int(s->isr); 424574bbf7bSbellard if (isrv < 0) 425574bbf7bSbellard return; 426edf9735eSMichael S. Tsirkin apic_reset_bit(s->isr, isrv); 427edf9735eSMichael S. Tsirkin if (!(s->spurious_vec & APIC_SV_DIRECTED_IO) && apic_get_bit(s->tmr, isrv)) { 4280280b571SJan Kiszka ioapic_eoi_broadcast(isrv); 4290280b571SJan Kiszka } 430e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC | SYNC_TO_VAPIC); 431574bbf7bSbellard apic_update_irq(s); 432574bbf7bSbellard } 433574bbf7bSbellard 434678e12ccSGleb Natapov static int apic_find_dest(uint8_t dest) 435678e12ccSGleb Natapov { 436dae01685SJan Kiszka APICCommonState *apic = local_apics[dest]; 437678e12ccSGleb Natapov int i; 438678e12ccSGleb Natapov 439678e12ccSGleb Natapov if (apic && apic->id == dest) 4401dfe3282SIgor Mammedov return dest; /* shortcut in case apic->id == local_apics[dest]->id */ 441678e12ccSGleb Natapov 442678e12ccSGleb Natapov for (i = 0; i < MAX_APICS; i++) { 443678e12ccSGleb Natapov apic = local_apics[i]; 444678e12ccSGleb Natapov if (apic && apic->id == dest) 445678e12ccSGleb Natapov return i; 446b538e53eSAlex Williamson if (!apic) 447b538e53eSAlex Williamson break; 448678e12ccSGleb Natapov } 449678e12ccSGleb Natapov 450678e12ccSGleb Natapov return -1; 451678e12ccSGleb Natapov } 452678e12ccSGleb Natapov 453d3e9db93Sbellard static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask, 454d3e9db93Sbellard uint8_t dest, uint8_t dest_mode) 455d592d303Sbellard { 456dae01685SJan Kiszka APICCommonState *apic_iter; 457d3e9db93Sbellard int i; 458d592d303Sbellard 459d592d303Sbellard if (dest_mode == 0) { 460d3e9db93Sbellard if (dest == 0xff) { 461d3e9db93Sbellard memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t)); 462d3e9db93Sbellard } else { 463678e12ccSGleb Natapov int idx = apic_find_dest(dest); 464d3e9db93Sbellard memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); 465678e12ccSGleb Natapov if (idx >= 0) 466edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, idx); 467d3e9db93Sbellard } 468d592d303Sbellard } else { 469d592d303Sbellard /* XXX: cluster mode */ 470d3e9db93Sbellard memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t)); 471d3e9db93Sbellard for(i = 0; i < MAX_APICS; i++) { 472d3e9db93Sbellard apic_iter = local_apics[i]; 473d3e9db93Sbellard if (apic_iter) { 474d3e9db93Sbellard if (apic_iter->dest_mode == 0xf) { 475d592d303Sbellard if (dest & apic_iter->log_dest) 476edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, i); 477d3e9db93Sbellard } else if (apic_iter->dest_mode == 0x0) { 478d3e9db93Sbellard if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) && 479d3e9db93Sbellard (dest & apic_iter->log_dest & 0x0f)) { 480edf9735eSMichael S. Tsirkin apic_set_bit(deliver_bitmask, i); 481d592d303Sbellard } 482d592d303Sbellard } 483b538e53eSAlex Williamson } else { 484b538e53eSAlex Williamson break; 485d3e9db93Sbellard } 486d3e9db93Sbellard } 487d3e9db93Sbellard } 488d592d303Sbellard } 489d592d303Sbellard 490dae01685SJan Kiszka static void apic_startup(APICCommonState *s, int vector_num) 491e0fd8781Sbellard { 492b09ea7d5SGleb Natapov s->sipi_vector = vector_num; 493c3affe56SAndreas Färber cpu_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); 494b09ea7d5SGleb Natapov } 495b09ea7d5SGleb Natapov 496d3b0c9e9Sxiaoqiang zhao void apic_sipi(DeviceState *dev) 497b09ea7d5SGleb Natapov { 498927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 49992a16d7aSBlue Swirl 500d8ed887bSAndreas Färber cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI); 501b09ea7d5SGleb Natapov 502b09ea7d5SGleb Natapov if (!s->wait_for_sipi) 503e0fd8781Sbellard return; 504e9f9d6b1SAndreas Färber cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector); 505b09ea7d5SGleb Natapov s->wait_for_sipi = 0; 506e0fd8781Sbellard } 507e0fd8781Sbellard 508d3b0c9e9Sxiaoqiang zhao static void apic_deliver(DeviceState *dev, uint8_t dest, uint8_t dest_mode, 509d592d303Sbellard uint8_t delivery_mode, uint8_t vector_num, 5101f6f408cSJan Kiszka uint8_t trigger_mode) 511d592d303Sbellard { 512927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 513d3e9db93Sbellard uint32_t deliver_bitmask[MAX_APIC_WORDS]; 514d592d303Sbellard int dest_shorthand = (s->icr[0] >> 18) & 3; 515dae01685SJan Kiszka APICCommonState *apic_iter; 516d592d303Sbellard 517e0fd8781Sbellard switch (dest_shorthand) { 518e0fd8781Sbellard case 0: 519d3e9db93Sbellard apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode); 520e0fd8781Sbellard break; 521e0fd8781Sbellard case 1: 522d3e9db93Sbellard memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask)); 5231dfe3282SIgor Mammedov apic_set_bit(deliver_bitmask, s->id); 524e0fd8781Sbellard break; 525e0fd8781Sbellard case 2: 526d3e9db93Sbellard memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); 527e0fd8781Sbellard break; 528e0fd8781Sbellard case 3: 529d3e9db93Sbellard memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask)); 5301dfe3282SIgor Mammedov apic_reset_bit(deliver_bitmask, s->id); 531e0fd8781Sbellard break; 532e0fd8781Sbellard } 533e0fd8781Sbellard 534d592d303Sbellard switch (delivery_mode) { 535d592d303Sbellard case APIC_DM_INIT: 536d592d303Sbellard { 537d592d303Sbellard int trig_mode = (s->icr[0] >> 15) & 1; 538d592d303Sbellard int level = (s->icr[0] >> 14) & 1; 539d592d303Sbellard if (level == 0 && trig_mode == 1) { 540d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 541d3e9db93Sbellard apic_iter->arb_id = apic_iter->id ); 542d592d303Sbellard return; 543d592d303Sbellard } 544d592d303Sbellard } 545d592d303Sbellard break; 546d592d303Sbellard 547d592d303Sbellard case APIC_DM_SIPI: 548d3e9db93Sbellard foreach_apic(apic_iter, deliver_bitmask, 549d3e9db93Sbellard apic_startup(apic_iter, vector_num) ); 550d592d303Sbellard return; 551d592d303Sbellard } 552d592d303Sbellard 5531f6f408cSJan Kiszka apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode); 554d592d303Sbellard } 555d592d303Sbellard 556a94820ddSJan Kiszka static bool apic_check_pic(APICCommonState *s) 557a94820ddSJan Kiszka { 558be9f8a08SZhu Guihua DeviceState *dev = (DeviceState *)s; 559be9f8a08SZhu Guihua 560be9f8a08SZhu Guihua if (!apic_accept_pic_intr(dev) || !pic_get_output(isa_pic)) { 561a94820ddSJan Kiszka return false; 562a94820ddSJan Kiszka } 563be9f8a08SZhu Guihua apic_deliver_pic_intr(dev, 1); 564a94820ddSJan Kiszka return true; 565a94820ddSJan Kiszka } 566a94820ddSJan Kiszka 567d3b0c9e9Sxiaoqiang zhao int apic_get_interrupt(DeviceState *dev) 568574bbf7bSbellard { 569927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 570574bbf7bSbellard int intno; 571574bbf7bSbellard 572574bbf7bSbellard /* if the APIC is installed or enabled, we let the 8259 handle the 573574bbf7bSbellard IRQs */ 574574bbf7bSbellard if (!s) 575574bbf7bSbellard return -1; 576574bbf7bSbellard if (!(s->spurious_vec & APIC_SV_ENABLE)) 577574bbf7bSbellard return -1; 578574bbf7bSbellard 579e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 5800fbfbb59SGleb Natapov intno = apic_irq_pending(s); 5810fbfbb59SGleb Natapov 5825224c88dSPaolo Bonzini /* if there is an interrupt from the 8259, let the caller handle 5835224c88dSPaolo Bonzini * that first since ExtINT interrupts ignore the priority. 5845224c88dSPaolo Bonzini */ 5855224c88dSPaolo Bonzini if (intno == 0 || apic_check_pic(s)) { 586e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 587574bbf7bSbellard return -1; 5880fbfbb59SGleb Natapov } else if (intno < 0) { 589e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 590d592d303Sbellard return s->spurious_vec & 0xff; 5910fbfbb59SGleb Natapov } 592edf9735eSMichael S. Tsirkin apic_reset_bit(s->irr, intno); 593edf9735eSMichael S. Tsirkin apic_set_bit(s->isr, intno); 594e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 5953db3659bSJan Kiszka 596574bbf7bSbellard apic_update_irq(s); 5973db3659bSJan Kiszka 598574bbf7bSbellard return intno; 599574bbf7bSbellard } 600574bbf7bSbellard 601d3b0c9e9Sxiaoqiang zhao int apic_accept_pic_intr(DeviceState *dev) 6020e21e12bSths { 603927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 6040e21e12bSths uint32_t lvt0; 6050e21e12bSths 6060e21e12bSths if (!s) 6070e21e12bSths return -1; 6080e21e12bSths 6090e21e12bSths lvt0 = s->lvt[APIC_LVT_LINT0]; 6100e21e12bSths 611a5b38b51Saurel32 if ((s->apicbase & MSR_IA32_APICBASE_ENABLE) == 0 || 612a5b38b51Saurel32 (lvt0 & APIC_LVT_MASKED) == 0) 61378cafff8SSergio Lopez return isa_pic != NULL; 6140e21e12bSths 6150e21e12bSths return 0; 6160e21e12bSths } 6170e21e12bSths 618dae01685SJan Kiszka static uint32_t apic_get_current_count(APICCommonState *s) 619574bbf7bSbellard { 620574bbf7bSbellard int64_t d; 621574bbf7bSbellard uint32_t val; 622bc72ad67SAlex Bligh d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >> 623574bbf7bSbellard s->count_shift; 624574bbf7bSbellard if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) { 625574bbf7bSbellard /* periodic */ 626d592d303Sbellard val = s->initial_count - (d % ((uint64_t)s->initial_count + 1)); 627574bbf7bSbellard } else { 628574bbf7bSbellard if (d >= s->initial_count) 629574bbf7bSbellard val = 0; 630574bbf7bSbellard else 631574bbf7bSbellard val = s->initial_count - d; 632574bbf7bSbellard } 633574bbf7bSbellard return val; 634574bbf7bSbellard } 635574bbf7bSbellard 636dae01685SJan Kiszka static void apic_timer_update(APICCommonState *s, int64_t current_time) 637574bbf7bSbellard { 6387a380ca3SJan Kiszka if (apic_next_timer(s, current_time)) { 639bc72ad67SAlex Bligh timer_mod(s->timer, s->next_time); 640574bbf7bSbellard } else { 641bc72ad67SAlex Bligh timer_del(s->timer); 642574bbf7bSbellard } 643574bbf7bSbellard } 644574bbf7bSbellard 645574bbf7bSbellard static void apic_timer(void *opaque) 646574bbf7bSbellard { 647dae01685SJan Kiszka APICCommonState *s = opaque; 648574bbf7bSbellard 649cf6d64bfSBlue Swirl apic_local_deliver(s, APIC_LVT_TIMER); 650574bbf7bSbellard apic_timer_update(s, s->next_time); 651574bbf7bSbellard } 652574bbf7bSbellard 65321f80e8fSPeter Maydell static uint64_t apic_mem_read(void *opaque, hwaddr addr, unsigned size) 654574bbf7bSbellard { 655d3b0c9e9Sxiaoqiang zhao DeviceState *dev; 656dae01685SJan Kiszka APICCommonState *s; 657574bbf7bSbellard uint32_t val; 658574bbf7bSbellard int index; 659574bbf7bSbellard 66021f80e8fSPeter Maydell if (size < 4) { 66121f80e8fSPeter Maydell return 0; 66221f80e8fSPeter Maydell } 66321f80e8fSPeter Maydell 664d3b0c9e9Sxiaoqiang zhao dev = cpu_get_current_apic(); 665d3b0c9e9Sxiaoqiang zhao if (!dev) { 666574bbf7bSbellard return 0; 6670e26b7b8SBlue Swirl } 668927d5a1dSWanpeng Li s = APIC(dev); 669574bbf7bSbellard 670574bbf7bSbellard index = (addr >> 4) & 0xff; 671574bbf7bSbellard switch(index) { 672574bbf7bSbellard case 0x02: /* id */ 673574bbf7bSbellard val = s->id << 24; 674574bbf7bSbellard break; 675574bbf7bSbellard case 0x03: /* version */ 676aa93200bSGabriel L. Somlo val = s->version | ((APIC_LVT_NB - 1) << 16); 677574bbf7bSbellard break; 678574bbf7bSbellard case 0x08: 679e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 680e5ad936bSJan Kiszka if (apic_report_tpr_access) { 68160671e58SAndreas Färber cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_READ); 682e5ad936bSJan Kiszka } 683574bbf7bSbellard val = s->tpr; 684574bbf7bSbellard break; 685d592d303Sbellard case 0x09: 686d592d303Sbellard val = apic_get_arb_pri(s); 687d592d303Sbellard break; 688574bbf7bSbellard case 0x0a: 689574bbf7bSbellard /* ppr */ 690574bbf7bSbellard val = apic_get_ppr(s); 691574bbf7bSbellard break; 692b237db36Saurel32 case 0x0b: 693b237db36Saurel32 val = 0; 694b237db36Saurel32 break; 695d592d303Sbellard case 0x0d: 696d592d303Sbellard val = s->log_dest << 24; 697d592d303Sbellard break; 698d592d303Sbellard case 0x0e: 699d6c140a7SJan Kiszka val = (s->dest_mode << 28) | 0xfffffff; 700d592d303Sbellard break; 701574bbf7bSbellard case 0x0f: 702574bbf7bSbellard val = s->spurious_vec; 703574bbf7bSbellard break; 704574bbf7bSbellard case 0x10 ... 0x17: 705574bbf7bSbellard val = s->isr[index & 7]; 706574bbf7bSbellard break; 707574bbf7bSbellard case 0x18 ... 0x1f: 708574bbf7bSbellard val = s->tmr[index & 7]; 709574bbf7bSbellard break; 710574bbf7bSbellard case 0x20 ... 0x27: 711574bbf7bSbellard val = s->irr[index & 7]; 712574bbf7bSbellard break; 713574bbf7bSbellard case 0x28: 714574bbf7bSbellard val = s->esr; 715574bbf7bSbellard break; 716574bbf7bSbellard case 0x30: 717574bbf7bSbellard case 0x31: 718574bbf7bSbellard val = s->icr[index & 1]; 719574bbf7bSbellard break; 720e0fd8781Sbellard case 0x32 ... 0x37: 721e0fd8781Sbellard val = s->lvt[index - 0x32]; 722e0fd8781Sbellard break; 723574bbf7bSbellard case 0x38: 724574bbf7bSbellard val = s->initial_count; 725574bbf7bSbellard break; 726574bbf7bSbellard case 0x39: 727574bbf7bSbellard val = apic_get_current_count(s); 728574bbf7bSbellard break; 729574bbf7bSbellard case 0x3e: 730574bbf7bSbellard val = s->divide_conf; 731574bbf7bSbellard break; 732574bbf7bSbellard default: 733a22bf99cSPavel Butsykin s->esr |= APIC_ESR_ILLEGAL_ADDRESS; 734574bbf7bSbellard val = 0; 735574bbf7bSbellard break; 736574bbf7bSbellard } 737d8023f31SBlue Swirl trace_apic_mem_readl(addr, val); 738574bbf7bSbellard return val; 739574bbf7bSbellard } 740574bbf7bSbellard 741267ee357SRadim Krčmář static void apic_send_msi(MSIMessage *msi) 74254c96da7SMichael S. Tsirkin { 743267ee357SRadim Krčmář uint64_t addr = msi->address; 744267ee357SRadim Krčmář uint32_t data = msi->data; 74554c96da7SMichael S. Tsirkin uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; 74654c96da7SMichael S. Tsirkin uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; 74754c96da7SMichael S. Tsirkin uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; 74854c96da7SMichael S. Tsirkin uint8_t trigger_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1; 74954c96da7SMichael S. Tsirkin uint8_t delivery = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7; 75054c96da7SMichael S. Tsirkin /* XXX: Ignore redirection hint. */ 7511f6f408cSJan Kiszka apic_deliver_irq(dest, dest_mode, delivery, vector, trigger_mode); 75254c96da7SMichael S. Tsirkin } 75354c96da7SMichael S. Tsirkin 75421f80e8fSPeter Maydell static void apic_mem_write(void *opaque, hwaddr addr, uint64_t val, 75521f80e8fSPeter Maydell unsigned size) 756574bbf7bSbellard { 757d3b0c9e9Sxiaoqiang zhao DeviceState *dev; 758dae01685SJan Kiszka APICCommonState *s; 75954c96da7SMichael S. Tsirkin int index = (addr >> 4) & 0xff; 76021f80e8fSPeter Maydell 76121f80e8fSPeter Maydell if (size < 4) { 76221f80e8fSPeter Maydell return; 76321f80e8fSPeter Maydell } 76421f80e8fSPeter Maydell 76554c96da7SMichael S. Tsirkin if (addr > 0xfff || !index) { 76654c96da7SMichael S. Tsirkin /* MSI and MMIO APIC are at the same memory location, 76754c96da7SMichael S. Tsirkin * but actually not on the global bus: MSI is on PCI bus 76854c96da7SMichael S. Tsirkin * APIC is connected directly to the CPU. 76954c96da7SMichael S. Tsirkin * Mapping them on the global bus happens to work because 77054c96da7SMichael S. Tsirkin * MSI registers are reserved in APIC MMIO and vice versa. */ 771267ee357SRadim Krčmář MSIMessage msi = { .address = addr, .data = val }; 772267ee357SRadim Krčmář apic_send_msi(&msi); 77354c96da7SMichael S. Tsirkin return; 77454c96da7SMichael S. Tsirkin } 775574bbf7bSbellard 776d3b0c9e9Sxiaoqiang zhao dev = cpu_get_current_apic(); 777d3b0c9e9Sxiaoqiang zhao if (!dev) { 778574bbf7bSbellard return; 7790e26b7b8SBlue Swirl } 780927d5a1dSWanpeng Li s = APIC(dev); 781574bbf7bSbellard 782d8023f31SBlue Swirl trace_apic_mem_writel(addr, val); 783574bbf7bSbellard 784574bbf7bSbellard switch(index) { 785574bbf7bSbellard case 0x02: 786574bbf7bSbellard s->id = (val >> 24); 787574bbf7bSbellard break; 788e0fd8781Sbellard case 0x03: 789e0fd8781Sbellard break; 790574bbf7bSbellard case 0x08: 791e5ad936bSJan Kiszka if (apic_report_tpr_access) { 79260671e58SAndreas Färber cpu_report_tpr_access(&s->cpu->env, TPR_ACCESS_WRITE); 793e5ad936bSJan Kiszka } 794574bbf7bSbellard s->tpr = val; 795e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_TO_VAPIC); 796d592d303Sbellard apic_update_irq(s); 797574bbf7bSbellard break; 798e0fd8781Sbellard case 0x09: 799e0fd8781Sbellard case 0x0a: 800e0fd8781Sbellard break; 801574bbf7bSbellard case 0x0b: /* EOI */ 802574bbf7bSbellard apic_eoi(s); 803574bbf7bSbellard break; 804d592d303Sbellard case 0x0d: 805d592d303Sbellard s->log_dest = val >> 24; 806d592d303Sbellard break; 807d592d303Sbellard case 0x0e: 808d592d303Sbellard s->dest_mode = val >> 28; 809d592d303Sbellard break; 810574bbf7bSbellard case 0x0f: 811574bbf7bSbellard s->spurious_vec = val & 0x1ff; 812d592d303Sbellard apic_update_irq(s); 813574bbf7bSbellard break; 814e0fd8781Sbellard case 0x10 ... 0x17: 815e0fd8781Sbellard case 0x18 ... 0x1f: 816e0fd8781Sbellard case 0x20 ... 0x27: 817e0fd8781Sbellard case 0x28: 818e0fd8781Sbellard break; 819574bbf7bSbellard case 0x30: 820d592d303Sbellard s->icr[0] = val; 821d3b0c9e9Sxiaoqiang zhao apic_deliver(dev, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1, 822d592d303Sbellard (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff), 8231f6f408cSJan Kiszka (s->icr[0] >> 15) & 1); 824d592d303Sbellard break; 825574bbf7bSbellard case 0x31: 826d592d303Sbellard s->icr[1] = val; 827574bbf7bSbellard break; 828574bbf7bSbellard case 0x32 ... 0x37: 829574bbf7bSbellard { 830574bbf7bSbellard int n = index - 0x32; 831574bbf7bSbellard s->lvt[n] = val; 832a94820ddSJan Kiszka if (n == APIC_LVT_TIMER) { 833bc72ad67SAlex Bligh apic_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); 834a94820ddSJan Kiszka } else if (n == APIC_LVT_LINT0 && apic_check_pic(s)) { 835a94820ddSJan Kiszka apic_update_irq(s); 836a94820ddSJan Kiszka } 837574bbf7bSbellard } 838574bbf7bSbellard break; 839574bbf7bSbellard case 0x38: 840574bbf7bSbellard s->initial_count = val; 841bc72ad67SAlex Bligh s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 842574bbf7bSbellard apic_timer_update(s, s->initial_count_load_time); 843574bbf7bSbellard break; 844e0fd8781Sbellard case 0x39: 845e0fd8781Sbellard break; 846574bbf7bSbellard case 0x3e: 847574bbf7bSbellard { 848574bbf7bSbellard int v; 849574bbf7bSbellard s->divide_conf = val & 0xb; 850574bbf7bSbellard v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4); 851574bbf7bSbellard s->count_shift = (v + 1) & 7; 852574bbf7bSbellard } 853574bbf7bSbellard break; 854574bbf7bSbellard default: 855a22bf99cSPavel Butsykin s->esr |= APIC_ESR_ILLEGAL_ADDRESS; 856574bbf7bSbellard break; 857574bbf7bSbellard } 858574bbf7bSbellard } 859574bbf7bSbellard 860e5ad936bSJan Kiszka static void apic_pre_save(APICCommonState *s) 861e5ad936bSJan Kiszka { 862e5ad936bSJan Kiszka apic_sync_vapic(s, SYNC_FROM_VAPIC); 863e5ad936bSJan Kiszka } 864e5ad936bSJan Kiszka 8657a380ca3SJan Kiszka static void apic_post_load(APICCommonState *s) 8667a380ca3SJan Kiszka { 8677a380ca3SJan Kiszka if (s->timer_expiry != -1) { 868bc72ad67SAlex Bligh timer_mod(s->timer, s->timer_expiry); 8697a380ca3SJan Kiszka } else { 870bc72ad67SAlex Bligh timer_del(s->timer); 8717a380ca3SJan Kiszka } 8727a380ca3SJan Kiszka } 8737a380ca3SJan Kiszka 874312b4234SAvi Kivity static const MemoryRegionOps apic_io_ops = { 87521f80e8fSPeter Maydell .read = apic_mem_read, 87621f80e8fSPeter Maydell .write = apic_mem_write, 87721f80e8fSPeter Maydell .impl.min_access_size = 1, 87821f80e8fSPeter Maydell .impl.max_access_size = 4, 87921f80e8fSPeter Maydell .valid.min_access_size = 1, 88021f80e8fSPeter Maydell .valid.max_access_size = 4, 881312b4234SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 882574bbf7bSbellard }; 883574bbf7bSbellard 884ff6986ceSxiaoqiang zhao static void apic_realize(DeviceState *dev, Error **errp) 8858546b099SBlue Swirl { 886927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 887889211b1SIgor Mammedov 8881dfe3282SIgor Mammedov if (s->id >= MAX_APICS) { 8891dfe3282SIgor Mammedov error_setg(errp, "%s initialization failed. APIC ID %d is invalid", 8901dfe3282SIgor Mammedov object_get_typename(OBJECT(dev)), s->id); 891889211b1SIgor Mammedov return; 892889211b1SIgor Mammedov } 893ff6986ceSxiaoqiang zhao 8941437c94bSPaolo Bonzini memory_region_init_io(&s->io_memory, OBJECT(s), &apic_io_ops, s, "apic-msi", 895baaeda08SIgor Mammedov APIC_SPACE_SIZE); 8968546b099SBlue Swirl 897bc72ad67SAlex Bligh s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, apic_timer, s); 8981dfe3282SIgor Mammedov local_apics[s->id] = s; 89908a82ac0SJan Kiszka 900226419d6SMichael S. Tsirkin msi_nonbroken = true; 9018546b099SBlue Swirl } 9028546b099SBlue Swirl 9039c156f9dSIgor Mammedov static void apic_unrealize(DeviceState *dev, Error **errp) 9049c156f9dSIgor Mammedov { 905927d5a1dSWanpeng Li APICCommonState *s = APIC(dev); 9069c156f9dSIgor Mammedov 9079c156f9dSIgor Mammedov timer_del(s->timer); 9089c156f9dSIgor Mammedov timer_free(s->timer); 9099c156f9dSIgor Mammedov local_apics[s->id] = NULL; 9109c156f9dSIgor Mammedov } 9119c156f9dSIgor Mammedov 912999e12bbSAnthony Liguori static void apic_class_init(ObjectClass *klass, void *data) 913999e12bbSAnthony Liguori { 914999e12bbSAnthony Liguori APICCommonClass *k = APIC_COMMON_CLASS(klass); 915999e12bbSAnthony Liguori 916ff6986ceSxiaoqiang zhao k->realize = apic_realize; 9179c156f9dSIgor Mammedov k->unrealize = apic_unrealize; 918999e12bbSAnthony Liguori k->set_base = apic_set_base; 919999e12bbSAnthony Liguori k->set_tpr = apic_set_tpr; 920e5ad936bSJan Kiszka k->get_tpr = apic_get_tpr; 921e5ad936bSJan Kiszka k->vapic_base_update = apic_vapic_base_update; 922999e12bbSAnthony Liguori k->external_nmi = apic_external_nmi; 923e5ad936bSJan Kiszka k->pre_save = apic_pre_save; 924999e12bbSAnthony Liguori k->post_load = apic_post_load; 925267ee357SRadim Krčmář k->send_msi = apic_send_msi; 926999e12bbSAnthony Liguori } 927999e12bbSAnthony Liguori 9288c43a6f0SAndreas Färber static const TypeInfo apic_info = { 929927d5a1dSWanpeng Li .name = TYPE_APIC, 93039bffca2SAnthony Liguori .instance_size = sizeof(APICCommonState), 93139bffca2SAnthony Liguori .parent = TYPE_APIC_COMMON, 932999e12bbSAnthony Liguori .class_init = apic_class_init, 9338546b099SBlue Swirl }; 9348546b099SBlue Swirl 93583f7d43aSAndreas Färber static void apic_register_types(void) 9368546b099SBlue Swirl { 93739bffca2SAnthony Liguori type_register_static(&apic_info); 9388546b099SBlue Swirl } 9398546b099SBlue Swirl 94083f7d43aSAndreas Färber type_init(apic_register_types) 941