[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <uc62gsttzmh5o35uh7viy326bqwpq5gxmcxqqyqb4zp4blp7tg@v3kfsotqtaay>
Date: Fri, 6 Feb 2026 08:32:51 -0800
From: Josh Poimboeuf <jpoimboe@...nel.org>
To: Thomas Gleixner <tglx@...-um.de>
Cc: Thorsten Leemhuis <regressions@...mhuis.info>,
Alexey Makhalov <alexey.makhalov@...adcom.com>, x86@...nel.org, linux-kernel@...r.kernel.org,
Ajay Kaher <ajay.kaher@...adcom.com>, bcm-kernel-feedback-list@...adcom.com,
Peter Zijlstra <peterz@...radead.org>, Justin Forbes <jforbes@...oraproject.org>,
Linux kernel regressions list <regressions@...ts.linux.dev>, Linus Torvalds <torvalds@...ux-foundation.org>
Subject: Re: [PATCH] x86/vmware: Fix hypercall clobbers
On Fri, Feb 06, 2026 at 11:07:22AM +0100, Thomas Gleixner wrote:
> So unless there is a compelling argument why the existing hypercall
> implementation is broken by design, the trivial one-line fix from Alexey
> is addressing the actual root cause (it just needs a big fat comment)
> and good enough to cure the regression, no?
While my original patch might be overkill, Alexey's one-line fix doesn't
go far enough:
1) It only changes one hypercall site, the vmmouse driver has several.
All of the following commands are subject to register corruption by
QEMU:
VMWARE_CMD_ABSPOINTER_DATA
VMWARE_CMD_ABSPOINTER_STATUS
VMWARE_CMD_ABSPOINTER_COMMAND
2) While the inline asm for vmware_hypercall7() does have RSI/RDI
listed as input constraints, it doesn't clobber them.
So a spot fix would need to be something like so:
diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
index c9cf43d5ef23..9f72569fc8c2 100644
--- a/arch/x86/include/asm/vmware.h
+++ b/arch/x86/include/asm/vmware.h
@@ -119,6 +119,27 @@ unsigned long vmware_hypercall1(unsigned long cmd, unsigned long in1)
return out0;
}
+static inline
+unsigned long vmware_hypercall1_clobber(unsigned long cmd, unsigned long in1)
+{
+ unsigned long out0, tmp = 0;
+
+ if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
+ return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL);
+
+ if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
+ return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
+ NULL, NULL, NULL, NULL, NULL);
+
+ asm_inline volatile (VMWARE_HYPERCALL
+ : "=a" (out0), "+b" (in1), "+c" (cmd), "+d" (tmp)
+ : [port] "i" (VMWARE_HYPERVISOR_PORT),
+ "a" (VMWARE_HYPERVISOR_MAGIC)
+ : "di", "si", "cc", "memory");
+ return out0;
+}
+
static inline
unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
u32 *out1, u32 *out2)
@@ -144,6 +165,30 @@ unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
return out0;
}
+static inline
+unsigned long vmware_hypercall3_clobber(unsigned long cmd, unsigned long in1,
+ u32 *out1, u32 *out2)
+{
+ unsigned long out0, tmp = 0;
+
+ if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
+ return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
+ out1, out2, NULL, NULL, NULL);
+
+ if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
+ return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
+ out1, out2, NULL, NULL, NULL);
+
+ asm_inline volatile (VMWARE_HYPERCALL
+ : "=a" (out0), "=b" (*out1), "=c" (*out2), "+d" (tmp)
+ : [port] "i" (VMWARE_HYPERVISOR_PORT),
+ "a" (VMWARE_HYPERVISOR_MAGIC),
+ "b" (in1),
+ "c" (cmd)
+ : "di", "si", "cc", "memory");
+ return out0;
+}
+
static inline
unsigned long vmware_hypercall4(unsigned long cmd, unsigned long in1,
u32 *out1, u32 *out2, u32 *out3)
@@ -169,6 +214,31 @@ unsigned long vmware_hypercall4(unsigned long cmd, unsigned long in1,
return out0;
}
+static inline
+unsigned long vmware_hypercall4_clobber(unsigned long cmd, unsigned long in1,
+ u32 *out1, u32 *out2, u32 *out3)
+{
+ unsigned long out0;
+
+ if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
+ return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
+ out1, out2, out3, NULL, NULL);
+
+ if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
+ return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
+ out1, out2, out3, NULL, NULL);
+
+ asm_inline volatile (VMWARE_HYPERCALL
+ : "=a" (out0), "=b" (*out1), "=c" (*out2), "=d" (*out3)
+ : [port] "i" (VMWARE_HYPERVISOR_PORT),
+ "a" (VMWARE_HYPERVISOR_MAGIC),
+ "b" (in1),
+ "c" (cmd),
+ "d" (0)
+ : "di", "si", "cc", "memory");
+ return out0;
+}
+
static inline
unsigned long vmware_hypercall5(unsigned long cmd, unsigned long in1,
unsigned long in3, unsigned long in4,
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c
index fb1d986a6895..0ab04b8bb923 100644
--- a/drivers/input/mouse/vmmouse.c
+++ b/drivers/input/mouse/vmmouse.c
@@ -125,7 +125,7 @@ static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse)
while (count--) {
/* See if we have motion data. */
- status = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_STATUS, 0);
+ status = vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_STATUS, 0);
if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) {
psmouse_err(psmouse, "failed to fetch status data\n");
/*
@@ -145,8 +145,8 @@ static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse)
}
/* Now get it */
- status = vmware_hypercall4(VMWARE_CMD_ABSPOINTER_DATA, 4,
- &x, &y, &z);
+ status = vmware_hypercall4_clobber(VMWARE_CMD_ABSPOINTER_DATA, 4,
+ &x, &y, &z);
/*
* And report what we've got. Prefer to report button
@@ -222,9 +222,9 @@ static void vmmouse_disable(struct psmouse *psmouse)
{
u32 status;
- vmware_hypercall1(VMWARE_CMD_ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE);
+ vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE);
- status = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_STATUS, 0);
+ status = vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_STATUS, 0);
if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR)
psmouse_warn(psmouse, "failed to disable vmmouse device\n");
}
@@ -246,19 +246,19 @@ static int vmmouse_enable(struct psmouse *psmouse)
* Try enabling the device. If successful, we should be able to
* read valid version ID back from it.
*/
- vmware_hypercall1(VMWARE_CMD_ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE);
+ vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE);
/*
* See if version ID can be retrieved.
*/
- status = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_STATUS, 0);
+ status = vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_STATUS, 0);
if ((status & 0x0000ffff) == 0) {
psmouse_dbg(psmouse, "empty flags - assuming no device\n");
return -ENXIO;
}
- version = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_DATA,
- 1 /* single item */);
+ version = vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_DATA,
+ 1 /* single item */);
if (version != VMMOUSE_VERSION_ID) {
psmouse_dbg(psmouse, "Unexpected version value: %u vs %u\n",
(unsigned) version, VMMOUSE_VERSION_ID);
@@ -269,11 +269,10 @@ static int vmmouse_enable(struct psmouse *psmouse)
/*
* Restrict ioport access, if possible.
*/
- vmware_hypercall1(VMWARE_CMD_ABSPOINTER_RESTRICT,
- VMMOUSE_RESTRICT_CPL0);
+ vmware_hypercall1(VMWARE_CMD_ABSPOINTER_RESTRICT, VMMOUSE_RESTRICT_CPL0);
- vmware_hypercall1(VMWARE_CMD_ABSPOINTER_COMMAND,
- VMMOUSE_CMD_REQUEST_ABSOLUTE);
+ vmware_hypercall1_clobber(VMWARE_CMD_ABSPOINTER_COMMAND,
+ VMMOUSE_CMD_REQUEST_ABSOLUTE);
return 0;
}
@@ -320,7 +319,7 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
/* Check if the device is present */
response = ~VMWARE_HYPERVISOR_MAGIC;
- version = vmware_hypercall3(VMWARE_CMD_GETVERSION, 0, &response, &type);
+ version = vmware_hypercall3_clobber(VMWARE_CMD_GETVERSION, 0, &response, &type);
if (response != VMWARE_HYPERVISOR_MAGIC || version == 0xffffffffU)
return -ENXIO;
Powered by blists - more mailing lists