cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

apic.c (7713B)


      1/*
      2 * KVM in-kernel APIC support
      3 *
      4 * Copyright (c) 2011 Siemens AG
      5 *
      6 * Authors:
      7 *  Jan Kiszka          <jan.kiszka@siemens.com>
      8 *
      9 * This work is licensed under the terms of the GNU GPL version 2.
     10 * See the COPYING file in the top-level directory.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qemu/module.h"
     15#include "hw/i386/apic_internal.h"
     16#include "hw/pci/msi.h"
     17#include "sysemu/hw_accel.h"
     18#include "sysemu/kvm.h"
     19#include "kvm/kvm_i386.h"
     20
     21static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
     22                                    int reg_id, uint32_t val)
     23{
     24    *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
     25}
     26
     27static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
     28                                        int reg_id)
     29{
     30    return *((uint32_t *)(kapic->regs + (reg_id << 4)));
     31}
     32
     33static void kvm_put_apic_state(APICCommonState *s, struct kvm_lapic_state *kapic)
     34{
     35    int i;
     36
     37    memset(kapic, 0, sizeof(*kapic));
     38    if (kvm_has_x2apic_api() && s->apicbase & MSR_IA32_APICBASE_EXTD) {
     39        kvm_apic_set_reg(kapic, 0x2, s->initial_apic_id);
     40    } else {
     41        kvm_apic_set_reg(kapic, 0x2, s->id << 24);
     42    }
     43    kvm_apic_set_reg(kapic, 0x8, s->tpr);
     44    kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
     45    kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
     46    kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
     47    for (i = 0; i < 8; i++) {
     48        kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
     49        kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
     50        kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
     51    }
     52    kvm_apic_set_reg(kapic, 0x28, s->esr);
     53    kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
     54    kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
     55    for (i = 0; i < APIC_LVT_NB; i++) {
     56        kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
     57    }
     58    kvm_apic_set_reg(kapic, 0x38, s->initial_count);
     59    kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
     60}
     61
     62void kvm_get_apic_state(DeviceState *dev, struct kvm_lapic_state *kapic)
     63{
     64    APICCommonState *s = APIC_COMMON(dev);
     65    int i, v;
     66
     67    if (kvm_has_x2apic_api() && s->apicbase & MSR_IA32_APICBASE_EXTD) {
     68        assert(kvm_apic_get_reg(kapic, 0x2) == s->initial_apic_id);
     69    } else {
     70        s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
     71    }
     72    s->tpr = kvm_apic_get_reg(kapic, 0x8);
     73    s->arb_id = kvm_apic_get_reg(kapic, 0x9);
     74    s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
     75    s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
     76    s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
     77    for (i = 0; i < 8; i++) {
     78        s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
     79        s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
     80        s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
     81    }
     82    s->esr = kvm_apic_get_reg(kapic, 0x28);
     83    s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
     84    s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
     85    for (i = 0; i < APIC_LVT_NB; i++) {
     86        s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
     87    }
     88    s->initial_count = kvm_apic_get_reg(kapic, 0x38);
     89    s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
     90
     91    v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
     92    s->count_shift = (v + 1) & 7;
     93
     94    s->initial_count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
     95    apic_next_timer(s, s->initial_count_load_time);
     96}
     97
     98static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
     99{
    100    s->apicbase = val;
    101}
    102
    103static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
    104{
    105    s->tpr = (val & 0x0f) << 4;
    106}
    107
    108static uint8_t kvm_apic_get_tpr(APICCommonState *s)
    109{
    110    return s->tpr >> 4;
    111}
    112
    113static void kvm_apic_enable_tpr_reporting(APICCommonState *s, bool enable)
    114{
    115    struct kvm_tpr_access_ctl ctl = {
    116        .enabled = enable
    117    };
    118
    119    kvm_vcpu_ioctl(CPU(s->cpu), KVM_TPR_ACCESS_REPORTING, &ctl);
    120}
    121
    122static void kvm_apic_vapic_base_update(APICCommonState *s)
    123{
    124    struct kvm_vapic_addr vapid_addr = {
    125        .vapic_addr = s->vapic_paddr,
    126    };
    127    int ret;
    128
    129    ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_VAPIC_ADDR, &vapid_addr);
    130    if (ret < 0) {
    131        fprintf(stderr, "KVM: setting VAPIC address failed (%s)\n",
    132                strerror(-ret));
    133        abort();
    134    }
    135}
    136
    137static void kvm_apic_put(CPUState *cs, run_on_cpu_data data)
    138{
    139    APICCommonState *s = data.host_ptr;
    140    struct kvm_lapic_state kapic;
    141    int ret;
    142
    143    kvm_put_apicbase(s->cpu, s->apicbase);
    144    kvm_put_apic_state(s, &kapic);
    145
    146    ret = kvm_vcpu_ioctl(CPU(s->cpu), KVM_SET_LAPIC, &kapic);
    147    if (ret < 0) {
    148        fprintf(stderr, "KVM_SET_LAPIC failed: %s\n", strerror(-ret));
    149        abort();
    150    }
    151}
    152
    153static void kvm_apic_post_load(APICCommonState *s)
    154{
    155    run_on_cpu(CPU(s->cpu), kvm_apic_put, RUN_ON_CPU_HOST_PTR(s));
    156}
    157
    158static void do_inject_external_nmi(CPUState *cpu, run_on_cpu_data data)
    159{
    160    APICCommonState *s = data.host_ptr;
    161    uint32_t lvt;
    162    int ret;
    163
    164    cpu_synchronize_state(cpu);
    165
    166    lvt = s->lvt[APIC_LVT_LINT1];
    167    if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
    168        ret = kvm_vcpu_ioctl(cpu, KVM_NMI);
    169        if (ret < 0) {
    170            fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
    171                    strerror(-ret));
    172        }
    173    }
    174}
    175
    176static void kvm_apic_external_nmi(APICCommonState *s)
    177{
    178    run_on_cpu(CPU(s->cpu), do_inject_external_nmi, RUN_ON_CPU_HOST_PTR(s));
    179}
    180
    181static void kvm_send_msi(MSIMessage *msg)
    182{
    183    int ret;
    184
    185    /*
    186     * The message has already passed through interrupt remapping if enabled,
    187     * but the legacy extended destination ID in low bits still needs to be
    188     * handled.
    189     */
    190    msg->address = kvm_swizzle_msi_ext_dest_id(msg->address);
    191
    192    ret = kvm_irqchip_send_msi(kvm_state, *msg);
    193    if (ret < 0) {
    194        fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
    195                strerror(-ret));
    196    }
    197}
    198
    199static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
    200                                  unsigned size)
    201{
    202    return ~(uint64_t)0;
    203}
    204
    205static void kvm_apic_mem_write(void *opaque, hwaddr addr,
    206                               uint64_t data, unsigned size)
    207{
    208    MSIMessage msg = { .address = addr, .data = data };
    209
    210    kvm_send_msi(&msg);
    211}
    212
    213static const MemoryRegionOps kvm_apic_io_ops = {
    214    .read = kvm_apic_mem_read,
    215    .write = kvm_apic_mem_write,
    216    .endianness = DEVICE_NATIVE_ENDIAN,
    217};
    218
    219static void kvm_apic_reset(APICCommonState *s)
    220{
    221    /* Not used by KVM, which uses the CPU mp_state instead.  */
    222    s->wait_for_sipi = 0;
    223
    224    run_on_cpu(CPU(s->cpu), kvm_apic_put, RUN_ON_CPU_HOST_PTR(s));
    225}
    226
    227static void kvm_apic_realize(DeviceState *dev, Error **errp)
    228{
    229    APICCommonState *s = APIC_COMMON(dev);
    230
    231    memory_region_init_io(&s->io_memory, OBJECT(s), &kvm_apic_io_ops, s,
    232                          "kvm-apic-msi", APIC_SPACE_SIZE);
    233
    234    assert(kvm_has_gsi_routing());
    235    msi_nonbroken = true;
    236}
    237
    238static void kvm_apic_unrealize(DeviceState *dev)
    239{
    240}
    241
    242static void kvm_apic_class_init(ObjectClass *klass, void *data)
    243{
    244    APICCommonClass *k = APIC_COMMON_CLASS(klass);
    245
    246    k->realize = kvm_apic_realize;
    247    k->unrealize = kvm_apic_unrealize;
    248    k->reset = kvm_apic_reset;
    249    k->set_base = kvm_apic_set_base;
    250    k->set_tpr = kvm_apic_set_tpr;
    251    k->get_tpr = kvm_apic_get_tpr;
    252    k->post_load = kvm_apic_post_load;
    253    k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
    254    k->vapic_base_update = kvm_apic_vapic_base_update;
    255    k->external_nmi = kvm_apic_external_nmi;
    256    k->send_msi = kvm_send_msi;
    257}
    258
    259static const TypeInfo kvm_apic_info = {
    260    .name = "kvm-apic",
    261    .parent = TYPE_APIC_COMMON,
    262    .instance_size = sizeof(APICCommonState),
    263    .class_init = kvm_apic_class_init,
    264};
    265
    266static void kvm_apic_register_types(void)
    267{
    268    type_register_static(&kvm_apic_info);
    269}
    270
    271type_init(kvm_apic_register_types)