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

xen-host-pci-device.c (9964B)


      1/*
      2 * Copyright (C) 2011       Citrix Ltd.
      3 *
      4 * This work is licensed under the terms of the GNU GPL, version 2.  See
      5 * the COPYING file in the top-level directory.
      6 *
      7 */
      8
      9#include "qemu/osdep.h"
     10#include "qapi/error.h"
     11#include "qemu/cutils.h"
     12#include "xen-host-pci-device.h"
     13
     14#define XEN_HOST_PCI_MAX_EXT_CAP \
     15    ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
     16
     17#ifdef XEN_HOST_PCI_DEVICE_DEBUG
     18#  define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
     19#else
     20#  define XEN_HOST_PCI_LOG(f, a...) (void)0
     21#endif
     22
     23/*
     24 * from linux/ioport.h
     25 * IO resources have these defined flags.
     26 */
     27#define IORESOURCE_BITS         0x000000ff      /* Bus-specific bits */
     28
     29#define IORESOURCE_TYPE_BITS    0x00000f00      /* Resource type */
     30#define IORESOURCE_IO           0x00000100
     31#define IORESOURCE_MEM          0x00000200
     32
     33#define IORESOURCE_PREFETCH     0x00001000      /* No side effects */
     34#define IORESOURCE_MEM_64       0x00100000
     35
     36static void xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
     37                                    const char *name, char *buf, ssize_t size)
     38{
     39    int rc;
     40
     41    rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
     42                  d->domain, d->bus, d->dev, d->func, name);
     43    assert(rc >= 0 && rc < size);
     44}
     45
     46
     47/* This size should be enough to read the first 7 lines of a resource file */
     48#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
     49static void xen_host_pci_get_resource(XenHostPCIDevice *d, Error **errp)
     50{
     51    int i, rc, fd;
     52    char path[PATH_MAX];
     53    char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
     54    unsigned long long start, end, flags, size;
     55    char *endptr, *s;
     56    uint8_t type;
     57
     58    xen_host_pci_sysfs_path(d, "resource", path, sizeof(path));
     59
     60    fd = open(path, O_RDONLY);
     61    if (fd == -1) {
     62        error_setg_file_open(errp, errno, path);
     63        return;
     64    }
     65
     66    do {
     67        rc = read(fd, &buf, sizeof(buf) - 1);
     68        if (rc < 0 && errno != EINTR) {
     69            error_setg_errno(errp, errno, "read err");
     70            goto out;
     71        }
     72    } while (rc < 0);
     73    buf[rc] = 0;
     74
     75    s = buf;
     76    for (i = 0; i < PCI_NUM_REGIONS; i++) {
     77        type = 0;
     78
     79        start = strtoll(s, &endptr, 16);
     80        if (*endptr != ' ' || s == endptr) {
     81            break;
     82        }
     83        s = endptr + 1;
     84        end = strtoll(s, &endptr, 16);
     85        if (*endptr != ' ' || s == endptr) {
     86            break;
     87        }
     88        s = endptr + 1;
     89        flags = strtoll(s, &endptr, 16);
     90        if (*endptr != '\n' || s == endptr) {
     91            break;
     92        }
     93        s = endptr + 1;
     94
     95        if (start) {
     96            size = end - start + 1;
     97        } else {
     98            size = 0;
     99        }
    100
    101        if (flags & IORESOURCE_IO) {
    102            type |= XEN_HOST_PCI_REGION_TYPE_IO;
    103        }
    104        if (flags & IORESOURCE_MEM) {
    105            type |= XEN_HOST_PCI_REGION_TYPE_MEM;
    106        }
    107        if (flags & IORESOURCE_PREFETCH) {
    108            type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
    109        }
    110        if (flags & IORESOURCE_MEM_64) {
    111            type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
    112        }
    113
    114        if (i < PCI_ROM_SLOT) {
    115            d->io_regions[i].base_addr = start;
    116            d->io_regions[i].size = size;
    117            d->io_regions[i].type = type;
    118            d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
    119        } else {
    120            d->rom.base_addr = start;
    121            d->rom.size = size;
    122            d->rom.type = type;
    123            d->rom.bus_flags = flags & IORESOURCE_BITS;
    124        }
    125    }
    126
    127    if (i != PCI_NUM_REGIONS) {
    128        error_setg(errp, "Invalid format or input too short: %s", buf);
    129    }
    130
    131out:
    132    close(fd);
    133}
    134
    135/* This size should be enough to read a long from a file */
    136#define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
    137static void xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
    138                                   unsigned int *pvalue, int base, Error **errp)
    139{
    140    char path[PATH_MAX];
    141    char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
    142    int fd, rc;
    143    unsigned long value;
    144    const char *endptr;
    145
    146    xen_host_pci_sysfs_path(d, name, path, sizeof(path));
    147
    148    fd = open(path, O_RDONLY);
    149    if (fd == -1) {
    150        error_setg_file_open(errp, errno, path);
    151        return;
    152    }
    153
    154    do {
    155        rc = read(fd, &buf, sizeof(buf) - 1);
    156        if (rc < 0 && errno != EINTR) {
    157            error_setg_errno(errp, errno, "read err");
    158            goto out;
    159        }
    160    } while (rc < 0);
    161
    162    buf[rc] = 0;
    163    rc = qemu_strtoul(buf, &endptr, base, &value);
    164    if (!rc) {
    165        assert(value <= UINT_MAX);
    166        *pvalue = value;
    167    } else {
    168        error_setg_errno(errp, -rc, "failed to parse value '%s'", buf);
    169    }
    170
    171out:
    172    close(fd);
    173}
    174
    175static inline void xen_host_pci_get_hex_value(XenHostPCIDevice *d,
    176                                              const char *name,
    177                                              unsigned int *pvalue,
    178                                              Error **errp)
    179{
    180    xen_host_pci_get_value(d, name, pvalue, 16, errp);
    181}
    182
    183static inline void xen_host_pci_get_dec_value(XenHostPCIDevice *d,
    184                                              const char *name,
    185                                              unsigned int *pvalue,
    186                                              Error **errp)
    187{
    188    xen_host_pci_get_value(d, name, pvalue, 10, errp);
    189}
    190
    191static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
    192{
    193    char path[PATH_MAX];
    194    struct stat buf;
    195
    196    xen_host_pci_sysfs_path(d, "physfn", path, sizeof(path));
    197
    198    return !stat(path, &buf);
    199}
    200
    201static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp)
    202{
    203    char path[PATH_MAX];
    204
    205    xen_host_pci_sysfs_path(d, "config", path, sizeof(path));
    206
    207    d->config_fd = open(path, O_RDWR);
    208    if (d->config_fd == -1) {
    209        error_setg_file_open(errp, errno, path);
    210    }
    211}
    212
    213static int xen_host_pci_config_read(XenHostPCIDevice *d,
    214                                    int pos, void *buf, int len)
    215{
    216    int rc;
    217
    218    do {
    219        rc = pread(d->config_fd, buf, len, pos);
    220    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
    221    if (rc != len) {
    222        return -errno;
    223    }
    224    return 0;
    225}
    226
    227static int xen_host_pci_config_write(XenHostPCIDevice *d,
    228                                     int pos, const void *buf, int len)
    229{
    230    int rc;
    231
    232    do {
    233        rc = pwrite(d->config_fd, buf, len, pos);
    234    } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
    235    if (rc != len) {
    236        return -errno;
    237    }
    238    return 0;
    239}
    240
    241
    242int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
    243{
    244    uint8_t buf;
    245    int rc = xen_host_pci_config_read(d, pos, &buf, 1);
    246    if (!rc) {
    247        *p = buf;
    248    }
    249    return rc;
    250}
    251
    252int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
    253{
    254    uint16_t buf;
    255    int rc = xen_host_pci_config_read(d, pos, &buf, 2);
    256    if (!rc) {
    257        *p = le16_to_cpu(buf);
    258    }
    259    return rc;
    260}
    261
    262int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
    263{
    264    uint32_t buf;
    265    int rc = xen_host_pci_config_read(d, pos, &buf, 4);
    266    if (!rc) {
    267        *p = le32_to_cpu(buf);
    268    }
    269    return rc;
    270}
    271
    272int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
    273{
    274    return xen_host_pci_config_read(d, pos, buf, len);
    275}
    276
    277int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
    278{
    279    return xen_host_pci_config_write(d, pos, &data, 1);
    280}
    281
    282int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
    283{
    284    data = cpu_to_le16(data);
    285    return xen_host_pci_config_write(d, pos, &data, 2);
    286}
    287
    288int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
    289{
    290    data = cpu_to_le32(data);
    291    return xen_host_pci_config_write(d, pos, &data, 4);
    292}
    293
    294int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
    295{
    296    return xen_host_pci_config_write(d, pos, buf, len);
    297}
    298
    299int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
    300{
    301    uint32_t header = 0;
    302    int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
    303    int pos = PCI_CONFIG_SPACE_SIZE;
    304
    305    do {
    306        if (xen_host_pci_get_long(d, pos, &header)) {
    307            break;
    308        }
    309        /*
    310         * If we have no capabilities, this is indicated by cap ID,
    311         * cap version and next pointer all being 0.
    312         */
    313        if (header == 0) {
    314            break;
    315        }
    316
    317        if (PCI_EXT_CAP_ID(header) == cap) {
    318            return pos;
    319        }
    320
    321        pos = PCI_EXT_CAP_NEXT(header);
    322        if (pos < PCI_CONFIG_SPACE_SIZE) {
    323            break;
    324        }
    325
    326        max_cap--;
    327    } while (max_cap > 0);
    328
    329    return -1;
    330}
    331
    332void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
    333                             uint8_t bus, uint8_t dev, uint8_t func,
    334                             Error **errp)
    335{
    336    ERRP_GUARD();
    337    unsigned int v;
    338
    339    d->config_fd = -1;
    340    d->domain = domain;
    341    d->bus = bus;
    342    d->dev = dev;
    343    d->func = func;
    344
    345    xen_host_pci_config_open(d, errp);
    346    if (*errp) {
    347        goto error;
    348    }
    349
    350    xen_host_pci_get_resource(d, errp);
    351    if (*errp) {
    352        goto error;
    353    }
    354
    355    xen_host_pci_get_hex_value(d, "vendor", &v, errp);
    356    if (*errp) {
    357        goto error;
    358    }
    359    d->vendor_id = v;
    360
    361    xen_host_pci_get_hex_value(d, "device", &v, errp);
    362    if (*errp) {
    363        goto error;
    364    }
    365    d->device_id = v;
    366
    367    xen_host_pci_get_dec_value(d, "irq", &v, errp);
    368    if (*errp) {
    369        goto error;
    370    }
    371    d->irq = v;
    372
    373    xen_host_pci_get_hex_value(d, "class", &v, errp);
    374    if (*errp) {
    375        goto error;
    376    }
    377    d->class_code = v;
    378
    379    d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
    380
    381    return;
    382
    383error:
    384
    385    if (d->config_fd >= 0) {
    386        close(d->config_fd);
    387        d->config_fd = -1;
    388    }
    389}
    390
    391bool xen_host_pci_device_closed(XenHostPCIDevice *d)
    392{
    393    return d->config_fd == -1;
    394}
    395
    396void xen_host_pci_device_put(XenHostPCIDevice *d)
    397{
    398    if (d->config_fd >= 0) {
    399        close(d->config_fd);
    400        d->config_fd = -1;
    401    }
    402}