qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

apic_common.c (13679B)


      1 /*
      2  *  APIC support - common bits of emulated and KVM kernel model
      3  *
      4  *  Copyright (c) 2004-2005 Fabrice Bellard
      5  *  Copyright (c) 2011      Jan Kiszka, Siemens AG
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Lesser General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2.1 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Lesser General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Lesser General Public
     18  * License along with this library; if not, see <http://www.gnu.org/licenses/>
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/error-report.h"
     23 #include "qemu/module.h"
     24 #include "qapi/error.h"
     25 #include "qapi/visitor.h"
     26 #include "hw/i386/apic.h"
     27 #include "hw/i386/apic_internal.h"
     28 #include "trace.h"
     29 #include "hw/boards.h"
     30 #include "sysemu/hax.h"
     31 #include "sysemu/kvm.h"
     32 #include "hw/qdev-properties.h"
     33 #include "hw/sysbus.h"
     34 #include "migration/vmstate.h"
     35 
     36 static int apic_irq_delivered;
     37 bool apic_report_tpr_access;
     38 
     39 void cpu_set_apic_base(DeviceState *dev, uint64_t val)
     40 {
     41     trace_cpu_set_apic_base(val);
     42 
     43     if (dev) {
     44         APICCommonState *s = APIC_COMMON(dev);
     45         APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
     46         /* switching to x2APIC, reset possibly modified xAPIC ID */
     47         if (!(s->apicbase & MSR_IA32_APICBASE_EXTD) &&
     48             (val & MSR_IA32_APICBASE_EXTD)) {
     49             s->id = s->initial_apic_id;
     50         }
     51         info->set_base(s, val);
     52     }
     53 }
     54 
     55 uint64_t cpu_get_apic_base(DeviceState *dev)
     56 {
     57     if (dev) {
     58         APICCommonState *s = APIC_COMMON(dev);
     59         trace_cpu_get_apic_base((uint64_t)s->apicbase);
     60         return s->apicbase;
     61     } else {
     62         trace_cpu_get_apic_base(MSR_IA32_APICBASE_BSP);
     63         return MSR_IA32_APICBASE_BSP;
     64     }
     65 }
     66 
     67 void cpu_set_apic_tpr(DeviceState *dev, uint8_t val)
     68 {
     69     APICCommonState *s;
     70     APICCommonClass *info;
     71 
     72     if (!dev) {
     73         return;
     74     }
     75 
     76     s = APIC_COMMON(dev);
     77     info = APIC_COMMON_GET_CLASS(s);
     78 
     79     info->set_tpr(s, val);
     80 }
     81 
     82 uint8_t cpu_get_apic_tpr(DeviceState *dev)
     83 {
     84     APICCommonState *s;
     85     APICCommonClass *info;
     86 
     87     if (!dev) {
     88         return 0;
     89     }
     90 
     91     s = APIC_COMMON(dev);
     92     info = APIC_COMMON_GET_CLASS(s);
     93 
     94     return info->get_tpr(s);
     95 }
     96 
     97 void apic_enable_tpr_access_reporting(DeviceState *dev, bool enable)
     98 {
     99     APICCommonState *s = APIC_COMMON(dev);
    100     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    101 
    102     apic_report_tpr_access = enable;
    103     if (info->enable_tpr_reporting) {
    104         info->enable_tpr_reporting(s, enable);
    105     }
    106 }
    107 
    108 void apic_enable_vapic(DeviceState *dev, hwaddr paddr)
    109 {
    110     APICCommonState *s = APIC_COMMON(dev);
    111     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    112 
    113     s->vapic_paddr = paddr;
    114     info->vapic_base_update(s);
    115 }
    116 
    117 void apic_handle_tpr_access_report(DeviceState *dev, target_ulong ip,
    118                                    TPRAccess access)
    119 {
    120     APICCommonState *s = APIC_COMMON(dev);
    121 
    122     vapic_report_tpr_access(s->vapic, CPU(s->cpu), ip, access);
    123 }
    124 
    125 void apic_report_irq_delivered(int delivered)
    126 {
    127     apic_irq_delivered += delivered;
    128 
    129     trace_apic_report_irq_delivered(apic_irq_delivered);
    130 }
    131 
    132 void apic_reset_irq_delivered(void)
    133 {
    134     /* Copy this into a local variable to encourage gcc to emit a plain
    135      * register for a sys/sdt.h marker.  For details on this workaround, see:
    136      * https://sourceware.org/bugzilla/show_bug.cgi?id=13296
    137      */
    138     volatile int a_i_d = apic_irq_delivered;
    139     trace_apic_reset_irq_delivered(a_i_d);
    140 
    141     apic_irq_delivered = 0;
    142 }
    143 
    144 int apic_get_irq_delivered(void)
    145 {
    146     trace_apic_get_irq_delivered(apic_irq_delivered);
    147 
    148     return apic_irq_delivered;
    149 }
    150 
    151 void apic_deliver_nmi(DeviceState *dev)
    152 {
    153     APICCommonState *s = APIC_COMMON(dev);
    154     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    155 
    156     info->external_nmi(s);
    157 }
    158 
    159 bool apic_next_timer(APICCommonState *s, int64_t current_time)
    160 {
    161     int64_t d;
    162 
    163     /* We need to store the timer state separately to support APIC
    164      * implementations that maintain a non-QEMU timer, e.g. inside the
    165      * host kernel. This open-coded state allows us to migrate between
    166      * both models. */
    167     s->timer_expiry = -1;
    168 
    169     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
    170         return false;
    171     }
    172 
    173     d = (current_time - s->initial_count_load_time) >> s->count_shift;
    174 
    175     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
    176         if (!s->initial_count) {
    177             return false;
    178         }
    179         d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
    180             ((uint64_t)s->initial_count + 1);
    181     } else {
    182         if (d >= s->initial_count) {
    183             return false;
    184         }
    185         d = (uint64_t)s->initial_count + 1;
    186     }
    187     s->next_time = s->initial_count_load_time + (d << s->count_shift);
    188     s->timer_expiry = s->next_time;
    189     return true;
    190 }
    191 
    192 uint32_t apic_get_current_count(APICCommonState *s)
    193 {
    194     int64_t d;
    195     uint32_t val;
    196     d = (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->initial_count_load_time) >>
    197         s->count_shift;
    198     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
    199         /* periodic */
    200         val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
    201     } else {
    202         if (d >= s->initial_count) {
    203             val = 0;
    204         } else {
    205             val = s->initial_count - d;
    206         }
    207     }
    208     return val;
    209 }
    210 
    211 void apic_init_reset(DeviceState *dev)
    212 {
    213     APICCommonState *s;
    214     APICCommonClass *info;
    215     int i;
    216 
    217     if (!dev) {
    218         return;
    219     }
    220     s = APIC_COMMON(dev);
    221     s->tpr = 0;
    222     s->spurious_vec = 0xff;
    223     s->log_dest = 0;
    224     s->dest_mode = 0xf;
    225     memset(s->isr, 0, sizeof(s->isr));
    226     memset(s->tmr, 0, sizeof(s->tmr));
    227     memset(s->irr, 0, sizeof(s->irr));
    228     for (i = 0; i < APIC_LVT_NB; i++) {
    229         s->lvt[i] = APIC_LVT_MASKED;
    230     }
    231     s->esr = 0;
    232     memset(s->icr, 0, sizeof(s->icr));
    233     s->divide_conf = 0;
    234     s->count_shift = 0;
    235     s->initial_count = 0;
    236     s->initial_count_load_time = 0;
    237     s->next_time = 0;
    238     s->wait_for_sipi = !cpu_is_bsp(s->cpu);
    239 
    240     if (s->timer) {
    241         timer_del(s->timer);
    242     }
    243     s->timer_expiry = -1;
    244 
    245     info = APIC_COMMON_GET_CLASS(s);
    246     if (info->reset) {
    247         info->reset(s);
    248     }
    249 }
    250 
    251 void apic_designate_bsp(DeviceState *dev, bool bsp)
    252 {
    253     if (dev == NULL) {
    254         return;
    255     }
    256 
    257     APICCommonState *s = APIC_COMMON(dev);
    258     if (bsp) {
    259         s->apicbase |= MSR_IA32_APICBASE_BSP;
    260     } else {
    261         s->apicbase &= ~MSR_IA32_APICBASE_BSP;
    262     }
    263 }
    264 
    265 static void apic_reset_common(DeviceState *dev)
    266 {
    267     APICCommonState *s = APIC_COMMON(dev);
    268     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    269     uint32_t bsp;
    270 
    271     bsp = s->apicbase & MSR_IA32_APICBASE_BSP;
    272     s->apicbase = APIC_DEFAULT_ADDRESS | bsp | MSR_IA32_APICBASE_ENABLE;
    273     s->id = s->initial_apic_id;
    274 
    275     apic_reset_irq_delivered();
    276 
    277     s->vapic_paddr = 0;
    278     info->vapic_base_update(s);
    279 
    280     apic_init_reset(dev);
    281 }
    282 
    283 static const VMStateDescription vmstate_apic_common;
    284 
    285 static void apic_common_realize(DeviceState *dev, Error **errp)
    286 {
    287     APICCommonState *s = APIC_COMMON(dev);
    288     APICCommonClass *info;
    289     static DeviceState *vapic;
    290     uint32_t instance_id = s->initial_apic_id;
    291 
    292     /* Normally initial APIC ID should be no more than hundreds */
    293     assert(instance_id != VMSTATE_INSTANCE_ID_ANY);
    294 
    295     info = APIC_COMMON_GET_CLASS(s);
    296     info->realize(dev, errp);
    297 
    298     /* Note: We need at least 1M to map the VAPIC option ROM */
    299     if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
    300         !hax_enabled() && current_machine->ram_size >= 1024 * 1024) {
    301         vapic = sysbus_create_simple("kvmvapic", -1, NULL);
    302     }
    303     s->vapic = vapic;
    304     if (apic_report_tpr_access && info->enable_tpr_reporting) {
    305         info->enable_tpr_reporting(s, true);
    306     }
    307 
    308     if (s->legacy_instance_id) {
    309         instance_id = VMSTATE_INSTANCE_ID_ANY;
    310     }
    311     vmstate_register_with_alias_id(NULL, instance_id, &vmstate_apic_common,
    312                                    s, -1, 0, NULL);
    313 }
    314 
    315 static void apic_common_unrealize(DeviceState *dev)
    316 {
    317     APICCommonState *s = APIC_COMMON(dev);
    318     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    319 
    320     vmstate_unregister(NULL, &vmstate_apic_common, s);
    321     info->unrealize(dev);
    322 
    323     if (apic_report_tpr_access && info->enable_tpr_reporting) {
    324         info->enable_tpr_reporting(s, false);
    325     }
    326 }
    327 
    328 static int apic_pre_load(void *opaque)
    329 {
    330     APICCommonState *s = APIC_COMMON(opaque);
    331 
    332     /* The default is !cpu_is_bsp(s->cpu), but the common value is 0
    333      * so that's what apic_common_sipi_needed checks for.  Reset to
    334      * the value that is assumed when the apic_sipi subsection is
    335      * absent.
    336      */
    337     s->wait_for_sipi = 0;
    338     return 0;
    339 }
    340 
    341 static int apic_dispatch_pre_save(void *opaque)
    342 {
    343     APICCommonState *s = APIC_COMMON(opaque);
    344     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    345 
    346     if (info->pre_save) {
    347         info->pre_save(s);
    348     }
    349 
    350     return 0;
    351 }
    352 
    353 static int apic_dispatch_post_load(void *opaque, int version_id)
    354 {
    355     APICCommonState *s = APIC_COMMON(opaque);
    356     APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
    357 
    358     if (info->post_load) {
    359         info->post_load(s);
    360     }
    361     return 0;
    362 }
    363 
    364 static bool apic_common_sipi_needed(void *opaque)
    365 {
    366     APICCommonState *s = APIC_COMMON(opaque);
    367     return s->wait_for_sipi != 0;
    368 }
    369 
    370 static const VMStateDescription vmstate_apic_common_sipi = {
    371     .name = "apic_sipi",
    372     .version_id = 1,
    373     .minimum_version_id = 1,
    374     .needed = apic_common_sipi_needed,
    375     .fields = (VMStateField[]) {
    376         VMSTATE_INT32(sipi_vector, APICCommonState),
    377         VMSTATE_INT32(wait_for_sipi, APICCommonState),
    378         VMSTATE_END_OF_LIST()
    379     }
    380 };
    381 
    382 static const VMStateDescription vmstate_apic_common = {
    383     .name = "apic",
    384     .version_id = 3,
    385     .minimum_version_id = 3,
    386     .pre_load = apic_pre_load,
    387     .pre_save = apic_dispatch_pre_save,
    388     .post_load = apic_dispatch_post_load,
    389     .fields = (VMStateField[]) {
    390         VMSTATE_UINT32(apicbase, APICCommonState),
    391         VMSTATE_UINT8(id, APICCommonState),
    392         VMSTATE_UINT8(arb_id, APICCommonState),
    393         VMSTATE_UINT8(tpr, APICCommonState),
    394         VMSTATE_UINT32(spurious_vec, APICCommonState),
    395         VMSTATE_UINT8(log_dest, APICCommonState),
    396         VMSTATE_UINT8(dest_mode, APICCommonState),
    397         VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
    398         VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
    399         VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
    400         VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
    401         VMSTATE_UINT32(esr, APICCommonState),
    402         VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
    403         VMSTATE_UINT32(divide_conf, APICCommonState),
    404         VMSTATE_INT32(count_shift, APICCommonState),
    405         VMSTATE_UINT32(initial_count, APICCommonState),
    406         VMSTATE_INT64(initial_count_load_time, APICCommonState),
    407         VMSTATE_INT64(next_time, APICCommonState),
    408         VMSTATE_INT64(timer_expiry,
    409                       APICCommonState), /* open-coded timer state */
    410         VMSTATE_END_OF_LIST()
    411     },
    412     .subsections = (const VMStateDescription*[]) {
    413         &vmstate_apic_common_sipi,
    414         NULL
    415     }
    416 };
    417 
    418 static Property apic_properties_common[] = {
    419     DEFINE_PROP_UINT8("version", APICCommonState, version, 0x14),
    420     DEFINE_PROP_BIT("vapic", APICCommonState, vapic_control, VAPIC_ENABLE_BIT,
    421                     true),
    422     DEFINE_PROP_BOOL("legacy-instance-id", APICCommonState, legacy_instance_id,
    423                      false),
    424     DEFINE_PROP_END_OF_LIST(),
    425 };
    426 
    427 static void apic_common_get_id(Object *obj, Visitor *v, const char *name,
    428                                void *opaque, Error **errp)
    429 {
    430     APICCommonState *s = APIC_COMMON(obj);
    431     uint32_t value;
    432 
    433     value = s->apicbase & MSR_IA32_APICBASE_EXTD ? s->initial_apic_id : s->id;
    434     visit_type_uint32(v, name, &value, errp);
    435 }
    436 
    437 static void apic_common_set_id(Object *obj, Visitor *v, const char *name,
    438                                void *opaque, Error **errp)
    439 {
    440     APICCommonState *s = APIC_COMMON(obj);
    441     DeviceState *dev = DEVICE(obj);
    442     uint32_t value;
    443 
    444     if (dev->realized) {
    445         qdev_prop_set_after_realize(dev, name, errp);
    446         return;
    447     }
    448 
    449     if (!visit_type_uint32(v, name, &value, errp)) {
    450         return;
    451     }
    452 
    453     s->initial_apic_id = value;
    454     s->id = (uint8_t)value;
    455 }
    456 
    457 static void apic_common_initfn(Object *obj)
    458 {
    459     APICCommonState *s = APIC_COMMON(obj);
    460 
    461     s->id = s->initial_apic_id = -1;
    462     object_property_add(obj, "id", "uint32",
    463                         apic_common_get_id,
    464                         apic_common_set_id, NULL, NULL);
    465 }
    466 
    467 static void apic_common_class_init(ObjectClass *klass, void *data)
    468 {
    469     DeviceClass *dc = DEVICE_CLASS(klass);
    470 
    471     dc->reset = apic_reset_common;
    472     device_class_set_props(dc, apic_properties_common);
    473     dc->realize = apic_common_realize;
    474     dc->unrealize = apic_common_unrealize;
    475     /*
    476      * Reason: APIC and CPU need to be wired up by
    477      * x86_cpu_apic_create()
    478      */
    479     dc->user_creatable = false;
    480 }
    481 
    482 static const TypeInfo apic_common_type = {
    483     .name = TYPE_APIC_COMMON,
    484     .parent = TYPE_DEVICE,
    485     .instance_size = sizeof(APICCommonState),
    486     .instance_init = apic_common_initfn,
    487     .class_size = sizeof(APICCommonClass),
    488     .class_init = apic_common_class_init,
    489     .abstract = true,
    490 };
    491 
    492 static void apic_common_register_types(void)
    493 {
    494     type_register_static(&apic_common_type);
    495 }
    496 
    497 type_init(apic_common_register_types)