mirror of https://gitee.com/openkylin/qemu.git
hw: report invalid disable-legacy|modern usage for virtio-1-only devs
A number of virtio devices (gpu, crypto, mouse, keyboard, tablet) only support the virtio-1 (aka modern) mode. Currently if the user launches QEMU, setting those devices to enable legacy mode, QEMU will silently create them in modern mode, ignoring the user's (mistaken) request. This patch introduces proper data validation so that an attempt to configure a virtio-1-only devices in legacy mode gets reported as an error to the user. Checking this required introduction of a new field to explicitly track what operating model is to be used for a device, separately from the disable_modern and disable_legacy fields that record the user's requested configuration. Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> Message-Id: <20190215103239.28640-2-berrange@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
2259637b95
commit
f2784eed30
|
@ -102,9 +102,26 @@ const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7);
|
||||||
|
|
||||||
GlobalProperty hw_compat_2_6[] = {
|
GlobalProperty hw_compat_2_6[] = {
|
||||||
{ "virtio-mmio", "format_transport_address", "off" },
|
{ "virtio-mmio", "format_transport_address", "off" },
|
||||||
/* Optional because not all virtio-pci devices support legacy mode */
|
/*
|
||||||
{ "virtio-pci", "disable-modern", "on", .optional = true },
|
* don't include devices which are modern-only
|
||||||
{ "virtio-pci", "disable-legacy", "off", .optional = true },
|
* ie keyboard, mouse, tablet, gpu, vga & crypto
|
||||||
|
*/
|
||||||
|
{ "virtio-9p-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-9p-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-balloon-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-balloon-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-blk-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-blk-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-input-host-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-input-host-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-net-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-net-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-rng-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-rng-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-scsi-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-scsi-pci", "disable-legacy", "off" },
|
||||||
|
{ "virtio-serial-pci", "disable-modern", "on" },
|
||||||
|
{ "virtio-serial-pci", "disable-legacy", "off" },
|
||||||
};
|
};
|
||||||
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
|
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,9 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
Error *local_error = NULL;
|
Error *local_error = NULL;
|
||||||
|
|
||||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||||
virtio_pci_force_virtio_1(vpci_dev);
|
if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
object_property_set_bool(OBJECT(vdev), true, "realized", &local_error);
|
object_property_set_bool(OBJECT(vdev), true, "realized", &local_error);
|
||||||
|
|
||||||
if (local_error) {
|
if (local_error) {
|
||||||
|
|
|
@ -154,7 +154,9 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
|
|
||||||
/* init virtio bits */
|
/* init virtio bits */
|
||||||
qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
|
qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
|
||||||
virtio_pci_force_virtio_1(vpci_dev);
|
if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
object_property_set_bool(OBJECT(g), true, "realized", &err);
|
object_property_set_bool(OBJECT(g), true, "realized", &err);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_propagate(errp, err);
|
error_propagate(errp, err);
|
||||||
|
|
|
@ -51,7 +51,9 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
}
|
}
|
||||||
|
|
||||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||||
virtio_pci_force_virtio_1(vpci_dev);
|
if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||||
object_property_set_link(OBJECT(vcrypto),
|
object_property_set_link(OBJECT(vcrypto),
|
||||||
OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",
|
OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",
|
||||||
|
|
|
@ -48,7 +48,9 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
||||||
DeviceState *vdev = DEVICE(&vinput->vdev);
|
DeviceState *vdev = DEVICE(&vinput->vdev);
|
||||||
|
|
||||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||||
virtio_pci_force_virtio_1(vpci_dev);
|
if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1721,16 +1721,22 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
|
||||||
/* PCI BAR regions must be powers of 2 */
|
/* PCI BAR regions must be powers of 2 */
|
||||||
pow2ceil(proxy->notify.offset + proxy->notify.size));
|
pow2ceil(proxy->notify.offset + proxy->notify.size));
|
||||||
|
|
||||||
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
|
if ((proxy->disable_legacy == ON_OFF_AUTO_ON) ||
|
||||||
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
((proxy->disable_legacy == ON_OFF_AUTO_AUTO) && pcie_port)) {
|
||||||
}
|
if (proxy->disable_modern) {
|
||||||
|
error_setg(errp, "device cannot work as neither modern nor "
|
||||||
if (!virtio_pci_modern(proxy) && !virtio_pci_legacy(proxy)) {
|
"legacy mode is enabled");
|
||||||
error_setg(errp, "device cannot work as neither modern nor legacy mode"
|
error_append_hint(errp, "Set either disable-modern or "
|
||||||
" is enabled");
|
"disable-legacy to off\n");
|
||||||
error_append_hint(errp, "Set either disable-modern or disable-legacy"
|
return;
|
||||||
" to off\n");
|
}
|
||||||
return;
|
proxy->mode = VIRTIO_PCI_MODE_MODERN;
|
||||||
|
} else {
|
||||||
|
if (proxy->disable_modern) {
|
||||||
|
proxy->mode = VIRTIO_PCI_MODE_LEGACY;
|
||||||
|
} else {
|
||||||
|
proxy->mode = VIRTIO_PCI_MODE_TRANSITIONAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcie_port && pci_is_express(pci_dev)) {
|
if (pcie_port && pci_is_express(pci_dev)) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#ifndef QEMU_VIRTIO_PCI_H
|
#ifndef QEMU_VIRTIO_PCI_H
|
||||||
#define QEMU_VIRTIO_PCI_H
|
#define QEMU_VIRTIO_PCI_H
|
||||||
|
|
||||||
|
#include "qapi/error.h"
|
||||||
#include "hw/pci/msi.h"
|
#include "hw/pci/msi.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
|
|
||||||
|
@ -118,6 +119,12 @@ typedef struct VirtIOPCIQueue {
|
||||||
uint32_t used[2];
|
uint32_t used[2];
|
||||||
} VirtIOPCIQueue;
|
} VirtIOPCIQueue;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VIRTIO_PCI_MODE_LEGACY,
|
||||||
|
VIRTIO_PCI_MODE_TRANSITIONAL,
|
||||||
|
VIRTIO_PCI_MODE_MODERN,
|
||||||
|
} VirtIOPCIMode;
|
||||||
|
|
||||||
struct VirtIOPCIProxy {
|
struct VirtIOPCIProxy {
|
||||||
PCIDevice pci_dev;
|
PCIDevice pci_dev;
|
||||||
MemoryRegion bar;
|
MemoryRegion bar;
|
||||||
|
@ -142,6 +149,7 @@ struct VirtIOPCIProxy {
|
||||||
bool disable_modern;
|
bool disable_modern;
|
||||||
bool ignore_backend_features;
|
bool ignore_backend_features;
|
||||||
OnOffAuto disable_legacy;
|
OnOffAuto disable_legacy;
|
||||||
|
VirtIOPCIMode mode;
|
||||||
uint32_t class_code;
|
uint32_t class_code;
|
||||||
uint32_t nvectors;
|
uint32_t nvectors;
|
||||||
uint32_t dfselect;
|
uint32_t dfselect;
|
||||||
|
@ -156,23 +164,34 @@ struct VirtIOPCIProxy {
|
||||||
|
|
||||||
static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy)
|
static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy)
|
||||||
{
|
{
|
||||||
return !proxy->disable_modern;
|
return proxy->mode != VIRTIO_PCI_MODE_LEGACY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy)
|
static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy)
|
||||||
{
|
{
|
||||||
return proxy->disable_legacy == ON_OFF_AUTO_OFF;
|
return proxy->mode != VIRTIO_PCI_MODE_MODERN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy)
|
static inline bool virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy,
|
||||||
|
Error **errp)
|
||||||
{
|
{
|
||||||
proxy->disable_modern = false;
|
if (proxy->disable_legacy == ON_OFF_AUTO_OFF) {
|
||||||
proxy->disable_legacy = ON_OFF_AUTO_ON;
|
error_setg(errp, "Unable to set disable-legacy=off on a virtio-1.0 "
|
||||||
|
"only device");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (proxy->disable_modern == true) {
|
||||||
|
error_setg(errp, "Unable to set disable-modern=on on a virtio-1.0 "
|
||||||
|
"only device");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
proxy->mode = VIRTIO_PCI_MODE_MODERN;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
|
static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
|
||||||
{
|
{
|
||||||
proxy->disable_modern = true;
|
proxy->mode = VIRTIO_PCI_MODE_LEGACY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue