[PATCH v2 1/6] qemu: Improve PS/2 controller detection

Kamil Szczęk posted 6 patches 3 months, 1 week ago
There is a newer version of this series
[PATCH v2 1/6] qemu: Improve PS/2 controller detection
Posted by Kamil Szczęk 3 months, 1 week ago
Up until now, we've assumed that all x86 machines have a PS/2
controller built-in. This assumption was correct until QEMU v4.2
introduced a new x86-based machine type - microvm.

Due to this assumption, a pair of unnecessary PS/2 inputs are implicitly
added to all microvm domains. This patch fixes that by whitelisting
machine types which are known to include the i8042 PS/2 controller.

Signed-off-by: Kamil Szczęk <kamil@szczek.dev>
---
 src/qemu/qemu_capabilities.c | 20 ++++++++++++++++++++
 src/qemu/qemu_capabilities.h |  5 ++++-
 src/qemu/qemu_domain.c       | 28 +++++++++++++++++++++++++---
 src/qemu/qemu_domain.h       |  1 +
 src/qemu/qemu_validate.c     |  4 ++--
 5 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 2f66a49711..2765fba7c8 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -1360,6 +1360,13 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
     { "vhost-user-vga", QEMU_CAPS_DEVICE_VHOST_USER_VGA },
     { "ramfb", QEMU_CAPS_DEVICE_RAMFB },
     { "max-arm-cpu", QEMU_CAPS_ARM_MAX_CPU },
+    /*
+     * The i8042 controller is a built-in device and is not user-creatable.
+     * However, since not all machine types include this controller, you should
+     * avoid checking for this capability directly.
+     *
+     * Prefer using virQEMUCapsSupportsI8042() instead.
+     */
     { "i8042", QEMU_CAPS_DEVICE_I8042 },
     { "rng-builtin", QEMU_CAPS_OBJECT_RNG_BUILTIN },
     { "tpm-spapr", QEMU_CAPS_DEVICE_TPM_SPAPR },
@@ -6008,6 +6015,19 @@ virQEMUCapsSupportsVmport(virQEMUCaps *qemuCaps,
         STREQ(def->os.machine, "isapc");
 }
 
+bool
+virQEMUCapsSupportsI8042(virQEMUCaps *qemuCaps,
+                         const virDomainDef *def)
+{
+    if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_I8042))
+        return false;
+
+    return qemuDomainIsI440FX(def) ||
+        qemuDomainIsQ35(def) ||
+        qemuDomainIsXenFV(def) ||
+        STREQ(def->os.machine, "isapc");
+}
+
 
 /*
  * The preferred machine to use if none is listed explicitly
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index edeb870e01..659efd9182 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -535,7 +535,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
     QEMU_CAPS_SMP_DIES, /*  -smp dies= */
 
     /* 350 */
-    QEMU_CAPS_DEVICE_I8042, /* PS/2 controller */
+    QEMU_CAPS_DEVICE_I8042, /* PS/2 controller, use virQEMUCapsSupportsI8042() to query this capability */
     QEMU_CAPS_OBJECT_RNG_BUILTIN, /* -object rng-builtin */
     X_QEMU_CAPS_VIRTIO_NET_FAILOVER, /* virtio-net-*.failover */
     QEMU_CAPS_DEVICE_TPM_SPAPR, /* -device tpm-spapr */
@@ -718,6 +718,9 @@ void virQEMUCapsInitProcessCapsInterlock(virQEMUCaps *qemuCaps);
 bool virQEMUCapsSupportsVmport(virQEMUCaps *qemuCaps,
                                const virDomainDef *def);
 
+bool virQEMUCapsSupportsI8042(virQEMUCaps *qemuCaps,
+                              const virDomainDef *def);
+
 const char *virQEMUCapsGetBinary(virQEMUCaps *qemuCaps);
 virArch virQEMUCapsGetArch(virQEMUCaps *qemuCaps);
 unsigned int virQEMUCapsGetVersion(virQEMUCaps *qemuCaps);
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index f87ba6ba51..2b4bb54efc 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -3925,9 +3925,10 @@ virXMLNamespace virQEMUDriverDomainXMLNamespace = {
 
 
 static int
-qemuDomainDefAddImplicitInputDevice(virDomainDef *def)
+qemuDomainDefAddImplicitInputDevice(virDomainDef *def,
+                                    virQEMUCaps *qemuCaps)
 {
-    if (ARCH_IS_X86(def->os.arch)) {
+    if (virQEMUCapsSupportsI8042(qemuCaps, def)) {
         if (virDomainDefMaybeAddInput(def,
                                       VIR_DOMAIN_INPUT_TYPE_MOUSE,
                                       VIR_DOMAIN_INPUT_BUS_PS2) < 0)
@@ -4166,7 +4167,7 @@ qemuDomainDefAddDefaultDevices(virQEMUDriver *driver,
     bool addITCOWatchdog = false;
 
     /* add implicit input devices */
-    if (qemuDomainDefAddImplicitInputDevice(def) < 0)
+    if (qemuDomainDefAddImplicitInputDevice(def, qemuCaps) < 0)
         return -1;
 
     /* Add implicit PCI root controller if the machine has one */
@@ -9177,6 +9178,21 @@ qemuDomainMachineIsMipsMalta(const char *machine,
     return false;
 }
 
+static bool
+qemuDomainMachineIsXenFV(const char *machine,
+                         const virArch arch)
+{
+    if (!ARCH_IS_X86(arch))
+        return false;
+
+    if (STREQ(machine, "xenfv") ||
+        STRPREFIX(machine, "xenfv-")) {
+        return true;
+    }
+
+    return false;
+}
+
 
 /* You should normally avoid this function and use
  * qemuDomainHasBuiltinIDE() instead. */
@@ -9263,6 +9279,12 @@ qemuDomainIsLoongArchVirt(const virDomainDef *def)
     return qemuDomainMachineIsLoongArchVirt(def->os.machine, def->os.arch);
 }
 
+bool
+qemuDomainIsXenFV(const virDomainDef *def)
+{
+    return qemuDomainMachineIsXenFV(def->os.machine, def->os.arch);
+}
+
 
 bool
 qemuDomainHasPCIRoot(const virDomainDef *def)
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
index af0bb04c45..1179b0d6dc 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -838,6 +838,7 @@ bool qemuDomainIsLoongArchVirt(const virDomainDef *def);
 bool qemuDomainIsRISCVVirt(const virDomainDef *def);
 bool qemuDomainIsPSeries(const virDomainDef *def);
 bool qemuDomainIsMipsMalta(const virDomainDef *def);
+bool qemuDomainIsXenFV(const virDomainDef *def);
 bool qemuDomainHasPCIRoot(const virDomainDef *def);
 bool qemuDomainHasPCIeRoot(const virDomainDef *def);
 bool qemuDomainHasBuiltinIDE(const virDomainDef *def);
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index b885fe7c77..6f7aeababe 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4868,8 +4868,8 @@ qemuValidateDomainDeviceDefInput(const virDomainInputDef *input,
     int cap;
     int ccwCap;
 
-    if (input->bus == VIR_DOMAIN_INPUT_BUS_PS2 && !ARCH_IS_X86(def->os.arch) &&
-        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_I8042)) {
+    if (input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
+        !virQEMUCapsSupportsI8042(qemuCaps, def)) {
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("%1$s is not supported by this QEMU binary"),
                        virDomainInputBusTypeToString(input->bus));
-- 
2.45.0