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

generic_event_device.c (13316B)


      1/*
      2 *
      3 * Copyright (c) 2018 Intel Corporation
      4 * Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
      5 * Written by Samuel Ortiz, Shameer Kolothum
      6 *
      7 * This program is free software; you can redistribute it and/or modify it
      8 * under the terms and conditions of the GNU General Public License,
      9 * version 2 or later, as published by the Free Software Foundation.
     10 */
     11
     12#include "qemu/osdep.h"
     13#include "qapi/error.h"
     14#include "hw/acpi/acpi.h"
     15#include "hw/acpi/generic_event_device.h"
     16#include "hw/irq.h"
     17#include "hw/mem/pc-dimm.h"
     18#include "hw/mem/nvdimm.h"
     19#include "hw/qdev-properties.h"
     20#include "migration/vmstate.h"
     21#include "qemu/error-report.h"
     22#include "sysemu/runstate.h"
     23
     24static const uint32_t ged_supported_events[] = {
     25    ACPI_GED_MEM_HOTPLUG_EVT,
     26    ACPI_GED_PWR_DOWN_EVT,
     27    ACPI_GED_NVDIMM_HOTPLUG_EVT,
     28};
     29
     30/*
     31 * The ACPI Generic Event Device (GED) is a hardware-reduced specific
     32 * device[ACPI v6.1 Section 5.6.9] that handles all platform events,
     33 * including the hotplug ones. Platforms need to specify their own
     34 * GED Event bitmap to describe what kind of events they want to support
     35 * through GED. This routine uses a single interrupt for the GED device,
     36 * relying on IO memory region to communicate the type of device
     37 * affected by the interrupt. This way, we can support up to 32 events
     38 * with a unique interrupt.
     39 */
     40void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
     41                   uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
     42{
     43    AcpiGedState *s = ACPI_GED(hotplug_dev);
     44    Aml *crs = aml_resource_template();
     45    Aml *evt, *field;
     46    Aml *dev = aml_device("%s", name);
     47    Aml *evt_sel = aml_local(0);
     48    Aml *esel = aml_name(AML_GED_EVT_SEL);
     49
     50    /* _CRS interrupt */
     51    aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
     52                                  AML_EXCLUSIVE, &ged_irq, 1));
     53
     54    aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013")));
     55    aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE)));
     56    aml_append(dev, aml_name_decl("_CRS", crs));
     57
     58    /* Append IO region */
     59    aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs,
     60               aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET),
     61               ACPI_GED_EVT_SEL_LEN));
     62    field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK,
     63                      AML_WRITE_AS_ZEROS);
     64    aml_append(field, aml_named_field(AML_GED_EVT_SEL,
     65                                      ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE));
     66    aml_append(dev, field);
     67
     68    /*
     69     * For each GED event we:
     70     * - Add a conditional block for each event, inside a loop.
     71     * - Call a method for each supported GED event type.
     72     *
     73     * The resulting ASL code looks like:
     74     *
     75     * Local0 = ESEL
     76     * If ((Local0 & One) == One)
     77     * {
     78     *     MethodEvent0()
     79     * }
     80     *
     81     * If ((Local0 & 0x2) == 0x2)
     82     * {
     83     *     MethodEvent1()
     84     * }
     85     * ...
     86     */
     87    evt = aml_method("_EVT", 1, AML_SERIALIZED);
     88    {
     89        Aml *if_ctx;
     90        uint32_t i;
     91        uint32_t ged_events = ctpop32(s->ged_event_bitmap);
     92
     93        /* Local0 = ESEL */
     94        aml_append(evt, aml_store(esel, evt_sel));
     95
     96        for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
     97            uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
     98
     99            if (!event) {
    100                continue;
    101            }
    102
    103            if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL),
    104                                      aml_int(event)));
    105            switch (event) {
    106            case ACPI_GED_MEM_HOTPLUG_EVT:
    107                aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
    108                                             MEMORY_SLOT_SCAN_METHOD));
    109                break;
    110            case ACPI_GED_PWR_DOWN_EVT:
    111                aml_append(if_ctx,
    112                           aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
    113                                      aml_int(0x80)));
    114                break;
    115            case ACPI_GED_NVDIMM_HOTPLUG_EVT:
    116                aml_append(if_ctx,
    117                           aml_notify(aml_name("\\_SB.NVDR"),
    118                                      aml_int(0x80)));
    119                break;
    120            default:
    121                /*
    122                 * Please make sure all the events in ged_supported_events[]
    123                 * are handled above.
    124                 */
    125                g_assert_not_reached();
    126            }
    127
    128            aml_append(evt, if_ctx);
    129            ged_events--;
    130        }
    131
    132        if (ged_events) {
    133            error_report("Unsupported events specified");
    134            abort();
    135        }
    136    }
    137
    138    /* Append _EVT method */
    139    aml_append(dev, evt);
    140
    141    aml_append(table, dev);
    142}
    143
    144void acpi_dsdt_add_power_button(Aml *scope)
    145{
    146    Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
    147    aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
    148    aml_append(dev, aml_name_decl("_UID", aml_int(0)));
    149    aml_append(scope, dev);
    150}
    151
    152/* Memory read by the GED _EVT AML dynamic method */
    153static uint64_t ged_evt_read(void *opaque, hwaddr addr, unsigned size)
    154{
    155    uint64_t val = 0;
    156    GEDState *ged_st = opaque;
    157
    158    switch (addr) {
    159    case ACPI_GED_EVT_SEL_OFFSET:
    160        /* Read the selector value and reset it */
    161        val = ged_st->sel;
    162        ged_st->sel = 0;
    163        break;
    164    default:
    165        break;
    166    }
    167
    168    return val;
    169}
    170
    171/* Nothing is expected to be written to the GED memory region */
    172static void ged_evt_write(void *opaque, hwaddr addr, uint64_t data,
    173                          unsigned int size)
    174{
    175}
    176
    177static const MemoryRegionOps ged_evt_ops = {
    178    .read = ged_evt_read,
    179    .write = ged_evt_write,
    180    .endianness = DEVICE_LITTLE_ENDIAN,
    181    .valid = {
    182        .min_access_size = 4,
    183        .max_access_size = 4,
    184    },
    185};
    186
    187static uint64_t ged_regs_read(void *opaque, hwaddr addr, unsigned size)
    188{
    189    return 0;
    190}
    191
    192static void ged_regs_write(void *opaque, hwaddr addr, uint64_t data,
    193                           unsigned int size)
    194{
    195    bool slp_en;
    196    int slp_typ;
    197
    198    switch (addr) {
    199    case ACPI_GED_REG_SLEEP_CTL:
    200        slp_typ = (data >> 2) & 0x07;
    201        slp_en  = (data >> 5) & 0x01;
    202        if (slp_en && slp_typ == 5) {
    203            qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
    204        }
    205        return;
    206    case ACPI_GED_REG_SLEEP_STS:
    207        return;
    208    case ACPI_GED_REG_RESET:
    209        if (data == ACPI_GED_RESET_VALUE) {
    210            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
    211        }
    212        return;
    213    }
    214}
    215
    216static const MemoryRegionOps ged_regs_ops = {
    217    .read = ged_regs_read,
    218    .write = ged_regs_write,
    219    .endianness = DEVICE_LITTLE_ENDIAN,
    220    .valid = {
    221        .min_access_size = 1,
    222        .max_access_size = 1,
    223    },
    224};
    225
    226static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
    227                                    DeviceState *dev, Error **errp)
    228{
    229    AcpiGedState *s = ACPI_GED(hotplug_dev);
    230
    231    if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
    232        if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
    233            nvdimm_acpi_plug_cb(hotplug_dev, dev);
    234        } else {
    235            acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
    236        }
    237    } else {
    238        error_setg(errp, "virt: device plug request for unsupported device"
    239                   " type: %s", object_get_typename(OBJECT(dev)));
    240    }
    241}
    242
    243static void acpi_ged_unplug_request_cb(HotplugHandler *hotplug_dev,
    244                                       DeviceState *dev, Error **errp)
    245{
    246    AcpiGedState *s = ACPI_GED(hotplug_dev);
    247
    248    if ((object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
    249                       !(object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)))) {
    250        acpi_memory_unplug_request_cb(hotplug_dev, &s->memhp_state, dev, errp);
    251    } else {
    252        error_setg(errp, "acpi: device unplug request for unsupported device"
    253                   " type: %s", object_get_typename(OBJECT(dev)));
    254    }
    255}
    256
    257static void acpi_ged_unplug_cb(HotplugHandler *hotplug_dev,
    258                               DeviceState *dev, Error **errp)
    259{
    260    AcpiGedState *s = ACPI_GED(hotplug_dev);
    261
    262    if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
    263        acpi_memory_unplug_cb(&s->memhp_state, dev, errp);
    264    } else {
    265        error_setg(errp, "acpi: device unplug for unsupported device"
    266                   " type: %s", object_get_typename(OBJECT(dev)));
    267    }
    268}
    269
    270static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
    271{
    272    AcpiGedState *s = ACPI_GED(adev);
    273    GEDState *ged_st = &s->ged_state;
    274    uint32_t sel;
    275
    276    if (ev & ACPI_MEMORY_HOTPLUG_STATUS) {
    277        sel = ACPI_GED_MEM_HOTPLUG_EVT;
    278    } else if (ev & ACPI_POWER_DOWN_STATUS) {
    279        sel = ACPI_GED_PWR_DOWN_EVT;
    280    } else if (ev & ACPI_NVDIMM_HOTPLUG_STATUS) {
    281        sel = ACPI_GED_NVDIMM_HOTPLUG_EVT;
    282    } else {
    283        /* Unknown event. Return without generating interrupt. */
    284        warn_report("GED: Unsupported event %d. No irq injected", ev);
    285        return;
    286    }
    287
    288    /*
    289     * Set the GED selector field to communicate the event type.
    290     * This will be read by GED aml code to select the appropriate
    291     * event method.
    292     */
    293    ged_st->sel |= sel;
    294
    295    /* Trigger the event by sending an interrupt to the guest. */
    296    qemu_irq_pulse(s->irq);
    297}
    298
    299static Property acpi_ged_properties[] = {
    300    DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
    301    DEFINE_PROP_END_OF_LIST(),
    302};
    303
    304static const VMStateDescription vmstate_memhp_state = {
    305    .name = "acpi-ged/memhp",
    306    .version_id = 1,
    307    .minimum_version_id = 1,
    308    .fields      = (VMStateField[]) {
    309        VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState),
    310        VMSTATE_END_OF_LIST()
    311    }
    312};
    313
    314static const VMStateDescription vmstate_ged_state = {
    315    .name = "acpi-ged-state",
    316    .version_id = 1,
    317    .minimum_version_id = 1,
    318    .fields      = (VMStateField[]) {
    319        VMSTATE_UINT32(sel, GEDState),
    320        VMSTATE_END_OF_LIST()
    321    }
    322};
    323
    324static const VMStateDescription vmstate_ghes = {
    325    .name = "acpi-ghes",
    326    .version_id = 1,
    327    .minimum_version_id = 1,
    328    .fields     = (VMStateField[]) {
    329        VMSTATE_UINT64(ghes_addr_le, AcpiGhesState),
    330        VMSTATE_END_OF_LIST()
    331    },
    332};
    333
    334static bool ghes_needed(void *opaque)
    335{
    336    AcpiGedState *s = opaque;
    337    return s->ghes_state.ghes_addr_le;
    338}
    339
    340static const VMStateDescription vmstate_ghes_state = {
    341    .name = "acpi-ged/ghes",
    342    .version_id = 1,
    343    .minimum_version_id = 1,
    344    .needed = ghes_needed,
    345    .fields      = (VMStateField[]) {
    346        VMSTATE_STRUCT(ghes_state, AcpiGedState, 1,
    347                       vmstate_ghes, AcpiGhesState),
    348        VMSTATE_END_OF_LIST()
    349    }
    350};
    351
    352static const VMStateDescription vmstate_acpi_ged = {
    353    .name = "acpi-ged",
    354    .version_id = 1,
    355    .minimum_version_id = 1,
    356    .fields = (VMStateField[]) {
    357        VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState),
    358        VMSTATE_END_OF_LIST(),
    359    },
    360    .subsections = (const VMStateDescription * []) {
    361        &vmstate_memhp_state,
    362        &vmstate_ghes_state,
    363        NULL
    364    }
    365};
    366
    367static void acpi_ged_initfn(Object *obj)
    368{
    369    DeviceState *dev = DEVICE(obj);
    370    AcpiGedState *s = ACPI_GED(dev);
    371    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    372    GEDState *ged_st = &s->ged_state;
    373
    374    memory_region_init_io(&ged_st->evt, obj, &ged_evt_ops, ged_st,
    375                          TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
    376    sysbus_init_mmio(sbd, &ged_st->evt);
    377
    378    sysbus_init_irq(sbd, &s->irq);
    379
    380    s->memhp_state.is_enabled = true;
    381    /*
    382     * GED handles memory hotplug event and acpi-mem-hotplug
    383     * memory region gets initialized here. Create an exclusive
    384     * container for memory hotplug IO and expose it as GED sysbus
    385     * MMIO so that boards can map it separately.
    386     */
    387     memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
    388                        MEMORY_HOTPLUG_IO_LEN);
    389     sysbus_init_mmio(sbd, &s->container_memhp);
    390     acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
    391                              &s->memhp_state, 0);
    392
    393    memory_region_init_io(&ged_st->regs, obj, &ged_regs_ops, ged_st,
    394                          TYPE_ACPI_GED "-regs", ACPI_GED_REG_COUNT);
    395    sysbus_init_mmio(sbd, &ged_st->regs);
    396}
    397
    398static void acpi_ged_class_init(ObjectClass *class, void *data)
    399{
    400    DeviceClass *dc = DEVICE_CLASS(class);
    401    HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
    402    AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
    403
    404    dc->desc = "ACPI Generic Event Device";
    405    device_class_set_props(dc, acpi_ged_properties);
    406    dc->vmsd = &vmstate_acpi_ged;
    407
    408    hc->plug = acpi_ged_device_plug_cb;
    409    hc->unplug_request = acpi_ged_unplug_request_cb;
    410    hc->unplug = acpi_ged_unplug_cb;
    411
    412    adevc->send_event = acpi_ged_send_event;
    413}
    414
    415static const TypeInfo acpi_ged_info = {
    416    .name          = TYPE_ACPI_GED,
    417    .parent        = TYPE_SYS_BUS_DEVICE,
    418    .instance_size = sizeof(AcpiGedState),
    419    .instance_init  = acpi_ged_initfn,
    420    .class_init    = acpi_ged_class_init,
    421    .interfaces = (InterfaceInfo[]) {
    422        { TYPE_HOTPLUG_HANDLER },
    423        { TYPE_ACPI_DEVICE_IF },
    424        { }
    425    }
    426};
    427
    428static void acpi_ged_register_types(void)
    429{
    430    type_register_static(&acpi_ged_info);
    431}
    432
    433type_init(acpi_ged_register_types)