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_pt_graphics.c (8538B)


      1/*
      2 * graphics passthrough
      3 */
      4#include "qemu/osdep.h"
      5#include "qapi/error.h"
      6#include "xen_pt.h"
      7#include "xen-host-pci-device.h"
      8#include "hw/xen/xen-legacy-backend.h"
      9
     10static unsigned long igd_guest_opregion;
     11static unsigned long igd_host_opregion;
     12
     13#define XEN_PCI_INTEL_OPREGION_MASK 0xfff
     14
     15typedef struct VGARegion {
     16    int type;           /* Memory or port I/O */
     17    uint64_t guest_base_addr;
     18    uint64_t machine_base_addr;
     19    uint64_t size;    /* size of the region */
     20    int rc;
     21} VGARegion;
     22
     23#define IORESOURCE_IO           0x00000100
     24#define IORESOURCE_MEM          0x00000200
     25
     26static struct VGARegion vga_args[] = {
     27    {
     28        .type = IORESOURCE_IO,
     29        .guest_base_addr = 0x3B0,
     30        .machine_base_addr = 0x3B0,
     31        .size = 0xC,
     32        .rc = -1,
     33    },
     34    {
     35        .type = IORESOURCE_IO,
     36        .guest_base_addr = 0x3C0,
     37        .machine_base_addr = 0x3C0,
     38        .size = 0x20,
     39        .rc = -1,
     40    },
     41    {
     42        .type = IORESOURCE_MEM,
     43        .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
     44        .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
     45        .size = 0x20,
     46        .rc = -1,
     47    },
     48};
     49
     50/*
     51 * register VGA resources for the domain with assigned gfx
     52 */
     53int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
     54{
     55    int i = 0;
     56
     57    if (!is_igd_vga_passthrough(dev)) {
     58        return 0;
     59    }
     60
     61    for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
     62        if (vga_args[i].type == IORESOURCE_IO) {
     63            vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
     64                            vga_args[i].guest_base_addr,
     65                            vga_args[i].machine_base_addr,
     66                            vga_args[i].size, DPCI_ADD_MAPPING);
     67        } else {
     68            vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
     69                            vga_args[i].guest_base_addr,
     70                            vga_args[i].machine_base_addr,
     71                            vga_args[i].size, DPCI_ADD_MAPPING);
     72        }
     73
     74        if (vga_args[i].rc) {
     75            XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
     76                    vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
     77                    vga_args[i].rc);
     78            return vga_args[i].rc;
     79        }
     80    }
     81
     82    return 0;
     83}
     84
     85/*
     86 * unregister VGA resources for the domain with assigned gfx
     87 */
     88int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
     89{
     90    int i = 0;
     91    int ret = 0;
     92
     93    if (!is_igd_vga_passthrough(dev)) {
     94        return 0;
     95    }
     96
     97    for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
     98        if (vga_args[i].type == IORESOURCE_IO) {
     99            vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
    100                            vga_args[i].guest_base_addr,
    101                            vga_args[i].machine_base_addr,
    102                            vga_args[i].size, DPCI_REMOVE_MAPPING);
    103        } else {
    104            vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
    105                            vga_args[i].guest_base_addr,
    106                            vga_args[i].machine_base_addr,
    107                            vga_args[i].size, DPCI_REMOVE_MAPPING);
    108        }
    109
    110        if (vga_args[i].rc) {
    111            XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
    112                    vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
    113                    vga_args[i].rc);
    114            return vga_args[i].rc;
    115        }
    116    }
    117
    118    if (igd_guest_opregion) {
    119        ret = xc_domain_memory_mapping(xen_xc, xen_domid,
    120                (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
    121                (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
    122                3,
    123                DPCI_REMOVE_MAPPING);
    124        if (ret) {
    125            return ret;
    126        }
    127    }
    128
    129    return 0;
    130}
    131
    132static void *get_vgabios(XenPCIPassthroughState *s, int *size,
    133                       XenHostPCIDevice *dev)
    134{
    135    return pci_assign_dev_load_option_rom(&s->dev, size,
    136                                          dev->domain, dev->bus,
    137                                          dev->dev, dev->func);
    138}
    139
    140/* Refer to Seabios. */
    141struct rom_header {
    142    uint16_t signature;
    143    uint8_t size;
    144    uint8_t initVector[4];
    145    uint8_t reserved[17];
    146    uint16_t pcioffset;
    147    uint16_t pnpoffset;
    148} __attribute__((packed));
    149
    150struct pci_data {
    151    uint32_t signature;
    152    uint16_t vendor;
    153    uint16_t device;
    154    uint16_t vitaldata;
    155    uint16_t dlen;
    156    uint8_t drevision;
    157    uint8_t class_lo;
    158    uint16_t class_hi;
    159    uint16_t ilen;
    160    uint16_t irevision;
    161    uint8_t type;
    162    uint8_t indicator;
    163    uint16_t reserved;
    164} __attribute__((packed));
    165
    166void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
    167                     Error **errp)
    168{
    169    unsigned char *bios = NULL;
    170    struct rom_header *rom;
    171    int bios_size;
    172    char *c = NULL;
    173    char checksum = 0;
    174    uint32_t len = 0;
    175    struct pci_data *pd = NULL;
    176
    177    if (!is_igd_vga_passthrough(dev)) {
    178        error_setg(errp, "Need to enable igd-passthrough");
    179        return;
    180    }
    181
    182    bios = get_vgabios(s, &bios_size, dev);
    183    if (!bios) {
    184        error_setg(errp, "VGA: Can't get VBIOS");
    185        return;
    186    }
    187
    188    if (bios_size < sizeof(struct rom_header)) {
    189        error_setg(errp, "VGA: VBIOS image corrupt (too small)");
    190        return;
    191    }
    192
    193    /* Currently we fixed this address as a primary. */
    194    rom = (struct rom_header *)bios;
    195
    196    if (rom->pcioffset + sizeof(struct pci_data) > bios_size) {
    197        error_setg(errp, "VGA: VBIOS image corrupt (bad pcioffset field)");
    198        return;
    199    }
    200
    201    pd = (void *)(bios + (unsigned char)rom->pcioffset);
    202
    203    /* We may need to fixup Device Identification. */
    204    if (pd->device != s->real_device.device_id) {
    205        pd->device = s->real_device.device_id;
    206
    207        len = rom->size * 512;
    208        if (len > bios_size) {
    209            error_setg(errp, "VGA: VBIOS image corrupt (bad size field)");
    210            return;
    211        }
    212
    213        /* Then adjust the bios checksum */
    214        for (c = (char *)bios; c < ((char *)bios + len); c++) {
    215            checksum += *c;
    216        }
    217        if (checksum) {
    218            bios[len - 1] -= checksum;
    219            XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
    220                       checksum);
    221        }
    222    }
    223
    224    /* Currently we fixed this address as a primary for legacy BIOS. */
    225    cpu_physical_memory_write(0xc0000, bios, bios_size);
    226}
    227
    228uint32_t igd_read_opregion(XenPCIPassthroughState *s)
    229{
    230    uint32_t val = 0;
    231
    232    if (!igd_guest_opregion) {
    233        return val;
    234    }
    235
    236    val = igd_guest_opregion;
    237
    238    XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
    239    return val;
    240}
    241
    242#define XEN_PCI_INTEL_OPREGION_PAGES 0x3
    243#define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
    244void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
    245{
    246    int ret;
    247
    248    if (igd_guest_opregion) {
    249        XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
    250                   val);
    251        return;
    252    }
    253
    254    /* We just work with LE. */
    255    xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION,
    256            (uint8_t *)&igd_host_opregion, 4);
    257    igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK)
    258                            | (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK);
    259
    260    ret = xc_domain_iomem_permission(xen_xc, xen_domid,
    261            (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
    262            XEN_PCI_INTEL_OPREGION_PAGES,
    263            XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED);
    264
    265    if (ret) {
    266        XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:"
    267                    " 0x%lx.\n", ret,
    268                    (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)),
    269        igd_guest_opregion = 0;
    270        return;
    271    }
    272
    273    ret = xc_domain_memory_mapping(xen_xc, xen_domid,
    274            (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
    275            (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
    276            XEN_PCI_INTEL_OPREGION_PAGES,
    277            DPCI_ADD_MAPPING);
    278
    279    if (ret) {
    280        XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to"
    281                    " guest opregion:0x%lx.\n", ret,
    282                    (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
    283                    (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
    284        igd_guest_opregion = 0;
    285        return;
    286    }
    287
    288    XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n",
    289                    (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
    290                    (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
    291}