/* SPDX-License-Identifier: GPL-2.0 or MIT */
#ifndef _ASM_X86_VMWARE_H
#define _ASM_X86_VMWARE_H
#include <asm /cpufeatures.h>
#include <asm /alternative.h>
#include <linux/stringify.h>
/*
* 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
*
* - Low bandwidth TDX hypercalls ( x86_64 only ) are similar to LB
* hypercalls . They also have up to 6 input and 6 output on registers
* arguments , with different argument to register mapping :
* % r12 ( arg0 ) , % rbx ( arg1 ) , % r13 ( arg2 ) , % rdx ( arg3 ) ,
* % rsi ( arg4 ) , % rdi ( arg5 ) .
*
* - 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 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 0 x5658
#define VMWARE_HYPERVISOR_PORT_HB (VMWARE_HYPERVISOR_PORT | \
VMWARE_HYPERVISOR_HB)
#define VMWARE_HYPERVISOR_MAGIC 0 x564d5868U
#define VMWARE_CMD_GETVERSION 10
#define VMWARE_CMD_GETHZ 45
#define VMWARE_CMD_GETVCPU_INFO 68
#define VMWARE_CMD_STEALCLOCK 91
/*
* Hypercall command mask :
* bits [ 6 : 0 ] command , range [ 0 , 127 ]
* bits [ 19 : 16 ] sub - command , range [ 0 , 15 ]
*/
#define VMWARE_CMD_MASK 0 xf007fU
#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);
#define VMWARE_TDX_VENDOR_LEAF 0 x1af7e4909ULL
#define VMWARE_TDX_HCALL_FUNC 1
extern unsigned long vmware_tdx_hypercall(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 (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)
: [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 (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)
: [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 (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 )
: "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 (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
return vmware_tdx_hypercall(cmd, in1, in3, in4, in5,
NULL, out2, NULL, NULL, NULL);
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 (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
return vmware_tdx_hypercall(cmd, in1, in3, 0 , 0 ,
NULL, out2, out3, out4, out5);
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 (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
return vmware_tdx_hypercall(cmd, in1, in3, in4, in5,
out1, out2, out3, NULL, NULL);
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;
}
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;
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
#endif
Messung V0.5 in Prozent C=99 H=98 G=98
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland