The high-bandwidth hypercall helpers push %ebp before loading the in6
operand into it. On i386 without frame pointers, both GCC and Clang can
address the memory-constrained operand relative to %esp. The push then
moves the stack and the helpers load the wrong value.

Typical i386 configurations use the frame-pointer unwinder and happen to
address the operand through %ebp. However, UNWINDER_GUESS is available
with EXPERT and permits the affected frame-pointer-disabled configuration.
vmwgfx is also available on i386 and calls both helpers.

Stage in6 through %eax before changing either stack register, then save
%ebp and copy the staged value into it. Load the VMware magic immediately
before the string I/O instruction. Mark %eax early-clobber so it cannot
also provide in6 or an address register for it. Use the same sequence on
x86-64, where the full-width register preserves in6.

Fixes: 34bf25e820ae ("x86/vmware: Introduce VMware hypercall API")
Cc: [email protected] # 6.11+
Signed-off-by: Zack Rusin <[email protected]>
---

Notes:
    Built on v7.3-rc1 with W=1 on i386 using GCC and Clang, with frame
    pointers enabled and disabled. Disassembly in all four cases loads in6
    before changing %ebp or %esp.

 arch/x86/include/asm/vmware.h | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
index 4220dae14a2d..fb011cef01e7 100644
--- a/arch/x86/include/asm/vmware.h
+++ b/arch/x86/include/asm/vmware.h
@@ -276,20 +276,22 @@ unsigned long vmware_hypercall_hb_out(unsigned long cmd, 
unsigned long in2,
 
        asm_inline volatile (
                UNWIND_HINT_SAVE
+               "mov %[in6], %%" _ASM_AX "\n\t"
                "push %%" _ASM_BP "\n\t"
                UNWIND_HINT_UNDEFINED
-               "mov %[in6], %%" _ASM_BP "\n\t"
+               "mov %%" _ASM_AX ", %%" _ASM_BP "\n\t"
+               "mov %[magic], %%eax\n\t"
                "rep outsb\n\t"
                "pop %%" _ASM_BP "\n\t"
                UNWIND_HINT_RESTORE
-               : "=a" (out0), "=b" (*out1)
-               : "a" (VMWARE_HYPERVISOR_MAGIC),
-                 "b" (cmd),
+               : "=&a" (out0), "=b" (*out1)
+               : "b" (cmd),
                  "c" (in2),
                  "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
                  "S" (in4),
                  "D" (in5),
-                 [in6] VMW_BP_CONSTRAINT (in6)
+                 [in6] VMW_BP_CONSTRAINT(in6),
+                 [magic] "i" (VMWARE_HYPERVISOR_MAGIC)
                : "cc", "memory");
        return out0;
 }
@@ -304,20 +306,22 @@ unsigned long vmware_hypercall_hb_in(unsigned long cmd, 
unsigned long in2,
 
        asm_inline volatile (
                UNWIND_HINT_SAVE
+               "mov %[in6], %%" _ASM_AX "\n\t"
                "push %%" _ASM_BP "\n\t"
                UNWIND_HINT_UNDEFINED
-               "mov %[in6], %%" _ASM_BP "\n\t"
+               "mov %%" _ASM_AX ", %%" _ASM_BP "\n\t"
+               "mov %[magic], %%eax\n\t"
                "rep insb\n\t"
                "pop %%" _ASM_BP "\n\t"
                UNWIND_HINT_RESTORE
-               : "=a" (out0), "=b" (*out1)
-               : "a" (VMWARE_HYPERVISOR_MAGIC),
-                 "b" (cmd),
+               : "=&a" (out0), "=b" (*out1)
+               : "b" (cmd),
                  "c" (in2),
                  "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
                  "S" (in4),
                  "D" (in5),
-                 [in6] VMW_BP_CONSTRAINT (in6)
+                 [in6] VMW_BP_CONSTRAINT(in6),
+                 [magic] "i" (VMWARE_HYPERVISOR_MAGIC)
                : "cc", "memory");
        return out0;
 }

base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
-- 
2.53.0


Reply via email to