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

proxy.c (10949B)


      1/*
      2 * Copyright © 2018, 2021 Oracle and/or its affiliates.
      3 *
      4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      5 * See the COPYING file in the top-level directory.
      6 *
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qemu-common.h"
     11
     12#include "hw/remote/proxy.h"
     13#include "hw/pci/pci.h"
     14#include "qapi/error.h"
     15#include "io/channel-util.h"
     16#include "hw/qdev-properties.h"
     17#include "monitor/monitor.h"
     18#include "migration/blocker.h"
     19#include "qemu/sockets.h"
     20#include "hw/remote/mpqemu-link.h"
     21#include "qemu/error-report.h"
     22#include "hw/remote/proxy-memory-listener.h"
     23#include "qom/object.h"
     24#include "qemu/event_notifier.h"
     25#include "sysemu/kvm.h"
     26#include "util/event_notifier-posix.c"
     27
     28static void probe_pci_info(PCIDevice *dev, Error **errp);
     29static void proxy_device_reset(DeviceState *dev);
     30
     31static void proxy_intx_update(PCIDevice *pci_dev)
     32{
     33    PCIProxyDev *dev = PCI_PROXY_DEV(pci_dev);
     34    PCIINTxRoute route;
     35    int pin = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1;
     36
     37    if (dev->virq != -1) {
     38        kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &dev->intr, dev->virq);
     39        dev->virq = -1;
     40    }
     41
     42    route = pci_device_route_intx_to_irq(pci_dev, pin);
     43
     44    dev->virq = route.irq;
     45
     46    if (dev->virq != -1) {
     47        kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &dev->intr,
     48                                           &dev->resample, dev->virq);
     49    }
     50}
     51
     52static void setup_irqfd(PCIProxyDev *dev)
     53{
     54    PCIDevice *pci_dev = PCI_DEVICE(dev);
     55    MPQemuMsg msg;
     56    Error *local_err = NULL;
     57
     58    event_notifier_init(&dev->intr, 0);
     59    event_notifier_init(&dev->resample, 0);
     60
     61    memset(&msg, 0, sizeof(MPQemuMsg));
     62    msg.cmd = MPQEMU_CMD_SET_IRQFD;
     63    msg.num_fds = 2;
     64    msg.fds[0] = event_notifier_get_fd(&dev->intr);
     65    msg.fds[1] = event_notifier_get_fd(&dev->resample);
     66    msg.size = 0;
     67
     68    if (!mpqemu_msg_send(&msg, dev->ioc, &local_err)) {
     69        error_report_err(local_err);
     70    }
     71
     72    dev->virq = -1;
     73
     74    proxy_intx_update(pci_dev);
     75
     76    pci_device_set_intx_routing_notifier(pci_dev, proxy_intx_update);
     77}
     78
     79static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
     80{
     81    ERRP_GUARD();
     82    PCIProxyDev *dev = PCI_PROXY_DEV(device);
     83    uint8_t *pci_conf = device->config;
     84    int fd;
     85
     86    if (!dev->fd) {
     87        error_setg(errp, "fd parameter not specified for %s",
     88                   DEVICE(device)->id);
     89        return;
     90    }
     91
     92    fd = monitor_fd_param(monitor_cur(), dev->fd, errp);
     93    if (fd == -1) {
     94        error_prepend(errp, "proxy: unable to parse fd %s: ", dev->fd);
     95        return;
     96    }
     97
     98    if (!fd_is_socket(fd)) {
     99        error_setg(errp, "proxy: fd %d is not a socket", fd);
    100        close(fd);
    101        return;
    102    }
    103
    104    dev->ioc = qio_channel_new_fd(fd, errp);
    105    if (!dev->ioc) {
    106        close(fd);
    107        return;
    108    }
    109
    110    error_setg(&dev->migration_blocker, "%s does not support migration",
    111               TYPE_PCI_PROXY_DEV);
    112    if (migrate_add_blocker(dev->migration_blocker, errp) < 0) {
    113        error_free(dev->migration_blocker);
    114        object_unref(dev->ioc);
    115        return;
    116    }
    117
    118    qemu_mutex_init(&dev->io_mutex);
    119    qio_channel_set_blocking(dev->ioc, true, NULL);
    120
    121    pci_conf[PCI_LATENCY_TIMER] = 0xff;
    122    pci_conf[PCI_INTERRUPT_PIN] = 0x01;
    123
    124    proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc);
    125
    126    setup_irqfd(dev);
    127
    128    probe_pci_info(PCI_DEVICE(dev), errp);
    129}
    130
    131static void pci_proxy_dev_exit(PCIDevice *pdev)
    132{
    133    PCIProxyDev *dev = PCI_PROXY_DEV(pdev);
    134
    135    if (dev->ioc) {
    136        qio_channel_close(dev->ioc, NULL);
    137    }
    138
    139    migrate_del_blocker(dev->migration_blocker);
    140
    141    error_free(dev->migration_blocker);
    142
    143    proxy_memory_listener_deconfigure(&dev->proxy_listener);
    144
    145    event_notifier_cleanup(&dev->intr);
    146    event_notifier_cleanup(&dev->resample);
    147}
    148
    149static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val,
    150                           int len, unsigned int op)
    151{
    152    MPQemuMsg msg = { 0 };
    153    uint64_t ret = -EINVAL;
    154    Error *local_err = NULL;
    155
    156    msg.cmd = op;
    157    msg.data.pci_conf_data.addr = addr;
    158    msg.data.pci_conf_data.val = (op == MPQEMU_CMD_PCI_CFGWRITE) ? *val : 0;
    159    msg.data.pci_conf_data.len = len;
    160    msg.size = sizeof(PciConfDataMsg);
    161
    162    ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
    163    if (local_err) {
    164        error_report_err(local_err);
    165    }
    166
    167    if (ret == UINT64_MAX) {
    168        error_report("Failed to perform PCI config %s operation",
    169                     (op == MPQEMU_CMD_PCI_CFGREAD) ? "READ" : "WRITE");
    170    }
    171
    172    if (op == MPQEMU_CMD_PCI_CFGREAD) {
    173        *val = (uint32_t)ret;
    174    }
    175}
    176
    177static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len)
    178{
    179    uint32_t val;
    180
    181    config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGREAD);
    182
    183    return val;
    184}
    185
    186static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val,
    187                                   int len)
    188{
    189    /*
    190     * Some of the functions access the copy of remote device's PCI config
    191     * space which is cached in the proxy device. Therefore, maintain
    192     * it updated.
    193     */
    194    pci_default_write_config(d, addr, val, len);
    195
    196    config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE);
    197}
    198
    199static Property proxy_properties[] = {
    200    DEFINE_PROP_STRING("fd", PCIProxyDev, fd),
    201    DEFINE_PROP_END_OF_LIST(),
    202};
    203
    204static void pci_proxy_dev_class_init(ObjectClass *klass, void *data)
    205{
    206    DeviceClass *dc = DEVICE_CLASS(klass);
    207    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    208
    209    k->realize = pci_proxy_dev_realize;
    210    k->exit = pci_proxy_dev_exit;
    211    k->config_read = pci_proxy_read_config;
    212    k->config_write = pci_proxy_write_config;
    213
    214    dc->reset = proxy_device_reset;
    215
    216    device_class_set_props(dc, proxy_properties);
    217}
    218
    219static const TypeInfo pci_proxy_dev_type_info = {
    220    .name          = TYPE_PCI_PROXY_DEV,
    221    .parent        = TYPE_PCI_DEVICE,
    222    .instance_size = sizeof(PCIProxyDev),
    223    .class_init    = pci_proxy_dev_class_init,
    224    .interfaces = (InterfaceInfo[]) {
    225        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    226        { },
    227    },
    228};
    229
    230static void pci_proxy_dev_register_types(void)
    231{
    232    type_register_static(&pci_proxy_dev_type_info);
    233}
    234
    235type_init(pci_proxy_dev_register_types)
    236
    237static void send_bar_access_msg(PCIProxyDev *pdev, MemoryRegion *mr,
    238                                bool write, hwaddr addr, uint64_t *val,
    239                                unsigned size, bool memory)
    240{
    241    MPQemuMsg msg = { 0 };
    242    long ret = -EINVAL;
    243    Error *local_err = NULL;
    244
    245    msg.size = sizeof(BarAccessMsg);
    246    msg.data.bar_access.addr = mr->addr + addr;
    247    msg.data.bar_access.size = size;
    248    msg.data.bar_access.memory = memory;
    249
    250    if (write) {
    251        msg.cmd = MPQEMU_CMD_BAR_WRITE;
    252        msg.data.bar_access.val = *val;
    253    } else {
    254        msg.cmd = MPQEMU_CMD_BAR_READ;
    255    }
    256
    257    ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
    258    if (local_err) {
    259        error_report_err(local_err);
    260    }
    261
    262    if (!write) {
    263        *val = ret;
    264    }
    265}
    266
    267static void proxy_bar_write(void *opaque, hwaddr addr, uint64_t val,
    268                            unsigned size)
    269{
    270    ProxyMemoryRegion *pmr = opaque;
    271
    272    send_bar_access_msg(pmr->dev, &pmr->mr, true, addr, &val, size,
    273                        pmr->memory);
    274}
    275
    276static uint64_t proxy_bar_read(void *opaque, hwaddr addr, unsigned size)
    277{
    278    ProxyMemoryRegion *pmr = opaque;
    279    uint64_t val;
    280
    281    send_bar_access_msg(pmr->dev, &pmr->mr, false, addr, &val, size,
    282                        pmr->memory);
    283
    284    return val;
    285}
    286
    287const MemoryRegionOps proxy_mr_ops = {
    288    .read = proxy_bar_read,
    289    .write = proxy_bar_write,
    290    .endianness = DEVICE_NATIVE_ENDIAN,
    291    .impl = {
    292        .min_access_size = 1,
    293        .max_access_size = 8,
    294    },
    295};
    296
    297static void probe_pci_info(PCIDevice *dev, Error **errp)
    298{
    299    PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
    300    uint32_t orig_val, new_val, base_class, val;
    301    PCIProxyDev *pdev = PCI_PROXY_DEV(dev);
    302    DeviceClass *dc = DEVICE_CLASS(pc);
    303    uint8_t type;
    304    int i, size;
    305
    306    config_op_send(pdev, PCI_VENDOR_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
    307    pc->vendor_id = (uint16_t)val;
    308
    309    config_op_send(pdev, PCI_DEVICE_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
    310    pc->device_id = (uint16_t)val;
    311
    312    config_op_send(pdev, PCI_CLASS_DEVICE, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
    313    pc->class_id = (uint16_t)val;
    314
    315    config_op_send(pdev, PCI_SUBSYSTEM_ID, &val, 2, MPQEMU_CMD_PCI_CFGREAD);
    316    pc->subsystem_id = (uint16_t)val;
    317
    318    base_class = pc->class_id >> 4;
    319    switch (base_class) {
    320    case PCI_BASE_CLASS_BRIDGE:
    321        set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    322        break;
    323    case PCI_BASE_CLASS_STORAGE:
    324        set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
    325        break;
    326    case PCI_BASE_CLASS_NETWORK:
    327    case PCI_BASE_CLASS_WIRELESS:
    328        set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
    329        break;
    330    case PCI_BASE_CLASS_INPUT:
    331        set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
    332        break;
    333    case PCI_BASE_CLASS_DISPLAY:
    334        set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
    335        break;
    336    case PCI_BASE_CLASS_PROCESSOR:
    337        set_bit(DEVICE_CATEGORY_CPU, dc->categories);
    338        break;
    339    default:
    340        set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    341        break;
    342    }
    343
    344    for (i = 0; i < PCI_NUM_REGIONS; i++) {
    345        config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4,
    346                       MPQEMU_CMD_PCI_CFGREAD);
    347        new_val = 0xffffffff;
    348        config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4,
    349                       MPQEMU_CMD_PCI_CFGWRITE);
    350        config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &new_val, 4,
    351                       MPQEMU_CMD_PCI_CFGREAD);
    352        size = (~(new_val & 0xFFFFFFF0)) + 1;
    353        config_op_send(pdev, PCI_BASE_ADDRESS_0 + (4 * i), &orig_val, 4,
    354                       MPQEMU_CMD_PCI_CFGWRITE);
    355        type = (new_val & 0x1) ?
    356                   PCI_BASE_ADDRESS_SPACE_IO : PCI_BASE_ADDRESS_SPACE_MEMORY;
    357
    358        if (size) {
    359            g_autofree char *name = g_strdup_printf("bar-region-%d", i);
    360            pdev->region[i].dev = pdev;
    361            pdev->region[i].present = true;
    362            if (type == PCI_BASE_ADDRESS_SPACE_MEMORY) {
    363                pdev->region[i].memory = true;
    364            }
    365            memory_region_init_io(&pdev->region[i].mr, OBJECT(pdev),
    366                                  &proxy_mr_ops, &pdev->region[i],
    367                                  name, size);
    368            pci_register_bar(dev, i, type, &pdev->region[i].mr);
    369        }
    370    }
    371}
    372
    373static void proxy_device_reset(DeviceState *dev)
    374{
    375    PCIProxyDev *pdev = PCI_PROXY_DEV(dev);
    376    MPQemuMsg msg = { 0 };
    377    Error *local_err = NULL;
    378
    379    msg.cmd = MPQEMU_CMD_DEVICE_RESET;
    380    msg.size = 0;
    381
    382    mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
    383    if (local_err) {
    384        error_report_err(local_err);
    385    }
    386
    387}