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

pci_expander_bridge.c (10852B)


      1/*
      2 * PCI Expander Bridge Device Emulation
      3 *
      4 * Copyright (C) 2015 Red Hat Inc
      5 *
      6 * Authors:
      7 *   Marcel Apfelbaum <marcel@redhat.com>
      8 *
      9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10 * See the COPYING file in the top-level directory.
     11 */
     12
     13#include "qemu/osdep.h"
     14#include "qapi/error.h"
     15#include "hw/pci/pci.h"
     16#include "hw/pci/pci_bus.h"
     17#include "hw/pci/pci_host.h"
     18#include "hw/qdev-properties.h"
     19#include "hw/pci/pci_bridge.h"
     20#include "qemu/range.h"
     21#include "qemu/error-report.h"
     22#include "qemu/module.h"
     23#include "sysemu/numa.h"
     24#include "hw/boards.h"
     25#include "qom/object.h"
     26
     27#define TYPE_PXB_BUS "pxb-bus"
     28typedef struct PXBBus PXBBus;
     29DECLARE_INSTANCE_CHECKER(PXBBus, PXB_BUS,
     30                         TYPE_PXB_BUS)
     31
     32#define TYPE_PXB_PCIE_BUS "pxb-pcie-bus"
     33DECLARE_INSTANCE_CHECKER(PXBBus, PXB_PCIE_BUS,
     34                         TYPE_PXB_PCIE_BUS)
     35
     36struct PXBBus {
     37    /*< private >*/
     38    PCIBus parent_obj;
     39    /*< public >*/
     40
     41    char bus_path[8];
     42};
     43
     44#define TYPE_PXB_DEVICE "pxb"
     45typedef struct PXBDev PXBDev;
     46DECLARE_INSTANCE_CHECKER(PXBDev, PXB_DEV,
     47                         TYPE_PXB_DEVICE)
     48
     49#define TYPE_PXB_PCIE_DEVICE "pxb-pcie"
     50DECLARE_INSTANCE_CHECKER(PXBDev, PXB_PCIE_DEV,
     51                         TYPE_PXB_PCIE_DEVICE)
     52
     53struct PXBDev {
     54    /*< private >*/
     55    PCIDevice parent_obj;
     56    /*< public >*/
     57
     58    uint8_t bus_nr;
     59    uint16_t numa_node;
     60    bool bypass_iommu;
     61};
     62
     63static PXBDev *convert_to_pxb(PCIDevice *dev)
     64{
     65    return pci_bus_is_express(pci_get_bus(dev))
     66        ? PXB_PCIE_DEV(dev) : PXB_DEV(dev);
     67}
     68
     69static GList *pxb_dev_list;
     70
     71#define TYPE_PXB_HOST "pxb-host"
     72
     73static int pxb_bus_num(PCIBus *bus)
     74{
     75    PXBDev *pxb = convert_to_pxb(bus->parent_dev);
     76
     77    return pxb->bus_nr;
     78}
     79
     80static uint16_t pxb_bus_numa_node(PCIBus *bus)
     81{
     82    PXBDev *pxb = convert_to_pxb(bus->parent_dev);
     83
     84    return pxb->numa_node;
     85}
     86
     87static void pxb_bus_class_init(ObjectClass *class, void *data)
     88{
     89    PCIBusClass *pbc = PCI_BUS_CLASS(class);
     90
     91    pbc->bus_num = pxb_bus_num;
     92    pbc->numa_node = pxb_bus_numa_node;
     93}
     94
     95static const TypeInfo pxb_bus_info = {
     96    .name          = TYPE_PXB_BUS,
     97    .parent        = TYPE_PCI_BUS,
     98    .instance_size = sizeof(PXBBus),
     99    .class_init    = pxb_bus_class_init,
    100};
    101
    102static const TypeInfo pxb_pcie_bus_info = {
    103    .name          = TYPE_PXB_PCIE_BUS,
    104    .parent        = TYPE_PCIE_BUS,
    105    .instance_size = sizeof(PXBBus),
    106    .class_init    = pxb_bus_class_init,
    107};
    108
    109static const char *pxb_host_root_bus_path(PCIHostState *host_bridge,
    110                                          PCIBus *rootbus)
    111{
    112    PXBBus *bus = pci_bus_is_express(rootbus) ?
    113                  PXB_PCIE_BUS(rootbus) : PXB_BUS(rootbus);
    114
    115    snprintf(bus->bus_path, 8, "0000:%02x", pxb_bus_num(rootbus));
    116    return bus->bus_path;
    117}
    118
    119static char *pxb_host_ofw_unit_address(const SysBusDevice *dev)
    120{
    121    const PCIHostState *pxb_host;
    122    const PCIBus *pxb_bus;
    123    const PXBDev *pxb_dev;
    124    int position;
    125    const DeviceState *pxb_dev_base;
    126    const PCIHostState *main_host;
    127    const SysBusDevice *main_host_sbd;
    128
    129    pxb_host = PCI_HOST_BRIDGE(dev);
    130    pxb_bus = pxb_host->bus;
    131    pxb_dev = convert_to_pxb(pxb_bus->parent_dev);
    132    position = g_list_index(pxb_dev_list, pxb_dev);
    133    assert(position >= 0);
    134
    135    pxb_dev_base = DEVICE(pxb_dev);
    136    main_host = PCI_HOST_BRIDGE(pxb_dev_base->parent_bus->parent);
    137    main_host_sbd = SYS_BUS_DEVICE(main_host);
    138
    139    if (main_host_sbd->num_mmio > 0) {
    140        return g_strdup_printf(TARGET_FMT_plx ",%x",
    141                               main_host_sbd->mmio[0].addr, position + 1);
    142    }
    143    if (main_host_sbd->num_pio > 0) {
    144        return g_strdup_printf("i%04x,%x",
    145                               main_host_sbd->pio[0], position + 1);
    146    }
    147    return NULL;
    148}
    149
    150static void pxb_host_class_init(ObjectClass *class, void *data)
    151{
    152    DeviceClass *dc = DEVICE_CLASS(class);
    153    SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class);
    154    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class);
    155
    156    dc->fw_name = "pci";
    157    /* Reason: Internal part of the pxb/pxb-pcie device, not usable by itself */
    158    dc->user_creatable = false;
    159    sbc->explicit_ofw_unit_address = pxb_host_ofw_unit_address;
    160    hc->root_bus_path = pxb_host_root_bus_path;
    161}
    162
    163static const TypeInfo pxb_host_info = {
    164    .name          = TYPE_PXB_HOST,
    165    .parent        = TYPE_PCI_HOST_BRIDGE,
    166    .class_init    = pxb_host_class_init,
    167};
    168
    169/*
    170 * Registers the PXB bus as a child of pci host root bus.
    171 */
    172static void pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus, Error **errp)
    173{
    174    PCIBus *bus = pci_get_bus(dev);
    175    int pxb_bus_num = pci_bus_num(pxb_bus);
    176
    177    if (bus->parent_dev) {
    178        error_setg(errp, "PXB devices can be attached only to root bus");
    179        return;
    180    }
    181
    182    QLIST_FOREACH(bus, &bus->child, sibling) {
    183        if (pci_bus_num(bus) == pxb_bus_num) {
    184            error_setg(errp, "Bus %d is already in use", pxb_bus_num);
    185            return;
    186        }
    187    }
    188    QLIST_INSERT_HEAD(&pci_get_bus(dev)->child, pxb_bus, sibling);
    189}
    190
    191static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
    192{
    193    PCIDevice *pxb = pci_get_bus(pci_dev)->parent_dev;
    194
    195    /*
    196     * The bios does not index the pxb slot number when
    197     * it computes the IRQ because it resides on bus 0
    198     * and not on the current bus.
    199     * However QEMU routes the irq through bus 0 and adds
    200     * the pxb slot to the IRQ computation of the PXB
    201     * device.
    202     *
    203     * Synchronize between bios and QEMU by canceling
    204     * pxb's effect.
    205     */
    206    return pin - PCI_SLOT(pxb->devfn);
    207}
    208
    209static gint pxb_compare(gconstpointer a, gconstpointer b)
    210{
    211    const PXBDev *pxb_a = a, *pxb_b = b;
    212
    213    return pxb_a->bus_nr < pxb_b->bus_nr ? -1 :
    214           pxb_a->bus_nr > pxb_b->bus_nr ?  1 :
    215           0;
    216}
    217
    218static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
    219{
    220    PXBDev *pxb = convert_to_pxb(dev);
    221    DeviceState *ds, *bds = NULL;
    222    PCIBus *bus;
    223    const char *dev_name = NULL;
    224    Error *local_err = NULL;
    225    MachineState *ms = MACHINE(qdev_get_machine());
    226
    227    if (ms->numa_state == NULL) {
    228        error_setg(errp, "NUMA is not supported by this machine-type");
    229        return;
    230    }
    231
    232    if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
    233        pxb->numa_node >= ms->numa_state->num_nodes) {
    234        error_setg(errp, "Illegal numa node %d", pxb->numa_node);
    235        return;
    236    }
    237
    238    if (dev->qdev.id && *dev->qdev.id) {
    239        dev_name = dev->qdev.id;
    240    }
    241
    242    ds = qdev_new(TYPE_PXB_HOST);
    243    if (pcie) {
    244        bus = pci_root_bus_new(ds, dev_name, NULL, NULL, 0, TYPE_PXB_PCIE_BUS);
    245    } else {
    246        bus = pci_root_bus_new(ds, "pxb-internal", NULL, NULL, 0, TYPE_PXB_BUS);
    247        bds = qdev_new("pci-bridge");
    248        bds->id = dev_name;
    249        qdev_prop_set_uint8(bds, PCI_BRIDGE_DEV_PROP_CHASSIS_NR, pxb->bus_nr);
    250        qdev_prop_set_bit(bds, PCI_BRIDGE_DEV_PROP_SHPC, false);
    251    }
    252
    253    bus->parent_dev = dev;
    254    bus->address_space_mem = pci_get_bus(dev)->address_space_mem;
    255    bus->address_space_io = pci_get_bus(dev)->address_space_io;
    256    bus->map_irq = pxb_map_irq_fn;
    257
    258    PCI_HOST_BRIDGE(ds)->bus = bus;
    259    PCI_HOST_BRIDGE(ds)->bypass_iommu = pxb->bypass_iommu;
    260
    261    pxb_register_bus(dev, bus, &local_err);
    262    if (local_err) {
    263        error_propagate(errp, local_err);
    264        goto err_register_bus;
    265    }
    266
    267    sysbus_realize_and_unref(SYS_BUS_DEVICE(ds), &error_fatal);
    268    if (bds) {
    269        qdev_realize_and_unref(bds, &bus->qbus, &error_fatal);
    270    }
    271
    272    pci_word_test_and_set_mask(dev->config + PCI_STATUS,
    273                               PCI_STATUS_66MHZ | PCI_STATUS_FAST_BACK);
    274    pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
    275
    276    pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
    277    return;
    278
    279err_register_bus:
    280    object_unref(OBJECT(bds));
    281    object_unparent(OBJECT(bus));
    282    object_unref(OBJECT(ds));
    283}
    284
    285static void pxb_dev_realize(PCIDevice *dev, Error **errp)
    286{
    287    if (pci_bus_is_express(pci_get_bus(dev))) {
    288        error_setg(errp, "pxb devices cannot reside on a PCIe bus");
    289        return;
    290    }
    291
    292    pxb_dev_realize_common(dev, false, errp);
    293}
    294
    295static void pxb_dev_exitfn(PCIDevice *pci_dev)
    296{
    297    PXBDev *pxb = convert_to_pxb(pci_dev);
    298
    299    pxb_dev_list = g_list_remove(pxb_dev_list, pxb);
    300}
    301
    302static Property pxb_dev_properties[] = {
    303    /* Note: 0 is not a legal PXB bus number. */
    304    DEFINE_PROP_UINT8("bus_nr", PXBDev, bus_nr, 0),
    305    DEFINE_PROP_UINT16("numa_node", PXBDev, numa_node, NUMA_NODE_UNASSIGNED),
    306    DEFINE_PROP_BOOL("bypass_iommu", PXBDev, bypass_iommu, false),
    307    DEFINE_PROP_END_OF_LIST(),
    308};
    309
    310static void pxb_dev_class_init(ObjectClass *klass, void *data)
    311{
    312    DeviceClass *dc = DEVICE_CLASS(klass);
    313    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    314
    315    k->realize = pxb_dev_realize;
    316    k->exit = pxb_dev_exitfn;
    317    k->vendor_id = PCI_VENDOR_ID_REDHAT;
    318    k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
    319    k->class_id = PCI_CLASS_BRIDGE_HOST;
    320
    321    dc->desc = "PCI Expander Bridge";
    322    device_class_set_props(dc, pxb_dev_properties);
    323    dc->hotpluggable = false;
    324    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    325}
    326
    327static const TypeInfo pxb_dev_info = {
    328    .name          = TYPE_PXB_DEVICE,
    329    .parent        = TYPE_PCI_DEVICE,
    330    .instance_size = sizeof(PXBDev),
    331    .class_init    = pxb_dev_class_init,
    332    .interfaces = (InterfaceInfo[]) {
    333        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    334        { },
    335    },
    336};
    337
    338static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp)
    339{
    340    if (!pci_bus_is_express(pci_get_bus(dev))) {
    341        error_setg(errp, "pxb-pcie devices cannot reside on a PCI bus");
    342        return;
    343    }
    344
    345    pxb_dev_realize_common(dev, true, errp);
    346}
    347
    348static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
    349{
    350    DeviceClass *dc = DEVICE_CLASS(klass);
    351    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    352
    353    k->realize = pxb_pcie_dev_realize;
    354    k->exit = pxb_dev_exitfn;
    355    k->vendor_id = PCI_VENDOR_ID_REDHAT;
    356    k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE;
    357    k->class_id = PCI_CLASS_BRIDGE_HOST;
    358
    359    dc->desc = "PCI Express Expander Bridge";
    360    device_class_set_props(dc, pxb_dev_properties);
    361    dc->hotpluggable = false;
    362    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    363}
    364
    365static const TypeInfo pxb_pcie_dev_info = {
    366    .name          = TYPE_PXB_PCIE_DEVICE,
    367    .parent        = TYPE_PCI_DEVICE,
    368    .instance_size = sizeof(PXBDev),
    369    .class_init    = pxb_pcie_dev_class_init,
    370    .interfaces = (InterfaceInfo[]) {
    371        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    372        { },
    373    },
    374};
    375
    376static void pxb_register_types(void)
    377{
    378    type_register_static(&pxb_bus_info);
    379    type_register_static(&pxb_pcie_bus_info);
    380    type_register_static(&pxb_host_info);
    381    type_register_static(&pxb_dev_info);
    382    type_register_static(&pxb_pcie_dev_info);
    383}
    384
    385type_init(pxb_register_types)