summaryrefslogtreecommitdiffstats
path: root/qemu/hw/xen
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/hw/xen')
-rw-r--r--qemu/hw/xen/Makefile.objs5
-rw-r--r--qemu/hw/xen/xen-host-pci-device.c404
-rw-r--r--qemu/hw/xen/xen-host-pci-device.h58
-rw-r--r--qemu/hw/xen/xen_backend.c802
-rw-r--r--qemu/hw/xen/xen_devconfig.c176
-rw-r--r--qemu/hw/xen/xen_pt.c974
-rw-r--r--qemu/hw/xen/xen_pt.h335
-rw-r--r--qemu/hw/xen/xen_pt_config_init.c2090
-rw-r--r--qemu/hw/xen/xen_pt_graphics.c275
-rw-r--r--qemu/hw/xen/xen_pt_msi.c635
10 files changed, 0 insertions, 5754 deletions
diff --git a/qemu/hw/xen/Makefile.objs b/qemu/hw/xen/Makefile.objs
deleted file mode 100644
index d3670940b..000000000
--- a/qemu/hw/xen/Makefile.objs
+++ /dev/null
@@ -1,5 +0,0 @@
-# xen backend driver support
-common-obj-$(CONFIG_XEN_BACKEND) += xen_backend.o xen_devconfig.o
-
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen-host-pci-device.o
-obj-$(CONFIG_XEN_PCI_PASSTHROUGH) += xen_pt.o xen_pt_config_init.o xen_pt_graphics.o xen_pt_msi.o
diff --git a/qemu/hw/xen/xen-host-pci-device.c b/qemu/hw/xen/xen-host-pci-device.c
deleted file mode 100644
index eed8cc88e..000000000
--- a/qemu/hw/xen/xen-host-pci-device.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2011 Citrix Ltd.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu-common.h"
-#include "qemu/cutils.h"
-#include "xen-host-pci-device.h"
-
-#define XEN_HOST_PCI_MAX_EXT_CAP \
- ((PCIE_CONFIG_SPACE_SIZE - PCI_CONFIG_SPACE_SIZE) / (PCI_CAP_SIZEOF + 4))
-
-#ifdef XEN_HOST_PCI_DEVICE_DEBUG
-# define XEN_HOST_PCI_LOG(f, a...) fprintf(stderr, "%s: " f, __func__, ##a)
-#else
-# define XEN_HOST_PCI_LOG(f, a...) (void)0
-#endif
-
-/*
- * from linux/ioport.h
- * IO resources have these defined flags.
- */
-#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
-
-#define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */
-#define IORESOURCE_IO 0x00000100
-#define IORESOURCE_MEM 0x00000200
-
-#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
-#define IORESOURCE_MEM_64 0x00100000
-
-static void xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
- const char *name, char *buf, ssize_t size)
-{
- int rc;
-
- rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
- d->domain, d->bus, d->dev, d->func, name);
- assert(rc >= 0 && rc < size);
-}
-
-
-/* This size should be enough to read the first 7 lines of a resource file */
-#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
-static void xen_host_pci_get_resource(XenHostPCIDevice *d, Error **errp)
-{
- int i, rc, fd;
- char path[PATH_MAX];
- char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
- unsigned long long start, end, flags, size;
- char *endptr, *s;
- uint8_t type;
-
- xen_host_pci_sysfs_path(d, "resource", path, sizeof(path));
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- error_setg_file_open(errp, errno, path);
- return;
- }
-
- do {
- rc = read(fd, &buf, sizeof(buf) - 1);
- if (rc < 0 && errno != EINTR) {
- error_setg_errno(errp, errno, "read err");
- goto out;
- }
- } while (rc < 0);
- buf[rc] = 0;
-
- s = buf;
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- type = 0;
-
- start = strtoll(s, &endptr, 16);
- if (*endptr != ' ' || s == endptr) {
- break;
- }
- s = endptr + 1;
- end = strtoll(s, &endptr, 16);
- if (*endptr != ' ' || s == endptr) {
- break;
- }
- s = endptr + 1;
- flags = strtoll(s, &endptr, 16);
- if (*endptr != '\n' || s == endptr) {
- break;
- }
- s = endptr + 1;
-
- if (start) {
- size = end - start + 1;
- } else {
- size = 0;
- }
-
- if (flags & IORESOURCE_IO) {
- type |= XEN_HOST_PCI_REGION_TYPE_IO;
- }
- if (flags & IORESOURCE_MEM) {
- type |= XEN_HOST_PCI_REGION_TYPE_MEM;
- }
- if (flags & IORESOURCE_PREFETCH) {
- type |= XEN_HOST_PCI_REGION_TYPE_PREFETCH;
- }
- if (flags & IORESOURCE_MEM_64) {
- type |= XEN_HOST_PCI_REGION_TYPE_MEM_64;
- }
-
- if (i < PCI_ROM_SLOT) {
- d->io_regions[i].base_addr = start;
- d->io_regions[i].size = size;
- d->io_regions[i].type = type;
- d->io_regions[i].bus_flags = flags & IORESOURCE_BITS;
- } else {
- d->rom.base_addr = start;
- d->rom.size = size;
- d->rom.type = type;
- d->rom.bus_flags = flags & IORESOURCE_BITS;
- }
- }
-
- if (i != PCI_NUM_REGIONS) {
- error_setg(errp, "Invalid format or input too short: %s", buf);
- }
-
-out:
- close(fd);
-}
-
-/* This size should be enough to read a long from a file */
-#define XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE 22
-static void xen_host_pci_get_value(XenHostPCIDevice *d, const char *name,
- unsigned int *pvalue, int base, Error **errp)
-{
- char path[PATH_MAX];
- char buf[XEN_HOST_PCI_GET_VALUE_BUFFER_SIZE];
- int fd, rc;
- unsigned long value;
- const char *endptr;
-
- xen_host_pci_sysfs_path(d, name, path, sizeof(path));
-
- fd = open(path, O_RDONLY);
- if (fd == -1) {
- error_setg_file_open(errp, errno, path);
- return;
- }
-
- do {
- rc = read(fd, &buf, sizeof(buf) - 1);
- if (rc < 0 && errno != EINTR) {
- error_setg_errno(errp, errno, "read err");
- goto out;
- }
- } while (rc < 0);
-
- buf[rc] = 0;
- rc = qemu_strtoul(buf, &endptr, base, &value);
- if (!rc) {
- assert(value <= UINT_MAX);
- *pvalue = value;
- } else {
- error_setg_errno(errp, -rc, "failed to parse value '%s'", buf);
- }
-
-out:
- close(fd);
-}
-
-static inline void xen_host_pci_get_hex_value(XenHostPCIDevice *d,
- const char *name,
- unsigned int *pvalue,
- Error **errp)
-{
- xen_host_pci_get_value(d, name, pvalue, 16, errp);
-}
-
-static inline void xen_host_pci_get_dec_value(XenHostPCIDevice *d,
- const char *name,
- unsigned int *pvalue,
- Error **errp)
-{
- xen_host_pci_get_value(d, name, pvalue, 10, errp);
-}
-
-static bool xen_host_pci_dev_is_virtfn(XenHostPCIDevice *d)
-{
- char path[PATH_MAX];
- struct stat buf;
-
- xen_host_pci_sysfs_path(d, "physfn", path, sizeof(path));
-
- return !stat(path, &buf);
-}
-
-static void xen_host_pci_config_open(XenHostPCIDevice *d, Error **errp)
-{
- char path[PATH_MAX];
-
- xen_host_pci_sysfs_path(d, "config", path, sizeof(path));
-
- d->config_fd = open(path, O_RDWR);
- if (d->config_fd == -1) {
- error_setg_file_open(errp, errno, path);
- }
-}
-
-static int xen_host_pci_config_read(XenHostPCIDevice *d,
- int pos, void *buf, int len)
-{
- int rc;
-
- do {
- rc = pread(d->config_fd, buf, len, pos);
- } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
- if (rc != len) {
- return -errno;
- }
- return 0;
-}
-
-static int xen_host_pci_config_write(XenHostPCIDevice *d,
- int pos, const void *buf, int len)
-{
- int rc;
-
- do {
- rc = pwrite(d->config_fd, buf, len, pos);
- } while (rc < 0 && (errno == EINTR || errno == EAGAIN));
- if (rc != len) {
- return -errno;
- }
- return 0;
-}
-
-
-int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p)
-{
- uint8_t buf;
- int rc = xen_host_pci_config_read(d, pos, &buf, 1);
- if (!rc) {
- *p = buf;
- }
- return rc;
-}
-
-int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p)
-{
- uint16_t buf;
- int rc = xen_host_pci_config_read(d, pos, &buf, 2);
- if (!rc) {
- *p = le16_to_cpu(buf);
- }
- return rc;
-}
-
-int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p)
-{
- uint32_t buf;
- int rc = xen_host_pci_config_read(d, pos, &buf, 4);
- if (!rc) {
- *p = le32_to_cpu(buf);
- }
- return rc;
-}
-
-int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
-{
- return xen_host_pci_config_read(d, pos, buf, len);
-}
-
-int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data)
-{
- return xen_host_pci_config_write(d, pos, &data, 1);
-}
-
-int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data)
-{
- data = cpu_to_le16(data);
- return xen_host_pci_config_write(d, pos, &data, 2);
-}
-
-int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data)
-{
- data = cpu_to_le32(data);
- return xen_host_pci_config_write(d, pos, &data, 4);
-}
-
-int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf, int len)
-{
- return xen_host_pci_config_write(d, pos, buf, len);
-}
-
-int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *d, uint32_t cap)
-{
- uint32_t header = 0;
- int max_cap = XEN_HOST_PCI_MAX_EXT_CAP;
- int pos = PCI_CONFIG_SPACE_SIZE;
-
- do {
- if (xen_host_pci_get_long(d, pos, &header)) {
- break;
- }
- /*
- * If we have no capabilities, this is indicated by cap ID,
- * cap version and next pointer all being 0.
- */
- if (header == 0) {
- break;
- }
-
- if (PCI_EXT_CAP_ID(header) == cap) {
- return pos;
- }
-
- pos = PCI_EXT_CAP_NEXT(header);
- if (pos < PCI_CONFIG_SPACE_SIZE) {
- break;
- }
-
- max_cap--;
- } while (max_cap > 0);
-
- return -1;
-}
-
-void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
- uint8_t bus, uint8_t dev, uint8_t func,
- Error **errp)
-{
- unsigned int v;
- Error *err = NULL;
-
- d->config_fd = -1;
- d->domain = domain;
- d->bus = bus;
- d->dev = dev;
- d->func = func;
-
- xen_host_pci_config_open(d, &err);
- if (err) {
- goto error;
- }
-
- xen_host_pci_get_resource(d, &err);
- if (err) {
- goto error;
- }
-
- xen_host_pci_get_hex_value(d, "vendor", &v, &err);
- if (err) {
- goto error;
- }
- d->vendor_id = v;
-
- xen_host_pci_get_hex_value(d, "device", &v, &err);
- if (err) {
- goto error;
- }
- d->device_id = v;
-
- xen_host_pci_get_dec_value(d, "irq", &v, &err);
- if (err) {
- goto error;
- }
- d->irq = v;
-
- xen_host_pci_get_hex_value(d, "class", &v, &err);
- if (err) {
- goto error;
- }
- d->class_code = v;
-
- d->is_virtfn = xen_host_pci_dev_is_virtfn(d);
-
- return;
-
-error:
- error_propagate(errp, err);
-
- if (d->config_fd >= 0) {
- close(d->config_fd);
- d->config_fd = -1;
- }
-}
-
-bool xen_host_pci_device_closed(XenHostPCIDevice *d)
-{
- return d->config_fd == -1;
-}
-
-void xen_host_pci_device_put(XenHostPCIDevice *d)
-{
- if (d->config_fd >= 0) {
- close(d->config_fd);
- d->config_fd = -1;
- }
-}
diff --git a/qemu/hw/xen/xen-host-pci-device.h b/qemu/hw/xen/xen-host-pci-device.h
deleted file mode 100644
index 6acf36e13..000000000
--- a/qemu/hw/xen/xen-host-pci-device.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef XEN_HOST_PCI_DEVICE_H
-#define XEN_HOST_PCI_DEVICE_H
-
-#include "hw/pci/pci.h"
-
-enum {
- XEN_HOST_PCI_REGION_TYPE_IO = 1 << 1,
- XEN_HOST_PCI_REGION_TYPE_MEM = 1 << 2,
- XEN_HOST_PCI_REGION_TYPE_PREFETCH = 1 << 3,
- XEN_HOST_PCI_REGION_TYPE_MEM_64 = 1 << 4,
-};
-
-typedef struct XenHostPCIIORegion {
- pcibus_t base_addr;
- pcibus_t size;
- uint8_t type;
- uint8_t bus_flags; /* Bus-specific bits */
-} XenHostPCIIORegion;
-
-typedef struct XenHostPCIDevice {
- uint16_t domain;
- uint8_t bus;
- uint8_t dev;
- uint8_t func;
-
- uint16_t vendor_id;
- uint16_t device_id;
- uint32_t class_code;
- int irq;
-
- XenHostPCIIORegion io_regions[PCI_NUM_REGIONS - 1];
- XenHostPCIIORegion rom;
-
- bool is_virtfn;
-
- int config_fd;
-} XenHostPCIDevice;
-
-void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
- uint8_t bus, uint8_t dev, uint8_t func,
- Error **errp);
-void xen_host_pci_device_put(XenHostPCIDevice *pci_dev);
-bool xen_host_pci_device_closed(XenHostPCIDevice *d);
-
-int xen_host_pci_get_byte(XenHostPCIDevice *d, int pos, uint8_t *p);
-int xen_host_pci_get_word(XenHostPCIDevice *d, int pos, uint16_t *p);
-int xen_host_pci_get_long(XenHostPCIDevice *d, int pos, uint32_t *p);
-int xen_host_pci_get_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
- int len);
-int xen_host_pci_set_byte(XenHostPCIDevice *d, int pos, uint8_t data);
-int xen_host_pci_set_word(XenHostPCIDevice *d, int pos, uint16_t data);
-int xen_host_pci_set_long(XenHostPCIDevice *d, int pos, uint32_t data);
-int xen_host_pci_set_block(XenHostPCIDevice *d, int pos, uint8_t *buf,
- int len);
-
-int xen_host_pci_find_ext_cap_offset(XenHostPCIDevice *s, uint32_t cap);
-
-#endif /* !XEN_HOST_PCI_DEVICE_H_ */
diff --git a/qemu/hw/xen/xen_backend.c b/qemu/hw/xen/xen_backend.c
deleted file mode 100644
index 60575ad38..000000000
--- a/qemu/hw/xen/xen_backend.c
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
- * xen backend driver infrastructure
- * (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
- */
-
-/*
- * TODO: add some xenbus / xenstore concepts overview here.
- */
-
-#include "qemu/osdep.h"
-#include <sys/mman.h>
-#include <sys/signal.h>
-
-#include "hw/hw.h"
-#include "sysemu/char.h"
-#include "qemu/log.h"
-#include "hw/xen/xen_backend.h"
-
-#include <xen/grant_table.h>
-
-/* ------------------------------------------------------------- */
-
-/* public */
-xc_interface *xen_xc = NULL;
-xenforeignmemory_handle *xen_fmem = NULL;
-struct xs_handle *xenstore = NULL;
-const char *xen_protocol;
-
-/* private */
-static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
-static int debug = 0;
-
-/* ------------------------------------------------------------- */
-
-int xenstore_write_str(const char *base, const char *node, const char *val)
-{
- char abspath[XEN_BUFSIZE];
-
- snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
- if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
- return -1;
- }
- return 0;
-}
-
-char *xenstore_read_str(const char *base, const char *node)
-{
- char abspath[XEN_BUFSIZE];
- unsigned int len;
- char *str, *ret = NULL;
-
- snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
- str = xs_read(xenstore, 0, abspath, &len);
- if (str != NULL) {
- /* move to qemu-allocated memory to make sure
- * callers can savely g_free() stuff. */
- ret = g_strdup(str);
- free(str);
- }
- return ret;
-}
-
-int xenstore_write_int(const char *base, const char *node, int ival)
-{
- char val[12];
-
- snprintf(val, sizeof(val), "%d", ival);
- return xenstore_write_str(base, node, val);
-}
-
-int xenstore_write_int64(const char *base, const char *node, int64_t ival)
-{
- char val[21];
-
- snprintf(val, sizeof(val), "%"PRId64, ival);
- return xenstore_write_str(base, node, val);
-}
-
-int xenstore_read_int(const char *base, const char *node, int *ival)
-{
- char *val;
- int rc = -1;
-
- val = xenstore_read_str(base, node);
- if (val && 1 == sscanf(val, "%d", ival)) {
- rc = 0;
- }
- g_free(val);
- return rc;
-}
-
-int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
-{
- char *val;
- int rc = -1;
-
- val = xenstore_read_str(base, node);
- if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
- rc = 0;
- }
- g_free(val);
- return rc;
-}
-
-int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
-{
- return xenstore_write_str(xendev->be, node, val);
-}
-
-int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
-{
- return xenstore_write_int(xendev->be, node, ival);
-}
-
-int xenstore_write_be_int64(struct XenDevice *xendev, const char *node, int64_t ival)
-{
- return xenstore_write_int64(xendev->be, node, ival);
-}
-
-char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
-{
- return xenstore_read_str(xendev->be, node);
-}
-
-int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
-{
- return xenstore_read_int(xendev->be, node, ival);
-}
-
-char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
-{
- return xenstore_read_str(xendev->fe, node);
-}
-
-int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
-{
- return xenstore_read_int(xendev->fe, node, ival);
-}
-
-int xenstore_read_fe_uint64(struct XenDevice *xendev, const char *node, uint64_t *uval)
-{
- return xenstore_read_uint64(xendev->fe, node, uval);
-}
-
-/* ------------------------------------------------------------- */
-
-const char *xenbus_strstate(enum xenbus_state state)
-{
- static const char *const name[] = {
- [ XenbusStateUnknown ] = "Unknown",
- [ XenbusStateInitialising ] = "Initialising",
- [ XenbusStateInitWait ] = "InitWait",
- [ XenbusStateInitialised ] = "Initialised",
- [ XenbusStateConnected ] = "Connected",
- [ XenbusStateClosing ] = "Closing",
- [ XenbusStateClosed ] = "Closed",
- };
- return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
-}
-
-int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
-{
- int rc;
-
- rc = xenstore_write_be_int(xendev, "state", state);
- if (rc < 0) {
- return rc;
- }
- xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
- xenbus_strstate(xendev->be_state), xenbus_strstate(state));
- xendev->be_state = state;
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
-{
- struct XenDevice *xendev;
-
- QTAILQ_FOREACH(xendev, &xendevs, next) {
- if (xendev->dom != dom) {
- continue;
- }
- if (xendev->dev != dev) {
- continue;
- }
- if (strcmp(xendev->type, type) != 0) {
- continue;
- }
- return xendev;
- }
- return NULL;
-}
-
-/*
- * get xen backend device, allocate a new one if it doesn't exist.
- */
-static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
- struct XenDevOps *ops)
-{
- struct XenDevice *xendev;
-
- xendev = xen_be_find_xendev(type, dom, dev);
- if (xendev) {
- return xendev;
- }
-
- /* init new xendev */
- xendev = g_malloc0(ops->size);
- xendev->type = type;
- xendev->dom = dom;
- xendev->dev = dev;
- xendev->ops = ops;
-
- snprintf(xendev->be, sizeof(xendev->be), "backend/%s/%d/%d",
- xendev->type, xendev->dom, xendev->dev);
- snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
- xendev->type, xendev->dev);
-
- xendev->debug = debug;
- xendev->local_port = -1;
-
- xendev->evtchndev = xenevtchn_open(NULL, 0);
- if (xendev->evtchndev == NULL) {
- xen_be_printf(NULL, 0, "can't open evtchn device\n");
- g_free(xendev);
- return NULL;
- }
- fcntl(xenevtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
-
- if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
- xendev->gnttabdev = xengnttab_open(NULL, 0);
- if (xendev->gnttabdev == NULL) {
- xen_be_printf(NULL, 0, "can't open gnttab device\n");
- xenevtchn_close(xendev->evtchndev);
- g_free(xendev);
- return NULL;
- }
- } else {
- xendev->gnttabdev = NULL;
- }
-
- QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
-
- if (xendev->ops->alloc) {
- xendev->ops->alloc(xendev);
- }
-
- return xendev;
-}
-
-/*
- * release xen backend device.
- */
-static struct XenDevice *xen_be_del_xendev(int dom, int dev)
-{
- struct XenDevice *xendev, *xnext;
-
- /*
- * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
- * we save the next pointer in xnext because we might free xendev.
- */
- xnext = xendevs.tqh_first;
- while (xnext) {
- xendev = xnext;
- xnext = xendev->next.tqe_next;
-
- if (xendev->dom != dom) {
- continue;
- }
- if (xendev->dev != dev && dev != -1) {
- continue;
- }
-
- if (xendev->ops->free) {
- xendev->ops->free(xendev);
- }
-
- if (xendev->fe) {
- char token[XEN_BUFSIZE];
- snprintf(token, sizeof(token), "fe:%p", xendev);
- xs_unwatch(xenstore, xendev->fe, token);
- g_free(xendev->fe);
- }
-
- if (xendev->evtchndev != NULL) {
- xenevtchn_close(xendev->evtchndev);
- }
- if (xendev->gnttabdev != NULL) {
- xengnttab_close(xendev->gnttabdev);
- }
-
- QTAILQ_REMOVE(&xendevs, xendev, next);
- g_free(xendev);
- }
- return NULL;
-}
-
-/*
- * Sync internal data structures on xenstore updates.
- * Node specifies the changed field. node = NULL means
- * update all fields (used for initialization).
- */
-static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
-{
- if (node == NULL || strcmp(node, "online") == 0) {
- if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1) {
- xendev->online = 0;
- }
- }
-
- if (node) {
- xen_be_printf(xendev, 2, "backend update: %s\n", node);
- if (xendev->ops->backend_changed) {
- xendev->ops->backend_changed(xendev, node);
- }
- }
-}
-
-static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
-{
- int fe_state;
-
- if (node == NULL || strcmp(node, "state") == 0) {
- if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1) {
- fe_state = XenbusStateUnknown;
- }
- if (xendev->fe_state != fe_state) {
- xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
- xenbus_strstate(xendev->fe_state),
- xenbus_strstate(fe_state));
- }
- xendev->fe_state = fe_state;
- }
- if (node == NULL || strcmp(node, "protocol") == 0) {
- g_free(xendev->protocol);
- xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
- if (xendev->protocol) {
- xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
- }
- }
-
- if (node) {
- xen_be_printf(xendev, 2, "frontend update: %s\n", node);
- if (xendev->ops->frontend_changed) {
- xendev->ops->frontend_changed(xendev, node);
- }
- }
-}
-
-/* ------------------------------------------------------------- */
-/* Check for possible state transitions and perform them. */
-
-/*
- * Initial xendev setup. Read frontend path, register watch for it.
- * Should succeed once xend finished setting up the backend device.
- *
- * Also sets initial state (-> Initializing) when done. Which
- * only affects the xendev->be_state variable as xenbus should
- * already be put into that state by xend.
- */
-static int xen_be_try_setup(struct XenDevice *xendev)
-{
- char token[XEN_BUFSIZE];
- int be_state;
-
- if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
- xen_be_printf(xendev, 0, "reading backend state failed\n");
- return -1;
- }
-
- if (be_state != XenbusStateInitialising) {
- xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
- xenbus_strstate(be_state));
- return -1;
- }
-
- xendev->fe = xenstore_read_be_str(xendev, "frontend");
- if (xendev->fe == NULL) {
- xen_be_printf(xendev, 0, "reading frontend path failed\n");
- return -1;
- }
-
- /* setup frontend watch */
- snprintf(token, sizeof(token), "fe:%p", xendev);
- if (!xs_watch(xenstore, xendev->fe, token)) {
- xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
- xendev->fe);
- return -1;
- }
- xen_be_set_state(xendev, XenbusStateInitialising);
-
- xen_be_backend_changed(xendev, NULL);
- xen_be_frontend_changed(xendev, NULL);
- return 0;
-}
-
-/*
- * Try initialize xendev. Prepare everything the backend can do
- * without synchronizing with the frontend. Fakes hotplug-status. No
- * hotplug involved here because this is about userspace drivers, thus
- * there are kernel backend devices which could invoke hotplug.
- *
- * Goes to InitWait on success.
- */
-static int xen_be_try_init(struct XenDevice *xendev)
-{
- int rc = 0;
-
- if (!xendev->online) {
- xen_be_printf(xendev, 1, "not online\n");
- return -1;
- }
-
- if (xendev->ops->init) {
- rc = xendev->ops->init(xendev);
- }
- if (rc != 0) {
- xen_be_printf(xendev, 1, "init() failed\n");
- return rc;
- }
-
- xenstore_write_be_str(xendev, "hotplug-status", "connected");
- xen_be_set_state(xendev, XenbusStateInitWait);
- return 0;
-}
-
-/*
- * Try to initialise xendev. Depends on the frontend being ready
- * for it (shared ring and evtchn info in xenstore, state being
- * Initialised or Connected).
- *
- * Goes to Connected on success.
- */
-static int xen_be_try_initialise(struct XenDevice *xendev)
-{
- int rc = 0;
-
- if (xendev->fe_state != XenbusStateInitialised &&
- xendev->fe_state != XenbusStateConnected) {
- if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
- xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
- } else {
- xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
- return -1;
- }
- }
-
- if (xendev->ops->initialise) {
- rc = xendev->ops->initialise(xendev);
- }
- if (rc != 0) {
- xen_be_printf(xendev, 0, "initialise() failed\n");
- return rc;
- }
-
- xen_be_set_state(xendev, XenbusStateConnected);
- return 0;
-}
-
-/*
- * Try to let xendev know that it is connected. Depends on the
- * frontend being Connected. Note that this may be called more
- * than once since the backend state is not modified.
- */
-static void xen_be_try_connected(struct XenDevice *xendev)
-{
- if (!xendev->ops->connected) {
- return;
- }
-
- if (xendev->fe_state != XenbusStateConnected) {
- if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
- xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
- } else {
- xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
- return;
- }
- }
-
- xendev->ops->connected(xendev);
-}
-
-/*
- * Teardown connection.
- *
- * Goes to Closed when done.
- */
-static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
-{
- if (xendev->be_state != XenbusStateClosing &&
- xendev->be_state != XenbusStateClosed &&
- xendev->ops->disconnect) {
- xendev->ops->disconnect(xendev);
- }
- if (xendev->be_state != state) {
- xen_be_set_state(xendev, state);
- }
-}
-
-/*
- * Try to reset xendev, for reconnection by another frontend instance.
- */
-static int xen_be_try_reset(struct XenDevice *xendev)
-{
- if (xendev->fe_state != XenbusStateInitialising) {
- return -1;
- }
-
- xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
- xen_be_set_state(xendev, XenbusStateInitialising);
- return 0;
-}
-
-/*
- * state change dispatcher function
- */
-void xen_be_check_state(struct XenDevice *xendev)
-{
- int rc = 0;
-
- /* frontend may request shutdown from almost anywhere */
- if (xendev->fe_state == XenbusStateClosing ||
- xendev->fe_state == XenbusStateClosed) {
- xen_be_disconnect(xendev, xendev->fe_state);
- return;
- }
-
- /* check for possible backend state transitions */
- for (;;) {
- switch (xendev->be_state) {
- case XenbusStateUnknown:
- rc = xen_be_try_setup(xendev);
- break;
- case XenbusStateInitialising:
- rc = xen_be_try_init(xendev);
- break;
- case XenbusStateInitWait:
- rc = xen_be_try_initialise(xendev);
- break;
- case XenbusStateConnected:
- /* xendev->be_state doesn't change */
- xen_be_try_connected(xendev);
- rc = -1;
- break;
- case XenbusStateClosed:
- rc = xen_be_try_reset(xendev);
- break;
- default:
- rc = -1;
- }
- if (rc != 0) {
- break;
- }
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
-{
- struct XenDevice *xendev;
- char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
- char **dev = NULL;
- unsigned int cdev, j;
-
- /* setup watch */
- snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
- snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
- if (!xs_watch(xenstore, path, token)) {
- xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
- return -1;
- }
-
- /* look for backends */
- dev = xs_directory(xenstore, 0, path, &cdev);
- if (!dev) {
- return 0;
- }
- for (j = 0; j < cdev; j++) {
- xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
- if (xendev == NULL) {
- continue;
- }
- xen_be_check_state(xendev);
- }
- free(dev);
- return 0;
-}
-
-static void xenstore_update_be(char *watch, char *type, int dom,
- struct XenDevOps *ops)
-{
- struct XenDevice *xendev;
- char path[XEN_BUFSIZE], *bepath;
- unsigned int len, dev;
-
- len = snprintf(path, sizeof(path), "backend/%s/%d", type, dom);
- if (strncmp(path, watch, len) != 0) {
- return;
- }
- if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
- strcpy(path, "");
- if (sscanf(watch+len, "/%u", &dev) != 1) {
- dev = -1;
- }
- }
- if (dev == -1) {
- return;
- }
-
- xendev = xen_be_get_xendev(type, dom, dev, ops);
- if (xendev != NULL) {
- bepath = xs_read(xenstore, 0, xendev->be, &len);
- if (bepath == NULL) {
- xen_be_del_xendev(dom, dev);
- } else {
- free(bepath);
- xen_be_backend_changed(xendev, path);
- xen_be_check_state(xendev);
- }
- }
-}
-
-static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
-{
- char *node;
- unsigned int len;
-
- len = strlen(xendev->fe);
- if (strncmp(xendev->fe, watch, len) != 0) {
- return;
- }
- if (watch[len] != '/') {
- return;
- }
- node = watch + len + 1;
-
- xen_be_frontend_changed(xendev, node);
- xen_be_check_state(xendev);
-}
-
-static void xenstore_update(void *unused)
-{
- char **vec = NULL;
- intptr_t type, ops, ptr;
- unsigned int dom, count;
-
- vec = xs_read_watch(xenstore, &count);
- if (vec == NULL) {
- goto cleanup;
- }
-
- if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
- &type, &dom, &ops) == 3) {
- xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
- }
- if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
- xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
- }
-
-cleanup:
- free(vec);
-}
-
-static void xen_be_evtchn_event(void *opaque)
-{
- struct XenDevice *xendev = opaque;
- evtchn_port_t port;
-
- port = xenevtchn_pending(xendev->evtchndev);
- if (port != xendev->local_port) {
- xen_be_printf(xendev, 0,
- "xenevtchn_pending returned %d (expected %d)\n",
- port, xendev->local_port);
- return;
- }
- xenevtchn_unmask(xendev->evtchndev, port);
-
- if (xendev->ops->event) {
- xendev->ops->event(xendev);
- }
-}
-
-/* -------------------------------------------------------------------- */
-
-int xen_be_init(void)
-{
- xenstore = xs_daemon_open();
- if (!xenstore) {
- xen_be_printf(NULL, 0, "can't connect to xenstored\n");
- return -1;
- }
-
- qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL);
-
- if (xen_xc == NULL || xen_fmem == NULL) {
- /* Check if xen_init() have been called */
- goto err;
- }
- return 0;
-
-err:
- qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
- xs_daemon_close(xenstore);
- xenstore = NULL;
-
- return -1;
-}
-
-int xen_be_register(const char *type, struct XenDevOps *ops)
-{
- return xenstore_scan(type, xen_domid, ops);
-}
-
-int xen_be_bind_evtchn(struct XenDevice *xendev)
-{
- if (xendev->local_port != -1) {
- return 0;
- }
- xendev->local_port = xenevtchn_bind_interdomain
- (xendev->evtchndev, xendev->dom, xendev->remote_port);
- if (xendev->local_port == -1) {
- xen_be_printf(xendev, 0, "xenevtchn_bind_interdomain failed\n");
- return -1;
- }
- xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
- qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev),
- xen_be_evtchn_event, NULL, xendev);
- return 0;
-}
-
-void xen_be_unbind_evtchn(struct XenDevice *xendev)
-{
- if (xendev->local_port == -1) {
- return;
- }
- qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
- xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
- xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
- xendev->local_port = -1;
-}
-
-int xen_be_send_notify(struct XenDevice *xendev)
-{
- return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
-}
-
-/*
- * msg_level:
- * 0 == errors (stderr + logfile).
- * 1 == informative debug messages (logfile only).
- * 2 == noisy debug messages (logfile only).
- * 3 == will flood your log (logfile only).
- */
-void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
-{
- va_list args;
-
- if (xendev) {
- if (msg_level > xendev->debug) {
- return;
- }
- qemu_log("xen be: %s: ", xendev->name);
- if (msg_level == 0) {
- fprintf(stderr, "xen be: %s: ", xendev->name);
- }
- } else {
- if (msg_level > debug) {
- return;
- }
- qemu_log("xen be core: ");
- if (msg_level == 0) {
- fprintf(stderr, "xen be core: ");
- }
- }
- va_start(args, fmt);
- qemu_log_vprintf(fmt, args);
- va_end(args);
- if (msg_level == 0) {
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- }
- qemu_log_flush();
-}
diff --git a/qemu/hw/xen/xen_devconfig.c b/qemu/hw/xen/xen_devconfig.c
deleted file mode 100644
index 1f30fe4f5..000000000
--- a/qemu/hw/xen/xen_devconfig.c
+++ /dev/null
@@ -1,176 +0,0 @@
-#include "qemu/osdep.h"
-#include "hw/xen/xen_backend.h"
-#include "sysemu/block-backend.h"
-#include "sysemu/blockdev.h"
-
-/* ------------------------------------------------------------- */
-
-struct xs_dirs {
- char *xs_dir;
- QTAILQ_ENTRY(xs_dirs) list;
-};
-static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup);
-
-static void xen_config_cleanup_dir(char *dir)
-{
- struct xs_dirs *d;
-
- d = g_malloc(sizeof(*d));
- d->xs_dir = dir;
- QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
-}
-
-void xen_config_cleanup(void)
-{
- struct xs_dirs *d;
-
- QTAILQ_FOREACH(d, &xs_cleanup, list) {
- xs_rm(xenstore, 0, d->xs_dir);
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xen_config_dev_mkdir(char *dev, int p)
-{
- struct xs_permissions perms[2] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = p,
- }};
-
- if (!xs_mkdir(xenstore, 0, dev)) {
- xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
- return -1;
- }
- xen_config_cleanup_dir(g_strdup(dev));
-
- if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
- xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
- return -1;
- }
- return 0;
-}
-
-static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
- char *fe, char *be, int len)
-{
- char *dom;
-
- dom = xs_get_domain_path(xenstore, xen_domid);
- snprintf(fe, len, "%s/device/%s/%d", dom, ftype, vdev);
- free(dom);
-
- dom = xs_get_domain_path(xenstore, 0);
- snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
- free(dom);
-
- xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
- xen_config_dev_mkdir(be, XS_PERM_READ);
- return 0;
-}
-
-static int xen_config_dev_all(char *fe, char *be)
-{
- /* frontend */
- if (xen_protocol)
- xenstore_write_str(fe, "protocol", xen_protocol);
-
- xenstore_write_int(fe, "state", XenbusStateInitialising);
- xenstore_write_int(fe, "backend-id", 0);
- xenstore_write_str(fe, "backend", be);
-
- /* backend */
- xenstore_write_str(be, "domain", qemu_name ? qemu_name : "no-name");
- xenstore_write_int(be, "online", 1);
- xenstore_write_int(be, "state", XenbusStateInitialising);
- xenstore_write_int(be, "frontend-id", xen_domid);
- xenstore_write_str(be, "frontend", fe);
-
- return 0;
-}
-
-/* ------------------------------------------------------------- */
-
-int xen_config_dev_blk(DriveInfo *disk)
-{
- char fe[256], be[256], device_name[32];
- int vdev = 202 * 256 + 16 * disk->unit;
- int cdrom = disk->media_cd;
- const char *devtype = cdrom ? "cdrom" : "disk";
- const char *mode = cdrom ? "r" : "w";
- const char *filename = qemu_opt_get(disk->opts, "file");
-
- snprintf(device_name, sizeof(device_name), "xvd%c", 'a' + disk->unit);
- xen_be_printf(NULL, 1, "config disk %d [%s]: %s\n",
- disk->unit, device_name, filename);
- xen_config_dev_dirs("vbd", "qdisk", vdev, fe, be, sizeof(fe));
-
- /* frontend */
- xenstore_write_int(fe, "virtual-device", vdev);
- xenstore_write_str(fe, "device-type", devtype);
-
- /* backend */
- xenstore_write_str(be, "dev", device_name);
- xenstore_write_str(be, "type", "file");
- xenstore_write_str(be, "params", filename);
- xenstore_write_str(be, "mode", mode);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_nic(NICInfo *nic)
-{
- char fe[256], be[256];
- char mac[20];
- int vlan_id = -1;
-
- net_hub_id_for_client(nic->netdev, &vlan_id);
- snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
- nic->macaddr.a[0], nic->macaddr.a[1], nic->macaddr.a[2],
- nic->macaddr.a[3], nic->macaddr.a[4], nic->macaddr.a[5]);
- xen_be_printf(NULL, 1, "config nic %d: mac=\"%s\"\n", vlan_id, mac);
- xen_config_dev_dirs("vif", "qnic", vlan_id, fe, be, sizeof(fe));
-
- /* frontend */
- xenstore_write_int(fe, "handle", vlan_id);
- xenstore_write_str(fe, "mac", mac);
-
- /* backend */
- xenstore_write_int(be, "handle", vlan_id);
- xenstore_write_str(be, "mac", mac);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_vfb(int vdev, const char *type)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("vfb", "vfb", vdev, fe, be, sizeof(fe));
-
- /* backend */
- xenstore_write_str(be, "type", type);
-
- /* common stuff */
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_vkbd(int vdev)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("vkbd", "vkbd", vdev, fe, be, sizeof(fe));
- return xen_config_dev_all(fe, be);
-}
-
-int xen_config_dev_console(int vdev)
-{
- char fe[256], be[256];
-
- xen_config_dev_dirs("console", "console", vdev, fe, be, sizeof(fe));
- return xen_config_dev_all(fe, be);
-}
diff --git a/qemu/hw/xen/xen_pt.c b/qemu/hw/xen/xen_pt.c
deleted file mode 100644
index f593b046e..000000000
--- a/qemu/hw/xen/xen_pt.c
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-/*
- * Interrupt Disable policy:
- *
- * INTx interrupt:
- * Initialize(register_real_device)
- * Map INTx(xc_physdev_map_pirq):
- * <fail>
- * - Set real Interrupt Disable bit to '1'.
- * - Set machine_irq and assigned_device->machine_irq to '0'.
- * * Don't bind INTx.
- *
- * Bind INTx(xc_domain_bind_pt_pci_irq):
- * <fail>
- * - Set real Interrupt Disable bit to '1'.
- * - Unmap INTx.
- * - Decrement xen_pt_mapped_machine_irq[machine_irq]
- * - Set assigned_device->machine_irq to '0'.
- *
- * Write to Interrupt Disable bit by guest software(xen_pt_cmd_reg_write)
- * Write '0'
- * - Set real bit to '0' if assigned_device->machine_irq isn't '0'.
- *
- * Write '1'
- * - Set real bit to '1'.
- *
- * MSI interrupt:
- * Initialize MSI register(xen_pt_msi_setup, xen_pt_msi_update)
- * Bind MSI(xc_domain_update_msi_irq)
- * <fail>
- * - Unmap MSI.
- * - Set dev->msi->pirq to '-1'.
- *
- * MSI-X interrupt:
- * Initialize MSI-X register(xen_pt_msix_update_one)
- * Bind MSI-X(xc_domain_update_msi_irq)
- * <fail>
- * - Unmap MSI-X.
- * - Set entry->pirq to '-1'.
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include <sys/ioctl.h>
-
-#include "hw/pci/pci.h"
-#include "hw/xen/xen.h"
-#include "hw/i386/pc.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
-#include "qemu/range.h"
-#include "exec/address-spaces.h"
-
-#define XEN_PT_NR_IRQS (256)
-static uint8_t xen_pt_mapped_machine_irq[XEN_PT_NR_IRQS] = {0};
-
-void xen_pt_log(const PCIDevice *d, const char *f, ...)
-{
- va_list ap;
-
- va_start(ap, f);
- if (d) {
- fprintf(stderr, "[%02x:%02x.%d] ", pci_bus_num(d->bus),
- PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
- }
- vfprintf(stderr, f, ap);
- va_end(ap);
-}
-
-/* Config Space */
-
-static int xen_pt_pci_config_access_check(PCIDevice *d, uint32_t addr, int len)
-{
- /* check offset range */
- if (addr >= 0xFF) {
- XEN_PT_ERR(d, "Failed to access register with offset exceeding 0xFF. "
- "(addr: 0x%02x, len: %d)\n", addr, len);
- return -1;
- }
-
- /* check read size */
- if ((len != 1) && (len != 2) && (len != 4)) {
- XEN_PT_ERR(d, "Failed to access register with invalid access length. "
- "(addr: 0x%02x, len: %d)\n", addr, len);
- return -1;
- }
-
- /* check offset alignment */
- if (addr & (len - 1)) {
- XEN_PT_ERR(d, "Failed to access register with invalid access size "
- "alignment. (addr: 0x%02x, len: %d)\n", addr, len);
- return -1;
- }
-
- return 0;
-}
-
-int xen_pt_bar_offset_to_index(uint32_t offset)
-{
- int index = 0;
-
- /* check Exp ROM BAR */
- if (offset == PCI_ROM_ADDRESS) {
- return PCI_ROM_SLOT;
- }
-
- /* calculate BAR index */
- index = (offset - PCI_BASE_ADDRESS_0) >> 2;
- if (index >= PCI_NUM_REGIONS) {
- return -1;
- }
-
- return index;
-}
-
-static uint32_t xen_pt_pci_read_config(PCIDevice *d, uint32_t addr, int len)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- uint32_t val = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
- XenPTReg *reg_entry = NULL;
- int rc = 0;
- int emul_len = 0;
- uint32_t find_addr = addr;
-
- if (xen_pt_pci_config_access_check(d, addr, len)) {
- goto exit;
- }
-
- /* find register group entry */
- reg_grp_entry = xen_pt_find_reg_grp(s, addr);
- if (reg_grp_entry) {
- /* check 0-Hardwired register group */
- if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
- /* no need to emulate, just return 0 */
- val = 0;
- goto exit;
- }
- }
-
- /* read I/O device register value */
- rc = xen_host_pci_get_block(&s->real_device, addr, (uint8_t *)&val, len);
- if (rc < 0) {
- XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
- memset(&val, 0xff, len);
- }
-
- /* just return the I/O device register value for
- * passthrough type register group */
- if (reg_grp_entry == NULL) {
- goto exit;
- }
-
- /* adjust the read value to appropriate CFC-CFF window */
- val <<= (addr & 3) << 3;
- emul_len = len;
-
- /* loop around the guest requested size */
- while (emul_len > 0) {
- /* find register entry to be emulated */
- reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
- if (reg_entry) {
- XenPTRegInfo *reg = reg_entry->reg;
- uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
- uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
- uint8_t *ptr_val = NULL;
-
- valid_mask <<= (find_addr - real_offset) << 3;
- ptr_val = (uint8_t *)&val + (real_offset & 3);
-
- /* do emulation based on register size */
- switch (reg->size) {
- case 1:
- if (reg->u.b.read) {
- rc = reg->u.b.read(s, reg_entry, ptr_val, valid_mask);
- }
- break;
- case 2:
- if (reg->u.w.read) {
- rc = reg->u.w.read(s, reg_entry,
- (uint16_t *)ptr_val, valid_mask);
- }
- break;
- case 4:
- if (reg->u.dw.read) {
- rc = reg->u.dw.read(s, reg_entry,
- (uint32_t *)ptr_val, valid_mask);
- }
- break;
- }
-
- if (rc < 0) {
- xen_shutdown_fatal_error("Internal error: Invalid read "
- "emulation. (%s, rc: %d)\n",
- __func__, rc);
- return 0;
- }
-
- /* calculate next address to find */
- emul_len -= reg->size;
- if (emul_len > 0) {
- find_addr = real_offset + reg->size;
- }
- } else {
- /* nothing to do with passthrough type register,
- * continue to find next byte */
- emul_len--;
- find_addr++;
- }
- }
-
- /* need to shift back before returning them to pci bus emulator */
- val >>= ((addr & 3) << 3);
-
-exit:
- XEN_PT_LOG_CONFIG(d, addr, val, len);
- return val;
-}
-
-static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
- uint32_t val, int len)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- int index = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
- int rc = 0;
- uint32_t read_val = 0, wb_mask;
- int emul_len = 0;
- XenPTReg *reg_entry = NULL;
- uint32_t find_addr = addr;
- XenPTRegInfo *reg = NULL;
- bool wp_flag = false;
-
- if (xen_pt_pci_config_access_check(d, addr, len)) {
- return;
- }
-
- XEN_PT_LOG_CONFIG(d, addr, val, len);
-
- /* check unused BAR register */
- index = xen_pt_bar_offset_to_index(addr);
- if ((index >= 0) && (val != 0)) {
- uint32_t chk = val;
-
- if (index == PCI_ROM_SLOT)
- chk |= (uint32_t)~PCI_ROM_ADDRESS_MASK;
-
- if ((chk != XEN_PT_BAR_ALLF) &&
- (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED)) {
- XEN_PT_WARN(d, "Guest attempt to set address to unused "
- "Base Address Register. (addr: 0x%02x, len: %d)\n",
- addr, len);
- }
- }
-
- /* find register group entry */
- reg_grp_entry = xen_pt_find_reg_grp(s, addr);
- if (reg_grp_entry) {
- /* check 0-Hardwired register group */
- if (reg_grp_entry->reg_grp->grp_type == XEN_PT_GRP_TYPE_HARDWIRED) {
- /* ignore silently */
- XEN_PT_WARN(d, "Access to 0-Hardwired register. "
- "(addr: 0x%02x, len: %d)\n", addr, len);
- return;
- }
- }
-
- rc = xen_host_pci_get_block(&s->real_device, addr,
- (uint8_t *)&read_val, len);
- if (rc < 0) {
- XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc);
- memset(&read_val, 0xff, len);
- wb_mask = 0;
- } else {
- wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
- }
-
- /* pass directly to the real device for passthrough type register group */
- if (reg_grp_entry == NULL) {
- if (!s->permissive) {
- wb_mask = 0;
- wp_flag = true;
- }
- goto out;
- }
-
- memory_region_transaction_begin();
- pci_default_write_config(d, addr, val, len);
-
- /* adjust the read and write value to appropriate CFC-CFF window */
- read_val <<= (addr & 3) << 3;
- val <<= (addr & 3) << 3;
- emul_len = len;
-
- /* loop around the guest requested size */
- while (emul_len > 0) {
- /* find register entry to be emulated */
- reg_entry = xen_pt_find_reg(reg_grp_entry, find_addr);
- if (reg_entry) {
- reg = reg_entry->reg;
- uint32_t real_offset = reg_grp_entry->base_offset + reg->offset;
- uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3);
- uint8_t *ptr_val = NULL;
- uint32_t wp_mask = reg->emu_mask | reg->ro_mask;
-
- valid_mask <<= (find_addr - real_offset) << 3;
- ptr_val = (uint8_t *)&val + (real_offset & 3);
- if (!s->permissive) {
- wp_mask |= reg->res_mask;
- }
- if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
- wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3))
- << ((len - emul_len) << 3));
- }
-
- /* do emulation based on register size */
- switch (reg->size) {
- case 1:
- if (reg->u.b.write) {
- rc = reg->u.b.write(s, reg_entry, ptr_val,
- read_val >> ((real_offset & 3) << 3),
- valid_mask);
- }
- break;
- case 2:
- if (reg->u.w.write) {
- rc = reg->u.w.write(s, reg_entry, (uint16_t *)ptr_val,
- (read_val >> ((real_offset & 3) << 3)),
- valid_mask);
- }
- break;
- case 4:
- if (reg->u.dw.write) {
- rc = reg->u.dw.write(s, reg_entry, (uint32_t *)ptr_val,
- (read_val >> ((real_offset & 3) << 3)),
- valid_mask);
- }
- break;
- }
-
- if (rc < 0) {
- xen_shutdown_fatal_error("Internal error: Invalid write"
- " emulation. (%s, rc: %d)\n",
- __func__, rc);
- return;
- }
-
- /* calculate next address to find */
- emul_len -= reg->size;
- if (emul_len > 0) {
- find_addr = real_offset + reg->size;
- }
- } else {
- /* nothing to do with passthrough type register,
- * continue to find next byte */
- if (!s->permissive) {
- wb_mask &= ~(0xff << ((len - emul_len) << 3));
- /* Unused BARs will make it here, but we don't want to issue
- * warnings for writes to them (bogus writes get dealt with
- * above).
- */
- if (index < 0) {
- wp_flag = true;
- }
- }
- emul_len--;
- find_addr++;
- }
- }
-
- /* need to shift back before passing them to xen_host_pci_set_block. */
- val >>= (addr & 3) << 3;
-
- memory_region_transaction_commit();
-
-out:
- if (wp_flag && !s->permissive_warned) {
- s->permissive_warned = true;
- xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
- addr, len * 2, wb_mask);
- xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n");
- xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n");
- }
- for (index = 0; wb_mask; index += len) {
- /* unknown regs are passed through */
- while (!(wb_mask & 0xff)) {
- index++;
- wb_mask >>= 8;
- }
- len = 0;
- do {
- len++;
- wb_mask >>= 8;
- } while (wb_mask & 0xff);
- rc = xen_host_pci_set_block(&s->real_device, addr + index,
- (uint8_t *)&val + index, len);
-
- if (rc < 0) {
- XEN_PT_ERR(d, "xen_host_pci_set_block failed. return value: %d.\n", rc);
- }
- }
-}
-
-/* register regions */
-
-static uint64_t xen_pt_bar_read(void *o, hwaddr addr,
- unsigned size)
-{
- PCIDevice *d = o;
- /* if this function is called, that probably means that there is a
- * misconfiguration of the IOMMU. */
- XEN_PT_ERR(d, "Should not read BAR through QEMU. @0x"TARGET_FMT_plx"\n",
- addr);
- return 0;
-}
-static void xen_pt_bar_write(void *o, hwaddr addr, uint64_t val,
- unsigned size)
-{
- PCIDevice *d = o;
- /* Same comment as xen_pt_bar_read function */
- XEN_PT_ERR(d, "Should not write BAR through QEMU. @0x"TARGET_FMT_plx"\n",
- addr);
-}
-
-static const MemoryRegionOps ops = {
- .endianness = DEVICE_NATIVE_ENDIAN,
- .read = xen_pt_bar_read,
- .write = xen_pt_bar_write,
-};
-
-static int xen_pt_register_regions(XenPCIPassthroughState *s, uint16_t *cmd)
-{
- int i = 0;
- XenHostPCIDevice *d = &s->real_device;
-
- /* Register PIO/MMIO BARs */
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- XenHostPCIIORegion *r = &d->io_regions[i];
- uint8_t type;
-
- if (r->base_addr == 0 || r->size == 0) {
- continue;
- }
-
- s->bases[i].access.u = r->base_addr;
-
- if (r->type & XEN_HOST_PCI_REGION_TYPE_IO) {
- type = PCI_BASE_ADDRESS_SPACE_IO;
- *cmd |= PCI_COMMAND_IO;
- } else {
- type = PCI_BASE_ADDRESS_SPACE_MEMORY;
- if (r->type & XEN_HOST_PCI_REGION_TYPE_PREFETCH) {
- type |= PCI_BASE_ADDRESS_MEM_PREFETCH;
- }
- if (r->type & XEN_HOST_PCI_REGION_TYPE_MEM_64) {
- type |= PCI_BASE_ADDRESS_MEM_TYPE_64;
- }
- *cmd |= PCI_COMMAND_MEMORY;
- }
-
- memory_region_init_io(&s->bar[i], OBJECT(s), &ops, &s->dev,
- "xen-pci-pt-bar", r->size);
- pci_register_bar(&s->dev, i, type, &s->bar[i]);
-
- XEN_PT_LOG(&s->dev, "IO region %i registered (size=0x%08"PRIx64
- " base_addr=0x%08"PRIx64" type: %#x)\n",
- i, r->size, r->base_addr, type);
- }
-
- /* Register expansion ROM address */
- if (d->rom.base_addr && d->rom.size) {
- uint32_t bar_data = 0;
-
- /* Re-set BAR reported by OS, otherwise ROM can't be read. */
- if (xen_host_pci_get_long(d, PCI_ROM_ADDRESS, &bar_data)) {
- return 0;
- }
- if ((bar_data & PCI_ROM_ADDRESS_MASK) == 0) {
- bar_data |= d->rom.base_addr & PCI_ROM_ADDRESS_MASK;
- xen_host_pci_set_long(d, PCI_ROM_ADDRESS, bar_data);
- }
-
- s->bases[PCI_ROM_SLOT].access.maddr = d->rom.base_addr;
-
- memory_region_init_io(&s->rom, OBJECT(s), &ops, &s->dev,
- "xen-pci-pt-rom", d->rom.size);
- pci_register_bar(&s->dev, PCI_ROM_SLOT, PCI_BASE_ADDRESS_MEM_PREFETCH,
- &s->rom);
-
- XEN_PT_LOG(&s->dev, "Expansion ROM registered (size=0x%08"PRIx64
- " base_addr=0x%08"PRIx64")\n",
- d->rom.size, d->rom.base_addr);
- }
-
- xen_pt_register_vga_regions(d);
- return 0;
-}
-
-/* region mapping */
-
-static int xen_pt_bar_from_region(XenPCIPassthroughState *s, MemoryRegion *mr)
-{
- int i = 0;
-
- for (i = 0; i < PCI_NUM_REGIONS - 1; i++) {
- if (mr == &s->bar[i]) {
- return i;
- }
- }
- if (mr == &s->rom) {
- return PCI_ROM_SLOT;
- }
- return -1;
-}
-
-/*
- * This function checks if an io_region overlaps an io_region from another
- * device. The io_region to check is provided with (addr, size and type)
- * A callback can be provided and will be called for every region that is
- * overlapped.
- * The return value indicates if the region is overlappsed */
-struct CheckBarArgs {
- XenPCIPassthroughState *s;
- pcibus_t addr;
- pcibus_t size;
- uint8_t type;
- bool rc;
-};
-static void xen_pt_check_bar_overlap(PCIBus *bus, PCIDevice *d, void *opaque)
-{
- struct CheckBarArgs *arg = opaque;
- XenPCIPassthroughState *s = arg->s;
- uint8_t type = arg->type;
- int i;
-
- if (d->devfn == s->dev.devfn) {
- return;
- }
-
- /* xxx: This ignores bridges. */
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- const PCIIORegion *r = &d->io_regions[i];
-
- if (!r->size) {
- continue;
- }
- if ((type & PCI_BASE_ADDRESS_SPACE_IO)
- != (r->type & PCI_BASE_ADDRESS_SPACE_IO)) {
- continue;
- }
-
- if (ranges_overlap(arg->addr, arg->size, r->addr, r->size)) {
- XEN_PT_WARN(&s->dev,
- "Overlapped to device [%02x:%02x.%d] Region: %i"
- " (addr: %#"FMT_PCIBUS", len: %#"FMT_PCIBUS")\n",
- pci_bus_num(bus), PCI_SLOT(d->devfn),
- PCI_FUNC(d->devfn), i, r->addr, r->size);
- arg->rc = true;
- }
- }
-}
-
-static void xen_pt_region_update(XenPCIPassthroughState *s,
- MemoryRegionSection *sec, bool adding)
-{
- PCIDevice *d = &s->dev;
- MemoryRegion *mr = sec->mr;
- int bar = -1;
- int rc;
- int op = adding ? DPCI_ADD_MAPPING : DPCI_REMOVE_MAPPING;
- struct CheckBarArgs args = {
- .s = s,
- .addr = sec->offset_within_address_space,
- .size = int128_get64(sec->size),
- .rc = false,
- };
-
- bar = xen_pt_bar_from_region(s, mr);
- if (bar == -1 && (!s->msix || &s->msix->mmio != mr)) {
- return;
- }
-
- if (s->msix && &s->msix->mmio == mr) {
- if (adding) {
- s->msix->mmio_base_addr = sec->offset_within_address_space;
- rc = xen_pt_msix_update_remap(s, s->msix->bar_index);
- }
- return;
- }
-
- args.type = d->io_regions[bar].type;
- pci_for_each_device(d->bus, pci_bus_num(d->bus),
- xen_pt_check_bar_overlap, &args);
- if (args.rc) {
- XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS
- ", len: %#"FMT_PCIBUS") is overlapped.\n",
- bar, sec->offset_within_address_space,
- int128_get64(sec->size));
- }
-
- if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) {
- uint32_t guest_port = sec->offset_within_address_space;
- uint32_t machine_port = s->bases[bar].access.pio_base;
- uint32_t size = int128_get64(sec->size);
- rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
- guest_port, machine_port, size,
- op);
- if (rc) {
- XEN_PT_ERR(d, "%s ioport mapping failed! (err: %i)\n",
- adding ? "create new" : "remove old", errno);
- }
- } else {
- pcibus_t guest_addr = sec->offset_within_address_space;
- pcibus_t machine_addr = s->bases[bar].access.maddr
- + sec->offset_within_region;
- pcibus_t size = int128_get64(sec->size);
- rc = xc_domain_memory_mapping(xen_xc, xen_domid,
- XEN_PFN(guest_addr + XC_PAGE_SIZE - 1),
- XEN_PFN(machine_addr + XC_PAGE_SIZE - 1),
- XEN_PFN(size + XC_PAGE_SIZE - 1),
- op);
- if (rc) {
- XEN_PT_ERR(d, "%s mem mapping failed! (err: %i)\n",
- adding ? "create new" : "remove old", errno);
- }
- }
-}
-
-static void xen_pt_region_add(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- memory_listener);
-
- memory_region_ref(sec->mr);
- xen_pt_region_update(s, sec, true);
-}
-
-static void xen_pt_region_del(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- memory_listener);
-
- xen_pt_region_update(s, sec, false);
- memory_region_unref(sec->mr);
-}
-
-static void xen_pt_io_region_add(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- io_listener);
-
- memory_region_ref(sec->mr);
- xen_pt_region_update(s, sec, true);
-}
-
-static void xen_pt_io_region_del(MemoryListener *l, MemoryRegionSection *sec)
-{
- XenPCIPassthroughState *s = container_of(l, XenPCIPassthroughState,
- io_listener);
-
- xen_pt_region_update(s, sec, false);
- memory_region_unref(sec->mr);
-}
-
-static const MemoryListener xen_pt_memory_listener = {
- .region_add = xen_pt_region_add,
- .region_del = xen_pt_region_del,
- .priority = 10,
-};
-
-static const MemoryListener xen_pt_io_listener = {
- .region_add = xen_pt_io_region_add,
- .region_del = xen_pt_io_region_del,
- .priority = 10,
-};
-
-static void
-xen_igd_passthrough_isa_bridge_create(XenPCIPassthroughState *s,
- XenHostPCIDevice *dev)
-{
- uint16_t gpu_dev_id;
- PCIDevice *d = &s->dev;
-
- gpu_dev_id = dev->device_id;
- igd_passthrough_isa_bridge_create(d->bus, gpu_dev_id);
-}
-
-/* destroy. */
-static void xen_pt_destroy(PCIDevice *d) {
-
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- XenHostPCIDevice *host_dev = &s->real_device;
- uint8_t machine_irq = s->machine_irq;
- uint8_t intx;
- int rc;
-
- if (machine_irq && !xen_host_pci_device_closed(&s->real_device)) {
- intx = xen_pt_pci_intx(s);
- rc = xc_domain_unbind_pt_irq(xen_xc, xen_domid, machine_irq,
- PT_IRQ_TYPE_PCI,
- pci_bus_num(d->bus),
- PCI_SLOT(s->dev.devfn),
- intx,
- 0 /* isa_irq */);
- if (rc < 0) {
- XEN_PT_ERR(d, "unbinding of interrupt INT%c failed."
- " (machine irq: %i, err: %d)"
- " But bravely continuing on..\n",
- 'a' + intx, machine_irq, errno);
- }
- }
-
- /* N.B. xen_pt_config_delete takes care of freeing them. */
- if (s->msi) {
- xen_pt_msi_disable(s);
- }
- if (s->msix) {
- xen_pt_msix_disable(s);
- }
-
- if (machine_irq) {
- xen_pt_mapped_machine_irq[machine_irq]--;
-
- if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
- rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq);
-
- if (rc < 0) {
- XEN_PT_ERR(d, "unmapping of interrupt %i failed. (err: %d)"
- " But bravely continuing on..\n",
- machine_irq, errno);
- }
- }
- s->machine_irq = 0;
- }
-
- /* delete all emulated config registers */
- xen_pt_config_delete(s);
-
- xen_pt_unregister_vga_regions(host_dev);
-
- if (s->listener_set) {
- memory_listener_unregister(&s->memory_listener);
- memory_listener_unregister(&s->io_listener);
- s->listener_set = false;
- }
- if (!xen_host_pci_device_closed(&s->real_device)) {
- xen_host_pci_device_put(&s->real_device);
- }
-}
-/* init */
-
-static void xen_pt_realize(PCIDevice *d, Error **errp)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
- int i, rc = 0;
- uint8_t machine_irq = 0, scratch;
- uint16_t cmd = 0;
- int pirq = XEN_PT_UNASSIGNED_PIRQ;
- Error *err = NULL;
-
- /* register real device */
- XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
- " to devfn %#x\n",
- s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function,
- s->dev.devfn);
-
- xen_host_pci_device_get(&s->real_device,
- s->hostaddr.domain, s->hostaddr.bus,
- s->hostaddr.slot, s->hostaddr.function,
- &err);
- if (err) {
- error_append_hint(&err, "Failed to \"open\" the real pci device");
- error_propagate(errp, err);
- return;
- }
-
- s->is_virtfn = s->real_device.is_virtfn;
- if (s->is_virtfn) {
- XEN_PT_LOG(d, "%04x:%02x:%02x.%d is a SR-IOV Virtual Function\n",
- s->real_device.domain, s->real_device.bus,
- s->real_device.dev, s->real_device.func);
- }
-
- /* Initialize virtualized PCI configuration (Extended 256 Bytes) */
- memset(d->config, 0, PCI_CONFIG_SPACE_SIZE);
-
- s->memory_listener = xen_pt_memory_listener;
- s->io_listener = xen_pt_io_listener;
-
- /* Setup VGA bios for passthrough GFX */
- if ((s->real_device.domain == 0) && (s->real_device.bus == 0) &&
- (s->real_device.dev == 2) && (s->real_device.func == 0)) {
- if (!is_igd_vga_passthrough(&s->real_device)) {
- error_setg(errp, "Need to enable igd-passthru if you're trying"
- " to passthrough IGD GFX");
- xen_host_pci_device_put(&s->real_device);
- return;
- }
-
- xen_pt_setup_vga(s, &s->real_device, &err);
- if (err) {
- error_append_hint(&err, "Setup VGA BIOS of passthrough"
- " GFX failed");
- error_propagate(errp, err);
- xen_host_pci_device_put(&s->real_device);
- return;
- }
-
- /* Register ISA bridge for passthrough GFX. */
- xen_igd_passthrough_isa_bridge_create(s, &s->real_device);
- }
-
- /* Handle real device's MMIO/PIO BARs */
- xen_pt_register_regions(s, &cmd);
-
- /* reinitialize each config register to be emulated */
- xen_pt_config_init(s, &err);
- if (err) {
- error_append_hint(&err, "PCI Config space initialisation failed");
- error_report_err(err);
- rc = -1;
- goto err_out;
- }
-
- /* Bind interrupt */
- rc = xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &scratch);
- if (rc) {
- error_setg_errno(errp, errno, "Failed to read PCI_INTERRUPT_PIN");
- goto err_out;
- }
- if (!scratch) {
- error_setg(errp, "no pin interrupt");
- goto out;
- }
-
- machine_irq = s->real_device.irq;
- rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
- if (rc < 0) {
- error_setg_errno(errp, errno, "Mapping machine irq %u to"
- " pirq %i failed", machine_irq, pirq);
-
- /* Disable PCI intx assertion (turn on bit10 of devctl) */
- cmd |= PCI_COMMAND_INTX_DISABLE;
- machine_irq = 0;
- s->machine_irq = 0;
- } else {
- machine_irq = pirq;
- s->machine_irq = pirq;
- xen_pt_mapped_machine_irq[machine_irq]++;
- }
-
- /* bind machine_irq to device */
- if (machine_irq != 0) {
- uint8_t e_intx = xen_pt_pci_intx(s);
-
- rc = xc_domain_bind_pt_pci_irq(xen_xc, xen_domid, machine_irq,
- pci_bus_num(d->bus),
- PCI_SLOT(d->devfn),
- e_intx);
- if (rc < 0) {
- error_setg_errno(errp, errno, "Binding of interrupt %u failed",
- e_intx);
-
- /* Disable PCI intx assertion (turn on bit10 of devctl) */
- cmd |= PCI_COMMAND_INTX_DISABLE;
- xen_pt_mapped_machine_irq[machine_irq]--;
-
- if (xen_pt_mapped_machine_irq[machine_irq] == 0) {
- if (xc_physdev_unmap_pirq(xen_xc, xen_domid, machine_irq)) {
- error_setg_errno(errp, errno, "Unmapping of machine"
- " interrupt %u failed", machine_irq);
- }
- }
- s->machine_irq = 0;
- }
- }
-
-out:
- if (cmd) {
- uint16_t val;
-
- rc = xen_host_pci_get_word(&s->real_device, PCI_COMMAND, &val);
- if (rc) {
- error_setg_errno(errp, errno, "Failed to read PCI_COMMAND");
- goto err_out;
- } else {
- val |= cmd;
- rc = xen_host_pci_set_word(&s->real_device, PCI_COMMAND, val);
- if (rc) {
- error_setg_errno(errp, errno, "Failed to write PCI_COMMAND"
- " val = 0x%x", val);
- goto err_out;
- }
- }
- }
-
- memory_listener_register(&s->memory_listener, &s->dev.bus_master_as);
- memory_listener_register(&s->io_listener, &address_space_io);
- s->listener_set = true;
- XEN_PT_LOG(d,
- "Real physical device %02x:%02x.%d registered successfully\n",
- s->hostaddr.bus, s->hostaddr.slot, s->hostaddr.function);
-
- return;
-
-err_out:
- for (i = 0; i < PCI_ROM_SLOT; i++) {
- object_unparent(OBJECT(&s->bar[i]));
- }
- object_unparent(OBJECT(&s->rom));
-
- xen_pt_destroy(d);
- assert(rc);
-}
-
-static void xen_pt_unregister_device(PCIDevice *d)
-{
- xen_pt_destroy(d);
-}
-
-static Property xen_pci_passthrough_properties[] = {
- DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr),
- DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->realize = xen_pt_realize;
- k->exit = xen_pt_unregister_device;
- k->config_read = xen_pt_pci_read_config;
- k->config_write = xen_pt_pci_write_config;
- set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- dc->desc = "Assign an host PCI device with Xen";
- dc->props = xen_pci_passthrough_properties;
-};
-
-static void xen_pci_passthrough_finalize(Object *obj)
-{
- XenPCIPassthroughState *s = XEN_PT_DEVICE(obj);
-
- xen_pt_msix_delete(s);
-}
-
-static const TypeInfo xen_pci_passthrough_info = {
- .name = TYPE_XEN_PT_DEVICE,
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(XenPCIPassthroughState),
- .instance_finalize = xen_pci_passthrough_finalize,
- .class_init = xen_pci_passthrough_class_init,
-};
-
-static void xen_pci_passthrough_register_types(void)
-{
- type_register_static(&xen_pci_passthrough_info);
-}
-
-type_init(xen_pci_passthrough_register_types)
diff --git a/qemu/hw/xen/xen_pt.h b/qemu/hw/xen/xen_pt.h
deleted file mode 100644
index c2f8e1fc2..000000000
--- a/qemu/hw/xen/xen_pt.h
+++ /dev/null
@@ -1,335 +0,0 @@
-#ifndef XEN_PT_H
-#define XEN_PT_H
-
-#include "qemu-common.h"
-#include "hw/xen/xen_common.h"
-#include "hw/pci/pci.h"
-#include "xen-host-pci-device.h"
-
-void xen_pt_log(const PCIDevice *d, const char *f, ...) GCC_FMT_ATTR(2, 3);
-
-#define XEN_PT_ERR(d, _f, _a...) xen_pt_log(d, "%s: Error: "_f, __func__, ##_a)
-
-#ifdef XEN_PT_LOGGING_ENABLED
-# define XEN_PT_LOG(d, _f, _a...) xen_pt_log(d, "%s: " _f, __func__, ##_a)
-# define XEN_PT_WARN(d, _f, _a...) \
- xen_pt_log(d, "%s: Warning: "_f, __func__, ##_a)
-#else
-# define XEN_PT_LOG(d, _f, _a...)
-# define XEN_PT_WARN(d, _f, _a...)
-#endif
-
-#ifdef XEN_PT_DEBUG_PCI_CONFIG_ACCESS
-# define XEN_PT_LOG_CONFIG(d, addr, val, len) \
- xen_pt_log(d, "%s: address=0x%04x val=0x%08x len=%d\n", \
- __func__, addr, val, len)
-#else
-# define XEN_PT_LOG_CONFIG(d, addr, val, len)
-#endif
-
-
-/* Helper */
-#define XEN_PFN(x) ((x) >> XC_PAGE_SHIFT)
-
-typedef const struct XenPTRegInfo XenPTRegInfo;
-typedef struct XenPTReg XenPTReg;
-
-typedef struct XenPCIPassthroughState XenPCIPassthroughState;
-
-#define TYPE_XEN_PT_DEVICE "xen-pci-passthrough"
-#define XEN_PT_DEVICE(obj) \
- OBJECT_CHECK(XenPCIPassthroughState, (obj), TYPE_XEN_PT_DEVICE)
-
-uint32_t igd_read_opregion(XenPCIPassthroughState *s);
-void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val);
-
-/* function type for config reg */
-typedef int (*xen_pt_conf_reg_init)
- (XenPCIPassthroughState *, XenPTRegInfo *, uint32_t real_offset,
- uint32_t *data);
-typedef int (*xen_pt_conf_dword_write)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value, uint32_t valid_mask);
-typedef int (*xen_pt_conf_word_write)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value, uint16_t valid_mask);
-typedef int (*xen_pt_conf_byte_write)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t dev_value, uint8_t valid_mask);
-typedef int (*xen_pt_conf_dword_read)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t valid_mask);
-typedef int (*xen_pt_conf_word_read)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t valid_mask);
-typedef int (*xen_pt_conf_byte_read)
- (XenPCIPassthroughState *, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t valid_mask);
-
-#define XEN_PT_BAR_ALLF 0xFFFFFFFF
-#define XEN_PT_BAR_UNMAPPED (-1)
-
-#define XEN_PCI_CAP_MAX 48
-
-#define XEN_PCI_INTEL_OPREGION 0xfc
-
-typedef enum {
- XEN_PT_GRP_TYPE_HARDWIRED = 0, /* 0 Hardwired reg group */
- XEN_PT_GRP_TYPE_EMU, /* emul reg group */
-} XenPTRegisterGroupType;
-
-typedef enum {
- XEN_PT_BAR_FLAG_MEM = 0, /* Memory type BAR */
- XEN_PT_BAR_FLAG_IO, /* I/O type BAR */
- XEN_PT_BAR_FLAG_UPPER, /* upper 64bit BAR */
- XEN_PT_BAR_FLAG_UNUSED, /* unused BAR */
-} XenPTBarFlag;
-
-
-typedef struct XenPTRegion {
- /* BAR flag */
- XenPTBarFlag bar_flag;
- /* Translation of the emulated address */
- union {
- uint64_t maddr;
- uint64_t pio_base;
- uint64_t u;
- } access;
-} XenPTRegion;
-
-/* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- * other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
-
-/* emulated register information */
-struct XenPTRegInfo {
- uint32_t offset;
- uint32_t size;
- uint32_t init_val;
- /* reg reserved field mask (ON:reserved, OFF:defined) */
- uint32_t res_mask;
- /* reg read only field mask (ON:RO/ROS, OFF:other) */
- uint32_t ro_mask;
- /* reg read/write-1-clear field mask (ON:RW1C/RW1CS, OFF:other) */
- uint32_t rw1c_mask;
- /* reg emulate field mask (ON:emu, OFF:passthrough) */
- uint32_t emu_mask;
- xen_pt_conf_reg_init init;
- /* read/write function pointer
- * for double_word/word/byte size */
- union {
- struct {
- xen_pt_conf_dword_write write;
- xen_pt_conf_dword_read read;
- } dw;
- struct {
- xen_pt_conf_word_write write;
- xen_pt_conf_word_read read;
- } w;
- struct {
- xen_pt_conf_byte_write write;
- xen_pt_conf_byte_read read;
- } b;
- } u;
-};
-
-/* emulated register management */
-struct XenPTReg {
- QLIST_ENTRY(XenPTReg) entries;
- XenPTRegInfo *reg;
- union {
- uint8_t *byte;
- uint16_t *half_word;
- uint32_t *word;
- } ptr; /* pointer to dev.config. */
-};
-
-typedef const struct XenPTRegGroupInfo XenPTRegGroupInfo;
-
-/* emul reg group size initialize method */
-typedef int (*xen_pt_reg_size_init_fn)
- (XenPCIPassthroughState *, XenPTRegGroupInfo *,
- uint32_t base_offset, uint8_t *size);
-
-/* emulated register group information */
-struct XenPTRegGroupInfo {
- uint8_t grp_id;
- XenPTRegisterGroupType grp_type;
- uint8_t grp_size;
- xen_pt_reg_size_init_fn size_init;
- XenPTRegInfo *emu_regs;
-};
-
-/* emul register group management table */
-typedef struct XenPTRegGroup {
- QLIST_ENTRY(XenPTRegGroup) entries;
- XenPTRegGroupInfo *reg_grp;
- uint32_t base_offset;
- uint8_t size;
- QLIST_HEAD(, XenPTReg) reg_tbl_list;
-} XenPTRegGroup;
-
-
-#define XEN_PT_UNASSIGNED_PIRQ (-1)
-typedef struct XenPTMSI {
- uint16_t flags;
- uint32_t addr_lo; /* guest message address */
- uint32_t addr_hi; /* guest message upper address */
- uint16_t data; /* guest message data */
- uint32_t ctrl_offset; /* saved control offset */
- int pirq; /* guest pirq corresponding */
- bool initialized; /* when guest MSI is initialized */
- bool mapped; /* when pirq is mapped */
-} XenPTMSI;
-
-typedef struct XenPTMSIXEntry {
- int pirq;
- uint64_t addr;
- uint32_t data;
- uint32_t latch[4];
- bool updated; /* indicate whether MSI ADDR or DATA is updated */
-} XenPTMSIXEntry;
-typedef struct XenPTMSIX {
- uint32_t ctrl_offset;
- bool enabled;
- bool maskall;
- int total_entries;
- int bar_index;
- uint64_t table_base;
- uint32_t table_offset_adjust; /* page align mmap */
- uint64_t mmio_base_addr;
- MemoryRegion mmio;
- void *phys_iomem_base;
- XenPTMSIXEntry msix_entry[0];
-} XenPTMSIX;
-
-struct XenPCIPassthroughState {
- PCIDevice dev;
-
- PCIHostDeviceAddress hostaddr;
- bool is_virtfn;
- bool permissive;
- bool permissive_warned;
- XenHostPCIDevice real_device;
- XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
- QLIST_HEAD(, XenPTRegGroup) reg_grps;
-
- uint32_t machine_irq;
-
- XenPTMSI *msi;
- XenPTMSIX *msix;
-
- MemoryRegion bar[PCI_NUM_REGIONS - 1];
- MemoryRegion rom;
-
- MemoryListener memory_listener;
- MemoryListener io_listener;
- bool listener_set;
-};
-
-void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp);
-void xen_pt_config_delete(XenPCIPassthroughState *s);
-XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address);
-XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address);
-int xen_pt_bar_offset_to_index(uint32_t offset);
-
-static inline pcibus_t xen_pt_get_emul_size(XenPTBarFlag flag, pcibus_t r_size)
-{
- /* align resource size (memory type only) */
- if (flag == XEN_PT_BAR_FLAG_MEM) {
- return (r_size + XC_PAGE_SIZE - 1) & XC_PAGE_MASK;
- } else {
- return r_size;
- }
-}
-
-/* INTx */
-/* The PCI Local Bus Specification, Rev. 3.0,
- * Section 6.2.4 Miscellaneous Registers, pp 223
- * outlines 5 valid values for the interrupt pin (intx).
- * 0: For devices (or device functions) that don't use an interrupt in
- * 1: INTA#
- * 2: INTB#
- * 3: INTC#
- * 4: INTD#
- *
- * Xen uses the following 4 values for intx
- * 0: INTA#
- * 1: INTB#
- * 2: INTC#
- * 3: INTD#
- *
- * Observing that these list of values are not the same, xen_pt_pci_read_intx()
- * uses the following mapping from hw to xen values.
- * This seems to reflect the current usage within Xen.
- *
- * PCI hardware | Xen | Notes
- * ----------------+-----+----------------------------------------------------
- * 0 | 0 | No interrupt
- * 1 | 0 | INTA#
- * 2 | 1 | INTB#
- * 3 | 2 | INTC#
- * 4 | 3 | INTD#
- * any other value | 0 | This should never happen, log error message
- */
-
-static inline uint8_t xen_pt_pci_read_intx(XenPCIPassthroughState *s)
-{
- uint8_t v = 0;
- xen_host_pci_get_byte(&s->real_device, PCI_INTERRUPT_PIN, &v);
- return v;
-}
-
-static inline uint8_t xen_pt_pci_intx(XenPCIPassthroughState *s)
-{
- uint8_t r_val = xen_pt_pci_read_intx(s);
-
- XEN_PT_LOG(&s->dev, "intx=%i\n", r_val);
- if (r_val < 1 || r_val > 4) {
- XEN_PT_LOG(&s->dev, "Interrupt pin read from hardware is out of range:"
- " value=%i, acceptable range is 1 - 4\n", r_val);
- r_val = 0;
- } else {
- /* Note that if s.real_device.config_fd is closed we make 0xff. */
- r_val -= 1;
- }
-
- return r_val;
-}
-
-/* MSI/MSI-X */
-int xen_pt_msi_setup(XenPCIPassthroughState *s);
-int xen_pt_msi_update(XenPCIPassthroughState *d);
-void xen_pt_msi_disable(XenPCIPassthroughState *s);
-
-int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base);
-void xen_pt_msix_delete(XenPCIPassthroughState *s);
-void xen_pt_msix_unmap(XenPCIPassthroughState *s);
-int xen_pt_msix_update(XenPCIPassthroughState *s);
-int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index);
-void xen_pt_msix_disable(XenPCIPassthroughState *s);
-
-static inline bool xen_pt_has_msix_mapping(XenPCIPassthroughState *s, int bar)
-{
- return s->msix && s->msix->bar_index == bar;
-}
-
-extern void *pci_assign_dev_load_option_rom(PCIDevice *dev,
- struct Object *owner, int *size,
- unsigned int domain,
- unsigned int bus, unsigned int slot,
- unsigned int function);
-extern bool has_igd_gfx_passthru;
-static inline bool is_igd_vga_passthrough(XenHostPCIDevice *dev)
-{
- return (has_igd_gfx_passthru
- && ((dev->class_code >> 0x8) == PCI_CLASS_DISPLAY_VGA));
-}
-int xen_pt_register_vga_regions(XenHostPCIDevice *dev);
-int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev);
-void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
- Error **errp);
-#endif /* !XEN_PT_H */
diff --git a/qemu/hw/xen/xen_pt_config_init.c b/qemu/hw/xen/xen_pt_config_init.c
deleted file mode 100644
index 9869ffda0..000000000
--- a/qemu/hw/xen/xen_pt_config_init.c
+++ /dev/null
@@ -1,2090 +0,0 @@
-/*
- * Copyright (c) 2007, Neocleus Corporation.
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Alex Novik <alex@neocleus.com>
- * Allen Kay <allen.m.kay@intel.com>
- * Guy Zana <guy@neocleus.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "qemu/timer.h"
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
-
-#define XEN_PT_MERGE_VALUE(value, data, val_mask) \
- (((value) & (val_mask)) | ((data) & ~(val_mask)))
-
-#define XEN_PT_INVALID_REG 0xFFFFFFFF /* invalid register value */
-
-/* prototype */
-
-static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
- uint32_t real_offset, uint32_t *data);
-
-
-/* helper */
-
-/* A return value of 1 means the capability should NOT be exposed to guest. */
-static int xen_pt_hide_dev_cap(const XenHostPCIDevice *d, uint8_t grp_id)
-{
- switch (grp_id) {
- case PCI_CAP_ID_EXP:
- /* The PCI Express Capability Structure of the VF of Intel 82599 10GbE
- * Controller looks trivial, e.g., the PCI Express Capabilities
- * Register is 0. We should not try to expose it to guest.
- *
- * The datasheet is available at
- * http://download.intel.com/design/network/datashts/82599_datasheet.pdf
- *
- * See 'Table 9.7. VF PCIe Configuration Space' of the datasheet, the
- * PCI Express Capability Structure of the VF of Intel 82599 10GbE
- * Controller looks trivial, e.g., the PCI Express Capabilities
- * Register is 0, so the Capability Version is 0 and
- * xen_pt_pcie_size_init() would fail.
- */
- if (d->vendor_id == PCI_VENDOR_ID_INTEL &&
- d->device_id == PCI_DEVICE_ID_INTEL_82599_SFP_VF) {
- return 1;
- }
- break;
- }
- return 0;
-}
-
-/* find emulate register group entry */
-XenPTRegGroup *xen_pt_find_reg_grp(XenPCIPassthroughState *s, uint32_t address)
-{
- XenPTRegGroup *entry = NULL;
-
- /* find register group entry */
- QLIST_FOREACH(entry, &s->reg_grps, entries) {
- /* check address */
- if ((entry->base_offset <= address)
- && ((entry->base_offset + entry->size) > address)) {
- return entry;
- }
- }
-
- /* group entry not found */
- return NULL;
-}
-
-/* find emulate register entry */
-XenPTReg *xen_pt_find_reg(XenPTRegGroup *reg_grp, uint32_t address)
-{
- XenPTReg *reg_entry = NULL;
- XenPTRegInfo *reg = NULL;
- uint32_t real_offset = 0;
-
- /* find register entry */
- QLIST_FOREACH(reg_entry, &reg_grp->reg_tbl_list, entries) {
- reg = reg_entry->reg;
- real_offset = reg_grp->base_offset + reg->offset;
- /* check address */
- if ((real_offset <= address)
- && ((real_offset + reg->size) > address)) {
- return reg_entry;
- }
- }
-
- return NULL;
-}
-
-static uint32_t get_throughable_mask(const XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t valid_mask)
-{
- uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
-
- if (!s->permissive) {
- throughable_mask &= ~reg->res_mask;
- }
-
- return throughable_mask & valid_mask;
-}
-
-/****************
- * general register functions
- */
-
-/* register initialization function */
-
-static int xen_pt_common_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = reg->init_val;
- return 0;
-}
-
-/* Read register functions */
-
-static int xen_pt_byte_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint8_t *value, uint8_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint8_t valid_emu_mask = 0;
- uint8_t *data = cfg_entry->ptr.byte;
-
- /* emulate byte register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
-
- return 0;
-}
-static int xen_pt_word_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t valid_emu_mask = 0;
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* emulate word register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
-
- return 0;
-}
-static int xen_pt_long_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t valid_emu_mask = 0;
- uint32_t *data = cfg_entry->ptr.word;
-
- /* emulate long register */
- valid_emu_mask = reg->emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *data, ~valid_emu_mask);
-
- return 0;
-}
-
-/* Write register functions */
-
-static int xen_pt_byte_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint8_t *val, uint8_t dev_value,
- uint8_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint8_t writable_mask = 0;
- uint8_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint8_t *data = cfg_entry->ptr.byte;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
-
- return 0;
-}
-static int xen_pt_word_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value,
- uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
-
- return 0;
-}
-static int xen_pt_long_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint32_t *data = cfg_entry->ptr.word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value & ~reg->rw1c_mask,
- throughable_mask);
-
- return 0;
-}
-
-
-/* XenPTRegInfo declaration
- * - only for emulated register (either a part or whole bit).
- * - for passthrough register that need special behavior (like interacting with
- * other component), set emu_mask to all 0 and specify r/w func properly.
- * - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
- */
-
-/********************
- * Header Type0
- */
-
-static int xen_pt_vendor_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = s->real_device.vendor_id;
- return 0;
-}
-static int xen_pt_device_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = s->real_device.device_id;
- return 0;
-}
-static int xen_pt_status_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- XenPTRegGroup *reg_grp_entry = NULL;
- XenPTReg *reg_entry = NULL;
- uint32_t reg_field = 0;
-
- /* find Header register group */
- reg_grp_entry = xen_pt_find_reg_grp(s, PCI_CAPABILITY_LIST);
- if (reg_grp_entry) {
- /* find Capabilities Pointer register */
- reg_entry = xen_pt_find_reg(reg_grp_entry, PCI_CAPABILITY_LIST);
- if (reg_entry) {
- /* check Capabilities Pointer register */
- if (*reg_entry->ptr.half_word) {
- reg_field |= PCI_STATUS_CAP_LIST;
- } else {
- reg_field &= ~PCI_STATUS_CAP_LIST;
- }
- } else {
- xen_shutdown_fatal_error("Internal error: Couldn't find XenPTReg*"
- " for Capabilities Pointer register."
- " (%s)\n", __func__);
- return -1;
- }
- } else {
- xen_shutdown_fatal_error("Internal error: Couldn't find XenPTRegGroup"
- " for Header. (%s)\n", __func__);
- return -1;
- }
-
- *data = reg_field;
- return 0;
-}
-static int xen_pt_header_type_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- /* read PCI_HEADER_TYPE */
- *data = reg->init_val | 0x80;
- return 0;
-}
-
-/* initialize Interrupt Pin register */
-static int xen_pt_irqpin_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- *data = xen_pt_pci_read_intx(s);
- return 0;
-}
-
-/* Command register */
-static int xen_pt_cmd_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint16_t *val, uint16_t dev_value,
- uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* modify emulate register */
- writable_mask = ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- if (*val & PCI_COMMAND_INTX_DISABLE) {
- throughable_mask |= PCI_COMMAND_INTX_DISABLE;
- } else {
- if (s->machine_irq) {
- throughable_mask |= PCI_COMMAND_INTX_DISABLE;
- }
- }
-
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- return 0;
-}
-
-/* BAR */
-#define XEN_PT_BAR_MEM_RO_MASK 0x0000000F /* BAR ReadOnly mask(Memory) */
-#define XEN_PT_BAR_MEM_EMU_MASK 0xFFFFFFF0 /* BAR emul mask(Memory) */
-#define XEN_PT_BAR_IO_RO_MASK 0x00000003 /* BAR ReadOnly mask(I/O) */
-#define XEN_PT_BAR_IO_EMU_MASK 0xFFFFFFFC /* BAR emul mask(I/O) */
-
-static bool is_64bit_bar(PCIIORegion *r)
-{
- return !!(r->type & PCI_BASE_ADDRESS_MEM_TYPE_64);
-}
-
-static uint64_t xen_pt_get_bar_size(PCIIORegion *r)
-{
- if (is_64bit_bar(r)) {
- uint64_t size64;
- size64 = (r + 1)->size;
- size64 <<= 32;
- size64 += r->size;
- return size64;
- }
- return r->size;
-}
-
-static XenPTBarFlag xen_pt_bar_reg_parse(XenPCIPassthroughState *s,
- int index)
-{
- PCIDevice *d = &s->dev;
- XenPTRegion *region = NULL;
- PCIIORegion *r;
-
- /* check 64bit BAR */
- if ((0 < index) && (index < PCI_ROM_SLOT)) {
- int type = s->real_device.io_regions[index - 1].type;
-
- if ((type & XEN_HOST_PCI_REGION_TYPE_MEM)
- && (type & XEN_HOST_PCI_REGION_TYPE_MEM_64)) {
- region = &s->bases[index - 1];
- if (region->bar_flag != XEN_PT_BAR_FLAG_UPPER) {
- return XEN_PT_BAR_FLAG_UPPER;
- }
- }
- }
-
- /* check unused BAR */
- r = &d->io_regions[index];
- if (!xen_pt_get_bar_size(r)) {
- return XEN_PT_BAR_FLAG_UNUSED;
- }
-
- /* for ExpROM BAR */
- if (index == PCI_ROM_SLOT) {
- return XEN_PT_BAR_FLAG_MEM;
- }
-
- /* check BAR I/O indicator */
- if (s->real_device.io_regions[index].type & XEN_HOST_PCI_REGION_TYPE_IO) {
- return XEN_PT_BAR_FLAG_IO;
- } else {
- return XEN_PT_BAR_FLAG_MEM;
- }
-}
-
-static inline uint32_t base_address_with_flags(XenHostPCIIORegion *hr)
-{
- if (hr->type & XEN_HOST_PCI_REGION_TYPE_IO) {
- return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_IO_MASK);
- } else {
- return hr->base_addr | (hr->bus_flags & ~PCI_BASE_ADDRESS_MEM_MASK);
- }
-}
-
-static int xen_pt_bar_reg_init(XenPCIPassthroughState *s, XenPTRegInfo *reg,
- uint32_t real_offset, uint32_t *data)
-{
- uint32_t reg_field = 0;
- int index;
-
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
-
- /* set BAR flag */
- s->bases[index].bar_flag = xen_pt_bar_reg_parse(s, index);
- if (s->bases[index].bar_flag == XEN_PT_BAR_FLAG_UNUSED) {
- reg_field = XEN_PT_INVALID_REG;
- }
-
- *data = reg_field;
- return 0;
-}
-static int xen_pt_bar_reg_read(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t valid_emu_mask = 0;
- uint32_t bar_emu_mask = 0;
- int index;
-
- /* get BAR index */
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS - 1) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
-
- /* use fixed-up value from kernel sysfs */
- *value = base_address_with_flags(&s->real_device.io_regions[index]);
-
- /* set emulate mask depend on BAR flag */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_MEM:
- bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
- break;
- case XEN_PT_BAR_FLAG_IO:
- bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
- break;
- case XEN_PT_BAR_FLAG_UPPER:
- bar_emu_mask = XEN_PT_BAR_ALLF;
- break;
- default:
- break;
- }
-
- /* emulate BAR */
- valid_emu_mask = bar_emu_mask & valid_mask;
- *value = XEN_PT_MERGE_VALUE(*value, *cfg_entry->ptr.word, ~valid_emu_mask);
-
- return 0;
-}
-static int xen_pt_bar_reg_write(XenPCIPassthroughState *s, XenPTReg *cfg_entry,
- uint32_t *val, uint32_t dev_value,
- uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTRegion *base = NULL;
- PCIDevice *d = &s->dev;
- const PCIIORegion *r;
- uint32_t writable_mask = 0;
- uint32_t bar_emu_mask = 0;
- uint32_t bar_ro_mask = 0;
- uint32_t r_size = 0;
- int index = 0;
- uint32_t *data = cfg_entry->ptr.word;
-
- index = xen_pt_bar_offset_to_index(reg->offset);
- if (index < 0 || index >= PCI_NUM_REGIONS) {
- XEN_PT_ERR(d, "Internal error: Invalid BAR index [%d].\n", index);
- return -1;
- }
-
- r = &d->io_regions[index];
- base = &s->bases[index];
- r_size = xen_pt_get_emul_size(base->bar_flag, r->size);
-
- /* set emulate mask and read-only mask values depend on the BAR flag */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_MEM:
- bar_emu_mask = XEN_PT_BAR_MEM_EMU_MASK;
- if (!r_size) {
- /* low 32 bits mask for 64 bit bars */
- bar_ro_mask = XEN_PT_BAR_ALLF;
- } else {
- bar_ro_mask = XEN_PT_BAR_MEM_RO_MASK | (r_size - 1);
- }
- break;
- case XEN_PT_BAR_FLAG_IO:
- bar_emu_mask = XEN_PT_BAR_IO_EMU_MASK;
- bar_ro_mask = XEN_PT_BAR_IO_RO_MASK | (r_size - 1);
- break;
- case XEN_PT_BAR_FLAG_UPPER:
- bar_emu_mask = XEN_PT_BAR_ALLF;
- bar_ro_mask = r_size ? r_size - 1 : 0;
- break;
- default:
- break;
- }
-
- /* modify emulate register */
- writable_mask = bar_emu_mask & ~bar_ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* check whether we need to update the virtual region address or not */
- switch (s->bases[index].bar_flag) {
- case XEN_PT_BAR_FLAG_UPPER:
- case XEN_PT_BAR_FLAG_MEM:
- /* nothing to do */
- break;
- case XEN_PT_BAR_FLAG_IO:
- /* nothing to do */
- break;
- default:
- break;
- }
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- return 0;
-}
-
-/* write Exp ROM BAR */
-static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTRegion *base = NULL;
- PCIDevice *d = (PCIDevice *)&s->dev;
- uint32_t writable_mask = 0;
- uint32_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- pcibus_t r_size = 0;
- uint32_t bar_ro_mask = 0;
- uint32_t *data = cfg_entry->ptr.word;
-
- r_size = d->io_regions[PCI_ROM_SLOT].size;
- base = &s->bases[PCI_ROM_SLOT];
- /* align memory type resource size */
- r_size = xen_pt_get_emul_size(base->bar_flag, r_size);
-
- /* set emulate mask and read-only mask */
- bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
-
- /* modify emulate register */
- writable_mask = ~bar_ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- return 0;
-}
-
-static int xen_pt_intel_opregion_read(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry,
- uint32_t *value, uint32_t valid_mask)
-{
- *value = igd_read_opregion(s);
- return 0;
-}
-
-static int xen_pt_intel_opregion_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *value,
- uint32_t dev_value, uint32_t valid_mask)
-{
- igd_write_opregion(s, *value);
- return 0;
-}
-
-/* Header Type0 reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_header0[] = {
- /* Vendor ID reg */
- {
- .offset = PCI_VENDOR_ID,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xFFFF,
- .init = xen_pt_vendor_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device ID reg */
- {
- .offset = PCI_DEVICE_ID,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xFFFF,
- .init = xen_pt_device_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Command reg */
- {
- .offset = PCI_COMMAND,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0xF880,
- .emu_mask = 0x0743,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_cmd_reg_write,
- },
- /* Capabilities Pointer reg */
- {
- .offset = PCI_CAPABILITY_LIST,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Status reg */
- /* use emulated Cap Ptr value to initialize,
- * so need to be declared after Cap Ptr reg
- */
- {
- .offset = PCI_STATUS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0x0007,
- .ro_mask = 0x06F8,
- .rw1c_mask = 0xF900,
- .emu_mask = 0x0010,
- .init = xen_pt_status_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Cache Line Size reg */
- {
- .offset = PCI_CACHE_LINE_SIZE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Latency Timer reg */
- {
- .offset = PCI_LATENCY_TIMER,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Header Type reg */
- {
- .offset = PCI_HEADER_TYPE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0x00,
- .init = xen_pt_header_type_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Interrupt Line reg */
- {
- .offset = PCI_INTERRUPT_LINE,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0x00,
- .emu_mask = 0xFF,
- .init = xen_pt_common_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Interrupt Pin reg */
- {
- .offset = PCI_INTERRUPT_PIN,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_irqpin_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* BAR 0 reg */
- /* mask of BAR need to be decided later, depends on IO/MEM type */
- {
- .offset = PCI_BASE_ADDRESS_0,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 1 reg */
- {
- .offset = PCI_BASE_ADDRESS_1,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 2 reg */
- {
- .offset = PCI_BASE_ADDRESS_2,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 3 reg */
- {
- .offset = PCI_BASE_ADDRESS_3,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 4 reg */
- {
- .offset = PCI_BASE_ADDRESS_4,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* BAR 5 reg */
- {
- .offset = PCI_BASE_ADDRESS_5,
- .size = 4,
- .init_val = 0x00000000,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_bar_reg_read,
- .u.dw.write = xen_pt_bar_reg_write,
- },
- /* Expansion ROM BAR reg */
- {
- .offset = PCI_ROM_ADDRESS,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = ~PCI_ROM_ADDRESS_MASK & ~PCI_ROM_ADDRESS_ENABLE,
- .emu_mask = (uint32_t)PCI_ROM_ADDRESS_MASK,
- .init = xen_pt_bar_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_exp_rom_bar_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/*********************************
- * Vital Product Data Capability
- */
-
-/* Vital Product Data Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- {
- .offset = PCI_VPD_ADDR,
- .size = 2,
- .ro_mask = 0x0003,
- .emu_mask = 0x0003,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/**************************************
- * Vendor Specific Capability
- */
-
-/* Vendor Specific Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/*****************************
- * PCI Express Capability
- */
-
-static inline uint8_t get_capability_version(XenPCIPassthroughState *s,
- uint32_t offset)
-{
- uint8_t flag;
- if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
- return 0;
- }
- return flag & PCI_EXP_FLAGS_VERS;
-}
-
-static inline uint8_t get_device_type(XenPCIPassthroughState *s,
- uint32_t offset)
-{
- uint8_t flag;
- if (xen_host_pci_get_byte(&s->real_device, offset + PCI_EXP_FLAGS, &flag)) {
- return 0;
- }
- return (flag & PCI_EXP_FLAGS_TYPE) >> 4;
-}
-
-/* initialize Link Control register */
-static int xen_pt_linkctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- uint8_t dev_type = get_device_type(s, real_offset - reg->offset);
-
- /* no need to initialize in case of Root Complex Integrated Endpoint
- * with cap_ver 1.x
- */
- if ((dev_type == PCI_EXP_TYPE_RC_END) && (cap_ver == 1)) {
- *data = XEN_PT_INVALID_REG;
- }
-
- *data = reg->init_val;
- return 0;
-}
-/* initialize Device Control 2 register */
-static int xen_pt_devctrl2_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
-
- /* no need to initialize in case of cap_ver 1.x */
- if (cap_ver == 1) {
- *data = XEN_PT_INVALID_REG;
- }
-
- *data = reg->init_val;
- return 0;
-}
-/* initialize Link Control 2 register */
-static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint8_t cap_ver = get_capability_version(s, real_offset - reg->offset);
- uint32_t reg_field = 0;
-
- /* no need to initialize in case of cap_ver 1.x */
- if (cap_ver == 1) {
- reg_field = XEN_PT_INVALID_REG;
- } else {
- /* set Supported Link Speed */
- uint8_t lnkcap;
- int rc;
- rc = xen_host_pci_get_byte(&s->real_device,
- real_offset - reg->offset + PCI_EXP_LNKCAP,
- &lnkcap);
- if (rc) {
- return rc;
- }
- reg_field |= PCI_EXP_LNKCAP_SLS & lnkcap;
- }
-
- *data = reg_field;
- return 0;
-}
-
-/* PCI Express Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Device Capabilities reg */
- {
- .offset = PCI_EXP_DEVCAP,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x10000000,
- .init = xen_pt_common_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Device Control reg */
- {
- .offset = PCI_EXP_DEVCTL,
- .size = 2,
- .init_val = 0x2810,
- .ro_mask = 0x8400,
- .emu_mask = 0xFFFF,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device Status reg */
- {
- .offset = PCI_EXP_DEVSTA,
- .size = 2,
- .res_mask = 0xFFC0,
- .ro_mask = 0x0030,
- .rw1c_mask = 0x000F,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Control reg */
- {
- .offset = PCI_EXP_LNKCTL,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFC34,
- .emu_mask = 0xFFFF,
- .init = xen_pt_linkctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Status reg */
- {
- .offset = PCI_EXP_LNKSTA,
- .size = 2,
- .ro_mask = 0x3FFF,
- .rw1c_mask = 0xC000,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Device Control 2 reg */
- {
- .offset = 0x28,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFE0,
- .emu_mask = 0xFFFF,
- .init = xen_pt_devctrl2_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* Link Control 2 reg */
- {
- .offset = 0x30,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xE040,
- .emu_mask = 0xFFFF,
- .init = xen_pt_linkctrl2_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/*********************************
- * Power Management Capability
- */
-
-/* Power Management Capability reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_pm[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Power Management Capabilities reg */
- {
- .offset = PCI_CAP_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0xFFFF,
- .emu_mask = 0xF9C8,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- /* PCI Power Management Control/Status reg */
- {
- .offset = PCI_PM_CTRL,
- .size = 2,
- .init_val = 0x0008,
- .res_mask = 0x00F0,
- .ro_mask = 0x610C,
- .rw1c_mask = 0x8000,
- .emu_mask = 0x810B,
- .init = xen_pt_common_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_word_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/********************************
- * MSI Capability
- */
-
-/* Helper */
-#define xen_pt_msi_check_type(offset, flags, what) \
- ((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
- PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
-
-/* Message Control register */
-static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- XenPTMSI *msi = s->msi;
- uint16_t reg_field;
- int rc;
-
- /* use I/O device register's value as initial value */
- rc = xen_host_pci_get_word(&s->real_device, real_offset, &reg_field);
- if (rc) {
- return rc;
- }
- if (reg_field & PCI_MSI_FLAGS_ENABLE) {
- XEN_PT_LOG(&s->dev, "MSI already enabled, disabling it first\n");
- xen_host_pci_set_word(&s->real_device, real_offset,
- reg_field & ~PCI_MSI_FLAGS_ENABLE);
- }
- msi->flags |= reg_field;
- msi->ctrl_offset = real_offset;
- msi->initialized = false;
- msi->mapped = false;
-
- *data = reg->init_val;
- return 0;
-}
-static int xen_pt_msgctrl_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTMSI *msi = s->msi;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* Currently no support for multi-vector */
- if (*val & PCI_MSI_FLAGS_QSIZE) {
- XEN_PT_WARN(&s->dev, "Tries to set more than 1 vector ctrl %x\n", *val);
- }
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- msi->flags |= *data & ~PCI_MSI_FLAGS_ENABLE;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- /* update MSI */
- if (*val & PCI_MSI_FLAGS_ENABLE) {
- /* setup MSI pirq for the first time */
- if (!msi->initialized) {
- /* Init physical one */
- XEN_PT_LOG(&s->dev, "setup MSI (register: %x).\n", *val);
- if (xen_pt_msi_setup(s)) {
- /* We do not broadcast the error to the framework code, so
- * that MSI errors are contained in MSI emulation code and
- * QEMU can go on running.
- * Guest MSI would be actually not working.
- */
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not map MSI (register: %x)!\n", *val);
- return 0;
- }
- if (xen_pt_msi_update(s)) {
- *val &= ~PCI_MSI_FLAGS_ENABLE;
- XEN_PT_WARN(&s->dev, "Can not bind MSI (register: %x)!\n", *val);
- return 0;
- }
- msi->initialized = true;
- msi->mapped = true;
- }
- msi->flags |= PCI_MSI_FLAGS_ENABLE;
- } else if (msi->mapped) {
- xen_pt_msi_disable(s);
- }
-
- return 0;
-}
-
-/* initialize Message Upper Address register */
-static int xen_pt_msgaddr64_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- /* no need to initialize in case of 32 bit type */
- if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
- *data = XEN_PT_INVALID_REG;
- } else {
- *data = reg->init_val;
- }
-
- return 0;
-}
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Message Data register */
-static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint32_t flags = s->msi->flags;
- uint32_t offset = reg->offset;
-
- /* check the offset whether matches the type or not */
- if (xen_pt_msi_check_type(offset, flags, DATA)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
-}
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Mask register */
-static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint32_t flags = s->msi->flags;
-
- /* check the offset whether matches the type or not */
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- *data = XEN_PT_INVALID_REG;
- } else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
-}
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* initialize Pending register */
-static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint32_t flags = s->msi->flags;
-
- /* check the offset whether matches the type or not */
- if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
- *data = XEN_PT_INVALID_REG;
- } else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
- *data = reg->init_val;
- } else {
- *data = XEN_PT_INVALID_REG;
- }
- return 0;
-}
-
-/* write Message Address register */
-static int xen_pt_msgaddr32_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t old_addr = *cfg_entry->ptr.word;
- uint32_t *data = cfg_entry->ptr.word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- s->msi->addr_lo = *data;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- /* update MSI */
- if (*data != old_addr) {
- if (s->msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
-
- return 0;
-}
-/* write Message Upper Address register */
-static int xen_pt_msgaddr64_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint32_t *val,
- uint32_t dev_value, uint32_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint32_t writable_mask = 0;
- uint32_t old_addr = *cfg_entry->ptr.word;
- uint32_t *data = cfg_entry->ptr.word;
-
- /* check whether the type is 64 bit or not */
- if (!(s->msi->flags & PCI_MSI_FLAGS_64BIT)) {
- XEN_PT_ERR(&s->dev,
- "Can't write to the upper address without 64 bit support\n");
- return -1;
- }
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* update the msi_info too */
- s->msi->addr_hi = *data;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- /* update MSI */
- if (*data != old_addr) {
- if (s->msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
-
- return 0;
-}
-
-
-/* this function will be called twice (for 32 bit and 64 bit type) */
-/* write Message Data register */
-static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- XenPTMSI *msi = s->msi;
- uint16_t writable_mask = 0;
- uint16_t old_data = *cfg_entry->ptr.half_word;
- uint32_t offset = reg->offset;
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* check the offset whether matches the type or not */
- if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
- /* exit I/O emulator */
- XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
- return -1;
- }
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
- /* update the msi_info too */
- msi->data = *data;
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, 0);
-
- /* update MSI */
- if (*data != old_data) {
- if (msi->mapped) {
- xen_pt_msi_update(s);
- }
- }
-
- return 0;
-}
-
-/* MSI Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_msi[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Message Control reg */
- {
- .offset = PCI_MSI_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0xFE00,
- .ro_mask = 0x018E,
- .emu_mask = 0x017E,
- .init = xen_pt_msgctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgctrl_reg_write,
- },
- /* Message Address reg */
- {
- .offset = PCI_MSI_ADDRESS_LO,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0x00000003,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_common_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_msgaddr32_reg_write,
- },
- /* Message Upper Address reg (if PCI_MSI_FLAGS_64BIT set) */
- {
- .offset = PCI_MSI_ADDRESS_HI,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0x00000000,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_msgaddr64_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_msgaddr64_reg_write,
- },
- /* Message Data reg (16 bits of data for 32-bit devices) */
- {
- .offset = PCI_MSI_DATA_32,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0x0000,
- .emu_mask = 0xFFFF,
- .init = xen_pt_msgdata_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgdata_reg_write,
- },
- /* Message Data reg (16 bits of data for 64-bit devices) */
- {
- .offset = PCI_MSI_DATA_64,
- .size = 2,
- .init_val = 0x0000,
- .ro_mask = 0x0000,
- .emu_mask = 0xFFFF,
- .init = xen_pt_msgdata_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msgdata_reg_write,
- },
- /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
- {
- .offset = PCI_MSI_MASK_32,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_mask_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
- {
- .offset = PCI_MSI_MASK_64,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0xFFFFFFFF,
- .init = xen_pt_mask_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
- {
- .offset = PCI_MSI_MASK_32 + 4,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x00000000,
- .init = xen_pt_pending_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
- {
- .offset = PCI_MSI_MASK_64 + 4,
- .size = 4,
- .init_val = 0x00000000,
- .ro_mask = 0xFFFFFFFF,
- .emu_mask = 0x00000000,
- .init = xen_pt_pending_reg_init,
- .u.dw.read = xen_pt_long_reg_read,
- .u.dw.write = xen_pt_long_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-
-/**************************************
- * MSI-X Capability
- */
-
-/* Message Control register for MSI-X */
-static int xen_pt_msixctrl_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- uint16_t reg_field;
- int rc;
-
- /* use I/O device register's value as initial value */
- rc = xen_host_pci_get_word(&s->real_device, real_offset, &reg_field);
- if (rc) {
- return rc;
- }
- if (reg_field & PCI_MSIX_FLAGS_ENABLE) {
- XEN_PT_LOG(&s->dev, "MSIX already enabled, disabling it first\n");
- xen_host_pci_set_word(&s->real_device, real_offset,
- reg_field & ~PCI_MSIX_FLAGS_ENABLE);
- }
-
- s->msix->ctrl_offset = real_offset;
-
- *data = reg->init_val;
- return 0;
-}
-static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
- XenPTReg *cfg_entry, uint16_t *val,
- uint16_t dev_value, uint16_t valid_mask)
-{
- XenPTRegInfo *reg = cfg_entry->reg;
- uint16_t writable_mask = 0;
- uint16_t throughable_mask = get_throughable_mask(s, reg, valid_mask);
- int debug_msix_enabled_old;
- uint16_t *data = cfg_entry->ptr.half_word;
-
- /* modify emulate register */
- writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
- *data = XEN_PT_MERGE_VALUE(*val, *data, writable_mask);
-
- /* create value for writing to I/O device register */
- *val = XEN_PT_MERGE_VALUE(*val, dev_value, throughable_mask);
-
- /* update MSI-X */
- if ((*val & PCI_MSIX_FLAGS_ENABLE)
- && !(*val & PCI_MSIX_FLAGS_MASKALL)) {
- xen_pt_msix_update(s);
- } else if (!(*val & PCI_MSIX_FLAGS_ENABLE) && s->msix->enabled) {
- xen_pt_msix_disable(s);
- }
-
- s->msix->maskall = *val & PCI_MSIX_FLAGS_MASKALL;
-
- debug_msix_enabled_old = s->msix->enabled;
- s->msix->enabled = !!(*val & PCI_MSIX_FLAGS_ENABLE);
- if (s->msix->enabled != debug_msix_enabled_old) {
- XEN_PT_LOG(&s->dev, "%s MSI-X\n",
- s->msix->enabled ? "enable" : "disable");
- }
-
- return 0;
-}
-
-/* MSI-X Capability Structure reg static information table */
-static XenPTRegInfo xen_pt_emu_reg_msix[] = {
- /* Next Pointer reg */
- {
- .offset = PCI_CAP_LIST_NEXT,
- .size = 1,
- .init_val = 0x00,
- .ro_mask = 0xFF,
- .emu_mask = 0xFF,
- .init = xen_pt_ptr_reg_init,
- .u.b.read = xen_pt_byte_reg_read,
- .u.b.write = xen_pt_byte_reg_write,
- },
- /* Message Control reg */
- {
- .offset = PCI_MSI_FLAGS,
- .size = 2,
- .init_val = 0x0000,
- .res_mask = 0x3800,
- .ro_mask = 0x07FF,
- .emu_mask = 0x0000,
- .init = xen_pt_msixctrl_reg_init,
- .u.w.read = xen_pt_word_reg_read,
- .u.w.write = xen_pt_msixctrl_reg_write,
- },
- {
- .size = 0,
- },
-};
-
-static XenPTRegInfo xen_pt_emu_reg_igd_opregion[] = {
- /* Intel IGFX OpRegion reg */
- {
- .offset = 0x0,
- .size = 4,
- .init_val = 0,
- .u.dw.read = xen_pt_intel_opregion_read,
- .u.dw.write = xen_pt_intel_opregion_write,
- },
- {
- .size = 0,
- },
-};
-
-/****************************
- * Capabilities
- */
-
-/* capability structure register group size functions */
-
-static int xen_pt_reg_grp_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- *size = grp_reg->grp_size;
- return 0;
-}
-/* get Vendor Specific Capability Structure register group size */
-static int xen_pt_vendor_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- return xen_host_pci_get_byte(&s->real_device, base_offset + 0x02, size);
-}
-/* get PCI Express Capability Structure register group size */
-static int xen_pt_pcie_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- PCIDevice *d = &s->dev;
- uint8_t version = get_capability_version(s, base_offset);
- uint8_t type = get_device_type(s, base_offset);
- uint8_t pcie_size = 0;
-
-
- /* calculate size depend on capability version and device/port type */
- /* in case of PCI Express Base Specification Rev 1.x */
- if (version == 1) {
- /* The PCI Express Capabilities, Device Capabilities, and Device
- * Status/Control registers are required for all PCI Express devices.
- * The Link Capabilities and Link Status/Control are required for all
- * Endpoints that are not Root Complex Integrated Endpoints. Endpoints
- * are not required to implement registers other than those listed
- * above and terminate the capability structure.
- */
- switch (type) {
- case PCI_EXP_TYPE_ENDPOINT:
- case PCI_EXP_TYPE_LEG_END:
- pcie_size = 0x14;
- break;
- case PCI_EXP_TYPE_RC_END:
- /* has no link */
- pcie_size = 0x0C;
- break;
- /* only EndPoint passthrough is supported */
- case PCI_EXP_TYPE_ROOT_PORT:
- case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_PCI_BRIDGE:
- case PCI_EXP_TYPE_PCIE_BRIDGE:
- case PCI_EXP_TYPE_RC_EC:
- default:
- XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
- return -1;
- }
- }
- /* in case of PCI Express Base Specification Rev 2.0 */
- else if (version == 2) {
- switch (type) {
- case PCI_EXP_TYPE_ENDPOINT:
- case PCI_EXP_TYPE_LEG_END:
- case PCI_EXP_TYPE_RC_END:
- /* For Functions that do not implement the registers,
- * these spaces must be hardwired to 0b.
- */
- pcie_size = 0x3C;
- break;
- /* only EndPoint passthrough is supported */
- case PCI_EXP_TYPE_ROOT_PORT:
- case PCI_EXP_TYPE_UPSTREAM:
- case PCI_EXP_TYPE_DOWNSTREAM:
- case PCI_EXP_TYPE_PCI_BRIDGE:
- case PCI_EXP_TYPE_PCIE_BRIDGE:
- case PCI_EXP_TYPE_RC_EC:
- default:
- XEN_PT_ERR(d, "Unsupported device/port type %#x.\n", type);
- return -1;
- }
- } else {
- XEN_PT_ERR(d, "Unsupported capability version %#x.\n", version);
- return -1;
- }
-
- *size = pcie_size;
- return 0;
-}
-/* get MSI Capability Structure register group size */
-static int xen_pt_msi_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- uint16_t msg_ctrl = 0;
- uint8_t msi_size = 0xa;
- int rc;
-
- rc = xen_host_pci_get_word(&s->real_device, base_offset + PCI_MSI_FLAGS,
- &msg_ctrl);
- if (rc) {
- return rc;
- }
- /* check if 64-bit address is capable of per-vector masking */
- if (msg_ctrl & PCI_MSI_FLAGS_64BIT) {
- msi_size += 4;
- }
- if (msg_ctrl & PCI_MSI_FLAGS_MASKBIT) {
- msi_size += 10;
- }
-
- s->msi = g_new0(XenPTMSI, 1);
- s->msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
-
- *size = msi_size;
- return 0;
-}
-/* get MSI-X Capability Structure register group size */
-static int xen_pt_msix_size_init(XenPCIPassthroughState *s,
- const XenPTRegGroupInfo *grp_reg,
- uint32_t base_offset, uint8_t *size)
-{
- int rc = 0;
-
- rc = xen_pt_msix_init(s, base_offset);
-
- if (rc < 0) {
- XEN_PT_ERR(&s->dev, "Internal error: Invalid xen_pt_msix_init.\n");
- return rc;
- }
-
- *size = grp_reg->grp_size;
- return 0;
-}
-
-
-static const XenPTRegGroupInfo xen_pt_emu_reg_grps[] = {
- /* Header Type0 reg group */
- {
- .grp_id = 0xFF,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x40,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_header0,
- },
- /* PCI PowerManagement Capability reg group */
- {
- .grp_id = PCI_CAP_ID_PM,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = PCI_PM_SIZEOF,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_pm,
- },
- /* AGP Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_AGP,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x30,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Vital Product Data Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_VPD,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_vpd,
- },
- /* Slot Identification reg group */
- {
- .grp_id = PCI_CAP_ID_SLOTID,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x04,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* MSI Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_MSI,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_msi_size_init,
- .emu_regs = xen_pt_emu_reg_msi,
- },
- /* PCI-X Capabilities List Item reg group */
- {
- .grp_id = PCI_CAP_ID_PCIX,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x18,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Vendor Specific Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_VNDR,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_vendor_size_init,
- .emu_regs = xen_pt_emu_reg_vendor,
- },
- /* SHPC Capability List Item reg group */
- {
- .grp_id = PCI_CAP_ID_SHPC,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* Subsystem ID and Subsystem Vendor ID Capability List Item reg group */
- {
- .grp_id = PCI_CAP_ID_SSVID,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x08,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* AGP 8x Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_AGP3,
- .grp_type = XEN_PT_GRP_TYPE_HARDWIRED,
- .grp_size = 0x30,
- .size_init = xen_pt_reg_grp_size_init,
- },
- /* PCI Express Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_EXP,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0xFF,
- .size_init = xen_pt_pcie_size_init,
- .emu_regs = xen_pt_emu_reg_pcie,
- },
- /* MSI-X Capability Structure reg group */
- {
- .grp_id = PCI_CAP_ID_MSIX,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x0C,
- .size_init = xen_pt_msix_size_init,
- .emu_regs = xen_pt_emu_reg_msix,
- },
- /* Intel IGD Opregion group */
- {
- .grp_id = XEN_PCI_INTEL_OPREGION,
- .grp_type = XEN_PT_GRP_TYPE_EMU,
- .grp_size = 0x4,
- .size_init = xen_pt_reg_grp_size_init,
- .emu_regs = xen_pt_emu_reg_igd_opregion,
- },
- {
- .grp_size = 0,
- },
-};
-
-/* initialize Capabilities Pointer or Next Pointer register */
-static int xen_pt_ptr_reg_init(XenPCIPassthroughState *s,
- XenPTRegInfo *reg, uint32_t real_offset,
- uint32_t *data)
-{
- int i, rc;
- uint8_t reg_field;
- uint8_t cap_id = 0;
-
- rc = xen_host_pci_get_byte(&s->real_device, real_offset, &reg_field);
- if (rc) {
- return rc;
- }
- /* find capability offset */
- while (reg_field) {
- for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
- if (xen_pt_hide_dev_cap(&s->real_device,
- xen_pt_emu_reg_grps[i].grp_id)) {
- continue;
- }
-
- rc = xen_host_pci_get_byte(&s->real_device,
- reg_field + PCI_CAP_LIST_ID, &cap_id);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to read capability @0x%x (rc:%d)\n",
- reg_field + PCI_CAP_LIST_ID, rc);
- return rc;
- }
- if (xen_pt_emu_reg_grps[i].grp_id == cap_id) {
- if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
- goto out;
- }
- /* ignore the 0 hardwired capability, find next one */
- break;
- }
- }
-
- /* next capability */
- rc = xen_host_pci_get_byte(&s->real_device,
- reg_field + PCI_CAP_LIST_NEXT, &reg_field);
- if (rc) {
- return rc;
- }
- }
-
-out:
- *data = reg_field;
- return 0;
-}
-
-
-/*************
- * Main
- */
-
-static uint8_t find_cap_offset(XenPCIPassthroughState *s, uint8_t cap)
-{
- uint8_t id;
- unsigned max_cap = XEN_PCI_CAP_MAX;
- uint8_t pos = PCI_CAPABILITY_LIST;
- uint8_t status = 0;
-
- if (xen_host_pci_get_byte(&s->real_device, PCI_STATUS, &status)) {
- return 0;
- }
- if ((status & PCI_STATUS_CAP_LIST) == 0) {
- return 0;
- }
-
- while (max_cap--) {
- if (xen_host_pci_get_byte(&s->real_device, pos, &pos)) {
- break;
- }
- if (pos < PCI_CONFIG_HEADER_SIZE) {
- break;
- }
-
- pos &= ~3;
- if (xen_host_pci_get_byte(&s->real_device,
- pos + PCI_CAP_LIST_ID, &id)) {
- break;
- }
-
- if (id == 0xff) {
- break;
- }
- if (id == cap) {
- return pos;
- }
-
- pos += PCI_CAP_LIST_NEXT;
- }
- return 0;
-}
-
-static void xen_pt_config_reg_init(XenPCIPassthroughState *s,
- XenPTRegGroup *reg_grp, XenPTRegInfo *reg,
- Error **errp)
-{
- XenPTReg *reg_entry;
- uint32_t data = 0;
- int rc = 0;
-
- reg_entry = g_new0(XenPTReg, 1);
- reg_entry->reg = reg;
-
- if (reg->init) {
- uint32_t host_mask, size_mask;
- unsigned int offset;
- uint32_t val;
-
- /* initialize emulate register */
- rc = reg->init(s, reg_entry->reg,
- reg_grp->base_offset + reg->offset, &data);
- if (rc < 0) {
- g_free(reg_entry);
- error_setg(errp, "Init emulate register fail");
- return;
- }
- if (data == XEN_PT_INVALID_REG) {
- /* free unused BAR register entry */
- g_free(reg_entry);
- return;
- }
- /* Sync up the data to dev.config */
- offset = reg_grp->base_offset + reg->offset;
- size_mask = 0xFFFFFFFF >> ((4 - reg->size) << 3);
-
- switch (reg->size) {
- case 1: rc = xen_host_pci_get_byte(&s->real_device, offset, (uint8_t *)&val);
- break;
- case 2: rc = xen_host_pci_get_word(&s->real_device, offset, (uint16_t *)&val);
- break;
- case 4: rc = xen_host_pci_get_long(&s->real_device, offset, &val);
- break;
- default: abort();
- }
- if (rc) {
- /* Serious issues when we cannot read the host values! */
- g_free(reg_entry);
- error_setg(errp, "Cannot read host values");
- return;
- }
- /* Set bits in emu_mask are the ones we emulate. The dev.config shall
- * contain the emulated view of the guest - therefore we flip the mask
- * to mask out the host values (which dev.config initially has) . */
- host_mask = size_mask & ~reg->emu_mask;
-
- if ((data & host_mask) != (val & host_mask)) {
- uint32_t new_val;
-
- /* Mask out host (including past size). */
- new_val = val & host_mask;
- /* Merge emulated ones (excluding the non-emulated ones). */
- new_val |= data & host_mask;
- /* Leave intact host and emulated values past the size - even though
- * we do not care as we write per reg->size granularity, but for the
- * logging below lets have the proper value. */
- new_val |= ((val | data)) & ~size_mask;
- XEN_PT_LOG(&s->dev,"Offset 0x%04x mismatch! Emulated=0x%04x, host=0x%04x, syncing to 0x%04x.\n",
- offset, data, val, new_val);
- val = new_val;
- } else
- val = data;
-
- if (val & ~size_mask) {
- error_setg(errp, "Offset 0x%04x:0x%04x expands past"
- " register size (%d)", offset, val, reg->size);
- g_free(reg_entry);
- return;
- }
- /* This could be just pci_set_long as we don't modify the bits
- * past reg->size, but in case this routine is run in parallel or the
- * init value is larger, we do not want to over-write registers. */
- switch (reg->size) {
- case 1: pci_set_byte(s->dev.config + offset, (uint8_t)val);
- break;
- case 2: pci_set_word(s->dev.config + offset, (uint16_t)val);
- break;
- case 4: pci_set_long(s->dev.config + offset, val);
- break;
- default: abort();
- }
- /* set register value pointer to the data. */
- reg_entry->ptr.byte = s->dev.config + offset;
-
- }
- /* list add register entry */
- QLIST_INSERT_HEAD(&reg_grp->reg_tbl_list, reg_entry, entries);
-}
-
-void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
-{
- int i, rc;
- Error *err = NULL;
-
- QLIST_INIT(&s->reg_grps);
-
- for (i = 0; xen_pt_emu_reg_grps[i].grp_size != 0; i++) {
- uint32_t reg_grp_offset = 0;
- XenPTRegGroup *reg_grp_entry = NULL;
-
- if (xen_pt_emu_reg_grps[i].grp_id != 0xFF
- && xen_pt_emu_reg_grps[i].grp_id != XEN_PCI_INTEL_OPREGION) {
- if (xen_pt_hide_dev_cap(&s->real_device,
- xen_pt_emu_reg_grps[i].grp_id)) {
- continue;
- }
-
- reg_grp_offset = find_cap_offset(s, xen_pt_emu_reg_grps[i].grp_id);
-
- if (!reg_grp_offset) {
- continue;
- }
- }
-
- /*
- * By default we will trap up to 0x40 in the cfg space.
- * If an intel device is pass through we need to trap 0xfc,
- * therefore the size should be 0xff.
- */
- if (xen_pt_emu_reg_grps[i].grp_id == XEN_PCI_INTEL_OPREGION) {
- reg_grp_offset = XEN_PCI_INTEL_OPREGION;
- }
-
- reg_grp_entry = g_new0(XenPTRegGroup, 1);
- QLIST_INIT(&reg_grp_entry->reg_tbl_list);
- QLIST_INSERT_HEAD(&s->reg_grps, reg_grp_entry, entries);
-
- reg_grp_entry->base_offset = reg_grp_offset;
- reg_grp_entry->reg_grp = xen_pt_emu_reg_grps + i;
- if (xen_pt_emu_reg_grps[i].size_init) {
- /* get register group size */
- rc = xen_pt_emu_reg_grps[i].size_init(s, reg_grp_entry->reg_grp,
- reg_grp_offset,
- &reg_grp_entry->size);
- if (rc < 0) {
- error_setg(&err, "Failed to initialize %d/%zu, type = 0x%x,"
- " rc: %d", i, ARRAY_SIZE(xen_pt_emu_reg_grps),
- xen_pt_emu_reg_grps[i].grp_type, rc);
- error_propagate(errp, err);
- xen_pt_config_delete(s);
- return;
- }
- }
-
- if (xen_pt_emu_reg_grps[i].grp_type == XEN_PT_GRP_TYPE_EMU) {
- if (xen_pt_emu_reg_grps[i].emu_regs) {
- int j = 0;
- XenPTRegInfo *regs = xen_pt_emu_reg_grps[i].emu_regs;
-
- /* initialize capability register */
- for (j = 0; regs->size != 0; j++, regs++) {
- xen_pt_config_reg_init(s, reg_grp_entry, regs, &err);
- if (err) {
- error_append_hint(&err, "Failed to initialize %d/%zu"
- " reg 0x%x in grp_type = 0x%x (%d/%zu)",
- j, ARRAY_SIZE(xen_pt_emu_reg_grps[i].emu_regs),
- regs->offset, xen_pt_emu_reg_grps[i].grp_type,
- i, ARRAY_SIZE(xen_pt_emu_reg_grps));
- error_propagate(errp, err);
- xen_pt_config_delete(s);
- return;
- }
- }
- }
- }
- }
-}
-
-/* delete all emulate register */
-void xen_pt_config_delete(XenPCIPassthroughState *s)
-{
- struct XenPTRegGroup *reg_group, *next_grp;
- struct XenPTReg *reg, *next_reg;
-
- /* free MSI/MSI-X info table */
- if (s->msix) {
- xen_pt_msix_unmap(s);
- }
- g_free(s->msi);
-
- /* free all register group entry */
- QLIST_FOREACH_SAFE(reg_group, &s->reg_grps, entries, next_grp) {
- /* free all register entry */
- QLIST_FOREACH_SAFE(reg, &reg_group->reg_tbl_list, entries, next_reg) {
- QLIST_REMOVE(reg, entries);
- g_free(reg);
- }
-
- QLIST_REMOVE(reg_group, entries);
- g_free(reg_group);
- }
-}
diff --git a/qemu/hw/xen/xen_pt_graphics.c b/qemu/hw/xen/xen_pt_graphics.c
deleted file mode 100644
index 0f4c8d77e..000000000
--- a/qemu/hw/xen/xen_pt_graphics.c
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * graphics passthrough
- */
-#include "qemu/osdep.h"
-#include "qapi/error.h"
-#include "xen_pt.h"
-#include "xen-host-pci-device.h"
-#include "hw/xen/xen_backend.h"
-
-static unsigned long igd_guest_opregion;
-static unsigned long igd_host_opregion;
-
-#define XEN_PCI_INTEL_OPREGION_MASK 0xfff
-
-typedef struct VGARegion {
- int type; /* Memory or port I/O */
- uint64_t guest_base_addr;
- uint64_t machine_base_addr;
- uint64_t size; /* size of the region */
- int rc;
-} VGARegion;
-
-#define IORESOURCE_IO 0x00000100
-#define IORESOURCE_MEM 0x00000200
-
-static struct VGARegion vga_args[] = {
- {
- .type = IORESOURCE_IO,
- .guest_base_addr = 0x3B0,
- .machine_base_addr = 0x3B0,
- .size = 0xC,
- .rc = -1,
- },
- {
- .type = IORESOURCE_IO,
- .guest_base_addr = 0x3C0,
- .machine_base_addr = 0x3C0,
- .size = 0x20,
- .rc = -1,
- },
- {
- .type = IORESOURCE_MEM,
- .guest_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
- .machine_base_addr = 0xa0000 >> XC_PAGE_SHIFT,
- .size = 0x20,
- .rc = -1,
- },
-};
-
-/*
- * register VGA resources for the domain with assigned gfx
- */
-int xen_pt_register_vga_regions(XenHostPCIDevice *dev)
-{
- int i = 0;
-
- if (!is_igd_vga_passthrough(dev)) {
- return 0;
- }
-
- for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
- if (vga_args[i].type == IORESOURCE_IO) {
- vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_ADD_MAPPING);
- } else {
- vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_ADD_MAPPING);
- }
-
- if (vga_args[i].rc) {
- XEN_PT_ERR(NULL, "VGA %s mapping failed! (rc: %i)\n",
- vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
- vga_args[i].rc);
- return vga_args[i].rc;
- }
- }
-
- return 0;
-}
-
-/*
- * unregister VGA resources for the domain with assigned gfx
- */
-int xen_pt_unregister_vga_regions(XenHostPCIDevice *dev)
-{
- int i = 0;
- int ret = 0;
-
- if (!is_igd_vga_passthrough(dev)) {
- return 0;
- }
-
- for (i = 0 ; i < ARRAY_SIZE(vga_args); i++) {
- if (vga_args[i].type == IORESOURCE_IO) {
- vga_args[i].rc = xc_domain_ioport_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_REMOVE_MAPPING);
- } else {
- vga_args[i].rc = xc_domain_memory_mapping(xen_xc, xen_domid,
- vga_args[i].guest_base_addr,
- vga_args[i].machine_base_addr,
- vga_args[i].size, DPCI_REMOVE_MAPPING);
- }
-
- if (vga_args[i].rc) {
- XEN_PT_ERR(NULL, "VGA %s unmapping failed! (rc: %i)\n",
- vga_args[i].type == IORESOURCE_IO ? "ioport" : "memory",
- vga_args[i].rc);
- return vga_args[i].rc;
- }
- }
-
- if (igd_guest_opregion) {
- ret = xc_domain_memory_mapping(xen_xc, xen_domid,
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- 3,
- DPCI_REMOVE_MAPPING);
- if (ret) {
- return ret;
- }
- }
-
- return 0;
-}
-
-static void *get_vgabios(XenPCIPassthroughState *s, int *size,
- XenHostPCIDevice *dev)
-{
- return pci_assign_dev_load_option_rom(&s->dev, OBJECT(&s->dev), size,
- dev->domain, dev->bus,
- dev->dev, dev->func);
-}
-
-/* Refer to Seabios. */
-struct rom_header {
- uint16_t signature;
- uint8_t size;
- uint8_t initVector[4];
- uint8_t reserved[17];
- uint16_t pcioffset;
- uint16_t pnpoffset;
-} __attribute__((packed));
-
-struct pci_data {
- uint32_t signature;
- uint16_t vendor;
- uint16_t device;
- uint16_t vitaldata;
- uint16_t dlen;
- uint8_t drevision;
- uint8_t class_lo;
- uint16_t class_hi;
- uint16_t ilen;
- uint16_t irevision;
- uint8_t type;
- uint8_t indicator;
- uint16_t reserved;
-} __attribute__((packed));
-
-void xen_pt_setup_vga(XenPCIPassthroughState *s, XenHostPCIDevice *dev,
- Error **errp)
-{
- unsigned char *bios = NULL;
- struct rom_header *rom;
- int bios_size;
- char *c = NULL;
- char checksum = 0;
- uint32_t len = 0;
- struct pci_data *pd = NULL;
-
- if (!is_igd_vga_passthrough(dev)) {
- error_setg(errp, "Need to enable igd-passthrough");
- return;
- }
-
- bios = get_vgabios(s, &bios_size, dev);
- if (!bios) {
- error_setg(errp, "VGA: Can't get VBIOS");
- return;
- }
-
- /* Currently we fixed this address as a primary. */
- rom = (struct rom_header *)bios;
- pd = (void *)(bios + (unsigned char)rom->pcioffset);
-
- /* We may need to fixup Device Identification. */
- if (pd->device != s->real_device.device_id) {
- pd->device = s->real_device.device_id;
-
- len = rom->size * 512;
- /* Then adjust the bios checksum */
- for (c = (char *)bios; c < ((char *)bios + len); c++) {
- checksum += *c;
- }
- if (checksum) {
- bios[len - 1] -= checksum;
- XEN_PT_LOG(&s->dev, "vga bios checksum is adjusted %x!\n",
- checksum);
- }
- }
-
- /* Currently we fixed this address as a primary for legacy BIOS. */
- cpu_physical_memory_rw(0xc0000, bios, bios_size, 1);
-}
-
-uint32_t igd_read_opregion(XenPCIPassthroughState *s)
-{
- uint32_t val = 0;
-
- if (!igd_guest_opregion) {
- return val;
- }
-
- val = igd_guest_opregion;
-
- XEN_PT_LOG(&s->dev, "Read opregion val=%x\n", val);
- return val;
-}
-
-#define XEN_PCI_INTEL_OPREGION_PAGES 0x3
-#define XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED 0x1
-void igd_write_opregion(XenPCIPassthroughState *s, uint32_t val)
-{
- int ret;
-
- if (igd_guest_opregion) {
- XEN_PT_LOG(&s->dev, "opregion register already been set, ignoring %x\n",
- val);
- return;
- }
-
- /* We just work with LE. */
- xen_host_pci_get_block(&s->real_device, XEN_PCI_INTEL_OPREGION,
- (uint8_t *)&igd_host_opregion, 4);
- igd_guest_opregion = (unsigned long)(val & ~XEN_PCI_INTEL_OPREGION_MASK)
- | (igd_host_opregion & XEN_PCI_INTEL_OPREGION_MASK);
-
- ret = xc_domain_iomem_permission(xen_xc, xen_domid,
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- XEN_PCI_INTEL_OPREGION_PAGES,
- XEN_PCI_INTEL_OPREGION_ENABLE_ACCESSED);
-
- if (ret) {
- XEN_PT_ERR(&s->dev, "[%d]:Can't enable to access IGD host opregion:"
- " 0x%lx.\n", ret,
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT)),
- igd_guest_opregion = 0;
- return;
- }
-
- ret = xc_domain_memory_mapping(xen_xc, xen_domid,
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- XEN_PCI_INTEL_OPREGION_PAGES,
- DPCI_ADD_MAPPING);
-
- if (ret) {
- XEN_PT_ERR(&s->dev, "[%d]:Can't map IGD host opregion:0x%lx to"
- " guest opregion:0x%lx.\n", ret,
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
- igd_guest_opregion = 0;
- return;
- }
-
- XEN_PT_LOG(&s->dev, "Map OpRegion: 0x%lx -> 0x%lx\n",
- (unsigned long)(igd_host_opregion >> XC_PAGE_SHIFT),
- (unsigned long)(igd_guest_opregion >> XC_PAGE_SHIFT));
-}
diff --git a/qemu/hw/xen/xen_pt_msi.c b/qemu/hw/xen/xen_pt_msi.c
deleted file mode 100644
index 9a16f2bff..000000000
--- a/qemu/hw/xen/xen_pt_msi.c
+++ /dev/null
@@ -1,635 +0,0 @@
-/*
- * Copyright (c) 2007, Intel Corporation.
- *
- * This work is licensed under the terms of the GNU GPL, version 2. See
- * the COPYING file in the top-level directory.
- *
- * Jiang Yunhong <yunhong.jiang@intel.com>
- *
- * This file implements direct PCI assignment to a HVM guest
- */
-
-#include "qemu/osdep.h"
-#include <sys/mman.h>
-
-#include "hw/xen/xen_backend.h"
-#include "xen_pt.h"
-#include "hw/i386/apic-msidef.h"
-
-
-#define XEN_PT_AUTO_ASSIGN -1
-
-/* shift count for gflags */
-#define XEN_PT_GFLAGS_SHIFT_DEST_ID 0
-#define XEN_PT_GFLAGS_SHIFT_RH 8
-#define XEN_PT_GFLAGS_SHIFT_DM 9
-#define XEN_PT_GFLAGSSHIFT_DELIV_MODE 12
-#define XEN_PT_GFLAGSSHIFT_TRG_MODE 15
-
-#define latch(fld) latch[PCI_MSIX_ENTRY_##fld / sizeof(uint32_t)]
-
-/*
- * Helpers
- */
-
-static inline uint8_t msi_vector(uint32_t data)
-{
- return (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
-}
-
-static inline uint8_t msi_dest_id(uint32_t addr)
-{
- return (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
-}
-
-static inline uint32_t msi_ext_dest_id(uint32_t addr_hi)
-{
- return addr_hi & 0xffffff00;
-}
-
-static uint32_t msi_gflags(uint32_t data, uint64_t addr)
-{
- uint32_t result = 0;
- int rh, dm, dest_id, deliv_mode, trig_mode;
-
- rh = (addr >> MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
- dm = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
- dest_id = msi_dest_id(addr);
- deliv_mode = (data >> MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
- trig_mode = (data >> MSI_DATA_TRIGGER_SHIFT) & 0x1;
-
- result = dest_id | (rh << XEN_PT_GFLAGS_SHIFT_RH)
- | (dm << XEN_PT_GFLAGS_SHIFT_DM)
- | (deliv_mode << XEN_PT_GFLAGSSHIFT_DELIV_MODE)
- | (trig_mode << XEN_PT_GFLAGSSHIFT_TRG_MODE);
-
- return result;
-}
-
-static inline uint64_t msi_addr64(XenPTMSI *msi)
-{
- return (uint64_t)msi->addr_hi << 32 | msi->addr_lo;
-}
-
-static int msi_msix_enable(XenPCIPassthroughState *s,
- uint32_t address,
- uint16_t flag,
- bool enable)
-{
- uint16_t val = 0;
- int rc;
-
- if (!address) {
- return -1;
- }
-
- rc = xen_host_pci_get_word(&s->real_device, address, &val);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to read MSI/MSI-X register (0x%x), rc:%d\n",
- address, rc);
- return rc;
- }
- if (enable) {
- val |= flag;
- } else {
- val &= ~flag;
- }
- rc = xen_host_pci_set_word(&s->real_device, address, val);
- if (rc) {
- XEN_PT_ERR(&s->dev, "Failed to write MSI/MSI-X register (0x%x), rc:%d\n",
- address, rc);
- }
- return rc;
-}
-
-static int msi_msix_setup(XenPCIPassthroughState *s,
- uint64_t addr,
- uint32_t data,
- int *ppirq,
- bool is_msix,
- int msix_entry,
- bool is_not_mapped)
-{
- uint8_t gvec = msi_vector(data);
- int rc = 0;
-
- assert((!is_msix && msix_entry == 0) || is_msix);
-
- if (xen_is_pirq_msi(data)) {
- *ppirq = msi_ext_dest_id(addr >> 32) | msi_dest_id(addr);
- if (!*ppirq) {
- /* this probably identifies an misconfiguration of the guest,
- * try the emulated path */
- *ppirq = XEN_PT_UNASSIGNED_PIRQ;
- } else {
- XEN_PT_LOG(&s->dev, "requested pirq %d for MSI%s"
- " (vec: %#x, entry: %#x)\n",
- *ppirq, is_msix ? "-X" : "", gvec, msix_entry);
- }
- }
-
- if (is_not_mapped) {
- uint64_t table_base = 0;
-
- if (is_msix) {
- table_base = s->msix->table_base;
- }
-
- rc = xc_physdev_map_pirq_msi(xen_xc, xen_domid, XEN_PT_AUTO_ASSIGN,
- ppirq, PCI_DEVFN(s->real_device.dev,
- s->real_device.func),
- s->real_device.bus,
- msix_entry, table_base);
- if (rc) {
- XEN_PT_ERR(&s->dev,
- "Mapping of MSI%s (err: %i, vec: %#x, entry %#x)\n",
- is_msix ? "-X" : "", errno, gvec, msix_entry);
- return rc;
- }
- }
-
- return 0;
-}
-static int msi_msix_update(XenPCIPassthroughState *s,
- uint64_t addr,
- uint32_t data,
- int pirq,
- bool is_msix,
- int msix_entry,
- int *old_pirq)
-{
- PCIDevice *d = &s->dev;
- uint8_t gvec = msi_vector(data);
- uint32_t gflags = msi_gflags(data, addr);
- int rc = 0;
- uint64_t table_addr = 0;
-
- XEN_PT_LOG(d, "Updating MSI%s with pirq %d gvec %#x gflags %#x"
- " (entry: %#x)\n",
- is_msix ? "-X" : "", pirq, gvec, gflags, msix_entry);
-
- if (is_msix) {
- table_addr = s->msix->mmio_base_addr;
- }
-
- rc = xc_domain_update_msi_irq(xen_xc, xen_domid, gvec,
- pirq, gflags, table_addr);
-
- if (rc) {
- XEN_PT_ERR(d, "Updating of MSI%s failed. (err: %d)\n",
- is_msix ? "-X" : "", errno);
-
- if (xc_physdev_unmap_pirq(xen_xc, xen_domid, *old_pirq)) {
- XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %d)\n",
- is_msix ? "-X" : "", *old_pirq, errno);
- }
- *old_pirq = XEN_PT_UNASSIGNED_PIRQ;
- }
- return rc;
-}
-
-static int msi_msix_disable(XenPCIPassthroughState *s,
- uint64_t addr,
- uint32_t data,
- int pirq,
- bool is_msix,
- bool is_binded)
-{
- PCIDevice *d = &s->dev;
- uint8_t gvec = msi_vector(data);
- uint32_t gflags = msi_gflags(data, addr);
- int rc = 0;
-
- if (pirq == XEN_PT_UNASSIGNED_PIRQ) {
- return 0;
- }
-
- if (is_binded) {
- XEN_PT_LOG(d, "Unbind MSI%s with pirq %d, gvec %#x\n",
- is_msix ? "-X" : "", pirq, gvec);
- rc = xc_domain_unbind_msi_irq(xen_xc, xen_domid, gvec, pirq, gflags);
- if (rc) {
- XEN_PT_ERR(d, "Unbinding of MSI%s failed. (err: %d, pirq: %d, gvec: %#x)\n",
- is_msix ? "-X" : "", errno, pirq, gvec);
- return rc;
- }
- }
-
- XEN_PT_LOG(d, "Unmap MSI%s pirq %d\n", is_msix ? "-X" : "", pirq);
- rc = xc_physdev_unmap_pirq(xen_xc, xen_domid, pirq);
- if (rc) {
- XEN_PT_ERR(d, "Unmapping of MSI%s pirq %d failed. (err: %i)\n",
- is_msix ? "-X" : "", pirq, errno);
- return rc;
- }
-
- return 0;
-}
-
-/*
- * MSI virtualization functions
- */
-
-static int xen_pt_msi_set_enable(XenPCIPassthroughState *s, bool enable)
-{
- XEN_PT_LOG(&s->dev, "%s MSI.\n", enable ? "enabling" : "disabling");
-
- if (!s->msi) {
- return -1;
- }
-
- return msi_msix_enable(s, s->msi->ctrl_offset, PCI_MSI_FLAGS_ENABLE,
- enable);
-}
-
-/* setup physical msi, but don't enable it */
-int xen_pt_msi_setup(XenPCIPassthroughState *s)
-{
- int pirq = XEN_PT_UNASSIGNED_PIRQ;
- int rc = 0;
- XenPTMSI *msi = s->msi;
-
- if (msi->initialized) {
- XEN_PT_ERR(&s->dev,
- "Setup physical MSI when it has been properly initialized.\n");
- return -1;
- }
-
- rc = msi_msix_setup(s, msi_addr64(msi), msi->data, &pirq, false, 0, true);
- if (rc) {
- return rc;
- }
-
- if (pirq < 0) {
- XEN_PT_ERR(&s->dev, "Invalid pirq number: %d.\n", pirq);
- return -1;
- }
-
- msi->pirq = pirq;
- XEN_PT_LOG(&s->dev, "MSI mapped with pirq %d.\n", pirq);
-
- return 0;
-}
-
-int xen_pt_msi_update(XenPCIPassthroughState *s)
-{
- XenPTMSI *msi = s->msi;
- return msi_msix_update(s, msi_addr64(msi), msi->data, msi->pirq,
- false, 0, &msi->pirq);
-}
-
-void xen_pt_msi_disable(XenPCIPassthroughState *s)
-{
- XenPTMSI *msi = s->msi;
-
- if (!msi) {
- return;
- }
-
- (void)xen_pt_msi_set_enable(s, false);
-
- msi_msix_disable(s, msi_addr64(msi), msi->data, msi->pirq, false,
- msi->initialized);
-
- /* clear msi info */
- msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
- msi->initialized = false;
- msi->mapped = false;
- msi->pirq = XEN_PT_UNASSIGNED_PIRQ;
-}
-
-/*
- * MSI-X virtualization functions
- */
-
-static int msix_set_enable(XenPCIPassthroughState *s, bool enabled)
-{
- XEN_PT_LOG(&s->dev, "%s MSI-X.\n", enabled ? "enabling" : "disabling");
-
- if (!s->msix) {
- return -1;
- }
-
- return msi_msix_enable(s, s->msix->ctrl_offset, PCI_MSIX_FLAGS_ENABLE,
- enabled);
-}
-
-static int xen_pt_msix_update_one(XenPCIPassthroughState *s, int entry_nr,
- uint32_t vec_ctrl)
-{
- XenPTMSIXEntry *entry = NULL;
- int pirq;
- int rc;
-
- if (entry_nr < 0 || entry_nr >= s->msix->total_entries) {
- return -EINVAL;
- }
-
- entry = &s->msix->msix_entry[entry_nr];
-
- if (!entry->updated) {
- return 0;
- }
-
- pirq = entry->pirq;
-
- /*
- * Update the entry addr and data to the latest values only when the
- * entry is masked or they are all masked, as required by the spec.
- * Addr and data changes while the MSI-X entry is unmasked get deferred
- * until the next masked -> unmasked transition.
- */
- if (pirq == XEN_PT_UNASSIGNED_PIRQ || s->msix->maskall ||
- (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
- entry->addr = entry->latch(LOWER_ADDR) |
- ((uint64_t)entry->latch(UPPER_ADDR) << 32);
- entry->data = entry->latch(DATA);
- }
-
- rc = msi_msix_setup(s, entry->addr, entry->data, &pirq, true, entry_nr,
- entry->pirq == XEN_PT_UNASSIGNED_PIRQ);
- if (rc) {
- return rc;
- }
- if (entry->pirq == XEN_PT_UNASSIGNED_PIRQ) {
- entry->pirq = pirq;
- }
-
- rc = msi_msix_update(s, entry->addr, entry->data, pirq, true,
- entry_nr, &entry->pirq);
-
- if (!rc) {
- entry->updated = false;
- }
-
- return rc;
-}
-
-int xen_pt_msix_update(XenPCIPassthroughState *s)
-{
- XenPTMSIX *msix = s->msix;
- int i;
-
- for (i = 0; i < msix->total_entries; i++) {
- xen_pt_msix_update_one(s, i, msix->msix_entry[i].latch(VECTOR_CTRL));
- }
-
- return 0;
-}
-
-void xen_pt_msix_disable(XenPCIPassthroughState *s)
-{
- int i = 0;
-
- msix_set_enable(s, false);
-
- for (i = 0; i < s->msix->total_entries; i++) {
- XenPTMSIXEntry *entry = &s->msix->msix_entry[i];
-
- msi_msix_disable(s, entry->addr, entry->data, entry->pirq, true, true);
-
- /* clear MSI-X info */
- entry->pirq = XEN_PT_UNASSIGNED_PIRQ;
- entry->updated = false;
- }
-}
-
-int xen_pt_msix_update_remap(XenPCIPassthroughState *s, int bar_index)
-{
- XenPTMSIXEntry *entry;
- int i, ret;
-
- if (!(s->msix && s->msix->bar_index == bar_index)) {
- return 0;
- }
-
- for (i = 0; i < s->msix->total_entries; i++) {
- entry = &s->msix->msix_entry[i];
- if (entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
- ret = xc_domain_unbind_pt_irq(xen_xc, xen_domid, entry->pirq,
- PT_IRQ_TYPE_MSI, 0, 0, 0, 0);
- if (ret) {
- XEN_PT_ERR(&s->dev, "unbind MSI-X entry %d failed (err: %d)\n",
- entry->pirq, errno);
- }
- entry->updated = true;
- }
- }
- return xen_pt_msix_update(s);
-}
-
-static uint32_t get_entry_value(XenPTMSIXEntry *e, int offset)
-{
- assert(!(offset % sizeof(*e->latch)));
- return e->latch[offset / sizeof(*e->latch)];
-}
-
-static void set_entry_value(XenPTMSIXEntry *e, int offset, uint32_t val)
-{
- assert(!(offset % sizeof(*e->latch)));
- e->latch[offset / sizeof(*e->latch)] = val;
-}
-
-static void pci_msix_write(void *opaque, hwaddr addr,
- uint64_t val, unsigned size)
-{
- XenPCIPassthroughState *s = opaque;
- XenPTMSIX *msix = s->msix;
- XenPTMSIXEntry *entry;
- unsigned int entry_nr, offset;
-
- entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
- if (entry_nr >= msix->total_entries) {
- return;
- }
- entry = &msix->msix_entry[entry_nr];
- offset = addr % PCI_MSIX_ENTRY_SIZE;
-
- if (offset != PCI_MSIX_ENTRY_VECTOR_CTRL) {
- if (get_entry_value(entry, offset) == val
- && entry->pirq != XEN_PT_UNASSIGNED_PIRQ) {
- return;
- }
-
- entry->updated = true;
- } else if (msix->enabled && entry->updated &&
- !(val & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
- const volatile uint32_t *vec_ctrl;
-
- /*
- * If Xen intercepts the mask bit access, entry->vec_ctrl may not be
- * up-to-date. Read from hardware directly.
- */
- vec_ctrl = s->msix->phys_iomem_base + entry_nr * PCI_MSIX_ENTRY_SIZE
- + PCI_MSIX_ENTRY_VECTOR_CTRL;
- xen_pt_msix_update_one(s, entry_nr, *vec_ctrl);
- }
-
- set_entry_value(entry, offset, val);
-}
-
-static uint64_t pci_msix_read(void *opaque, hwaddr addr,
- unsigned size)
-{
- XenPCIPassthroughState *s = opaque;
- XenPTMSIX *msix = s->msix;
- int entry_nr, offset;
-
- entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
- if (entry_nr < 0) {
- XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
- return 0;
- }
-
- offset = addr % PCI_MSIX_ENTRY_SIZE;
-
- if (addr < msix->total_entries * PCI_MSIX_ENTRY_SIZE) {
- return get_entry_value(&msix->msix_entry[entry_nr], offset);
- } else {
- /* Pending Bit Array (PBA) */
- return *(uint32_t *)(msix->phys_iomem_base + addr);
- }
-}
-
-static bool pci_msix_accepts(void *opaque, hwaddr addr,
- unsigned size, bool is_write)
-{
- return !(addr & (size - 1));
-}
-
-static const MemoryRegionOps pci_msix_ops = {
- .read = pci_msix_read,
- .write = pci_msix_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false,
- .accepts = pci_msix_accepts
- },
- .impl = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- }
-};
-
-int xen_pt_msix_init(XenPCIPassthroughState *s, uint32_t base)
-{
- uint8_t id = 0;
- uint16_t control = 0;
- uint32_t table_off = 0;
- int i, total_entries, bar_index;
- XenHostPCIDevice *hd = &s->real_device;
- PCIDevice *d = &s->dev;
- int fd = -1;
- XenPTMSIX *msix = NULL;
- int rc = 0;
-
- rc = xen_host_pci_get_byte(hd, base + PCI_CAP_LIST_ID, &id);
- if (rc) {
- return rc;
- }
-
- if (id != PCI_CAP_ID_MSIX) {
- XEN_PT_ERR(d, "Invalid id %#x base %#x\n", id, base);
- return -1;
- }
-
- xen_host_pci_get_word(hd, base + PCI_MSIX_FLAGS, &control);
- total_entries = control & PCI_MSIX_FLAGS_QSIZE;
- total_entries += 1;
-
- s->msix = g_malloc0(sizeof (XenPTMSIX)
- + total_entries * sizeof (XenPTMSIXEntry));
- msix = s->msix;
-
- msix->total_entries = total_entries;
- for (i = 0; i < total_entries; i++) {
- msix->msix_entry[i].pirq = XEN_PT_UNASSIGNED_PIRQ;
- }
-
- memory_region_init_io(&msix->mmio, OBJECT(s), &pci_msix_ops,
- s, "xen-pci-pt-msix",
- (total_entries * PCI_MSIX_ENTRY_SIZE
- + XC_PAGE_SIZE - 1)
- & XC_PAGE_MASK);
-
- xen_host_pci_get_long(hd, base + PCI_MSIX_TABLE, &table_off);
- bar_index = msix->bar_index = table_off & PCI_MSIX_FLAGS_BIRMASK;
- table_off = table_off & ~PCI_MSIX_FLAGS_BIRMASK;
- msix->table_base = s->real_device.io_regions[bar_index].base_addr;
- XEN_PT_LOG(d, "get MSI-X table BAR base 0x%"PRIx64"\n", msix->table_base);
-
- fd = open("/dev/mem", O_RDWR);
- if (fd == -1) {
- rc = -errno;
- XEN_PT_ERR(d, "Can't open /dev/mem: %s\n", strerror(errno));
- goto error_out;
- }
- XEN_PT_LOG(d, "table_off = %#x, total_entries = %d\n",
- table_off, total_entries);
- msix->table_offset_adjust = table_off & 0x0fff;
- msix->phys_iomem_base =
- mmap(NULL,
- total_entries * PCI_MSIX_ENTRY_SIZE + msix->table_offset_adjust,
- PROT_READ,
- MAP_SHARED | MAP_LOCKED,
- fd,
- msix->table_base + table_off - msix->table_offset_adjust);
- close(fd);
- if (msix->phys_iomem_base == MAP_FAILED) {
- rc = -errno;
- XEN_PT_ERR(d, "Can't map physical MSI-X table: %s\n", strerror(errno));
- goto error_out;
- }
- msix->phys_iomem_base = (char *)msix->phys_iomem_base
- + msix->table_offset_adjust;
-
- XEN_PT_LOG(d, "mapping physical MSI-X table to %p\n",
- msix->phys_iomem_base);
-
- memory_region_add_subregion_overlap(&s->bar[bar_index], table_off,
- &msix->mmio,
- 2); /* Priority: pci default + 1 */
-
- return 0;
-
-error_out:
- g_free(s->msix);
- s->msix = NULL;
- return rc;
-}
-
-void xen_pt_msix_unmap(XenPCIPassthroughState *s)
-{
- XenPTMSIX *msix = s->msix;
-
- if (!msix) {
- return;
- }
-
- /* unmap the MSI-X memory mapped register area */
- if (msix->phys_iomem_base) {
- XEN_PT_LOG(&s->dev, "unmapping physical MSI-X table from %p\n",
- msix->phys_iomem_base);
- munmap(msix->phys_iomem_base, msix->total_entries * PCI_MSIX_ENTRY_SIZE
- + msix->table_offset_adjust);
- }
-
- memory_region_del_subregion(&s->bar[msix->bar_index], &msix->mmio);
-}
-
-void xen_pt_msix_delete(XenPCIPassthroughState *s)
-{
- XenPTMSIX *msix = s->msix;
-
- if (!msix) {
- return;
- }
-
- object_unparent(OBJECT(&msix->mmio));
-
- g_free(s->msix);
- s->msix = NULL;
-}