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_platform.c (14644B)


      1/*
      2 * XEN platform pci device, formerly known as the event channel device
      3 *
      4 * Copyright (c) 2003-2004 Intel Corp.
      5 * Copyright (c) 2006 XenSource
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a copy
      8 * of this software and associated documentation files (the "Software"), to deal
      9 * in the Software without restriction, including without limitation the rights
     10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 * copies of the Software, and to permit persons to whom the Software is
     12 * furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice shall be included in
     15 * all copies or substantial portions of the Software.
     16 *
     17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23 * THE SOFTWARE.
     24 */
     25
     26#include "qemu/osdep.h"
     27#include "qapi/error.h"
     28#include "hw/ide.h"
     29#include "hw/pci/pci.h"
     30#include "hw/xen/xen_common.h"
     31#include "migration/vmstate.h"
     32#include "hw/xen/xen-legacy-backend.h"
     33#include "trace.h"
     34#include "sysemu/xen.h"
     35#include "sysemu/block-backend.h"
     36#include "qemu/error-report.h"
     37#include "qemu/module.h"
     38#include "qom/object.h"
     39
     40//#define DEBUG_PLATFORM
     41
     42#ifdef DEBUG_PLATFORM
     43#define DPRINTF(fmt, ...) do { \
     44    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
     45} while (0)
     46#else
     47#define DPRINTF(fmt, ...) do { } while (0)
     48#endif
     49
     50#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
     51
     52struct PCIXenPlatformState {
     53    /*< private >*/
     54    PCIDevice parent_obj;
     55    /*< public >*/
     56
     57    MemoryRegion fixed_io;
     58    MemoryRegion bar;
     59    MemoryRegion mmio_bar;
     60    uint8_t flags; /* used only for version_id == 2 */
     61    uint16_t driver_product_version;
     62
     63    /* Log from guest drivers */
     64    char log_buffer[4096];
     65    int log_buffer_off;
     66};
     67
     68#define TYPE_XEN_PLATFORM "xen-platform"
     69OBJECT_DECLARE_SIMPLE_TYPE(PCIXenPlatformState, XEN_PLATFORM)
     70
     71#define XEN_PLATFORM_IOPORT 0x10
     72
     73/* Send bytes to syslog */
     74static void log_writeb(PCIXenPlatformState *s, char val)
     75{
     76    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
     77        /* Flush buffer */
     78        s->log_buffer[s->log_buffer_off] = 0;
     79        trace_xen_platform_log(s->log_buffer);
     80        s->log_buffer_off = 0;
     81    } else {
     82        s->log_buffer[s->log_buffer_off++] = val;
     83    }
     84}
     85
     86/*
     87 * Unplug device flags.
     88 *
     89 * The logic got a little confused at some point in the past but this is
     90 * what they do now.
     91 *
     92 * bit 0: Unplug all IDE and SCSI disks.
     93 * bit 1: Unplug all NICs.
     94 * bit 2: Unplug IDE disks except primary master. This is overridden if
     95 *        bit 0 is also present in the mask.
     96 * bit 3: Unplug all NVMe disks.
     97 *
     98 */
     99#define _UNPLUG_IDE_SCSI_DISKS 0
    100#define UNPLUG_IDE_SCSI_DISKS (1u << _UNPLUG_IDE_SCSI_DISKS)
    101
    102#define _UNPLUG_ALL_NICS 1
    103#define UNPLUG_ALL_NICS (1u << _UNPLUG_ALL_NICS)
    104
    105#define _UNPLUG_AUX_IDE_DISKS 2
    106#define UNPLUG_AUX_IDE_DISKS (1u << _UNPLUG_AUX_IDE_DISKS)
    107
    108#define _UNPLUG_NVME_DISKS 3
    109#define UNPLUG_NVME_DISKS (1u << _UNPLUG_NVME_DISKS)
    110
    111static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
    112{
    113    /* We have to ignore passthrough devices */
    114    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
    115            PCI_CLASS_NETWORK_ETHERNET
    116            && strcmp(d->name, "xen-pci-passthrough") != 0) {
    117        object_unparent(OBJECT(d));
    118    }
    119}
    120
    121/* Remove the peer of the NIC device. Normally, this would be a tap device. */
    122static void del_nic_peer(NICState *nic, void *opaque)
    123{
    124    NetClientState *nc;
    125
    126    nc = qemu_get_queue(nic);
    127    if (nc->peer)
    128        qemu_del_net_client(nc->peer);
    129}
    130
    131static void pci_unplug_nics(PCIBus *bus)
    132{
    133    qemu_foreach_nic(del_nic_peer, NULL);
    134    pci_for_each_device(bus, 0, unplug_nic, NULL);
    135}
    136
    137static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
    138{
    139    uint32_t flags = *(uint32_t *)opaque;
    140    bool aux = (flags & UNPLUG_AUX_IDE_DISKS) &&
    141        !(flags & UNPLUG_IDE_SCSI_DISKS);
    142
    143    /* We have to ignore passthrough devices */
    144    if (!strcmp(d->name, "xen-pci-passthrough")) {
    145        return;
    146    }
    147
    148    switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
    149    case PCI_CLASS_STORAGE_IDE:
    150        pci_piix3_xen_ide_unplug(DEVICE(d), aux);
    151        break;
    152
    153    case PCI_CLASS_STORAGE_SCSI:
    154        if (!aux) {
    155            object_unparent(OBJECT(d));
    156        }
    157        break;
    158
    159    case PCI_CLASS_STORAGE_EXPRESS:
    160        if (flags & UNPLUG_NVME_DISKS) {
    161            object_unparent(OBJECT(d));
    162        }
    163
    164    default:
    165        break;
    166    }
    167}
    168
    169static void pci_unplug_disks(PCIBus *bus, uint32_t flags)
    170{
    171    pci_for_each_device(bus, 0, unplug_disks, &flags);
    172}
    173
    174static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
    175{
    176    PCIXenPlatformState *s = opaque;
    177
    178    switch (addr) {
    179    case 0: {
    180        PCIDevice *pci_dev = PCI_DEVICE(s);
    181        /* Unplug devices. See comment above flag definitions */
    182        if (val & (UNPLUG_IDE_SCSI_DISKS | UNPLUG_AUX_IDE_DISKS |
    183                   UNPLUG_NVME_DISKS)) {
    184            DPRINTF("unplug disks\n");
    185            pci_unplug_disks(pci_get_bus(pci_dev), val);
    186        }
    187        if (val & UNPLUG_ALL_NICS) {
    188            DPRINTF("unplug nics\n");
    189            pci_unplug_nics(pci_get_bus(pci_dev));
    190        }
    191        break;
    192    }
    193    case 2:
    194        switch (val) {
    195        case 1:
    196            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
    197            break;
    198        case 0:
    199            DPRINTF("Guest claimed to be running PV product 0?\n");
    200            break;
    201        default:
    202            DPRINTF("Unknown PV product %d loaded in guest\n", val);
    203            break;
    204        }
    205        s->driver_product_version = val;
    206        break;
    207    }
    208}
    209
    210static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
    211                                         uint32_t val)
    212{
    213    switch (addr) {
    214    case 0:
    215        /* PV driver version */
    216        break;
    217    }
    218}
    219
    220static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
    221{
    222    PCIXenPlatformState *s = opaque;
    223
    224    switch (addr) {
    225    case 0: /* Platform flags */ {
    226        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
    227            HVMMEM_ram_ro : HVMMEM_ram_rw;
    228        if (xen_set_mem_type(xen_domid, mem_type, 0xc0, 0x40)) {
    229            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
    230        } else {
    231            s->flags = val & PFFLAG_ROM_LOCK;
    232            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
    233                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
    234        }
    235        break;
    236    }
    237    case 2:
    238        log_writeb(s, val);
    239        break;
    240    }
    241}
    242
    243static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
    244{
    245    switch (addr) {
    246    case 0:
    247        /* Magic value so that you can identify the interface. */
    248        return 0x49d2;
    249    default:
    250        return 0xffff;
    251    }
    252}
    253
    254static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
    255{
    256    PCIXenPlatformState *s = opaque;
    257
    258    switch (addr) {
    259    case 0:
    260        /* Platform flags */
    261        return s->flags;
    262    case 2:
    263        /* Version number */
    264        return 1;
    265    default:
    266        return 0xff;
    267    }
    268}
    269
    270static void platform_fixed_ioport_reset(void *opaque)
    271{
    272    PCIXenPlatformState *s = opaque;
    273
    274    platform_fixed_ioport_writeb(s, 0, 0);
    275}
    276
    277static uint64_t platform_fixed_ioport_read(void *opaque,
    278                                           hwaddr addr,
    279                                           unsigned size)
    280{
    281    switch (size) {
    282    case 1:
    283        return platform_fixed_ioport_readb(opaque, addr);
    284    case 2:
    285        return platform_fixed_ioport_readw(opaque, addr);
    286    default:
    287        return -1;
    288    }
    289}
    290
    291static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
    292
    293                                        uint64_t val, unsigned size)
    294{
    295    switch (size) {
    296    case 1:
    297        platform_fixed_ioport_writeb(opaque, addr, val);
    298        break;
    299    case 2:
    300        platform_fixed_ioport_writew(opaque, addr, val);
    301        break;
    302    case 4:
    303        platform_fixed_ioport_writel(opaque, addr, val);
    304        break;
    305    }
    306}
    307
    308
    309static const MemoryRegionOps platform_fixed_io_ops = {
    310    .read = platform_fixed_ioport_read,
    311    .write = platform_fixed_ioport_write,
    312    .valid = {
    313        .unaligned = true,
    314    },
    315    .impl = {
    316        .min_access_size = 1,
    317        .max_access_size = 4,
    318        .unaligned = true,
    319    },
    320    .endianness = DEVICE_LITTLE_ENDIAN,
    321};
    322
    323static void platform_fixed_ioport_init(PCIXenPlatformState* s)
    324{
    325    memory_region_init_io(&s->fixed_io, OBJECT(s), &platform_fixed_io_ops, s,
    326                          "xen-fixed", 16);
    327    memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
    328                                &s->fixed_io);
    329}
    330
    331/* Xen Platform PCI Device */
    332
    333static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
    334                                          unsigned int size)
    335{
    336    if (addr == 0) {
    337        return platform_fixed_ioport_readb(opaque, 0);
    338    } else {
    339        return ~0u;
    340    }
    341}
    342
    343static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
    344                                       uint64_t val, unsigned int size)
    345{
    346    PCIXenPlatformState *s = opaque;
    347    PCIDevice *pci_dev = PCI_DEVICE(s);
    348
    349    switch (addr) {
    350    case 0: /* Platform flags */
    351        platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
    352        break;
    353    case 4:
    354        if (val == 1) {
    355            /*
    356             * SUSE unplug for Xenlinux
    357             * xen-kmp used this since xen-3.0.4, instead the official protocol
    358             * from xen-3.3+ It did an unconditional "outl(1, (ioaddr + 4));"
    359             * Pre VMDP 1.7 used 4 and 8 depending on how VMDP was configured.
    360             * If VMDP was to control both disk and LAN it would use 4.
    361             * If it controlled just disk or just LAN, it would use 8 below.
    362             */
    363            pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS);
    364            pci_unplug_nics(pci_get_bus(pci_dev));
    365        }
    366        break;
    367    case 8:
    368        switch (val) {
    369        case 1:
    370            pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS);
    371            break;
    372        case 2:
    373            pci_unplug_nics(pci_get_bus(pci_dev));
    374            break;
    375        default:
    376            log_writeb(s, (uint32_t)val);
    377            break;
    378        }
    379        break;
    380    default:
    381        break;
    382    }
    383}
    384
    385static const MemoryRegionOps xen_pci_io_ops = {
    386    .read  = xen_platform_ioport_readb,
    387    .write = xen_platform_ioport_writeb,
    388    .impl.min_access_size = 1,
    389    .impl.max_access_size = 1,
    390};
    391
    392static void platform_ioport_bar_setup(PCIXenPlatformState *d)
    393{
    394    memory_region_init_io(&d->bar, OBJECT(d), &xen_pci_io_ops, d,
    395                          "xen-pci", 0x100);
    396}
    397
    398static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
    399                                   unsigned size)
    400{
    401    DPRINTF("Warning: attempted read from physical address "
    402            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
    403
    404    return 0;
    405}
    406
    407static void platform_mmio_write(void *opaque, hwaddr addr,
    408                                uint64_t val, unsigned size)
    409{
    410    DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
    411            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
    412            val, addr);
    413}
    414
    415static const MemoryRegionOps platform_mmio_handler = {
    416    .read = &platform_mmio_read,
    417    .write = &platform_mmio_write,
    418    .endianness = DEVICE_NATIVE_ENDIAN,
    419};
    420
    421static void platform_mmio_setup(PCIXenPlatformState *d)
    422{
    423    memory_region_init_io(&d->mmio_bar, OBJECT(d), &platform_mmio_handler, d,
    424                          "xen-mmio", 0x1000000);
    425}
    426
    427static int xen_platform_post_load(void *opaque, int version_id)
    428{
    429    PCIXenPlatformState *s = opaque;
    430
    431    platform_fixed_ioport_writeb(s, 0, s->flags);
    432
    433    return 0;
    434}
    435
    436static const VMStateDescription vmstate_xen_platform = {
    437    .name = "platform",
    438    .version_id = 4,
    439    .minimum_version_id = 4,
    440    .post_load = xen_platform_post_load,
    441    .fields = (VMStateField[]) {
    442        VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState),
    443        VMSTATE_UINT8(flags, PCIXenPlatformState),
    444        VMSTATE_END_OF_LIST()
    445    }
    446};
    447
    448static void xen_platform_realize(PCIDevice *dev, Error **errp)
    449{
    450    PCIXenPlatformState *d = XEN_PLATFORM(dev);
    451    uint8_t *pci_conf;
    452
    453    /* Device will crash on reset if xen is not initialized */
    454    if (!xen_enabled()) {
    455        error_setg(errp, "xen-platform device requires the Xen accelerator");
    456        return;
    457    }
    458
    459    pci_conf = dev->config;
    460
    461    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
    462
    463    pci_config_set_prog_interface(pci_conf, 0);
    464
    465    pci_conf[PCI_INTERRUPT_PIN] = 1;
    466
    467    platform_ioport_bar_setup(d);
    468    pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
    469
    470    /* reserve 16MB mmio address for share memory*/
    471    platform_mmio_setup(d);
    472    pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
    473                     &d->mmio_bar);
    474
    475    platform_fixed_ioport_init(d);
    476}
    477
    478static void platform_reset(DeviceState *dev)
    479{
    480    PCIXenPlatformState *s = XEN_PLATFORM(dev);
    481
    482    platform_fixed_ioport_reset(s);
    483}
    484
    485static void xen_platform_class_init(ObjectClass *klass, void *data)
    486{
    487    DeviceClass *dc = DEVICE_CLASS(klass);
    488    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
    489
    490    k->realize = xen_platform_realize;
    491    k->vendor_id = PCI_VENDOR_ID_XEN;
    492    k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
    493    k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
    494    k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
    495    k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
    496    k->revision = 1;
    497    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    498    dc->desc = "XEN platform pci device";
    499    dc->reset = platform_reset;
    500    dc->vmsd = &vmstate_xen_platform;
    501}
    502
    503static const TypeInfo xen_platform_info = {
    504    .name          = TYPE_XEN_PLATFORM,
    505    .parent        = TYPE_PCI_DEVICE,
    506    .instance_size = sizeof(PCIXenPlatformState),
    507    .class_init    = xen_platform_class_init,
    508    .interfaces = (InterfaceInfo[]) {
    509        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
    510        { },
    511    },
    512};
    513
    514static void xen_platform_register_types(void)
    515{
    516    type_register_static(&xen_platform_info);
    517}
    518
    519type_init(xen_platform_register_types)