lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <d366491d-2f5b-478c-8968-b0a3a298827c@broadcom.com>
Date: Wed, 12 Jun 2024 15:11:54 -0700
From: Alexey Makhalov <alexey.makhalov@...adcom.com>
To: linux-kernel@...r.kernel.org, virtualization@...ts.linux.dev,
 bp@...en8.de, hpa@...or.com, dave.hansen@...ux.intel.com, mingo@...hat.com,
 tglx@...utronix.de
Cc: x86@...nel.org, netdev@...r.kernel.org, richardcochran@...il.com,
 linux-input@...r.kernel.org, dmitry.torokhov@...il.com, zackr@...are.com,
 linux-graphics-maintainer@...are.com, pv-drivers@...are.com,
 timothym@...are.com, akaher@...are.com, dri-devel@...ts.freedesktop.org,
 daniel@...ll.ch, airlied@...il.com, tzimmermann@...e.de, mripard@...nel.org,
 maarten.lankhorst@...ux.intel.com, horms@...nel.org,
 kirill.shutemov@...ux.intel.com
Subject: Re: [PATCH v11 1/8] x86/vmware: Introduce VMware hypercall API

Borislav, please review v11 implementation of 1/8 based on your proposal.
I'm waiting for your feedback before sending full v11 patchset.
Thanks,
--Alexey

