X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=ui%2Fspice-core.c;h=0632c74e9fcb882a00741ce4a253c7f0e8d3b638;hb=79bcac250f96ba1d4fdecfdc6e3363c9024703a4;hp=fc850b3f50f5a835bdbe8e4e6a52172593c8dd1a;hpb=1b63665c2c0e0d52735e0dd5217f109fe0dd2322;p=mirror_qemu.git diff --git a/ui/spice-core.c b/ui/spice-core.c index fc850b3f50..0632c74e9f 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include -#include #include "sysemu/sysemu.h" #include "ui/qemu-spice.h" @@ -35,6 +34,7 @@ #include "qemu/option.h" #include "migration/misc.h" #include "hw/hw.h" +#include "hw/pci/pci_bus.h" #include "ui/spice-display.h" /* core bits */ @@ -398,6 +398,7 @@ static SpiceChannelList *qmp_query_spice_channels(void) static QemuOptsList qemu_spice_opts = { .name = "spice", .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), + .merge_lists = true, .desc = { { .name = "port", @@ -627,7 +628,7 @@ static void vm_change_state_handler(void *opaque, int running, { if (running) { qemu_spice_display_start(); - } else { + } else if (state != RUN_STATE_PAUSED) { qemu_spice_display_stop(); } } @@ -784,7 +785,7 @@ void qemu_spice_init(void) qemu_opt_foreach(opts, add_channel, &tls_port, &error_fatal); - spice_server_set_name(spice_server, qemu_name); + spice_server_set_name(spice_server, qemu_name ?: "QEMU " QEMU_VERSION); spice_server_set_uuid(spice_server, (unsigned char *)&qemu_uuid); seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); @@ -864,6 +865,56 @@ bool qemu_spice_have_display_interface(QemuConsole *con) return false; } +/* + * Recursively (in reverse order) appends addresses of PCI devices as it moves + * up in the PCI hierarchy. + * + * @returns true on success, false when the buffer wasn't large enough + */ +static bool append_pci_address(char *buf, size_t buf_size, const PCIDevice *pci) +{ + PCIBus *bus = pci_get_bus(pci); + /* + * equivalent to if (!pci_bus_is_root(bus)), but the function is not built + * with PCI_CONFIG=n, avoid using an #ifdef by checking directly + */ + if (bus->parent_dev != NULL) { + append_pci_address(buf, buf_size, bus->parent_dev); + } + + size_t len = strlen(buf); + ssize_t written = snprintf(buf + len, buf_size - len, "/%02x.%x", + PCI_SLOT(pci->devfn), PCI_FUNC(pci->devfn)); + + return written > 0 && written < buf_size - len; +} + +bool qemu_spice_fill_device_address(QemuConsole *con, + char *device_address, + size_t size) +{ + DeviceState *dev = DEVICE(object_property_get_link(OBJECT(con), + "device", + &error_abort)); + PCIDevice *pci = (PCIDevice *) object_dynamic_cast(OBJECT(dev), + TYPE_PCI_DEVICE); + + if (pci == NULL) { + warn_report("Setting device address of a display device to SPICE: " + "Not a PCI device."); + return false; + } + + strncpy(device_address, "pci/0000", size); + if (!append_pci_address(device_address, size, pci)) { + warn_report("Setting device address of a display device to SPICE: " + "Too many PCI devices in the chain."); + return false; + } + + return true; +} + int qemu_spice_add_display_interface(QXLInstance *qxlin, QemuConsole *con) { if (g_slist_find(spice_consoles, con)) { @@ -922,12 +973,20 @@ int qemu_spice_display_add_client(int csock, int skipauth, int tls) void qemu_spice_display_start(void) { + if (spice_display_is_running) { + return; + } + spice_display_is_running = true; spice_server_vm_start(spice_server); } void qemu_spice_display_stop(void) { + if (!spice_display_is_running) { + return; + } + spice_server_vm_stop(spice_server); spice_display_is_running = false; }