Skip to content

Commit 1152a04

Browse files
committed
Merge tag 'pull-xen-20240701' of https://xenbits.xen.org/git-http/people/aperard/qemu-dm into staging
Xen queue: * Improvement for running QEMU in a stubdomain. * Improve handling of buffered ioreqs. # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEE+AwAYwjiLP2KkueYDPVXL9f7Va8FAmaCq2IACgkQDPVXL9f7 # Va9PHQf+N4SGAo8rD6Nw7z73b9/Qd20Pz82Pm3BLnJtioxxOhVPU33HJsyjkQRSs # dVckRZk6IFfiAKWTPDsQfeL+qDBjL15usuZCLeq7zRr5NwV5OOlSh6fW6yurY8IR # zHoCJTjYcaXbMCVIzAXhM19rZjFZCLNFYb3ADRvDANaxbhSx60EAg69S8gQeQhgw # BVC5inDxMGSl4X7i8eh+E39H8X1RKNg4GQyLWOVksdElQuKeGFMThaSCmA3OHkOV # Ny70+PrCM3Z1sbUMI3lDHdT4f9JXcYqJbnCjCDHCZgOeF2Z5UEfFlPiVQIo4OA7o # b48LbOuThEZew4SrJS9lx9RKafoFyw== # =oLvq # -----END PGP SIGNATURE----- # gpg: Signature made Mon 01 Jul 2024 06:13:06 AM PDT # gpg: using RSA key F80C006308E22CFD8A92E7980CF5572FD7FB55AF # gpg: Good signature from "Anthony PERARD <anthony.perard@gmail.com>" [undefined] # gpg: aka "Anthony PERARD <anthony.perard@citrix.com>" [undefined] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 5379 2F71 024C 600F 778A 7161 D8D5 7199 DF83 42C8 # Subkey fingerprint: F80C 0063 08E2 2CFD 8A92 E798 0CF5 572F D7FB 55AF * tag 'pull-xen-20240701' of https://xenbits.xen.org/git-http/people/aperard/qemu-dm: xen-hvm: Avoid livelock while handling buffered ioreqs xen: fix stubdom PCI addr hw/xen: detect when running inside stubdomain Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
2 parents b6d32a0 + 410b4d5 commit 1152a04

File tree

6 files changed

+122
-10
lines changed

6 files changed

+122
-10
lines changed

hw/i386/xen/xen-hvm.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,26 @@ static void xen_wakeup_notifier(Notifier *notifier, void *data)
584584
xc_set_hvm_param(xen_xc, xen_domid, HVM_PARAM_ACPI_S_STATE, 0);
585585
}
586586

587+
static bool xen_check_stubdomain(struct xs_handle *xsh)
588+
{
589+
char *dm_path = g_strdup_printf(
590+
"/local/domain/%d/image/device-model-domid", xen_domid);
591+
char *val;
592+
int32_t dm_domid;
593+
bool is_stubdom = false;
594+
595+
val = xs_read(xsh, 0, dm_path, NULL);
596+
if (val) {
597+
if (sscanf(val, "%d", &dm_domid) == 1) {
598+
is_stubdom = dm_domid != 0;
599+
}
600+
free(val);
601+
}
602+
603+
g_free(dm_path);
604+
return is_stubdom;
605+
}
606+
587607
void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
588608
{
589609
MachineState *ms = MACHINE(pcms);
@@ -596,6 +616,8 @@ void xen_hvm_init_pc(PCMachineState *pcms, MemoryRegion **ram_memory)
596616

597617
xen_register_ioreq(state, max_cpus, &xen_memory_listener);
598618

619+
xen_is_stubdomain = xen_check_stubdomain(state->xenstore);
620+
599621
QLIST_INIT(&xen_physmap);
600622
xen_read_physmap(state);
601623

hw/xen/xen-host-pci-device.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "qemu/osdep.h"
1010
#include "qapi/error.h"
1111
#include "qemu/cutils.h"
12+
#include "hw/xen/xen-legacy-backend.h"
13+
#include "hw/xen/xen-bus-helper.h"
1214
#include "xen-host-pci-device.h"
1315

1416
#define XEN_HOST_PCI_MAX_EXT_CAP \
@@ -33,13 +35,73 @@
3335
#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */
3436
#define IORESOURCE_MEM_64 0x00100000
3537

38+
/*
39+
* Non-passthrough (dom0) accesses are local PCI devices and use the given BDF
40+
* Passthough (stubdom) accesses are through PV frontend PCI device. Those
41+
* either have a BDF identical to the backend's BDF (xen-backend.passthrough=1)
42+
* or a local virtual BDF (xen-backend.passthrough=0)
43+
*
44+
* We are always given the backend's BDF and need to lookup the appropriate
45+
* local BDF for sysfs access.
46+
*/
47+
static void xen_host_pci_fill_local_addr(XenHostPCIDevice *d, Error **errp)
48+
{
49+
unsigned int num_devs, len, i;
50+
unsigned int domain, bus, dev, func;
51+
char *be_path = NULL;
52+
char path[16];
53+
54+
be_path = qemu_xen_xs_read(xenstore, 0, "device/pci/0/backend", &len);
55+
if (!be_path) {
56+
error_setg(errp, "Failed to read device/pci/0/backend");
57+
goto out;
58+
}
59+
60+
if (xs_node_scanf(xenstore, 0, be_path, "num_devs", NULL,
61+
"%d", &num_devs) != 1) {
62+
error_setg(errp, "Failed to read or parse %s/num_devs", be_path);
63+
goto out;
64+
}
65+
66+
for (i = 0; i < num_devs; i++) {
67+
snprintf(path, sizeof(path), "dev-%d", i);
68+
if (xs_node_scanf(xenstore, 0, be_path, path, NULL,
69+
"%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
70+
error_setg(errp, "Failed to read or parse %s/%s", be_path, path);
71+
goto out;
72+
}
73+
if (domain != d->domain ||
74+
bus != d->bus ||
75+
dev != d->dev ||
76+
func != d->func)
77+
continue;
78+
snprintf(path, sizeof(path), "vdev-%d", i);
79+
if (xs_node_scanf(xenstore, 0, be_path, path, NULL,
80+
"%x:%x:%x.%x", &domain, &bus, &dev, &func) != 4) {
81+
error_setg(errp, "Failed to read or parse %s/%s", be_path, path);
82+
goto out;
83+
}
84+
d->local_domain = domain;
85+
d->local_bus = bus;
86+
d->local_dev = dev;
87+
d->local_func = func;
88+
goto out;
89+
}
90+
error_setg(errp, "Failed to find PCI device %x:%x:%x.%x in xenstore",
91+
d->domain, d->bus, d->dev, d->func);
92+
93+
out:
94+
free(be_path);
95+
}
96+
3697
static void xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
3798
const char *name, char *buf, ssize_t size)
3899
{
39100
int rc;
40101

41102
rc = snprintf(buf, size, "/sys/bus/pci/devices/%04x:%02x:%02x.%d/%s",
42-
d->domain, d->bus, d->dev, d->func, name);
103+
d->local_domain, d->local_bus, d->local_dev, d->local_func,
104+
name);
43105
assert(rc >= 0 && rc < size);
44106
}
45107

