Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 57b7b6a

Browse files
YustasSwampbp3tk0v
authored andcommitted
x86/vmware: Add TDX hypercall support
VMware hypercalls use I/O port, VMCALL or VMMCALL instructions. Add a call to __tdx_hypercall() in order to support TDX guests. No change in high bandwidth hypercalls, as only low bandwidth ones are supported for TDX guests. [ bp: Massage, clear on-stack struct tdx_module_args variable. ] Co-developed-by: Tim Merrifield <tim.merrifield@broadcom.com> Signed-off-by: Tim Merrifield <tim.merrifield@broadcom.com> Signed-off-by: Alexey Makhalov <alexey.makhalov@broadcom.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/20240613191650.9913-9-alexey.makhalov@broadcom.com
1 parent 9dfb180 commit 57b7b6a

File tree

2 files changed

+97
-0
lines changed

2 files changed

+97
-0
lines changed

arch/x86/include/asm/vmware.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
* arg2 - Hypercall command
1919
* arg3 bits [15:0] - Port number, LB and direction flags
2020
*
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+
*
2127
* - High bandwidth (HB) hypercalls are I/O port based only. They have
2228
* up to 7 input and 7 output arguments passed and returned using
2329
* registers: %eax (arg0), %ebx (arg1), %ecx (arg2), %edx (arg3),
@@ -54,6 +60,12 @@
5460
#define VMWARE_CMD_GETHZ 45
5561
#define VMWARE_CMD_GETVCPU_INFO 68
5662
#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
5769

5870
#define CPUID_VMWARE_FEATURES_ECX_VMMCALL BIT(0)
5971
#define CPUID_VMWARE_FEATURES_ECX_VMCALL BIT(1)
@@ -64,6 +76,15 @@ extern unsigned long vmware_hypercall_slow(unsigned long cmd,
6476
u32 *out1, u32 *out2, u32 *out3,
6577
u32 *out4, u32 *out5);
6678

79+
#define VMWARE_TDX_VENDOR_LEAF 0x1af7e4909ULL
80+
#define VMWARE_TDX_HCALL_FUNC 1
81+
82+
extern 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+
6788
/*
6889
* The low bandwidth call. The low word of %edx is presumed to have OUT bit
6990
* set. The high word of %edx may contain input data from the caller.
@@ -79,6 +100,10 @@ unsigned long vmware_hypercall1(unsigned long cmd, unsigned long in1)
79100
{
80101
unsigned long out0;
81102

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+
82107
if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
83108
return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
84109
NULL, NULL, NULL, NULL, NULL);
@@ -100,6 +125,10 @@ unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
100125
{
101126
unsigned long out0;
102127

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+
103132
if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
104133
return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
105134
out1, out2, NULL, NULL, NULL);
@@ -121,6 +150,10 @@ unsigned long vmware_hypercall4(unsigned long cmd, unsigned long in1,
121150
{
122151
unsigned long out0;
123152

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+
124157
if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
125158
return vmware_hypercall_slow(cmd, in1, 0, 0, 0,
126159
out1, out2, out3, NULL, NULL);
@@ -143,6 +176,10 @@ unsigned long vmware_hypercall5(unsigned long cmd, unsigned long in1,
143176
{
144177
unsigned long out0;
145178

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+
146183
if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
147184
return vmware_hypercall_slow(cmd, in1, in3, in4, in5,
148185
NULL, out2, NULL, NULL, NULL);
@@ -167,6 +204,10 @@ unsigned long vmware_hypercall6(unsigned long cmd, unsigned long in1,
167204
{
168205
unsigned long out0;
169206

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+
170211
if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
171212
return vmware_hypercall_slow(cmd, in1, in3, 0, 0,
172213
NULL, out2, out3, out4, out5);
@@ -191,6 +232,10 @@ unsigned long vmware_hypercall7(unsigned long cmd, unsigned long in1,
191232
{
192233
unsigned long out0;
193234

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+
194239
if (unlikely(!alternatives_patched) && !__is_defined(MODULE))
195240
return vmware_hypercall_slow(cmd, in1, in3, in4, in5,
196241
out1, out2, out3, NULL, NULL);

arch/x86/kernel/cpu/vmware.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,58 @@ static bool __init vmware_legacy_x2apic_available(void)
489489
(eax & GETVCPU_INFO_LEGACY_X2APIC);
490490
}
491491

492+
#ifdef CONFIG_INTEL_TDX_GUEST
493+
/*
494+
* TDCALL[TDG.VP.VMCALL] uses %rax (arg0) and %rcx (arg2). Therefore,
495+
* we remap those registers to %r12 and %r13, respectively.
496+
*/
497+
unsigned long vmware_tdx_hypercall(unsigned long cmd,
498+
unsigned long in1, unsigned long in3,
499+
unsigned long in4, unsigned long in5,
500+
u32 *out1, u32 *out2, u32 *out3,
501+
u32 *out4, u32 *out5)
502+
{
503+
struct tdx_module_args args = {};
504+
505+
if (!hypervisor_is_type(X86_HYPER_VMWARE)) {
506+
pr_warn_once("Incorrect usage\n");
507+
return ULONG_MAX;
508+
}
509+
510+
if (cmd & ~VMWARE_CMD_MASK) {
511+
pr_warn_once("Out of range command %lx\n", cmd);
512+
return ULONG_MAX;
513+
}
514+
515+
args.rbx = in1;
516+
args.rdx = in3;
517+
args.rsi = in4;
518+
args.rdi = in5;
519+
args.r10 = VMWARE_TDX_VENDOR_LEAF;
520+
args.r11 = VMWARE_TDX_HCALL_FUNC;
521+
args.r12 = VMWARE_HYPERVISOR_MAGIC;
522+
args.r13 = cmd;
523+
/* CPL */
524+
args.r15 = 0;
525+
526+
__tdx_hypercall(&args);
527+
528+
if (out1)
529+
*out1 = args.rbx;
530+
if (out2)
531+
*out2 = args.r13;
532+
if (out3)
533+
*out3 = args.rdx;
534+
if (out4)
535+
*out4 = args.rsi;
536+
if (out5)
537+
*out5 = args.rdi;
538+
539+
return args.r12;
540+
}
541+
EXPORT_SYMBOL_GPL(vmware_tdx_hypercall);
542+
#endif
543+
492544
#ifdef CONFIG_AMD_MEM_ENCRYPT
493545
static void vmware_sev_es_hcall_prepare(struct ghcb *ghcb,
494546
struct pt_regs *regs)

0 commit comments

Comments
 (0)