aboutsummaryrefslogtreecommitdiff
path: root/hw/xen
diff options
context:
space:
mode:
Diffstat (limited to 'hw/xen')
-rw-r--r--hw/xen/meson.build4
-rw-r--r--hw/xen/trace-events6
-rw-r--r--hw/xen/xen-bus-helper.c37
-rw-r--r--hw/xen/xen-bus.c35
-rw-r--r--hw/xen/xen-host-pci-device.c76
-rw-r--r--hw/xen/xen-host-pci-device.h6
-rw-r--r--hw/xen/xen-hvm-common.c140
-rw-r--r--hw/xen/xen-legacy-backend.c50
-rw-r--r--hw/xen/xen-mapcache.c49
-rw-r--r--hw/xen/xen-pvh-common.c399
-rw-r--r--hw/xen/xen_devconfig.c12
-rw-r--r--hw/xen/xen_pt.c67
-rw-r--r--hw/xen/xen_pt_graphics.c4
-rw-r--r--hw/xen/xen_pt_load_rom.c2
-rw-r--r--hw/xen/xen_pvdev.c8
-rw-r--r--hw/xen/xen_stubs.c51
16 files changed, 792 insertions, 154 deletions
diff --git a/hw/xen/meson.build b/hw/xen/meson.build
index d887fa9..a1850e7 100644
--- a/hw/xen/meson.build
+++ b/hw/xen/meson.build
@@ -9,12 +9,16 @@ system_ss.add(when: ['CONFIG_XEN_BUS'], if_true: files(
system_ss.add(when: ['CONFIG_XEN', xen], if_true: files(
'xen-operations.c',
+),
+if_false: files(
+ 'xen_stubs.c',
))
xen_specific_ss = ss.source_set()
xen_specific_ss.add(files(
'xen-mapcache.c',
'xen-hvm-common.c',
+ 'xen-pvh-common.c',
))
if have_xen_pci_passthrough
xen_specific_ss.add(files(
diff --git a/hw/xen/trace-events b/hw/xen/trace-events
index d1b27f6..b67942d 100644
--- a/hw/xen/trace-events
+++ b/hw/xen/trace-events
@@ -38,7 +38,7 @@ xen_device_remove_watch(const char *type, char *name, const char *node, const ch
xs_node_create(const char *node) "%s"
xs_node_destroy(const char *node) "%s"
xs_node_vprintf(char *path, char *value) "%s %s"
-xs_node_vscanf(char *path, char *value) "%s %s"
+xs_node_read(const char *path, const char *value) "%s %s"
xs_node_watch(char *path) "%s"
xs_node_unwatch(char *path) "%s"
@@ -64,6 +64,10 @@ destroy_hvm_domain_cannot_acquire_handle(void) "Cannot acquire xenctrl handle"
destroy_hvm_domain_failed_action(const char *action, int sts, char *errno_s) "xc_domain_shutdown failed to issue %s, sts %d, %s"
destroy_hvm_domain_action(int xen_domid, const char *action) "Issued domain %d %s"
+# xen-pvh-common.c
+xen_create_virtio_mmio_devices(int i, int irq, uint64_t base) "Created virtio-mmio device %d: irq %d base 0x%"PRIx64
+xen_enable_tpm(uint64_t addr) "Connected tpmdev at address 0x%"PRIx64
+
# xen-mapcache.c
xen_map_cache(uint64_t phys_addr) "want 0x%"PRIx64
xen_remap_bucket(uint64_t index) "index 0x%"PRIx64
diff --git a/hw/xen/xen-bus-helper.c b/hw/xen/xen-bus-helper.c
index b2b2cc9..288fad4 100644
--- a/hw/xen/xen-bus-helper.c
+++ b/hw/xen/xen-bus-helper.c
@@ -105,25 +105,22 @@ int xs_node_vscanf(struct qemu_xs_handle *h, xs_transaction_t tid,
const char *node, const char *key, Error **errp,
const char *fmt, va_list ap)
{
- char *path, *value;
+ char *value;
int rc;
- path = (strlen(node) != 0) ? g_strdup_printf("%s/%s", node, key) :
- g_strdup(key);
- value = qemu_xen_xs_read(h, tid, path, NULL);
-
- trace_xs_node_vscanf(path, value);
+ if (node && strlen(node) != 0) {
+ value = xs_node_read(h, tid, NULL, errp, "%s/%s", node, key);
+ } else {
+ value = xs_node_read(h, tid, NULL, errp, "%s", key);
+ }
if (value) {
rc = vsscanf(value, fmt, ap);
} else {
- error_setg_errno(errp, errno, "failed to read from '%s'",
- path);
rc = EOF;
}
free(value);
- g_free(path);
return rc;
}
@@ -142,6 +139,28 @@ int xs_node_scanf(struct qemu_xs_handle *h, xs_transaction_t tid,
return rc;
}
+char *xs_node_read(struct qemu_xs_handle *h, xs_transaction_t tid,
+ unsigned int *len, Error **errp,
+ const char *path_fmt, ...)
+{
+ char *path, *value;
+ va_list ap;
+
+ va_start(ap, path_fmt);
+ path = g_strdup_vprintf(path_fmt, ap);
+ va_end(ap);
+
+ value = qemu_xen_xs_read(h, tid, path, len);
+ trace_xs_node_read(path, value);
+ if (!value) {
+ error_setg_errno(errp, errno, "failed to read from '%s'", path);
+ }
+
+ g_free(path);
+
+ return value;
+}
+
struct qemu_xs_watch *xs_node_watch(struct qemu_xs_handle *h, const char *node,
const char *key, xs_watch_fn fn,
void *opaque, Error **errp)
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 95b207a..6bd2e54 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -18,8 +18,8 @@
#include "hw/xen/xen-bus-helper.h"
#include "monitor/monitor.h"
#include "qapi/error.h"
-#include "qapi/qmp/qdict.h"
-#include "sysemu/sysemu.h"
+#include "qobject/qdict.h"
+#include "system/system.h"
#include "net/net.h"
#include "trace.h"
@@ -156,8 +156,8 @@ again:
!strcmp(key[i], "hotplug-status"))
continue;
- if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
- &val) == 1) {
+ val = xs_node_read(xenbus->xsh, tid, NULL, NULL, "%s/%s", path, key[i]);
+ if (val) {
qdict_put_str(opts, key[i], val);
free(val);
}
@@ -353,10 +353,10 @@ static void xen_bus_realize(BusState *bus, Error **errp)
xs_node_watch(xenbus->xsh, node, key, xen_bus_backend_changed,
xenbus, &local_err);
if (local_err) {
- /* This need not be treated as a hard error so don't propagate */
- error_reportf_err(local_err,
- "failed to set up '%s' enumeration watch: ",
- type[i]);
+ warn_reportf_err(local_err,
+ "failed to set up '%s' enumeration watch: ",
+ type[i]);
+ local_err = NULL;
}
g_free(node);
@@ -380,7 +380,7 @@ static void xen_bus_unplug_request(HotplugHandler *hotplug,
xen_device_unplug(xendev, errp);
}
-static void xen_bus_class_init(ObjectClass *class, void *data)
+static void xen_bus_class_init(ObjectClass *class, const void *data)
{
BusClass *bus_class = BUS_CLASS(class);
HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
@@ -399,7 +399,7 @@ static const TypeInfo xen_bus_type_info = {
.instance_size = sizeof(XenBus),
.class_size = sizeof(XenBusClass),
.class_init = xen_bus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
},
@@ -650,6 +650,16 @@ int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
return rc;
}
+char *xen_device_frontend_read(XenDevice *xendev, const char *key)
+{
+ XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
+
+ g_assert(xenbus->xsh);
+
+ return xs_node_read(xenbus->xsh, XBT_NULL, NULL, NULL, "%s/%s",
+ xendev->frontend_path, key);
+}
+
static void xen_device_frontend_set_state(XenDevice *xendev,
enum xenbus_state state,
bool publish)
@@ -1092,13 +1102,12 @@ unrealize:
xen_device_unrealize(dev);
}
-static Property xen_device_props[] = {
+static const Property xen_device_props[] = {
DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
DOMID_INVALID),
- DEFINE_PROP_END_OF_LIST()
};
-static void xen_device_class_init(ObjectClass *class, void *data)
+static void xen_device_class_init(ObjectClass *class, const void *data)
{
DeviceClass *dev_class = DEVICE_CLASS(class);
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
index 8c6e9a1..eaf32f2 100644
--- a/hw/xen/xen-host-pci-device.c
+++ b/hw/xen/xen-host-pci-device.c
@@ -9,6 +9,8 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
+#include "hw/xen/xen-legacy-backend.h"
+#include "hw/xen/xen-bus-helper.h"
#include "xen-host-pci-device.h"
#define XEN_HOST_PCI_MAX_EXT_CAP \
@@ -33,13 +35,73 @@
#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
#define IORESOURCE_MEM_64 0x00100000
+/*
+ * Non-passthrough (dom0) accesses are local PCI devices and use the given BDF
+ * Passthough (stubdom) accesses are through PV frontend PCI device. Those
+ * either have a BDF identical to the backend's BDF (xen-backend.passthrough=1)
+ * or a local virtual BDF (xen-backend.passthrough=0)
+ *
+ * We are always given the backend's BDF and need to lookup the appropriate
+ * local BDF for sysfs access.
+ */
+static void xen_host_pci_fill_local_addr(XenHostPCIDevice *d, Error **errp)
+{
+ unsigned int num_devs, len, i;
+ unsigned int domain, bus, dev, func;
+ char *be_path = NULL;
+ char path[16];
+
+ be_path = qemu_xen_xs_read(xenstore, 0, "device/pci/0/backend", &len);
+ if (!be_path) {
+ error_setg(errp, "Failed to read device/pci/0/backend");
+ goto out;
+ }
+
+ if (xs_node_scanf(xenstore, 0, be_path, "num_devs", NULL,
+ "%d", &num_devs) != 1) {
+ error_setg(errp, "Failed to read or parse %s/num_devs", be_path);
+ goto out;
+ }
+
+ for (i = 0; i < num_devs; i++) {
+ snprintf(path, sizeof(path), "dev-%d", i);
+ if (xs_node_scanf(xenstore, 0, be_path, path, NULL,
+ "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
+ error_setg(errp, "Failed to read or parse %s/%s", be_path, path);
+ goto out;
+ }
+ if (domain != d->domain ||
+ bus != d->bus ||
+ dev != d->dev ||
+ func != d->func)
+ continue;
+ snprintf(path, sizeof(path), "vdev-%d", i);
+ if (xs_node_scanf(xenstore, 0, be_path, path, NULL,
+ "%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
+ error_setg(errp, "Failed to read or parse %s/%s", be_path, path);
+ goto out;
+ }
+ d->local_domain = domain;
+ d->local_bus = bus;
+ d->local_dev = dev;
+ d->local_func = func;
+ goto out;
+ }
+ error_setg(errp, "Failed to find PCI device %x:%x:%x.%x in xenstore",
+ d->domain, d->bus, d->dev, d->func);
+
+out:
+ free(be_path);
+}
+
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);
+ d->local_domain, d->local_bus, d->local_dev, d->local_func,
+ name);
assert(rc >= 0 && rc < size);
}
@@ -342,6 +404,18 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
d->dev = dev;
d->func = func;
+ if (xen_is_stubdomain) {
+ xen_host_pci_fill_local_addr(d, errp);
+ if (*errp) {
+ goto error;
+ }
+ } else {
+ d->local_domain = d->domain;
+ d->local_bus = d->bus;
+ d->local_dev = d->dev;
+ d->local_func = d->func;
+ }
+
xen_host_pci_config_open(d, errp);
if (*errp) {
goto error;
diff --git a/hw/xen/xen-host-pci-device.h b/hw/xen/xen-host-pci-device.h
index 4d8d34e..270dcb2 100644
--- a/hw/xen/xen-host-pci-device.h
+++ b/hw/xen/xen-host-pci-device.h
@@ -23,6 +23,12 @@ typedef struct XenHostPCIDevice {
uint8_t dev;
uint8_t func;
+ /* different from the above in case of stubdomain */
+ uint16_t local_domain;
+ uint8_t local_bus;
+ uint8_t local_dev;
+ uint8_t local_func;
+
uint16_t vendor_id;
uint16_t device_id;
uint32_t class_code;
diff --git a/hw/xen/xen-hvm-common.c b/hw/xen/xen-hvm-common.c
index b8ace1c..78e0bc8 100644
--- a/hw/xen/xen-hvm-common.c
+++ b/hw/xen/xen-hvm-common.c
@@ -1,14 +1,21 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
+#include "qemu/error-report.h"
#include "qapi/error.h"
+#include "exec/target_long.h"
#include "exec/target_page.h"
#include "trace.h"
+#include "hw/hw.h"
#include "hw/pci/pci_host.h"
#include "hw/xen/xen-hvm-common.h"
#include "hw/xen/xen-bus.h"
#include "hw/boards.h"
#include "hw/xen/arch_hvm.h"
+#include "system/runstate.h"
+#include "system/system.h"
+#include "system/xen.h"
+#include "system/xen-mapcache.h"
MemoryRegion xen_memory, xen_grants;
@@ -475,11 +482,11 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req)
}
}
-static bool handle_buffered_iopage(XenIOState *state)
+static unsigned int handle_buffered_iopage(XenIOState *state)
{
buffered_iopage_t *buf_page = state->buffered_io_page;
buf_ioreq_t *buf_req = NULL;
- bool handled_ioreq = false;
+ unsigned int handled = 0;
ioreq_t req;
int qw;
@@ -492,7 +499,7 @@ static bool handle_buffered_iopage(XenIOState *state)
req.count = 1;
req.dir = IOREQ_WRITE;
- for (;;) {
+ do {
uint32_t rdptr = buf_page->read_pointer, wrptr;
xen_rmb();
@@ -533,22 +540,30 @@ static bool handle_buffered_iopage(XenIOState *state)
assert(!req.data_is_ptr);
qatomic_add(&buf_page->read_pointer, qw + 1);
- handled_ioreq = true;
- }
+ handled += qw + 1;
+ } while (handled < IOREQ_BUFFER_SLOT_NUM);
- return handled_ioreq;
+ return handled;
}
static void handle_buffered_io(void *opaque)
{
+ unsigned int handled;
XenIOState *state = opaque;
- if (handle_buffered_iopage(state)) {
+ handled = handle_buffered_iopage(state);
+ if (handled >= IOREQ_BUFFER_SLOT_NUM) {
+ /* We handled a full page of ioreqs. Schedule a timer to continue
+ * processing while giving other stuff a chance to run.
+ */
timer_mod(state->buffered_io_timer,
- BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
- } else {
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
+ } else if (handled == 0) {
timer_del(state->buffered_io_timer);
qemu_xen_evtchn_unmask(state->xce_handle, state->bufioreq_local_port);
+ } else {
+ timer_mod(state->buffered_io_timer,
+ BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
}
}
@@ -659,6 +674,8 @@ static int xen_map_ioreq_server(XenIOState *state)
xen_pfn_t ioreq_pfn;
xen_pfn_t bufioreq_pfn;
evtchn_port_t bufioreq_evtchn;
+ unsigned long num_frames = 1;
+ unsigned long frame = 1;
int rc;
/*
@@ -667,65 +684,85 @@ static int xen_map_ioreq_server(XenIOState *state)
*/
QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_bufioreq != 0);
QEMU_BUILD_BUG_ON(XENMEM_resource_ioreq_server_frame_ioreq(0) != 1);
+
+ if (state->has_bufioreq) {
+ frame = 0;
+ num_frames = 2;
+ }
state->fres = xenforeignmemory_map_resource(xen_fmem, xen_domid,
XENMEM_resource_ioreq_server,
- state->ioservid, 0, 2,
+ state->ioservid,
+ frame, num_frames,
&addr,
PROT_READ | PROT_WRITE, 0);
if (state->fres != NULL) {
trace_xen_map_resource_ioreq(state->ioservid, addr);
- state->buffered_io_page = addr;
- state->shared_page = addr + XC_PAGE_SIZE;
+ state->shared_page = addr;
+ if (state->has_bufioreq) {
+ state->buffered_io_page = addr;
+ state->shared_page = addr + XC_PAGE_SIZE;
+ }
} else if (errno != EOPNOTSUPP) {
error_report("failed to map ioreq server resources: error %d handle=%p",
errno, xen_xc);
return -1;
}
- rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
- (state->shared_page == NULL) ?
- &ioreq_pfn : NULL,
- (state->buffered_io_page == NULL) ?
- &bufioreq_pfn : NULL,
- &bufioreq_evtchn);
- if (rc < 0) {
- error_report("failed to get ioreq server info: error %d handle=%p",
- errno, xen_xc);
- return rc;
- }
+ /*
+ * If we fail to map the shared page with xenforeignmemory_map_resource()
+ * or if we're using buffered ioreqs, we need xen_get_ioreq_server_info()
+ * to provide the addresses to map the shared page and/or to get the
+ * event-channel port for buffered ioreqs.
+ */
+ if (state->shared_page == NULL || state->has_bufioreq) {
+ rc = xen_get_ioreq_server_info(xen_domid, state->ioservid,
+ (state->shared_page == NULL) ?
+ &ioreq_pfn : NULL,
+ (state->has_bufioreq &&
+ state->buffered_io_page == NULL) ?
+ &bufioreq_pfn : NULL,
+ &bufioreq_evtchn);
+ if (rc < 0) {
+ error_report("failed to get ioreq server info: error %d handle=%p",
+ errno, xen_xc);
+ return rc;
+ }
- if (state->shared_page == NULL) {
- trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
+ if (state->shared_page == NULL) {
+ trace_xen_map_ioreq_server_shared_page(ioreq_pfn);
- state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
- 1, &ioreq_pfn, NULL);
+ state->shared_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &ioreq_pfn, NULL);
+ }
if (state->shared_page == NULL) {
error_report("map shared IO page returned error %d handle=%p",
errno, xen_xc);
}
- }
- if (state->buffered_io_page == NULL) {
- trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
+ if (state->has_bufioreq && state->buffered_io_page == NULL) {
+ trace_xen_map_ioreq_server_buffered_io_page(bufioreq_pfn);
- state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
- PROT_READ | PROT_WRITE,
- 1, &bufioreq_pfn,
- NULL);
- if (state->buffered_io_page == NULL) {
- error_report("map buffered IO page returned error %d", errno);
- return -1;
+ state->buffered_io_page = xenforeignmemory_map(xen_fmem, xen_domid,
+ PROT_READ | PROT_WRITE,
+ 1, &bufioreq_pfn,
+ NULL);
+ if (state->buffered_io_page == NULL) {
+ error_report("map buffered IO page returned error %d", errno);
+ return -1;
+ }
}
}
- if (state->shared_page == NULL || state->buffered_io_page == NULL) {
+ if (state->shared_page == NULL ||
+ (state->has_bufioreq && state->buffered_io_page == NULL)) {
return -1;
}
- trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
-
- state->bufioreq_remote_port = bufioreq_evtchn;
+ if (state->has_bufioreq) {
+ trace_xen_map_ioreq_server_buffered_io_evtchn(bufioreq_evtchn);
+ state->bufioreq_remote_port = bufioreq_evtchn;
+ }
return 0;
}
@@ -822,14 +859,15 @@ static void xen_do_ioreq_register(XenIOState *state,
state->ioreq_local_port[i] = rc;
}
- rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
- state->bufioreq_remote_port);
- if (rc == -1) {
- error_report("buffered evtchn bind error %d", errno);
- goto err;
+ if (state->has_bufioreq) {
+ rc = qemu_xen_evtchn_bind_interdomain(state->xce_handle, xen_domid,
+ state->bufioreq_remote_port);
+ if (rc == -1) {
+ error_report("buffered evtchn bind error %d", errno);
+ goto err;
+ }
+ state->bufioreq_local_port = rc;
}
- state->bufioreq_local_port = rc;
-
/* Init RAM management */
#ifdef XEN_COMPAT_PHYSMAP
xen_map_cache_init(xen_phys_offset_to_gaddr, state);
@@ -857,6 +895,7 @@ err:
}
void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
+ uint8_t handle_bufioreq,
const MemoryListener *xen_memory_listener)
{
int rc;
@@ -875,7 +914,8 @@ void xen_register_ioreq(XenIOState *state, unsigned int max_cpus,
goto err;
}
- rc = xen_create_ioreq_server(xen_domid, &state->ioservid);
+ state->has_bufioreq = handle_bufioreq != HVM_IOREQSRV_BUFIOREQ_OFF;
+ rc = xen_create_ioreq_server(xen_domid, handle_bufioreq, &state->ioservid);
if (!rc) {
xen_do_ioreq_register(state, max_cpus, xen_memory_listener);
} else {
diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c
index 5514184..5ed53f8 100644
--- a/hw/xen/xen-legacy-backend.c
+++ b/hw/xen/xen-legacy-backend.c
@@ -147,24 +147,6 @@ void xen_be_unmap_grant_refs(struct XenLegacyDevice *xendev, void *ptr,
}
}
-int xen_be_copy_grant_refs(struct XenLegacyDevice *xendev,
- bool to_domain,
- XenGrantCopySegment segs[],
- unsigned int nr_segs)
-{
- int rc;
-
- assert(xendev->ops->flags & DEVOPS_FLAG_NEED_GNTDEV);
-
- rc = qemu_xen_gnttab_grant_copy(xendev->gnttabdev, to_domain, xen_domid,
- segs, nr_segs, NULL);
- if (rc) {
- xen_pv_printf(xendev, 0, "xengnttab_grant_copy failed: %s\n",
- strerror(-rc));
- }
- return rc;
-}
-
/*
* get xen backend device, allocate a new one if it doesn't exist.
*/
@@ -181,7 +163,7 @@ static struct XenLegacyDevice *xen_be_get_xendev(const char *type, int dom,
/* init new xendev */
xendev = g_malloc0(ops->size);
- object_initialize(&xendev->qdev, ops->size, TYPE_XENBACKEND);
+ object_initialize(xendev, ops->size, TYPE_XENBACKEND);
OBJECT(xendev)->free = g_free;
qdev_set_id(DEVICE(xendev), g_strdup_printf("xen-%s-%d", type, dev),
&error_fatal);
@@ -653,29 +635,22 @@ int xen_be_bind_evtchn(struct XenLegacyDevice *xendev)
}
-static Property xendev_properties[] = {
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xendev_class_init(ObjectClass *klass, void *data)
+static void xendev_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- device_class_set_props(dc, xendev_properties);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
- /* xen-backend devices can be plugged/unplugged dynamically */
- dc->user_creatable = true;
dc->bus_type = TYPE_XENSYSBUS;
}
static const TypeInfo xendev_type_info = {
.name = TYPE_XENBACKEND,
- .parent = TYPE_DEVICE,
+ .parent = TYPE_DYNAMIC_SYS_BUS_DEVICE,
.class_init = xendev_class_init,
- .instance_size = sizeof(struct XenLegacyDevice),
+ .instance_size = sizeof(XenLegacyDevice),
};
-static void xen_sysbus_class_init(ObjectClass *klass, void *data)
+static void xen_sysbus_class_init(ObjectClass *klass, const void *data)
{
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
@@ -686,28 +661,15 @@ static const TypeInfo xensysbus_info = {
.name = TYPE_XENSYSBUS,
.parent = TYPE_BUS,
.class_init = xen_sysbus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
};
-static Property xen_sysdev_properties[] = {
- {/* end of property list */},
-};
-
-static void xen_sysdev_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
-
- device_class_set_props(dc, xen_sysdev_properties);
-}
-
static const TypeInfo xensysdev_info = {
.name = TYPE_XENSYSDEV,
.parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(SysBusDevice),
- .class_init = xen_sysdev_class_init,
};
static void xenbe_register_types(void)
diff --git a/hw/xen/xen-mapcache.c b/hw/xen/xen-mapcache.c
index 5f23b0a..e31d379 100644
--- a/hw/xen/xen-mapcache.c
+++ b/hw/xen/xen-mapcache.c
@@ -18,8 +18,8 @@
#include "hw/xen/xen_native.h"
#include "qemu/bitmap.h"
-#include "sysemu/runstate.h"
-#include "sysemu/xen-mapcache.h"
+#include "system/runstate.h"
+#include "system/xen-mapcache.h"
#include "trace.h"
#include <xenevtchn.h>
@@ -75,7 +75,8 @@ typedef struct MapCache {
} MapCache;
static MapCache *mapcache;
-static MapCache *mapcache_grants;
+static MapCache *mapcache_grants_ro;
+static MapCache *mapcache_grants_rw;
static xengnttab_handle *xen_region_gnttabdev;
static inline void mapcache_lock(MapCache *mc)
@@ -176,9 +177,12 @@ void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque)
* Grant mappings must use XC_PAGE_SIZE granularity since we can't
* map anything beyond the number of pages granted to us.
*/
- mapcache_grants = xen_map_cache_init_single(f, opaque,
- XC_PAGE_SHIFT,
- max_mcache_size);
+ mapcache_grants_ro = xen_map_cache_init_single(f, opaque,
+ XC_PAGE_SHIFT,
+ max_mcache_size);
+ mapcache_grants_rw = xen_map_cache_init_single(f, opaque,
+ XC_PAGE_SHIFT,
+ max_mcache_size);
setrlimit(RLIMIT_AS, &rlimit_as);
}
@@ -376,12 +380,12 @@ tryagain:
entry = &mc->entry[address_index % mc->nr_buckets];
- while (entry && (lock || entry->lock) && entry->vaddr_base &&
- (entry->paddr_index != address_index || entry->size != cache_size ||
+ while (entry && (!entry->vaddr_base ||
+ entry->paddr_index != address_index || entry->size != cache_size ||
!test_bits(address_offset >> XC_PAGE_SHIFT,
test_bit_size >> XC_PAGE_SHIFT,
entry->valid_mapping))) {
- if (!free_entry && !entry->lock) {
+ if (!free_entry && (!entry->lock || !entry->vaddr_base)) {
free_entry = entry;
free_pentry = pentry;
}
@@ -456,9 +460,13 @@ uint8_t *xen_map_cache(MemoryRegion *mr,
bool is_write)
{
bool grant = xen_mr_is_grants(mr);
- MapCache *mc = grant ? mapcache_grants : mapcache;
+ MapCache *mc = mapcache;
uint8_t *p;
+ if (grant) {
+ mc = is_write ? mapcache_grants_rw : mapcache_grants_ro;
+ }
+
if (grant && !lock) {
/*
* Grants are only supported via address_space_map(). Anything
@@ -523,7 +531,10 @@ ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
addr = xen_ram_addr_from_mapcache_single(mapcache, ptr);
if (addr == RAM_ADDR_INVALID) {
- addr = xen_ram_addr_from_mapcache_single(mapcache_grants, ptr);
+ addr = xen_ram_addr_from_mapcache_single(mapcache_grants_ro, ptr);
+ }
+ if (addr == RAM_ADDR_INVALID) {
+ addr = xen_ram_addr_from_mapcache_single(mapcache_grants_rw, ptr);
}
return addr;
@@ -597,7 +608,17 @@ static void xen_invalidate_map_cache_entry_unlocked(MapCache *mc,
pentry->next = entry->next;
g_free(entry);
} else {
- memset(entry, 0, sizeof *entry);
+ /*
+ * Invalidate mapping but keep entry->next pointing to the rest
+ * of the list.
+ *
+ * Note that lock is already zero here, otherwise we don't unmap.
+ */
+ entry->paddr_index = 0;
+ entry->vaddr_base = NULL;
+ entry->valid_mapping = NULL;
+ entry->flags = 0;
+ entry->size = 0;
}
}
@@ -616,7 +637,8 @@ static void xen_invalidate_map_cache_entry_single(MapCache *mc, uint8_t *buffer)
static void xen_invalidate_map_cache_entry_all(uint8_t *buffer)
{
xen_invalidate_map_cache_entry_single(mapcache, buffer);
- xen_invalidate_map_cache_entry_single(mapcache_grants, buffer);
+ xen_invalidate_map_cache_entry_single(mapcache_grants_ro, buffer);
+ xen_invalidate_map_cache_entry_single(mapcache_grants_rw, buffer);
}
static void xen_invalidate_map_cache_entry_bh(void *opaque)
@@ -690,7 +712,6 @@ void xen_invalidate_map_cache(void)
bdrv_drain_all();
xen_invalidate_map_cache_single(mapcache);
- xen_invalidate_map_cache_single(mapcache_grants);
}
static uint8_t *xen_replace_cache_entry_unlocked(MapCache *mc,
diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c
new file mode 100644
index 0000000..b93ff80
--- /dev/null
+++ b/hw/xen/xen-pvh-common.c
@@ -0,0 +1,399 @@
+/*
+ * QEMU Xen PVH machine - common code.
+ *
+ * Copyright (c) 2024 Advanced Micro Devices, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "qemu/units.h"
+#include "qapi/visitor.h"
+#include "hw/boards.h"
+#include "hw/irq.h"
+#include "system/tpm.h"
+#include "system/tpm_backend.h"
+#include "system/runstate.h"
+#include "hw/xen/xen-pvh-common.h"
+#include "trace.h"
+
+static const MemoryListener xen_memory_listener = {
+ .region_add = xen_region_add,
+ .region_del = xen_region_del,
+ .log_start = NULL,
+ .log_stop = NULL,
+ .log_sync = NULL,
+ .log_global_start = NULL,
+ .log_global_stop = NULL,
+ .priority = MEMORY_LISTENER_PRIORITY_ACCEL,
+};
+
+static void xen_pvh_init_ram(XenPVHMachineState *s,
+ MemoryRegion *sysmem)
+{
+ MachineState *ms = MACHINE(s);
+ ram_addr_t block_len, ram_size[2];
+
+ if (ms->ram_size <= s->cfg.ram_low.size) {
+ ram_size[0] = ms->ram_size;
+ ram_size[1] = 0;
+ block_len = s->cfg.ram_low.base + ram_size[0];
+ } else {
+ ram_size[0] = s->cfg.ram_low.size;
+ ram_size[1] = ms->ram_size - s->cfg.ram_low.size;
+ block_len = s->cfg.ram_high.base + ram_size[1];
+ }
+
+ memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
+ &error_fatal);
+
+ memory_region_init_alias(&s->ram.low, NULL, "xen.ram.lo", &xen_memory,
+ s->cfg.ram_low.base, ram_size[0]);
+ memory_region_add_subregion(sysmem, s->cfg.ram_low.base, &s->ram.low);
+ if (ram_size[1] > 0) {
+ memory_region_init_alias(&s->ram.high, NULL, "xen.ram.hi", &xen_memory,
+ s->cfg.ram_high.base, ram_size[1]);
+ memory_region_add_subregion(sysmem, s->cfg.ram_high.base, &s->ram.high);
+ }
+
+ /* Setup support for grants. */
+ memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
+ &error_fatal);
+ memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
+}
+
+static void xen_set_irq(void *opaque, int irq, int level)
+{
+ if (xendevicemodel_set_irq_level(xen_dmod, xen_domid, irq, level)) {
+ error_report("xendevicemodel_set_irq_level failed");
+ }
+}
+
+static void xen_create_virtio_mmio_devices(XenPVHMachineState *s)
+{
+ int i;
+
+ /*
+ * We create the transports in reverse order. Since qbus_realize()
+ * prepends (not appends) new child buses, the decrementing loop below will
+ * create a list of virtio-mmio buses with increasing base addresses.
+ *
+ * When a -device option is processed from the command line,
+ * qbus_find_recursive() picks the next free virtio-mmio bus in forwards
+ * order.
+ *
+ * This is what the Xen tools expect.
+ */
+ for (i = s->cfg.virtio_mmio_num - 1; i >= 0; i--) {
+ hwaddr base = s->cfg.virtio_mmio.base + i * s->cfg.virtio_mmio.size;
+ qemu_irq irq = qemu_allocate_irq(xen_set_irq, NULL,
+ s->cfg.virtio_mmio_irq_base + i);
+
+ sysbus_create_simple("virtio-mmio", base, irq);
+
+ trace_xen_create_virtio_mmio_devices(i,
+ s->cfg.virtio_mmio_irq_base + i,
+ base);
+ }
+}
+
+#ifdef CONFIG_TPM
+static void xen_enable_tpm(XenPVHMachineState *s)
+{
+ Error *errp = NULL;
+ DeviceState *dev;
+ SysBusDevice *busdev;
+
+ TPMBackend *be = qemu_find_tpm_be("tpm0");
+ if (be == NULL) {
+ error_report("Couldn't find tmp0 backend");
+ return;
+ }
+ dev = qdev_new(TYPE_TPM_TIS_SYSBUS);
+ object_property_set_link(OBJECT(dev), "tpmdev", OBJECT(be), &errp);
+ object_property_set_str(OBJECT(dev), "tpmdev", be->id, &errp);
+ busdev = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(busdev, &error_fatal);
+ sysbus_mmio_map(busdev, 0, s->cfg.tpm.base);
+
+ trace_xen_enable_tpm(s->cfg.tpm.base);
+}
+#endif
+
+/*
+ * We use the GPEX PCIe controller with its internal INTX PCI interrupt
+ * swizzling. This swizzling is emulated in QEMU and routes all INTX
+ * interrupts from endpoints down to only 4 INTX interrupts.
+ * See include/hw/pci/pci.h : pci_swizzle()
+ */
+static inline void xenpvh_gpex_init(XenPVHMachineState *s,
+ XenPVHMachineClass *xpc,
+ MemoryRegion *sysmem)
+{
+ MemoryRegion *ecam_reg;
+ MemoryRegion *mmio_reg;
+ DeviceState *dev;
+ int i;
+
+ object_initialize_child(OBJECT(s), "gpex", &s->pci.gpex,
+ TYPE_GPEX_HOST);
+ dev = DEVICE(&s->pci.gpex);
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+ ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+ memory_region_add_subregion(sysmem, s->cfg.pci_ecam.base, ecam_reg);
+
+ mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
+
+ if (s->cfg.pci_mmio.size) {
+ memory_region_init_alias(&s->pci.mmio_alias, OBJECT(dev), "pcie-mmio",
+ mmio_reg,
+ s->cfg.pci_mmio.base, s->cfg.pci_mmio.size);
+ memory_region_add_subregion(sysmem, s->cfg.pci_mmio.base,
+ &s->pci.mmio_alias);
+ }
+
+ if (s->cfg.pci_mmio_high.size) {
+ memory_region_init_alias(&s->pci.mmio_high_alias, OBJECT(dev),
+ "pcie-mmio-high",
+ mmio_reg, s->cfg.pci_mmio_high.base, s->cfg.pci_mmio_high.size);
+ memory_region_add_subregion(sysmem, s->cfg.pci_mmio_high.base,
+ &s->pci.mmio_high_alias);
+ }
+
+ /*
+ * PVH implementations with PCI enabled must provide set_pci_intx_irq()
+ * and optionally an implementation of set_pci_link_route().
+ */
+ assert(xpc->set_pci_intx_irq);
+
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ qemu_irq irq = qemu_allocate_irq(xpc->set_pci_intx_irq, s, i);
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
+ gpex_set_irq_num(GPEX_HOST(dev), i, s->cfg.pci_intx_irq_base + i);
+ if (xpc->set_pci_link_route) {
+ xpc->set_pci_link_route(i, s->cfg.pci_intx_irq_base + i);
+ }
+ }
+}
+
+static void xen_pvh_init(MachineState *ms)
+{
+ XenPVHMachineState *s = XEN_PVH_MACHINE(ms);
+ XenPVHMachineClass *xpc = XEN_PVH_MACHINE_GET_CLASS(s);
+ MemoryRegion *sysmem = get_system_memory();
+
+ if (ms->ram_size == 0) {
+ warn_report("%s: ram size not specified. QEMU machine started"
+ " without IOREQ (no emulated devices including virtio)",
+ MACHINE_CLASS(object_get_class(OBJECT(ms)))->desc);
+ return;
+ }
+
+ xen_pvh_init_ram(s, sysmem);
+ xen_register_ioreq(&s->ioreq, ms->smp.max_cpus,
+ xpc->handle_bufioreq,
+ &xen_memory_listener);
+
+ if (s->cfg.virtio_mmio_num) {
+ xen_create_virtio_mmio_devices(s);
+ }
+
+#ifdef CONFIG_TPM
+ if (xpc->has_tpm) {
+ if (s->cfg.tpm.base) {
+ xen_enable_tpm(s);
+ } else {
+ warn_report("tpm-base-addr is not set. TPM will not be enabled");
+ }
+ }
+#endif
+
+ /* Non-zero pci-ecam-size enables PCI. */
+ if (s->cfg.pci_ecam.size) {
+ if (s->cfg.pci_ecam.size != 256 * MiB) {
+ error_report("pci-ecam-size only supports values 0 or 0x10000000");
+ exit(EXIT_FAILURE);
+ }
+ if (!s->cfg.pci_intx_irq_base) {
+ error_report("PCI enabled but pci-intx-irq-base not set");
+ exit(EXIT_FAILURE);
+ }
+
+ xenpvh_gpex_init(s, xpc, sysmem);
+ }
+
+ /* Call the implementation specific init. */
+ if (xpc->init) {
+ xpc->init(ms);
+ }
+}
+
+#define XEN_PVH_PROP_MEMMAP_SETTER(n, f) \
+static void xen_pvh_set_ ## n ## _ ## f(Object *obj, Visitor *v, \
+ const char *name, void *opaque, \
+ Error **errp) \
+{ \
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \
+ uint64_t value; \
+ \
+ if (!visit_type_size(v, name, &value, errp)) { \
+ return; \
+ } \
+ xp->cfg.n.f = value; \
+}
+
+#define XEN_PVH_PROP_MEMMAP_GETTER(n, f) \
+static void xen_pvh_get_ ## n ## _ ## f(Object *obj, Visitor *v, \
+ const char *name, void *opaque, \
+ Error **errp) \
+{ \
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj); \
+ uint64_t value = xp->cfg.n.f; \
+ \
+ visit_type_uint64(v, name, &value, errp); \
+}
+
+#define XEN_PVH_PROP_MEMMAP_BASE(n) \
+ XEN_PVH_PROP_MEMMAP_SETTER(n, base) \
+ XEN_PVH_PROP_MEMMAP_GETTER(n, base) \
+
+#define XEN_PVH_PROP_MEMMAP_SIZE(n) \
+ XEN_PVH_PROP_MEMMAP_SETTER(n, size) \
+ XEN_PVH_PROP_MEMMAP_GETTER(n, size)
+
+#define XEN_PVH_PROP_MEMMAP(n) \
+ XEN_PVH_PROP_MEMMAP_BASE(n) \
+ XEN_PVH_PROP_MEMMAP_SIZE(n)
+
+XEN_PVH_PROP_MEMMAP(ram_low)
+XEN_PVH_PROP_MEMMAP(ram_high)
+/* TPM only has a base-addr option. */
+XEN_PVH_PROP_MEMMAP_BASE(tpm)
+XEN_PVH_PROP_MEMMAP(virtio_mmio)
+XEN_PVH_PROP_MEMMAP(pci_ecam)
+XEN_PVH_PROP_MEMMAP(pci_mmio)
+XEN_PVH_PROP_MEMMAP(pci_mmio_high)
+
+static void xen_pvh_set_pci_intx_irq_base(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
+ uint32_t value;
+
+ if (!visit_type_uint32(v, name, &value, errp)) {
+ return;
+ }
+
+ xp->cfg.pci_intx_irq_base = value;
+}
+
+static void xen_pvh_get_pci_intx_irq_base(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
+{
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
+ uint32_t value = xp->cfg.pci_intx_irq_base;
+
+ visit_type_uint32(v, name, &value, errp);
+}
+
+void xen_pvh_class_setup_common_props(XenPVHMachineClass *xpc)
+{
+ ObjectClass *oc = OBJECT_CLASS(xpc);
+ MachineClass *mc = MACHINE_CLASS(xpc);
+
+#define OC_MEMMAP_PROP_BASE(c, prop_name, name) \
+do { \
+ object_class_property_add(c, prop_name "-base", "uint64_t", \
+ xen_pvh_get_ ## name ## _base, \
+ xen_pvh_set_ ## name ## _base, NULL, NULL); \
+ object_class_property_set_description(oc, prop_name "-base", \
+ "Set base address for " prop_name); \
+} while (0)
+
+#define OC_MEMMAP_PROP_SIZE(c, prop_name, name) \
+do { \
+ object_class_property_add(c, prop_name "-size", "uint64_t", \
+ xen_pvh_get_ ## name ## _size, \
+ xen_pvh_set_ ## name ## _size, NULL, NULL); \
+ object_class_property_set_description(oc, prop_name "-size", \
+ "Set memory range size for " prop_name); \
+} while (0)
+
+#define OC_MEMMAP_PROP(c, prop_name, name) \
+do { \
+ OC_MEMMAP_PROP_BASE(c, prop_name, name); \
+ OC_MEMMAP_PROP_SIZE(c, prop_name, name); \
+} while (0)
+
+ /*
+ * We provide memmap properties to allow Xen to move things to other
+ * addresses for example when users need to accomodate the memory-map
+ * for 1:1 mapped devices/memory.
+ */
+ OC_MEMMAP_PROP(oc, "ram-low", ram_low);
+ OC_MEMMAP_PROP(oc, "ram-high", ram_high);
+
+ if (xpc->has_virtio_mmio) {
+ OC_MEMMAP_PROP(oc, "virtio-mmio", virtio_mmio);
+ }
+
+ if (xpc->has_pci) {
+ OC_MEMMAP_PROP(oc, "pci-ecam", pci_ecam);
+ OC_MEMMAP_PROP(oc, "pci-mmio", pci_mmio);
+ OC_MEMMAP_PROP(oc, "pci-mmio-high", pci_mmio_high);
+
+ object_class_property_add(oc, "pci-intx-irq-base", "uint32_t",
+ xen_pvh_get_pci_intx_irq_base,
+ xen_pvh_set_pci_intx_irq_base,
+ NULL, NULL);
+ object_class_property_set_description(oc, "pci-intx-irq-base",
+ "Set PCI INTX interrupt base line.");
+ }
+
+#ifdef CONFIG_TPM
+ if (xpc->has_tpm) {
+ object_class_property_add(oc, "tpm-base-addr", "uint64_t",
+ xen_pvh_get_tpm_base,
+ xen_pvh_set_tpm_base,
+ NULL, NULL);
+ object_class_property_set_description(oc, "tpm-base-addr",
+ "Set Base address for TPM device.");
+
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
+ }
+#endif
+}
+
+static void xen_pvh_class_init(ObjectClass *oc, const void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->init = xen_pvh_init;
+
+ mc->desc = "Xen PVH machine";
+ mc->max_cpus = 1;
+ mc->default_machine_opts = "accel=xen";
+ /* Set to zero to make sure that the real ram size is passed. */
+ mc->default_ram_size = 0;
+}
+
+static const TypeInfo xen_pvh_info = {
+ .name = TYPE_XEN_PVH_MACHINE,
+ .parent = TYPE_MACHINE,
+ .abstract = true,
+ .instance_size = sizeof(XenPVHMachineState),
+ .class_size = sizeof(XenPVHMachineClass),
+ .class_init = xen_pvh_class_init,
+};
+
+static void xen_pvh_register_types(void)
+{
+ type_register_static(&xen_pvh_info);
+}
+
+type_init(xen_pvh_register_types);
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index 2150869..5698cc7 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -1,8 +1,8 @@
#include "qemu/osdep.h"
#include "hw/xen/xen-legacy-backend.h"
#include "qemu/option.h"
-#include "sysemu/blockdev.h"
-#include "sysemu/sysemu.h"
+#include "system/blockdev.h"
+#include "system/system.h"
/* ------------------------------------------------------------- */
@@ -66,11 +66,3 @@ int xen_config_dev_vkbd(int vdev)
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/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index 3635d1b..9d16644 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -766,6 +766,57 @@ static void xen_pt_destroy(PCIDevice *d) {
}
/* init */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 42000
+static bool xen_pt_need_gsi(void)
+{
+ FILE *fp;
+ int len;
+ /*
+ * The max length of guest_type is "PVH"+'\n'+'\0', it is 5,
+ * so here set the length of type to be twice.
+ */
+ char type[10];
+ const char *guest_type = "/sys/hypervisor/guest_type";
+
+ fp = fopen(guest_type, "r");
+ if (!fp) {
+ error_report("Cannot open %s: %s", guest_type, strerror(errno));
+ return false;
+ }
+
+ if (fgets(type, sizeof(type), fp)) {
+ len = strlen(type);
+ if (len) {
+ type[len - 1] = '\0';
+ if (!strcmp(type, "PVH")) {
+ fclose(fp);
+ return true;
+ }
+ }
+ }
+
+ fclose(fp);
+ return false;
+}
+
+static int xen_pt_map_pirq_for_gsi(PCIDevice *d, int *pirq)
+{
+ int gsi;
+ XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
+
+ gsi = xc_pcidev_get_gsi(xen_xc,
+ PCI_SBDF(s->real_device.domain,
+ s->real_device.bus,
+ s->real_device.dev,
+ s->real_device.func));
+ if (gsi >= 0) {
+ return xc_physdev_map_pirq_gsi(xen_xc, xen_domid, gsi, pirq);
+ }
+
+ return gsi;
+}
+#endif
+
static void xen_pt_realize(PCIDevice *d, Error **errp)
{
ERRP_GUARD();
@@ -847,7 +898,16 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
goto out;
}
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION >= 42000
+ if (xen_pt_need_gsi()) {
+ rc = xen_pt_map_pirq_for_gsi(d, &pirq);
+ } else {
+ rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
+ }
+#else
rc = xc_physdev_map_pirq(xen_xc, xen_domid, machine_irq, &pirq);
+#endif
+
if (rc < 0) {
XEN_PT_ERR(d, "Mapping machine irq %u to pirq %i failed, (err: %d)\n",
machine_irq, pirq, errno);
@@ -931,10 +991,9 @@ static void xen_pt_unregister_device(PCIDevice *d)
xen_pt_destroy(d);
}
-static Property xen_pci_passthrough_properties[] = {
+static const 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_instance_init(Object *obj)
@@ -988,7 +1047,7 @@ static void xen_igd_clear_slot(DeviceState *qdev, Error **errp)
xpdc->pci_qdev_realize(qdev, errp);
}
-static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data)
+static void xen_pci_passthrough_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -1020,7 +1079,7 @@ static const TypeInfo xen_pci_passthrough_info = {
.class_init = xen_pci_passthrough_class_init,
.class_size = sizeof(XenPTDeviceClass),
.instance_init = xen_pci_passthrough_instance_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ INTERFACE_PCIE_DEVICE },
{ },
diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c
index 6c2e3f4..2c0cec9 100644
--- a/hw/xen/xen_pt_graphics.c
+++ b/hw/xen/xen_pt_graphics.c
@@ -347,7 +347,7 @@ static const IGDDeviceIDInfo igd_combo_id_infos[] = {
{0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */
};
-static void isa_bridge_class_init(ObjectClass *klass, void *data)
+static void isa_bridge_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
@@ -363,7 +363,7 @@ static const TypeInfo isa_bridge_info = {
.parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PCIDevice),
.class_init = isa_bridge_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ },
},
diff --git a/hw/xen/xen_pt_load_rom.c b/hw/xen/xen_pt_load_rom.c
index 03422a8..6bc64ac 100644
--- a/hw/xen/xen_pt_load_rom.c
+++ b/hw/xen/xen_pt_load_rom.c
@@ -53,7 +53,7 @@ void *pci_assign_dev_load_option_rom(PCIDevice *dev,
}
fseek(fp, 0, SEEK_SET);
- if (dev->romsize != -1) {
+ if (dev->romsize != UINT_MAX) {
if (st.st_size > dev->romsize) {
error_report("ROM BAR \"%s\" (%ld bytes) is too large for ROM size %u",
rom_file, (long) st.st_size, dev->romsize);
diff --git a/hw/xen/xen_pvdev.c b/hw/xen/xen_pvdev.c
index c5ad71e..fe95b62 100644
--- a/hw/xen/xen_pvdev.c
+++ b/hw/xen/xen_pvdev.c
@@ -22,6 +22,7 @@
#include "qemu/main-loop.h"
#include "hw/qdev-core.h"
#include "hw/xen/xen-legacy-backend.h"
+#include "hw/xen/xen-bus-helper.h"
#include "hw/xen/xen_pvdev.h"
/* private */
@@ -81,12 +82,9 @@ int xenstore_write_str(const char *base, const char *node, const char *val)
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 = qemu_xen_xs_read(xenstore, 0, abspath, &len);
+ str = xs_node_read(xenstore, 0, NULL, NULL, "%s/%s", base, node);
if (str != NULL) {
/* move to qemu-allocated memory to make sure
* callers can safely g_free() stuff. */
@@ -275,7 +273,7 @@ void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
QTAILQ_REMOVE(&xendevs, xendev, next);
- qdev_unplug(&xendev->qdev, NULL);
+ qdev_unplug(DEVICE(xendev), NULL);
}
void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
diff --git a/hw/xen/xen_stubs.c b/hw/xen/xen_stubs.c
new file mode 100644
index 0000000..5e565df
--- /dev/null
+++ b/hw/xen/xen_stubs.c
@@ -0,0 +1,51 @@
+/*
+ * Various stubs for xen functions
+ *
+ * Those functions are used only if xen_enabled(). This file is linked only if
+ * CONFIG_XEN is not set, so they should never be called.
+ *
+ * Copyright (c) 2025 Linaro, Ltd.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "system/xen.h"
+#include "system/xen-mapcache.h"
+
+void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length)
+{
+ g_assert_not_reached();
+}
+
+void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size,
+ struct MemoryRegion *mr, Error **errp)
+{
+ g_assert_not_reached();
+}
+
+bool xen_mr_is_memory(MemoryRegion *mr)
+{
+ g_assert_not_reached();
+}
+
+void xen_invalidate_map_cache_entry(uint8_t *buffer)
+{
+ g_assert_not_reached();
+}
+
+ram_addr_t xen_ram_addr_from_mapcache(void *ptr)
+{
+ g_assert_not_reached();
+}
+
+uint8_t *xen_map_cache(MemoryRegion *mr,
+ hwaddr phys_addr,
+ hwaddr size,
+ ram_addr_t ram_addr_offset,
+ uint8_t lock,
+ bool dma,
+ bool is_write)
+{
+ g_assert_not_reached();
+}