@@ -342,6 +404,18 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
342404
d->dev = dev;
343405
d->func = func;
344406

407+
if (xen_is_stubdomain) {
408+
xen_host_pci_fill_local_addr(d, errp);
409+
if (*errp) {
410+
goto error;
411+
}
412+
} else {
413+
d->local_domain = d->domain;
414+
d->local_bus = d->bus;
415+
d->local_dev = d->dev;
416+
d->local_func = d->func;
417+
}
418+
345419
xen_host_pci_config_open(d, errp);
346420
if (*errp) {
347421
goto error;

hw/xen/xen-host-pci-device.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ typedef struct XenHostPCIDevice {
2323
uint8_t dev;
2424
uint8_t func;
2525

26+
/* different from the above in case of stubdomain */
27+
uint16_t local_domain;
28+
uint8_t local_bus;
29+
uint8_t local_dev;
30+
uint8_t local_func;
31+
2632
uint16_t vendor_id;
2733
uint16_t device_id;
2834
uint32_t class_code;

hw/xen/xen-hvm-common.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -475,11 +475,11 @@ static void handle_ioreq(XenIOState *state, ioreq_t *req)
475475
}
476476
}
477477

478-
static bool handle_buffered_iopage(XenIOState *state)
478+
static unsigned int handle_buffered_iopage(XenIOState *state)
479479
{
480480
buffered_iopage_t *buf_page = state->buffered_io_page;
481481
buf_ioreq_t *buf_req = NULL;
482-
bool handled_ioreq = false;
482+
unsigned int handled = 0;
483483
ioreq_t req;
484484
int qw;
485485

@@ -492,7 +492,7 @@ static bool handle_buffered_iopage(XenIOState *state)
492492
req.count = 1;
493493
req.dir = IOREQ_WRITE;
494494

495-
for (;;) {
495+
do {
496496
uint32_t rdptr = buf_page->read_pointer, wrptr;
497497

498498
xen_rmb();
@@ -533,22 +533,30 @@ static bool handle_buffered_iopage(XenIOState *state)
533533
assert(!req.data_is_ptr);
534534

535535
qatomic_add(&buf_page->read_pointer, qw + 1);
536-
handled_ioreq = true;
537-
}
536+
handled += qw + 1;
537+
} while (handled < IOREQ_BUFFER_SLOT_NUM);
538538

539-
return handled_ioreq;
539+
return handled;
540540
}
541541

542542
static void handle_buffered_io(void *opaque)
543543
{
544+
unsigned int handled;
544545
XenIOState *state = opaque;
545546

546-
if (handle_buffered_iopage(state)) {
547+
handled = handle_buffered_iopage(state);
548+
if (handled >= IOREQ_BUFFER_SLOT_NUM) {
549+
/* We handled a full page of ioreqs. Schedule a timer to continue
550+
* processing while giving other stuff a chance to run.
551+
*/
547552
timer_mod(state->buffered_io_timer,
548-
BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
549-
} else {
553+
qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
554+
} else if (handled == 0) {
550555
timer_del(state->buffered_io_timer);
551556
qemu_xen_evtchn_unmask(state->xce_handle, state->bufioreq_local_port);
557+
} else {
558+
timer_mod(state->buffered_io_timer,
559+
BUFFER_IO_MAX_DELAY + qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
552560
}
553561
}
554562

include/hw/xen/xen.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum xen_mode {
3636
extern uint32_t xen_domid;
3737
extern enum xen_mode xen_mode;
3838
extern bool xen_domid_restrict;
39+
extern bool xen_is_stubdomain;
3940

4041
int xen_pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num);
4142
int xen_set_pci_link_route(uint8_t link, uint8_t irq);

system/globals.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ bool qemu_uuid_set;
6060
uint32_t xen_domid;
6161
enum xen_mode xen_mode = XEN_DISABLED;
6262
bool xen_domid_restrict;
63+
bool xen_is_stubdomain;
6364
struct evtchn_backend_ops *xen_evtchn_ops;
6465
struct gnttab_backend_ops *xen_gnttab_ops;
6566
struct foreignmem_backend_ops *xen_foreignmem_ops;

0 commit comments

Comments
 (0)