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

designware.c (26230B)


      1/*
      2 * Copyright (c) 2018, Impinj, Inc.
      3 *
      4 * Designware PCIe IP block emulation
      5 *
      6 * This library is free software; you can redistribute it and/or
      7 * modify it under the terms of the GNU Lesser General Public
      8 * License as published by the Free Software Foundation; either
      9 * version 2.1 of the License, or (at your option) any later version.
     10 *
     11 * This library is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14 * Lesser General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU Lesser General Public
     17 * License along with this library; if not, see
     18 * <http://www.gnu.org/licenses/>.
     19 */
     20
     21#include "qemu/osdep.h"
     22#include "qapi/error.h"
     23#include "qemu/module.h"
     24#include "qemu/log.h"
     25#include "hw/pci/msi.h"
     26#include "hw/pci/pci_bridge.h"
     27#include "hw/pci/pci_host.h"
     28#include "hw/pci/pcie_port.h"
     29#include "hw/qdev-properties.h"
     30#include "migration/vmstate.h"
     31#include "hw/irq.h"
     32#include "hw/pci-host/designware.h"
     33
     34#define DESIGNWARE_PCIE_PORT_LINK_CONTROL          0x710
     35#define DESIGNWARE_PCIE_PHY_DEBUG_R1               0x72C
     36#define DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP  BIT(4)
     37#define DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL   0x80C
     38#define DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE    BIT(17)
     39#define DESIGNWARE_PCIE_MSI_ADDR_LO                0x820
     40#define DESIGNWARE_PCIE_MSI_ADDR_HI                0x824
     41#define DESIGNWARE_PCIE_MSI_INTR0_ENABLE           0x828
     42#define DESIGNWARE_PCIE_MSI_INTR0_MASK             0x82C
     43#define DESIGNWARE_PCIE_MSI_INTR0_STATUS           0x830
     44#define DESIGNWARE_PCIE_ATU_VIEWPORT               0x900
     45#define DESIGNWARE_PCIE_ATU_REGION_INBOUND         BIT(31)
     46#define DESIGNWARE_PCIE_ATU_CR1                    0x904
     47#define DESIGNWARE_PCIE_ATU_TYPE_MEM               (0x0 << 0)
     48#define DESIGNWARE_PCIE_ATU_CR2                    0x908
     49#define DESIGNWARE_PCIE_ATU_ENABLE                 BIT(31)
     50#define DESIGNWARE_PCIE_ATU_LOWER_BASE             0x90C
     51#define DESIGNWARE_PCIE_ATU_UPPER_BASE             0x910
     52#define DESIGNWARE_PCIE_ATU_LIMIT                  0x914
     53#define DESIGNWARE_PCIE_ATU_LOWER_TARGET           0x918
     54#define DESIGNWARE_PCIE_ATU_BUS(x)                 (((x) >> 24) & 0xff)
     55#define DESIGNWARE_PCIE_ATU_DEVFN(x)               (((x) >> 16) & 0xff)
     56#define DESIGNWARE_PCIE_ATU_UPPER_TARGET           0x91C
     57
     58#define DESIGNWARE_PCIE_IRQ_MSI                    3
     59
     60static DesignwarePCIEHost *
     61designware_pcie_root_to_host(DesignwarePCIERoot *root)
     62{
     63    BusState *bus = qdev_get_parent_bus(DEVICE(root));
     64    return DESIGNWARE_PCIE_HOST(bus->parent);
     65}
     66
     67static uint64_t designware_pcie_root_msi_read(void *opaque, hwaddr addr,
     68                                              unsigned size)
     69{
     70    /*
     71     * Attempts to read from the MSI address are undefined in
     72     * the PCI specifications. For this hardware, the datasheet
     73     * specifies that a read from the magic address is simply not
     74     * intercepted by the MSI controller, and will go out to the
     75     * AHB/AXI bus like any other PCI-device-initiated DMA read.
     76     * This is not trivial to implement in QEMU, so since
     77     * well-behaved guests won't ever ask a PCI device to DMA from
     78     * this address we just log the missing functionality.
     79     */
     80    qemu_log_mask(LOG_UNIMP, "%s not implemented\n", __func__);
     81    return 0;
     82}
     83
     84static void designware_pcie_root_msi_write(void *opaque, hwaddr addr,
     85                                           uint64_t val, unsigned len)
     86{
     87    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(opaque);
     88    DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
     89
     90    root->msi.intr[0].status |= BIT(val) & root->msi.intr[0].enable;
     91
     92    if (root->msi.intr[0].status & ~root->msi.intr[0].mask) {
     93        qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 1);
     94    }
     95}
     96
     97static const MemoryRegionOps designware_pci_host_msi_ops = {
     98    .read = designware_pcie_root_msi_read,
     99    .write = designware_pcie_root_msi_write,
    100    .endianness = DEVICE_LITTLE_ENDIAN,
    101    .valid = {
    102        .min_access_size = 4,
    103        .max_access_size = 4,
    104    },
    105};
    106
    107static void designware_pcie_root_update_msi_mapping(DesignwarePCIERoot *root)
    108
    109{
    110    MemoryRegion *mem   = &root->msi.iomem;
    111    const uint64_t base = root->msi.base;
    112    const bool enable   = root->msi.intr[0].enable;
    113
    114    memory_region_set_address(mem, base);
    115    memory_region_set_enabled(mem, enable);
    116}
    117
    118static DesignwarePCIEViewport *
    119designware_pcie_root_get_current_viewport(DesignwarePCIERoot *root)
    120{
    121    const unsigned int idx = root->atu_viewport & 0xF;
    122    const unsigned int dir =
    123        !!(root->atu_viewport & DESIGNWARE_PCIE_ATU_REGION_INBOUND);
    124    return &root->viewports[dir][idx];
    125}
    126
    127static uint32_t
    128designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len)
    129{
    130    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
    131    DesignwarePCIEViewport *viewport =
    132        designware_pcie_root_get_current_viewport(root);
    133
    134    uint32_t val;
    135
    136    switch (address) {
    137    case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
    138        /*
    139         * Linux guest uses this register only to configure number of
    140         * PCIE lane (which in our case is irrelevant) and doesn't
    141         * really care about the value it reads from this register
    142         */
    143        val = 0xDEADBEEF;
    144        break;
    145
    146    case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
    147        /*
    148         * To make sure that any code in guest waiting for speed
    149         * change does not time out we always report
    150         * PORT_LOGIC_SPEED_CHANGE as set
    151         */
    152        val = DESIGNWARE_PCIE_PORT_LOGIC_SPEED_CHANGE;
    153        break;
    154
    155    case DESIGNWARE_PCIE_MSI_ADDR_LO:
    156        val = root->msi.base;
    157        break;
    158
    159    case DESIGNWARE_PCIE_MSI_ADDR_HI:
    160        val = root->msi.base >> 32;
    161        break;
    162
    163    case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
    164        val = root->msi.intr[0].enable;
    165        break;
    166
    167    case DESIGNWARE_PCIE_MSI_INTR0_MASK:
    168        val = root->msi.intr[0].mask;
    169        break;
    170
    171    case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
    172        val = root->msi.intr[0].status;
    173        break;
    174
    175    case DESIGNWARE_PCIE_PHY_DEBUG_R1:
    176        val = DESIGNWARE_PCIE_PHY_DEBUG_R1_XMLH_LINK_UP;
    177        break;
    178
    179    case DESIGNWARE_PCIE_ATU_VIEWPORT:
    180        val = root->atu_viewport;
    181        break;
    182
    183    case DESIGNWARE_PCIE_ATU_LOWER_BASE:
    184        val = viewport->base;
    185        break;
    186
    187    case DESIGNWARE_PCIE_ATU_UPPER_BASE:
    188        val = viewport->base >> 32;
    189        break;
    190
    191    case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
    192        val = viewport->target;
    193        break;
    194
    195    case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
    196        val = viewport->target >> 32;
    197        break;
    198
    199    case DESIGNWARE_PCIE_ATU_LIMIT:
    200        val = viewport->limit;
    201        break;
    202
    203    case DESIGNWARE_PCIE_ATU_CR1:
    204    case DESIGNWARE_PCIE_ATU_CR2:
    205        val = viewport->cr[(address - DESIGNWARE_PCIE_ATU_CR1) /
    206                           sizeof(uint32_t)];
    207        break;
    208
    209    default:
    210        val = pci_default_read_config(d, address, len);
    211        break;
    212    }
    213
    214    return val;
    215}
    216
    217static uint64_t designware_pcie_root_data_access(void *opaque, hwaddr addr,
    218                                                 uint64_t *val, unsigned len)
    219{
    220    DesignwarePCIEViewport *viewport = opaque;
    221    DesignwarePCIERoot *root = viewport->root;
    222
    223    const uint8_t busnum = DESIGNWARE_PCIE_ATU_BUS(viewport->target);
    224    const uint8_t devfn  = DESIGNWARE_PCIE_ATU_DEVFN(viewport->target);
    225    PCIBus    *pcibus    = pci_get_bus(PCI_DEVICE(root));
    226    PCIDevice *pcidev    = pci_find_device(pcibus, busnum, devfn);
    227
    228    if (pcidev) {
    229        addr &= pci_config_size(pcidev) - 1;
    230
    231        if (val) {
    232            pci_host_config_write_common(pcidev, addr,
    233                                         pci_config_size(pcidev),
    234                                         *val, len);
    235        } else {
    236            return pci_host_config_read_common(pcidev, addr,
    237                                               pci_config_size(pcidev),
    238                                               len);
    239        }
    240    }
    241
    242    return UINT64_MAX;
    243}
    244
    245static uint64_t designware_pcie_root_data_read(void *opaque, hwaddr addr,
    246                                               unsigned len)
    247{
    248    return designware_pcie_root_data_access(opaque, addr, NULL, len);
    249}
    250
    251static void designware_pcie_root_data_write(void *opaque, hwaddr addr,
    252                                            uint64_t val, unsigned len)
    253{
    254    designware_pcie_root_data_access(opaque, addr, &val, len);
    255}
    256
    257static const MemoryRegionOps designware_pci_host_conf_ops = {
    258    .read = designware_pcie_root_data_read,
    259    .write = designware_pcie_root_data_write,
    260    .endianness = DEVICE_LITTLE_ENDIAN,
    261    .valid = {
    262        .min_access_size = 1,
    263        .max_access_size = 4,
    264    },
    265};
    266
    267static void designware_pcie_update_viewport(DesignwarePCIERoot *root,
    268                                            DesignwarePCIEViewport *viewport)
    269{
    270    const uint64_t target = viewport->target;
    271    const uint64_t base   = viewport->base;
    272    const uint64_t size   = (uint64_t)viewport->limit - base + 1;
    273    const bool enabled    = viewport->cr[1] & DESIGNWARE_PCIE_ATU_ENABLE;
    274
    275    MemoryRegion *current, *other;
    276
    277    if (viewport->cr[0] == DESIGNWARE_PCIE_ATU_TYPE_MEM) {
    278        current = &viewport->mem;
    279        other   = &viewport->cfg;
    280        memory_region_set_alias_offset(current, target);
    281    } else {
    282        current = &viewport->cfg;
    283        other   = &viewport->mem;
    284    }
    285
    286    /*
    287     * An outbound viewport can be reconfigure from being MEM to CFG,
    288     * to account for that we disable the "other" memory region that
    289     * becomes unused due to that fact.
    290     */
    291    memory_region_set_enabled(other, false);
    292    if (enabled) {
    293        memory_region_set_size(current, size);
    294        memory_region_set_address(current, base);
    295    }
    296    memory_region_set_enabled(current, enabled);
    297}
    298
    299static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address,
    300                                              uint32_t val, int len)
    301{
    302    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(d);
    303    DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
    304    DesignwarePCIEViewport *viewport =
    305        designware_pcie_root_get_current_viewport(root);
    306
    307    switch (address) {
    308    case DESIGNWARE_PCIE_PORT_LINK_CONTROL:
    309    case DESIGNWARE_PCIE_LINK_WIDTH_SPEED_CONTROL:
    310    case DESIGNWARE_PCIE_PHY_DEBUG_R1:
    311        /* No-op */
    312        break;
    313
    314    case DESIGNWARE_PCIE_MSI_ADDR_LO:
    315        root->msi.base &= 0xFFFFFFFF00000000ULL;
    316        root->msi.base |= val;
    317        designware_pcie_root_update_msi_mapping(root);
    318        break;
    319
    320    case DESIGNWARE_PCIE_MSI_ADDR_HI:
    321        root->msi.base &= 0x00000000FFFFFFFFULL;
    322        root->msi.base |= (uint64_t)val << 32;
    323        designware_pcie_root_update_msi_mapping(root);
    324        break;
    325
    326    case DESIGNWARE_PCIE_MSI_INTR0_ENABLE:
    327        root->msi.intr[0].enable = val;
    328        designware_pcie_root_update_msi_mapping(root);
    329        break;
    330
    331    case DESIGNWARE_PCIE_MSI_INTR0_MASK:
    332        root->msi.intr[0].mask = val;
    333        break;
    334
    335    case DESIGNWARE_PCIE_MSI_INTR0_STATUS:
    336        root->msi.intr[0].status ^= val;
    337        if (!root->msi.intr[0].status) {
    338            qemu_set_irq(host->pci.irqs[DESIGNWARE_PCIE_IRQ_MSI], 0);
    339        }
    340        break;
    341
    342    case DESIGNWARE_PCIE_ATU_VIEWPORT:
    343        root->atu_viewport = val;
    344        break;
    345
    346    case DESIGNWARE_PCIE_ATU_LOWER_BASE:
    347        viewport->base &= 0xFFFFFFFF00000000ULL;
    348        viewport->base |= val;
    349        break;
    350
    351    case DESIGNWARE_PCIE_ATU_UPPER_BASE:
    352        viewport->base &= 0x00000000FFFFFFFFULL;
    353        viewport->base |= (uint64_t)val << 32;
    354        break;
    355
    356    case DESIGNWARE_PCIE_ATU_LOWER_TARGET:
    357        viewport->target &= 0xFFFFFFFF00000000ULL;
    358        viewport->target |= val;
    359        break;
    360
    361    case DESIGNWARE_PCIE_ATU_UPPER_TARGET:
    362        viewport->target &= 0x00000000FFFFFFFFULL;
    363        viewport->target |= val;
    364        break;
    365
    366    case DESIGNWARE_PCIE_ATU_LIMIT:
    367        viewport->limit = val;
    368        break;
    369
    370    case DESIGNWARE_PCIE_ATU_CR1:
    371        viewport->cr[0] = val;
    372        break;
    373    case DESIGNWARE_PCIE_ATU_CR2:
    374        viewport->cr[1] = val;
    375        designware_pcie_update_viewport(root, viewport);
    376        break;
    377
    378    default:
    379        pci_bridge_write_config(d, address, val, len);
    380        break;
    381    }
    382}
    383
    384static char *designware_pcie_viewport_name(const char *direction,
    385                                           unsigned int i,
    386                                           const char *type)
    387{
    388    return g_strdup_printf("PCI %s Viewport %u [%s]",
    389                           direction, i, type);
    390}
    391
    392static void designware_pcie_root_realize(PCIDevice *dev, Error **errp)
    393{
    394    DesignwarePCIERoot *root = DESIGNWARE_PCIE_ROOT(dev);
    395    DesignwarePCIEHost *host = designware_pcie_root_to_host(root);
    396    MemoryRegion *address_space = &host->pci.memory;
    397    PCIBridge *br = PCI_BRIDGE(dev);
    398    DesignwarePCIEViewport *viewport;
    399    /*
    400     * Dummy values used for initial configuration of MemoryRegions
    401     * that belong to a given viewport
    402     */
    403    const hwaddr dummy_offset = 0;
    404    const uint64_t dummy_size = 4;
    405    size_t i;
    406
    407    br->bus_name  = "dw-pcie";
    408
    409    pci_set_word(dev->config + PCI_COMMAND,
    410                 PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
    411
    412    pci_config_set_interrupt_pin(dev->config, 1);
    413    pci_bridge_initfn(dev, TYPE_PCIE_BUS);
    414
    415    pcie_port_init_reg(dev);
    416
    417    pcie_cap_init(dev, 0x70, PCI_EXP_TYPE_ROOT_PORT,
    418                  0, &error_fatal);
    419
    420    msi_nonbroken = true;
    421    msi_init(dev, 0x50, 32, true, true, &error_fatal);
    422
    423    for (i = 0; i < DESIGNWARE_PCIE_NUM_VIEWPORTS; i++) {
    424        MemoryRegion *source, *destination, *mem;
    425        const char *direction;
    426        char *name;
    427
    428        viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][i];
    429        viewport->inbound = true;
    430        viewport->base    = 0x0000000000000000ULL;
    431        viewport->target  = 0x0000000000000000ULL;
    432        viewport->limit   = UINT32_MAX;
    433        viewport->cr[0]   = DESIGNWARE_PCIE_ATU_TYPE_MEM;
    434
    435        source      = &host->pci.address_space_root;
    436        destination = get_system_memory();
    437        direction   = "Inbound";
    438
    439        /*
    440         * Configure MemoryRegion implementing PCI -> CPU memory
    441         * access
    442         */
    443        mem  = &viewport->mem;
    444        name = designware_pcie_viewport_name(direction, i, "MEM");
    445        memory_region_init_alias(mem, OBJECT(root), name, destination,
    446                                 dummy_offset, dummy_size);
    447        memory_region_add_subregion_overlap(source, dummy_offset, mem, -1);
    448        memory_region_set_enabled(mem, false);
    449        g_free(name);
    450
    451        viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_OUTBOUND][i];
    452        viewport->root    = root;
    453        viewport->inbound = false;
    454        viewport->base    = 0x0000000000000000ULL;
    455        viewport->target  = 0x0000000000000000ULL;
    456        viewport->limit   = UINT32_MAX;
    457        viewport->cr[0]   = DESIGNWARE_PCIE_ATU_TYPE_MEM;
    458
    459        destination = &host->pci.memory;
    460        direction   = "Outbound";
    461        source      = get_system_memory();
    462
    463        /*
    464         * Configure MemoryRegion implementing CPU -> PCI memory
    465         * access
    466         */
    467        mem  = &viewport->mem;
    468        name = designware_pcie_viewport_name(direction, i, "MEM");
    469        memory_region_init_alias(mem, OBJECT(root), name, destination,
    470                                 dummy_offset, dummy_size);
    471        memory_region_add_subregion(source, dummy_offset, mem);
    472        memory_region_set_enabled(mem, false);
    473        g_free(name);
    474
    475        /*
    476         * Configure MemoryRegion implementing access to configuration
    477         * space
    478         */
    479        mem  = &viewport->cfg;
    480        name = designware_pcie_viewport_name(direction, i, "CFG");
    481        memory_region_init_io(&viewport->cfg, OBJECT(root),
    482                              &designware_pci_host_conf_ops,
    483                              viewport, name, dummy_size);
    484        memory_region_add_subregion(source, dummy_offset, mem);
    485        memory_region_set_enabled(mem, false);
    486        g_free(name);
    487    }
    488
    489    /*
    490     * If no inbound iATU windows are configured, HW defaults to
    491     * letting inbound TLPs to pass in. We emulate that by exlicitly
    492     * configuring first inbound window to cover all of target's
    493     * address space.
    494     *
    495     * NOTE: This will not work correctly for the case when first
    496     * configured inbound window is window 0
    497     */
    498    viewport = &root->viewports[DESIGNWARE_PCIE_VIEWPORT_INBOUND][0];
    499    viewport->cr[1] = DESIGNWARE_PCIE_ATU_ENABLE;
    500    designware_pcie_update_viewport(root, viewport);
    501
    502    memory_region_init_io(&root->msi.iomem, OBJECT(root),
    503                          &designware_pci_host_msi_ops,
    504                          root, "pcie-msi", 0x4);
    505    /*
    506     * We initially place MSI interrupt I/O region a adress 0 and
    507     * disable it. It'll be later moved to correct offset and enabled
    508     * in designware_pcie_root_update_msi_mapping() as a part of
    509     * initialization done by guest OS
    510     */
    511    memory_region_add_subregion(address_space, dummy_offset, &root->msi.iomem);
    512    memory_region_set_enabled(&root->msi.iomem, false);
    513}
    514
    515static void designware_pcie_set_irq(void *opaque, int irq_num, int level)
    516{
    517    DesignwarePCIEHost *host = DESIGNWARE_PCIE_HOST(opaque);
    518
    519    qemu_set_irq(host->pci.irqs[irq_num], level);
    520}
    521
    522static const char *
    523designware_pcie_host_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus)
    524{
    525    return "0000:00";
    526}
    527
    528static const VMStateDescription vmstate_designware_pcie_msi_bank = {
    529    .name = "designware-pcie-msi-bank",
    530    .version_id = 1,
    531    .minimum_version_id = 1,
    532    .fields = (VMStateField[]) {
    533        VMSTATE_UINT32(enable, DesignwarePCIEMSIBank),
    534        VMSTATE_UINT32(mask, DesignwarePCIEMSIBank),
    535        VMSTATE_UINT32(status, DesignwarePCIEMSIBank),
    536        VMSTATE_END_OF_LIST()
    537    }
    538};
    539
    540static const VMStateDescription vmstate_designware_pcie_msi = {
    541    .name = "designware-pcie-msi",
    542    .version_id = 1,
    543    .minimum_version_id = 1,
    544    .fields = (VMStateField[]) {
    545        VMSTATE_UINT64(base, DesignwarePCIEMSI),
    546        VMSTATE_STRUCT_ARRAY(intr,
    547                             DesignwarePCIEMSI,
    548                             DESIGNWARE_PCIE_NUM_MSI_BANKS,
    549                             1,
    550                             vmstate_designware_pcie_msi_bank,
    551                             DesignwarePCIEMSIBank),
    552        VMSTATE_END_OF_LIST()
    553    }
    554};
    555
    556static const VMStateDescription vmstate_designware_pcie_viewport = {
    557    .name = "designware-pcie-viewport",
    558    .version_id = 1,
    559    .minimum_version_id = 1,
    560    .fields = (VMStateField[]) {
    561        VMSTATE_UINT64(base, DesignwarePCIEViewport),
    562        VMSTATE_UINT64(target, DesignwarePCIEViewport),
    563        VMSTATE_UINT32(limit, DesignwarePCIEViewport),
    564        VMSTATE_UINT32_ARRAY(cr, DesignwarePCIEViewport, 2),
    565        VMSTATE_END_OF_LIST()
    566    }
    567};
    568
    569static const VMStateDescription vmstate_designware_pcie_root = {
    570    .name = "designware-pcie-root",
    571    .version_id = 1,
    572    .minimum_version_id = 1,
    573    .fields = (VMStateField[]) {
    574        VMSTATE_PCI_DEVICE(parent_obj, PCIBridge),
    575        VMSTATE_UINT32(atu_viewport, DesignwarePCIERoot),
    576        VMSTATE_STRUCT_2DARRAY(viewports,
    577                               DesignwarePCIERoot,
    578                               2,
    579                               DESIGNWARE_PCIE_NUM_VIEWPORTS,
    580                               1,
    581                               vmstate_designware_pcie_viewport,
    582                               DesignwarePCIEViewport),
    583        VMSTATE_STRUCT(msi,
    584                       DesignwarePCIERoot,
    585                       1,
    586                       vmstate_designware_pcie_msi,
    587                       DesignwarePCIEMSI),
    588        VMSTATE_END_OF_LIST()
    589    }
    590};
    591
    592static void designware_pcie_root_class_init(ObjectClass *klass, void *data)
    593{
    594    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    595    DeviceClass *dc = DEVICE_CLASS(klass);
    596
    597    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    598
    599    k->vendor_id = PCI_VENDOR_ID_SYNOPSYS;
    600    k->device_id = 0xABCD;
    601    k->revision = 0;
    602    k->class_id = PCI_CLASS_BRIDGE_PCI;
    603    k->is_bridge = true;
    604    k->exit = pci_bridge_exitfn;
    605    k->realize = designware_pcie_root_realize;
    606    k->config_read = designware_pcie_root_config_read;
    607    k->config_write = designware_pcie_root_config_write;
    608
    609    dc->reset = pci_bridge_reset;
    610    /*
    611     * PCI-facing part of the host bridge, not usable without the
    612     * host-facing part, which can't be device_add'ed, yet.
    613     */
    614    dc->user_creatable = false;
    615    dc->vmsd = &vmstate_designware_pcie_root;
    616}
    617
    618static uint64_t designware_pcie_host_mmio_read(void *opaque, hwaddr addr,
    619                                               unsigned int size)
    620{
    621    PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
    622    PCIDevice *device = pci_find_device(pci->bus, 0, 0);
    623
    624    return pci_host_config_read_common(device,
    625                                       addr,
    626                                       pci_config_size(device),
    627                                       size);
    628}
    629
    630static void designware_pcie_host_mmio_write(void *opaque, hwaddr addr,
    631                                            uint64_t val, unsigned int size)
    632{
    633    PCIHostState *pci = PCI_HOST_BRIDGE(opaque);
    634    PCIDevice *device = pci_find_device(pci->bus, 0, 0);
    635
    636    return pci_host_config_write_common(device,
    637                                        addr,
    638                                        pci_config_size(device),
    639                                        val, size);
    640}
    641
    642static const MemoryRegionOps designware_pci_mmio_ops = {
    643    .read       = designware_pcie_host_mmio_read,
    644    .write      = designware_pcie_host_mmio_write,
    645    .endianness = DEVICE_LITTLE_ENDIAN,
    646    .impl = {
    647        /*
    648         * Our device would not work correctly if the guest was doing
    649         * unaligned access. This might not be a limitation on the real
    650         * device but in practice there is no reason for a guest to access
    651         * this device unaligned.
    652         */
    653        .min_access_size = 4,
    654        .max_access_size = 4,
    655        .unaligned = false,
    656    },
    657};
    658
    659static AddressSpace *designware_pcie_host_set_iommu(PCIBus *bus, void *opaque,
    660                                                    int devfn)
    661{
    662    DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(opaque);
    663
    664    return &s->pci.address_space;
    665}
    666
    667static void designware_pcie_host_realize(DeviceState *dev, Error **errp)
    668{
    669    PCIHostState *pci = PCI_HOST_BRIDGE(dev);
    670    DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(dev);
    671    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    672    size_t i;
    673
    674    for (i = 0; i < ARRAY_SIZE(s->pci.irqs); i++) {
    675        sysbus_init_irq(sbd, &s->pci.irqs[i]);
    676    }
    677
    678    memory_region_init_io(&s->mmio,
    679                          OBJECT(s),
    680                          &designware_pci_mmio_ops,
    681                          s,
    682                          "pcie.reg", 4 * 1024);
    683    sysbus_init_mmio(sbd, &s->mmio);
    684
    685    memory_region_init(&s->pci.io, OBJECT(s), "pcie-pio", 16);
    686    memory_region_init(&s->pci.memory, OBJECT(s),
    687                       "pcie-bus-memory",
    688                       UINT64_MAX);
    689
    690    pci->bus = pci_register_root_bus(dev, "pcie",
    691                                     designware_pcie_set_irq,
    692                                     pci_swizzle_map_irq_fn,
    693                                     s,
    694                                     &s->pci.memory,
    695                                     &s->pci.io,
    696                                     0, 4,
    697                                     TYPE_PCIE_BUS);
    698
    699    memory_region_init(&s->pci.address_space_root,
    700                       OBJECT(s),
    701                       "pcie-bus-address-space-root",
    702                       UINT64_MAX);
    703    memory_region_add_subregion(&s->pci.address_space_root,
    704                                0x0, &s->pci.memory);
    705    address_space_init(&s->pci.address_space,
    706                       &s->pci.address_space_root,
    707                       "pcie-bus-address-space");
    708    pci_setup_iommu(pci->bus, designware_pcie_host_set_iommu, s);
    709
    710    qdev_realize(DEVICE(&s->root), BUS(pci->bus), &error_fatal);
    711}
    712
    713static const VMStateDescription vmstate_designware_pcie_host = {
    714    .name = "designware-pcie-host",
    715    .version_id = 1,
    716    .minimum_version_id = 1,
    717    .fields = (VMStateField[]) {
    718        VMSTATE_STRUCT(root,
    719                       DesignwarePCIEHost,
    720                       1,
    721                       vmstate_designware_pcie_root,
    722                       DesignwarePCIERoot),
    723        VMSTATE_END_OF_LIST()
    724    }
    725};
    726
    727static void designware_pcie_host_class_init(ObjectClass *klass, void *data)
    728{
    729    DeviceClass *dc = DEVICE_CLASS(klass);
    730    PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
    731
    732    hc->root_bus_path = designware_pcie_host_root_bus_path;
    733    dc->realize = designware_pcie_host_realize;
    734    set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    735    dc->fw_name = "pci";
    736    dc->vmsd = &vmstate_designware_pcie_host;
    737}
    738
    739static void designware_pcie_host_init(Object *obj)
    740{
    741    DesignwarePCIEHost *s = DESIGNWARE_PCIE_HOST(obj);
    742    DesignwarePCIERoot *root = &s->root;
    743
    744    object_initialize_child(obj, "root", root, TYPE_DESIGNWARE_PCIE_ROOT);
    745    qdev_prop_set_int32(DEVICE(root), "addr", PCI_DEVFN(0, 0));
    746    qdev_prop_set_bit(DEVICE(root), "multifunction", false);
    747}
    748
    749static const TypeInfo designware_pcie_root_info = {
    750    .name = TYPE_DESIGNWARE_PCIE_ROOT,
    751    .parent = TYPE_PCI_BRIDGE,
    752    .instance_size = sizeof(DesignwarePCIERoot),
    753    .class_init = designware_pcie_root_class_init,
    754    .interfaces = (InterfaceInfo[]) {
    755        { INTERFACE_PCIE_DEVICE },
    756        { }
    757    },
    758};
    759
    760static const TypeInfo designware_pcie_host_info = {
    761    .name       = TYPE_DESIGNWARE_PCIE_HOST,
    762    .parent     = TYPE_PCI_HOST_BRIDGE,
    763    .instance_size = sizeof(DesignwarePCIEHost),
    764    .instance_init = designware_pcie_host_init,
    765    .class_init = designware_pcie_host_class_init,
    766};
    767
    768static void designware_pcie_register(void)
    769{
    770    type_register_static(&designware_pcie_root_info);
    771    type_register_static(&designware_pcie_host_info);
    772}
    773type_init(designware_pcie_register)