On 6/6/24 4:23 PM, Alexey Makhalov wrote:
> Introduce vmware_hypercall family of functions. It is a common
> implementation to be used by the VMware guest code and virtual
> device drivers in architecture independent manner.
> 
> The API consists of vmware_hypercallX and vmware_hypercall_hb_{out,in}
> set of functions by analogy with KVM hypercall API. Architecture
> specific implementation is hidden inside.
> 
> It will simplify future enhancements in VMware hypercalls such
> as SEV-ES and TDX related changes without needs to modify a
> caller in device drivers code.
> 
> Current implementation extends an idea from commit bac7b4e84323
> ("x86/vmware: Update platform detection code for VMCALL/VMMCALL
> hypercalls") to have a slow, but safe path vmware_hypercall_slow()
> earlier during the boot when alternatives are not yet applied.
> The code inherits VMWARE_CMD logic from the commit mentioned above.
> 
> Move common macros from vmware.c to vmware.h.
> 
> Signed-off-by: Alexey Makhalov <alexey.makhalov@...adcom.com>
> ---
>   arch/x86/include/asm/vmware.h | 279 ++++++++++++++++++++++++++++++++--
>   arch/x86/kernel/cpu/vmware.c  |  58 ++++++-
>   2 files changed, 315 insertions(+), 22 deletions(-)
> 
> diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
> index ac9fc51e2b18..724c8b9b4b8d 100644
> --- a/arch/x86/include/asm/vmware.h
> +++ b/arch/x86/include/asm/vmware.h
> @@ -7,26 +7,277 @@
>   #include <linux/stringify.h>
>   
>   /*
> - * The hypercall definitions differ in the low word of the %edx argument
> - * in the following way: the old port base interface uses the port
> - * number to distinguish between high- and low bandwidth versions.
> + * VMware hypercall ABI.
> + *
> + * - Low bandwidth (LB) hypercalls (I/O port based, vmcall and vmmcall)
> + * have up to 6 input and 6 output arguments passed and returned using
> + * registers: %eax (arg0), %ebx (arg1), %ecx (arg2), %edx (arg3),
> + * %esi (arg4), %edi (arg5).
> + * The following input arguments must be initialized by the caller:
> + * arg0 - VMWARE_HYPERVISOR_MAGIC
> + * arg2 - Hypercall command
> + * arg3 bits [15:0] - Port number, LB and direction flags
> + *
> + * - High bandwidth (HB) hypercalls are I/O port based only. They have
> + * up to 7 input and 7 output arguments passed and returned using
> + * registers: %eax (arg0), %ebx (arg1), %ecx (arg2), %edx (arg3),
> + * %esi (arg4), %edi (arg5), %ebp (arg6).
> + * The following input arguments must be initialized by the caller:
> + * arg0 - VMWARE_HYPERVISOR_MAGIC
> + * arg1 - Hypercall command
> + * arg3 bits [15:0] - Port number, HB and direction flags
> + *
> + * For compatibility purposes, x86_64 systems use only lower 32 bits
> + * for input and output arguments.
> + *
> + * The hypercall definitions differ in the low word of the %edx (arg3)
> + * in the following way: the old I/O port based interface uses the port
> + * number to distinguish between high- and low bandwidth versions, and
> + * uses IN/OUT instructions to define transfer direction.
>    *
>    * The new vmcall interface instead uses a set of flags to select
>    * bandwidth mode and transfer direction. The flags should be loaded
> - * into %dx by any user and are automatically replaced by the port
> - * number if the VMWARE_HYPERVISOR_PORT method is used.
> - *
> - * In short, new driver code should strictly use the new definition of
> - * %dx content.
> + * into arg3 by any user and are automatically replaced by the port
> + * number if the I/O port method is used.
> + */
> +
> +#define VMWARE_HYPERVISOR_HB		BIT(0)
> +#define VMWARE_HYPERVISOR_OUT		BIT(1)
> +
> +#define VMWARE_HYPERVISOR_PORT		0x5658
> +#define VMWARE_HYPERVISOR_PORT_HB	(VMWARE_HYPERVISOR_PORT | \
> +					 VMWARE_HYPERVISOR_HB)
> +
> +#define VMWARE_HYPERVISOR_MAGIC		0x564d5868U
> +
> +#define VMWARE_CMD_GETVERSION		10
> +#define VMWARE_CMD_GETHZ		45
> +#define VMWARE_CMD_GETVCPU_INFO		68
> +#define VMWARE_CMD_STEALCLOCK		91
> +
> +#define CPUID_VMWARE_FEATURES_ECX_VMMCALL	BIT(0)
> +#define CPUID_VMWARE_FEATURES_ECX_VMCALL	BIT(1)
> +
> +extern unsigned long vmware_hypercall_slow(unsigned long cmd,
> +					   unsigned long in1, unsigned long in3,
> +					   unsigned long in4, unsigned long in5,
> +					   u32 *out1, u32 *out2, u32 *out3,
> +					   u32 *out4, u32 *out5);
> +
> +/*
> + * The low bandwidth call. The low word of %edx is presumed to have OUT bit
> + * set. The high word of %edx may contain input data from the caller.
>    */
> +#define VMWARE_HYPERCALL					\
> +	ALTERNATIVE_2("movw %[port], %%dx\n\t"			\
> +		      "inl (%%dx), %%eax",			\
> +		      "vmcall", X86_FEATURE_VMCALL,		\
> +		      "vmmcall", X86_FEATURE_VMW_VMMCALL)
> +
> +static inline
> +unsigned long vmware_hypercall1(unsigned long cmd, unsigned long in1)
> +{
> +	unsigned long out0;
> +
> +	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)
> +		: [port] "i" (VMWARE_HYPERVISOR_PORT),
> +		  "a" (VMWARE_HYPERVISOR_MAGIC),
> +		  "b" (in1),
> +		  "c" (cmd),
> +		  "d" (0)
> +		: "cc", "memory");
> +	return out0;
> +}
> +
> +static inline
> +unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
> +				u32 *out1, u32 *out2)
> +{
> +	unsigned long out0;
> +
> +	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)
> +		: [port] "i" (VMWARE_HYPERVISOR_PORT),
> +		  "a" (VMWARE_HYPERVISOR_MAGIC),
> +		  "b" (in1),
> +		  "c" (cmd),
> +		  "d" (0)
> +		: "cc", "memory");
> +	return out0;
> +}
> +
> +static inline
> +unsigned long vmware_hypercall4(unsigned long cmd, unsigned long in1,
> +				u32 *out1, u32 *out2, u32 *out3)
> +{
> +	unsigned long out0;
> +
> +	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)
> +		: "cc", "memory");
> +	return out0;
> +}
> +
> +static inline
> +unsigned long vmware_hypercall5(unsigned long cmd, unsigned long in1,
> +				unsigned long in3, unsigned long in4,
> +				unsigned long in5, u32 *out2)
> +{
> +	unsigned long out0;
> +
> +	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
> +		return vmware_hypercall_slow(cmd, in1, in3, in4, in5,
> +					     NULL, out2, NULL, NULL, NULL);
> +
> +	asm_inline volatile (VMWARE_HYPERCALL
> +		: "=a" (out0), "=c" (*out2)
> +		: [port] "i" (VMWARE_HYPERVISOR_PORT),
> +		  "a" (VMWARE_HYPERVISOR_MAGIC),
> +		  "b" (in1),
> +		  "c" (cmd),
> +		  "d" (in3),
> +		  "S" (in4),
> +		  "D" (in5)
> +		: "cc", "memory");
> +	return out0;
> +}
> +
> +static inline
> +unsigned long vmware_hypercall6(unsigned long cmd, unsigned long in1,
> +				unsigned long in3, u32 *out2,
> +				u32 *out3, u32 *out4, u32 *out5)
> +{
> +	unsigned long out0;
> +
> +	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
> +		return vmware_hypercall_slow(cmd, in1, in3, 0, 0,
> +					     NULL, out2, out3, out4, out5);
> +
> +	asm_inline volatile (VMWARE_HYPERCALL
> +		: "=a" (out0), "=c" (*out2), "=d" (*out3), "=S" (*out4),
> +		  "=D" (*out5)
> +		: [port] "i" (VMWARE_HYPERVISOR_PORT),
> +		  "a" (VMWARE_HYPERVISOR_MAGIC),
> +		  "b" (in1),
> +		  "c" (cmd),
> +		  "d" (in3)
> +		: "cc", "memory");
> +	return out0;
> +}
> +
> +static inline
> +unsigned long vmware_hypercall7(unsigned long cmd, unsigned long in1,
> +				unsigned long in3, unsigned long in4,
> +				unsigned long in5, u32 *out1,
> +				u32 *out2, u32 *out3)
> +{
> +	unsigned long out0;
> +
> +	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
> +		return vmware_hypercall_slow(cmd, in1, in3, in4, in5,
> +					     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" (in3),
> +		  "S" (in4),
> +		  "D" (in5)
> +		: "cc", "memory");
> +	return out0;
> +}
> +
> +#ifdef CONFIG_X86_64
> +#define VMW_BP_CONSTRAINT "r"
> +#else
> +#define VMW_BP_CONSTRAINT "m"
> +#endif
> +
> +/*
> + * High bandwidth calls are not supported on encrypted memory guests.
> + * The caller should check cc_platform_has(CC_ATTR_MEM_ENCRYPT) and use
> + * low bandwidth hypercall if memory encryption is set.
> + * This assumption simplifies HB hypercall implementation to just I/O port
> + * based approach without alternative patching.
> + */
> +static inline
> +unsigned long vmware_hypercall_hb_out(unsigned long cmd, unsigned long in2,
> +				      unsigned long in3, unsigned long in4,
> +				      unsigned long in5, unsigned long in6,
> +				      u32 *out1)
> +{
> +	unsigned long out0;
> +
> +	asm_inline volatile (
> +		UNWIND_HINT_SAVE
> +		"push %%" _ASM_BP "\n\t"
> +		UNWIND_HINT_UNDEFINED
> +		"mov %[in6], %%" _ASM_BP "\n\t"
> +		"rep outsb\n\t"
> +		"pop %%" _ASM_BP "\n\t"
> +		UNWIND_HINT_RESTORE
> +		: "=a" (out0), "=b" (*out1)
> +		: "a" (VMWARE_HYPERVISOR_MAGIC),
> +		  "b" (cmd),
> +		  "c" (in2),
> +		  "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
> +		  "S" (in4),
> +		  "D" (in5),
> +		  [in6] VMW_BP_CONSTRAINT (in6)
> +		: "cc", "memory");
> +	return out0;
> +}
>   
> -/* Old port-based version */
> -#define VMWARE_HYPERVISOR_PORT    0x5658
> -#define VMWARE_HYPERVISOR_PORT_HB 0x5659
> +static inline
> +unsigned long vmware_hypercall_hb_in(unsigned long cmd, unsigned long in2,
> +				     unsigned long in3, unsigned long in4,
> +				     unsigned long in5, unsigned long in6,
> +				     u32 *out1)
> +{
> +	unsigned long out0;
>   
> -/* Current vmcall / vmmcall version */
> -#define VMWARE_HYPERVISOR_HB   BIT(0)
> -#define VMWARE_HYPERVISOR_OUT  BIT(1)
> +	asm_inline volatile (
> +		UNWIND_HINT_SAVE
> +		"push %%" _ASM_BP "\n\t"
> +		UNWIND_HINT_UNDEFINED
> +		"mov %[in6], %%" _ASM_BP "\n\t"
> +		"rep insb\n\t"
> +		"pop %%" _ASM_BP "\n\t"
> +		UNWIND_HINT_RESTORE
> +		: "=a" (out0), "=b" (*out1)
> +		: "a" (VMWARE_HYPERVISOR_MAGIC),
> +		  "b" (cmd),
> +		  "c" (in2),
> +		  "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
> +		  "S" (in4),
> +		  "D" (in5),
> +		  [in6] VMW_BP_CONSTRAINT (in6)
> +		: "cc", "memory");
> +	return out0;
> +}
> +#undef VMW_BP_CONSTRAINT
> +#undef VMWARE_HYPERCALL
>   
>   /* The low bandwidth call. The low word of edx is presumed clear. */
>   #define VMWARE_HYPERCALL						\
> diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
> index 11f83d07925e..533ac2d1de88 100644
> --- a/arch/x86/kernel/cpu/vmware.c
> +++ b/arch/x86/kernel/cpu/vmware.c
> @@ -41,17 +41,9 @@
>   
>   #define CPUID_VMWARE_INFO_LEAF               0x40000000
>   #define CPUID_VMWARE_FEATURES_LEAF           0x40000010
> -#define CPUID_VMWARE_FEATURES_ECX_VMMCALL    BIT(0)
> -#define CPUID_VMWARE_FEATURES_ECX_VMCALL     BIT(1)
>   
> -#define VMWARE_HYPERVISOR_MAGIC	0x564D5868
> -
> -#define VMWARE_CMD_GETVERSION    10
> -#define VMWARE_CMD_GETHZ         45
> -#define VMWARE_CMD_GETVCPU_INFO  68
>   #define VMWARE_CMD_LEGACY_X2APIC  3
>   #define VMWARE_CMD_VCPU_RESERVED 31
> -#define VMWARE_CMD_STEALCLOCK    91
>   
>   #define STEALCLOCK_NOT_AVAILABLE (-1)
>   #define STEALCLOCK_DISABLED        0
> @@ -110,6 +102,56 @@ struct vmware_steal_time {
>   static unsigned long vmware_tsc_khz __ro_after_init;
>   static u8 vmware_hypercall_mode     __ro_after_init;
>   
> +unsigned long vmware_hypercall_slow(unsigned long cmd,
> +				    unsigned long in1, unsigned long in3,
> +				    unsigned long in4, unsigned long in5,
> +				    u32 *out1, u32 *out2, u32 *out3,
> +				    u32 *out4, u32 *out5)
> +{
> +	unsigned long out0;
> +
> +	switch (vmware_hypercall_mode) {
> +	case CPUID_VMWARE_FEATURES_ECX_VMCALL:
> +		asm_inline volatile ("vmcall"
> +				: "=a" (out0), "=b" (*out1), "=c" (*out2),
> +				"=d" (*out3), "=S" (*out4), "=D" (*out5)
> +				: "a" (VMWARE_HYPERVISOR_MAGIC),
> +				"b" (in1),
> +				"c" (cmd),
> +				"d" (in3),
> +				"S" (in4),
> +				"D" (in5)
> +				: "cc", "memory");
> +		break;
> +	case CPUID_VMWARE_FEATURES_ECX_VMMCALL:
> +		asm_inline volatile ("vmmcall"
> +				: "=a" (out0), "=b" (*out1), "=c" (*out2),
> +				"=d" (*out3), "=S" (*out4), "=D" (*out5)
> +				: "a" (VMWARE_HYPERVISOR_MAGIC),
> +				"b" (in1),
> +				"c" (cmd),
> +				"d" (in3),
> +				"S" (in4),
> +				"D" (in5)
> +				: "cc", "memory");
> +		break;
> +	default:
> +		asm_inline volatile ("movw %[port], %%dx; inl (%%dx), %%eax"
> +				: "=a" (out0), "=b" (*out1), "=c" (*out2),
> +				"=d" (*out3), "=S" (*out4), "=D" (*out5)
> +				: [port] "i" (VMWARE_HYPERVISOR_PORT),
> +				"a" (VMWARE_HYPERVISOR_MAGIC),
> +				"b" (in1),
> +				"c" (cmd),
> +				"d" (in3),
> +				"S" (in4),
> +				"D" (in5)
> +				: "cc", "memory");
> +		break;
> +	}
> +	return out0;
> +}
> +
>   static inline int __vmware_platform(void)
>   {
>   	uint32_t eax, ebx, ecx, edx;

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