File Index
Files and directories
Sign in
FILE

vmware.h

File preview with syntax highlighting.

linux-6.19.14/arch/x86/include/asm/vmware.h C
  1/* SPDX-License-Identifier: GPL-2.0 or MIT */
  2#ifndef _ASM_X86_VMWARE_H
  3#define _ASM_X86_VMWARE_H
  4
  5#include <asm/cpufeatures.h>
  6#include <asm/alternative.h>
  7#include <linux/stringify.h>
  8
  9/*
 10 * VMware hypercall ABI.
 11 *
 12 * - Low bandwidth (LB) hypercalls (I/O port based, vmcall and vmmcall)
 13 * have up to 6 input and 6 output arguments passed and returned using
 14 * registers: %eax (arg0), %ebx (arg1), %ecx (arg2), %edx (arg3),
 15 * %esi (arg4), %edi (arg5).
 16 * The following input arguments must be initialized by the caller:
 17 * arg0 - VMWARE_HYPERVISOR_MAGIC
 18 * arg2 - Hypercall command
 19 * arg3 bits [15:0] - Port number, LB and direction flags
 20 *
 21 * - Low bandwidth TDX hypercalls (x86_64 only) are similar to LB
 22 * hypercalls. They also have up to 6 input and 6 output on registers
 23 * arguments, with different argument to register mapping:
 24 * %r12 (arg0), %rbx (arg1), %r13 (arg2), %rdx (arg3),
 25 * %rsi (arg4), %rdi (arg5).
 26 *
 27 * - High bandwidth (HB) hypercalls are I/O port based only. They have
 28 * up to 7 input and 7 output arguments passed and returned using
 29 * registers: %eax (arg0), %ebx (arg1), %ecx (arg2), %edx (arg3),
 30 * %esi (arg4), %edi (arg5), %ebp (arg6).
 31 * The following input arguments must be initialized by the caller:
 32 * arg0 - VMWARE_HYPERVISOR_MAGIC
 33 * arg1 - Hypercall command
 34 * arg3 bits [15:0] - Port number, HB and direction flags
 35 *
 36 * For compatibility purposes, x86_64 systems use only lower 32 bits
 37 * for input and output arguments.
 38 *
 39 * The hypercall definitions differ in the low word of the %edx (arg3)
 40 * in the following way: the old I/O port based interface uses the port
 41 * number to distinguish between high- and low bandwidth versions, and
 42 * uses IN/OUT instructions to define transfer direction.
 43 *
 44 * The new vmcall interface instead uses a set of flags to select
 45 * bandwidth mode and transfer direction. The flags should be loaded
 46 * into arg3 by any user and are automatically replaced by the port
 47 * number if the I/O port method is used.
 48 */
 49
 50#define VMWARE_HYPERVISOR_HB		BIT(0)
 51#define VMWARE_HYPERVISOR_OUT		BIT(1)
 52
 53#define VMWARE_HYPERVISOR_PORT		0x5658
 54#define VMWARE_HYPERVISOR_PORT_HB	(VMWARE_HYPERVISOR_PORT | \
 55					 VMWARE_HYPERVISOR_HB)
 56
 57#define VMWARE_HYPERVISOR_MAGIC		0x564d5868U
 58
 59#define VMWARE_CMD_GETVERSION		10
 60#define VMWARE_CMD_GETHZ		45
 61#define VMWARE_CMD_GETVCPU_INFO		68
 62#define VMWARE_CMD_STEALCLOCK		91
 63/*
 64 * Hypercall command mask:
 65 *   bits [6:0] command, range [0, 127]
 66 *   bits [19:16] sub-command, range [0, 15]
 67 */
 68#define VMWARE_CMD_MASK			0xf007fU
 69
 70#define CPUID_VMWARE_FEATURES_ECX_VMMCALL	BIT(0)
 71#define CPUID_VMWARE_FEATURES_ECX_VMCALL	BIT(1)
 72
 73extern unsigned long vmware_hypercall_slow(unsigned long cmd,
 74					   unsigned long in1, unsigned long in3,
 75					   unsigned long in4, unsigned long in5,
 76					   u32 *out1, u32 *out2, u32 *out3,
 77					   u32 *out4, u32 *out5);
 78
 79#define VMWARE_TDX_VENDOR_LEAF 0x1af7e4909ULL
 80#define VMWARE_TDX_HCALL_FUNC  1
 81
 82extern unsigned long vmware_tdx_hypercall(unsigned long cmd,
 83					  unsigned long in1, unsigned long in3,
 84					  unsigned long in4, unsigned long in5,
 85					  u32 *out1, u32 *out2, u32 *out3,
 86					  u32 *out4, u32 *out5);
 87
 88/*
 89 * The low bandwidth call. The low word of %edx is presumed to have OUT bit
 90 * set. The high word of %edx may contain input data from the caller.
 91 */
 92#define VMWARE_HYPERCALL					\
 93	ALTERNATIVE_2("movw %[port], %%dx\n\t"			\
 94		      "inl (%%dx), %%eax",			\
 95		      "vmcall", X86_FEATURE_VMCALL,		\
 96		      "vmmcall", X86_FEATURE_VMW_VMMCALL)
 97
 98static inline
 99unsigned long vmware_hypercall1(unsigned long cmd, unsigned long in1)
100{
101	unsigned long out0;
102
103	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
104		return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
105					    NULL, NULL, NULL, NULL, NULL);
106
107	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
108		return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
109					     NULL, NULL, NULL, NULL, NULL);
110
111	asm_inline volatile (VMWARE_HYPERCALL
112		: "=a" (out0)
113		: [port] "i" (VMWARE_HYPERVISOR_PORT),
114		  "a" (VMWARE_HYPERVISOR_MAGIC),
115		  "b" (in1),
116		  "c" (cmd),
117		  "d" (0)
118		: "cc", "memory");
119	return out0;
120}
121
122static inline
123unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
124				u32 *out1, u32 *out2)
125{
126	unsigned long out0;
127
128	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
129		return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
130					    out1, out2, NULL, NULL, NULL);
131
132	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
133		return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
134					     out1, out2, NULL, NULL, NULL);
135
136	asm_inline volatile (VMWARE_HYPERCALL
137		: "=a" (out0), "=b" (*out1), "=c" (*out2)
138		: [port] "i" (VMWARE_HYPERVISOR_PORT),
139		  "a" (VMWARE_HYPERVISOR_MAGIC),
140		  "b" (in1),
141		  "c" (cmd),
142		  "d" (0)
143		: "di", "si", "cc", "memory");
144	return out0;
145}
146
147static inline
148unsigned long vmware_hypercall4(unsigned long cmd, unsigned long in1,
149				u32 *out1, u32 *out2, u32 *out3)
150{
151	unsigned long out0;
152
153	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
154		return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
155					    out1, out2, out3, NULL, NULL);
156
157	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
158		return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
159					     out1, out2, out3, NULL, NULL);
160
161	asm_inline volatile (VMWARE_HYPERCALL
162		: "=a" (out0), "=b" (*out1), "=c" (*out2), "=d" (*out3)
163		: [port] "i" (VMWARE_HYPERVISOR_PORT),
164		  "a" (VMWARE_HYPERVISOR_MAGIC),
165		  "b" (in1),
166		  "c" (cmd),
167		  "d" (0)
168		: "di", "si", "cc", "memory");
169	return out0;
170}
171
172static inline
173unsigned long vmware_hypercall5(unsigned long cmd, unsigned long in1,
174				unsigned long in3, unsigned long in4,
175				unsigned long in5, u32 *out2)
176{
177	unsigned long out0;
178
179	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
180		return vmware_tdx_hypercall(cmd, in1, in3, in4, in5,
181					    NULL, out2, NULL, NULL, NULL);
182
183	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
184		return vmware_hypercall_slow(cmd, in1, in3, in4, in5,
185					     NULL, out2, NULL, NULL, NULL);
186
187	asm_inline volatile (VMWARE_HYPERCALL
188		: "=a" (out0), "=c" (*out2)
189		: [port] "i" (VMWARE_HYPERVISOR_PORT),
190		  "a" (VMWARE_HYPERVISOR_MAGIC),
191		  "b" (in1),
192		  "c" (cmd),
193		  "d" (in3),
194		  "S" (in4),
195		  "D" (in5)
196		: "cc", "memory");
197	return out0;
198}
199
200static inline
201unsigned long vmware_hypercall6(unsigned long cmd, unsigned long in1,
202				unsigned long in3, u32 *out2,
203				u32 *out3, u32 *out4, u32 *out5)
204{
205	unsigned long out0;
206
207	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
208		return vmware_tdx_hypercall(cmd, in1, in3, 0, 0,
209					    NULL, out2, out3, out4, out5);
210
211	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
212		return vmware_hypercall_slow(cmd, in1, in3, 0, 0,
213					     NULL, out2, out3, out4, out5);
214
215	asm_inline volatile (VMWARE_HYPERCALL
216		: "=a" (out0), "=c" (*out2), "=d" (*out3), "=S" (*out4),
217		  "=D" (*out5)
218		: [port] "i" (VMWARE_HYPERVISOR_PORT),
219		  "a" (VMWARE_HYPERVISOR_MAGIC),
220		  "b" (in1),
221		  "c" (cmd),
222		  "d" (in3)
223		: "cc", "memory");
224	return out0;
225}
226
227static inline
228unsigned long vmware_hypercall7(unsigned long cmd, unsigned long in1,
229				unsigned long in3, unsigned long in4,
230				unsigned long in5, u32 *out1,
231				u32 *out2, u32 *out3)
232{
233	unsigned long out0;
234
235	if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
236		return vmware_tdx_hypercall(cmd, in1, in3, in4, in5,
237					    out1, out2, out3, NULL, NULL);
238
239	if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
240		return vmware_hypercall_slow(cmd, in1, in3, in4, in5,
241					     out1, out2, out3, NULL, NULL);
242
243	asm_inline volatile (VMWARE_HYPERCALL
244		: "=a" (out0), "=b" (*out1), "=c" (*out2), "=d" (*out3)
245		: [port] "i" (VMWARE_HYPERVISOR_PORT),
246		  "a" (VMWARE_HYPERVISOR_MAGIC),
247		  "b" (in1),
248		  "c" (cmd),
249		  "d" (in3),
250		  "S" (in4),
251		  "D" (in5)
252		: "cc", "memory");
253	return out0;
254}
255
256#ifdef CONFIG_X86_64
257#define VMW_BP_CONSTRAINT "r"
258#else
259#define VMW_BP_CONSTRAINT "m"
260#endif
261
262/*
263 * High bandwidth calls are not supported on encrypted memory guests.
264 * The caller should check cc_platform_has(CC_ATTR_MEM_ENCRYPT) and use
265 * low bandwidth hypercall if memory encryption is set.
266 * This assumption simplifies HB hypercall implementation to just I/O port
267 * based approach without alternative patching.
268 */
269static inline
270unsigned long vmware_hypercall_hb_out(unsigned long cmd, unsigned long in2,
271				      unsigned long in3, unsigned long in4,
272				      unsigned long in5, unsigned long in6,
273				      u32 *out1)
274{
275	unsigned long out0;
276
277	asm_inline volatile (
278		UNWIND_HINT_SAVE
279		"push %%" _ASM_BP "\n\t"
280		UNWIND_HINT_UNDEFINED
281		"mov %[in6], %%" _ASM_BP "\n\t"
282		"rep outsb\n\t"
283		"pop %%" _ASM_BP "\n\t"
284		UNWIND_HINT_RESTORE
285		: "=a" (out0), "=b" (*out1)
286		: "a" (VMWARE_HYPERVISOR_MAGIC),
287		  "b" (cmd),
288		  "c" (in2),
289		  "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
290		  "S" (in4),
291		  "D" (in5),
292		  [in6] VMW_BP_CONSTRAINT (in6)
293		: "cc", "memory");
294	return out0;
295}
296
297static inline
298unsigned long vmware_hypercall_hb_in(unsigned long cmd, unsigned long in2,
299				     unsigned long in3, unsigned long in4,
300				     unsigned long in5, unsigned long in6,
301				     u32 *out1)
302{
303	unsigned long out0;
304
305	asm_inline volatile (
306		UNWIND_HINT_SAVE
307		"push %%" _ASM_BP "\n\t"
308		UNWIND_HINT_UNDEFINED
309		"mov %[in6], %%" _ASM_BP "\n\t"
310		"rep insb\n\t"
311		"pop %%" _ASM_BP "\n\t"
312		UNWIND_HINT_RESTORE
313		: "=a" (out0), "=b" (*out1)
314		: "a" (VMWARE_HYPERVISOR_MAGIC),
315		  "b" (cmd),
316		  "c" (in2),
317		  "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
318		  "S" (in4),
319		  "D" (in5),
320		  [in6] VMW_BP_CONSTRAINT (in6)
321		: "cc", "memory");
322	return out0;
323}
324#undef VMW_BP_CONSTRAINT
325#undef VMWARE_HYPERCALL
326
327#endif
~/ Read-only file preview.