Skip to content

Commit c641cfb

Browse files
kaihuanghansendc
authored andcommitted
x86/tdx: Make TDX_HYPERCALL asm similar to TDX_MODULE_CALL
Now the 'struct tdx_hypercall_args' and 'struct tdx_module_args' are almost the same, and the TDX_HYPERCALL and TDX_MODULE_CALL asm macro share similar code pattern too. The __tdx_hypercall() and __tdcall() should be unified to use the same assembly code. As a preparation to unify them, simplify the TDX_HYPERCALL to make it more like the TDX_MODULE_CALL. The TDX_HYPERCALL takes the pointer of 'struct tdx_hypercall_args' as function call argument, and does below extra things comparing to the TDX_MODULE_CALL: 1) It sets RAX to 0 (TDG.VP.VMCALL leaf) internally; 2) It sets RCX to the (fixed) bitmap of shared registers internally; 3) It calls __tdx_hypercall_failed() internally (and panics) when the TDCALL instruction itself fails; 4) After TDCALL, it moves R10 to RAX to return the return code of the VMCALL leaf, regardless the '\ret' asm macro argument; Firstly, change the TDX_HYPERCALL to take the same function call arguments as the TDX_MODULE_CALL does: TDCALL leaf ID, and the pointer to 'struct tdx_module_args'. Then 1) and 2) can be moved to the caller: - TDG.VP.VMCALL leaf ID can be passed via the function call argument; - 'struct tdx_module_args' is 'struct tdx_hypercall_args' + RCX, thus the bitmap of shared registers can be passed via RCX in the structure. Secondly, to move 3) and 4) out of assembly, make the TDX_HYPERCALL always save output registers to the structure. The caller then can: - Call __tdx_hypercall_failed() when TDX_HYPERCALL returns error; - Return R10 in the structure as the return code of the VMCALL leaf; With above changes, change the asm function from __tdx_hypercall() to __tdcall_hypercall(), and reimplement __tdx_hypercall() as the C wrapper of it. This avoids having to add another wrapper of __tdx_hypercall() (_tdx_hypercall() is already taken). The __tdcall_hypercall() will be replaced with a __tdcall() variant using TDX_MODULE_CALL in a later commit as the final goal is to have one assembly to handle both TDCALL and TDVMCALL. Currently, the __tdx_hypercall() asm is in '.noinstr.text'. To keep this unchanged, annotate __tdx_hypercall(), which is a C function now, as 'noinstr'. Remove the __tdx_hypercall_ret() as __tdx_hypercall() already does so. Implement __tdx_hypercall() in tdx-shared.c so it can be shared with the compressed code. Opportunistically fix a checkpatch error complaining using space around parenthesis '(' and ')' while moving the bitmap of shared registers to <asm/shared/tdx.h>. [ dhansen: quash new calls of __tdx_hypercall_ret() that showed up ] Suggested-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Kai Huang <kai.huang@intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/all/0cbf25e7aee3256288045023a31f65f0cef90af4.1692096753.git.kai.huang%40intel.com
1 parent 12f34ed commit c641cfb

File tree

7 files changed

+160
-152
lines changed

7 files changed

+160
-152
lines changed

arch/x86/boot/compressed/tdx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ static inline unsigned int tdx_io_in(int size, u16 port)
2626
.r14 = port,
2727
};
2828

29-
if (__tdx_hypercall_ret(&args))
29+
if (__tdx_hypercall(&args))
3030
return UINT_MAX;
3131

3232
return args.r11;

arch/x86/coco/tdx/tdcall.S

Lines changed: 50 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,12 @@
22
#include <asm/asm-offsets.h>
33
#include <asm/asm.h>
44
#include <asm/frame.h>
5-
#include <asm/unwind_hints.h>
65

76
#include <linux/linkage.h>
8-
#include <linux/bits.h>
97
#include <linux/errno.h>
108

119
#include "../../virt/vmx/tdx/tdxcall.S"
1210

13-
/*
14-
* Bitmasks of exposed registers (with VMM).
15-
*/
16-
#define TDX_RDX BIT(2)
17-
#define TDX_RBX BIT(3)
18-
#define TDX_RSI BIT(6)
19-
#define TDX_RDI BIT(7)
20-
#define TDX_R8 BIT(8)
21-
#define TDX_R9 BIT(9)
22-
#define TDX_R10 BIT(10)
23-
#define TDX_R11 BIT(11)
24-
#define TDX_R12 BIT(12)
25-
#define TDX_R13 BIT(13)
26-
#define TDX_R14 BIT(14)
27-
#define TDX_R15 BIT(15)
28-
29-
/*
30-
* These registers are clobbered to hold arguments for each
31-
* TDVMCALL. They are safe to expose to the VMM.
32-
* Each bit in this mask represents a register ID. Bit field
33-
* details can be found in TDX GHCI specification, section
34-
* titled "TDCALL [TDG.VP.VMCALL] leaf".
35-
*/
36-
#define TDVMCALL_EXPOSE_REGS_MASK \
37-
( TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \
38-
TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15 )
39-
4011
.section .noinstr.text, "ax"
4112

4213
/*
@@ -78,10 +49,13 @@ SYM_FUNC_END(__tdcall_ret)
7849
* TDX_HYPERCALL - Make hypercalls to a TDX VMM using TDVMCALL leaf of TDCALL
7950
* instruction
8051
*
81-
* Transforms values in function call argument struct tdx_hypercall_args @args
52+
* Transforms values in function call argument struct tdx_module_args @args
8253
* into the TDCALL register ABI. After TDCALL operation, VMM output is saved
8354
* back in @args, if \ret is 1.
8455
*
56+
* Depends on the caller to pass TDG.VP.VMCALL as the TDCALL leaf, and set
57+
* @args::rcx to TDVMCALL_EXPOSE_REGS_MASK.
58+
*
8559
*-------------------------------------------------------------------------
8660
* TD VMCALL ABI:
8761
*-------------------------------------------------------------------------
@@ -106,7 +80,7 @@ SYM_FUNC_END(__tdcall_ret)
10680
* R8-R15 - Same as above.
10781
*
10882
*/
109-
.macro TDX_HYPERCALL ret:req
83+
.macro TDX_HYPERCALL
11084
FRAME_BEGIN
11185

11286
/* Save callee-saved GPRs as mandated by the x86_64 ABI */
@@ -116,63 +90,52 @@ SYM_FUNC_END(__tdcall_ret)
11690
push %r12
11791
push %rbx
11892

119-
/* Free RDI to be used as TDVMCALL arguments */
93+
/* Move Leaf ID to RAX */
12094
movq %rdi, %rax
12195

96+
/* Move bitmap of shared registers to RCX */
97+
movq TDX_MODULE_rcx(%rsi), %rcx
98+
12299
/* Copy hypercall registers from arg struct: */
123-
movq TDX_HYPERCALL_r8(%rax), %r8
124-
movq TDX_HYPERCALL_r9(%rax), %r9
125-
movq TDX_HYPERCALL_r10(%rax), %r10
126-
movq TDX_HYPERCALL_r11(%rax), %r11
127-
movq TDX_HYPERCALL_r12(%rax), %r12
128-
movq TDX_HYPERCALL_r13(%rax), %r13
129-
movq TDX_HYPERCALL_r14(%rax), %r14
130-
movq TDX_HYPERCALL_r15(%rax), %r15
131-
movq TDX_HYPERCALL_rdi(%rax), %rdi
132-
movq TDX_HYPERCALL_rsi(%rax), %rsi
133-
movq TDX_HYPERCALL_rbx(%rax), %rbx
134-
movq TDX_HYPERCALL_rdx(%rax), %rdx
135-
136-
push %rax
137-
138-
/* Mangle function call ABI into TDCALL ABI: */
139-
/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
140-
xor %eax, %eax
141-
142-
movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
100+
movq TDX_MODULE_r8(%rsi), %r8
101+
movq TDX_MODULE_r9(%rsi), %r9
102+
movq TDX_MODULE_r10(%rsi), %r10
103+
movq TDX_MODULE_r11(%rsi), %r11
104+
movq TDX_MODULE_r12(%rsi), %r12
105+
movq TDX_MODULE_r13(%rsi), %r13
106+
movq TDX_MODULE_r14(%rsi), %r14
107+
movq TDX_MODULE_r15(%rsi), %r15
108+
movq TDX_MODULE_rdi(%rsi), %rdi
109+
movq TDX_MODULE_rbx(%rsi), %rbx
110+
movq TDX_MODULE_rdx(%rsi), %rdx
111+
112+
pushq %rsi
113+
movq TDX_MODULE_rsi(%rsi), %rsi
143114

144115
tdcall
145116

146117
/*
147-
* RAX!=0 indicates a failure of the TDVMCALL mechanism itself and that
148-
* something has gone horribly wrong with the TDX module.
118+
* Restore the pointer of the structure to save output registers.
149119
*
150-
* The return status of the hypercall operation is in a separate
151-
* register (in R10). Hypercall errors are a part of normal operation
152-
* and are handled by callers.
120+
* RCX is used as bitmap of shared registers and doesn't hold any
121+
* value provided by the VMM, thus it can be used as spare to
122+
* restore the structure pointer.
153123
*/
154-
testq %rax, %rax
155-
jne .Lpanic\@
156-
157-
pop %rax
158-
159-
.if \ret
160-
movq %r8, TDX_HYPERCALL_r8(%rax)
161-
movq %r9, TDX_HYPERCALL_r9(%rax)
162-
movq %r10, TDX_HYPERCALL_r10(%rax)
163-
movq %r11, TDX_HYPERCALL_r11(%rax)
164-
movq %r12, TDX_HYPERCALL_r12(%rax)
165-
movq %r13, TDX_HYPERCALL_r13(%rax)
166-
movq %r14, TDX_HYPERCALL_r14(%rax)
167-
movq %r15, TDX_HYPERCALL_r15(%rax)
168-
movq %rdi, TDX_HYPERCALL_rdi(%rax)
169-
movq %rsi, TDX_HYPERCALL_rsi(%rax)
170-
movq %rbx, TDX_HYPERCALL_rbx(%rax)
171-
movq %rdx, TDX_HYPERCALL_rdx(%rax)
172-
.endif
173-
174-
/* TDVMCALL leaf return code is in R10 */
175-
movq %r10, %rax
124+
popq %rcx
125+
movq %rsi, TDX_MODULE_rsi(%rcx)
126+
movq %rcx, %rsi
127+
128+
movq %r8, TDX_MODULE_r8(%rsi)
129+
movq %r9, TDX_MODULE_r9(%rsi)
130+
movq %r10, TDX_MODULE_r10(%rsi)
131+
movq %r11, TDX_MODULE_r11(%rsi)
132+
movq %r12, TDX_MODULE_r12(%rsi)
133+
movq %r13, TDX_MODULE_r13(%rsi)
134+
movq %r14, TDX_MODULE_r14(%rsi)
135+
movq %r15, TDX_MODULE_r15(%rsi)
136+
movq %rdi, TDX_MODULE_rdi(%rsi)
137+
movq %rbx, TDX_MODULE_rbx(%rsi)
138+
movq %rdx, TDX_MODULE_rdx(%rsi)
176139

177140
/*
178141
* Zero out registers exposed to the VMM to avoid speculative execution
@@ -198,33 +161,20 @@ SYM_FUNC_END(__tdcall_ret)
198161
FRAME_END
199162

200163
RET
201-
.Lpanic\@:
202-
call __tdx_hypercall_failed
203-
/* __tdx_hypercall_failed never returns */
204-
REACHABLE
205-
jmp .Lpanic\@
206164
.endm
207165

208166
/*
209167
*
210-
* __tdx_hypercall() function ABI:
211-
*
212-
* @args (RDI) - struct tdx_hypercall_args for input
213-
*
214-
* On successful completion, return the hypercall error code.
215-
*/
216-
SYM_FUNC_START(__tdx_hypercall)
217-
TDX_HYPERCALL ret=0
218-
SYM_FUNC_END(__tdx_hypercall)
219-
220-
/*
168+
* __tdcall_hypercall() function ABI:
221169
*
222-
* __tdx_hypercall_ret() function ABI:
170+
* @fn (RDI) - TDCALL leaf ID, moved to RAX
171+
* @args (RSI) - struct tdx_module_args for input/output
223172
*
224-
* @args (RDI) - struct tdx_hypercall_args for input and output
173+
* @fn and @args::rcx from the caller must be TDG_VP_VMCALL and
174+
* TDVMCALL_EXPOSE_REGS_MASK respectively.
225175
*
226176
* On successful completion, return the hypercall error code.
227177
*/
228-
SYM_FUNC_START(__tdx_hypercall_ret)
229-
TDX_HYPERCALL ret=1
230-
SYM_FUNC_END(__tdx_hypercall_ret)
178+
SYM_FUNC_START(__tdcall_hypercall)
179+
TDX_HYPERCALL
180+
SYM_FUNC_END(__tdcall_hypercall)

arch/x86/coco/tdx/tdx-shared.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,46 @@ bool tdx_accept_memory(phys_addr_t start, phys_addr_t end)
6969

7070
return true;
7171
}
72+
73+
noinstr u64 __tdx_hypercall(struct tdx_hypercall_args *args)
74+
{
75+
struct tdx_module_args margs = {
76+
.rcx = TDVMCALL_EXPOSE_REGS_MASK,
77+
.rdx = args->rdx,
78+
.r8 = args->r8,
79+
.r9 = args->r9,
80+
.r10 = args->r10,
81+
.r11 = args->r11,
82+
.r12 = args->r12,
83+
.r13 = args->r13,
84+
.r14 = args->r14,
85+
.r15 = args->r15,
86+
.rbx = args->rbx,
87+
.rdi = args->rdi,
88+
.rsi = args->rsi,
89+
};
90+
91+
/*
92+
* Failure of __tdcall_hypercall() indicates a failure of the TDVMCALL
93+
* mechanism itself and that something has gone horribly wrong with
94+
* the TDX module. __tdx_hypercall_failed() never returns.
95+
*/
96+
if (__tdcall_hypercall(TDG_VP_VMCALL, &margs))
97+
__tdx_hypercall_failed();
98+
99+
args->r8 = margs.r8;
100+
args->r9 = margs.r9;
101+
args->r10 = margs.r10;
102+
args->r11 = margs.r11;
103+
args->r12 = margs.r12;
104+
args->r13 = margs.r13;
105+
args->r14 = margs.r14;
106+
args->r15 = margs.r15;
107+
args->rdi = margs.rdi;
108+
args->rsi = margs.rsi;
109+
args->rbx = margs.rbx;
110+
args->rdx = margs.rdx;
111+
112+
/* TDVMCALL leaf return code is in R10 */
113+
return args->r10;
114+
}

arch/x86/coco/tdx/tdx.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
#define TDREPORT_SUBTYPE_0 0
3939

4040
/* Called from __tdx_hypercall() for unrecoverable failure */
41-
noinstr void __tdx_hypercall_failed(void)
41+
noinstr void __noreturn __tdx_hypercall_failed(void)
4242
{
4343
instrumentation_begin();
4444
panic("TDVMCALL failed. TDX module bug?");
@@ -285,7 +285,7 @@ static int read_msr(struct pt_regs *regs, struct ve_info *ve)
285285
* can be found in TDX Guest-Host-Communication Interface
286286
* (GHCI), section titled "TDG.VP.VMCALL<Instruction.RDMSR>".
287287
*/
288-
if (__tdx_hypercall_ret(&args))
288+
if (__tdx_hypercall(&args))
289289
return -EIO;
290290

291291
regs->ax = lower_32_bits(args.r11);
@@ -339,7 +339,7 @@ static int handle_cpuid(struct pt_regs *regs, struct ve_info *ve)
339339
* ABI can be found in TDX Guest-Host-Communication Interface
340340
* (GHCI), section titled "VP.VMCALL<Instruction.CPUID>".
341341
*/
342-
if (__tdx_hypercall_ret(&args))
342+
if (__tdx_hypercall(&args))
343343
return -EIO;
344344

345345
/*
@@ -366,8 +366,9 @@ static bool mmio_read(int size, unsigned long addr, unsigned long *val)
366366
.r15 = *val,
367367
};
368368

369-
if (__tdx_hypercall_ret(&args))
369+
if (__tdx_hypercall(&args))
370370
return false;
371+
371372
*val = args.r11;
372373
return true;
373374
}
@@ -500,7 +501,7 @@ static bool handle_in(struct pt_regs *regs, int size, int port)
500501
* in TDX Guest-Host-Communication Interface (GHCI) section titled
501502
* "TDG.VP.VMCALL<Instruction.IO>".
502503
*/
503-
success = !__tdx_hypercall_ret(&args);
504+
success = !__tdx_hypercall(&args);
504505

505506
/* Update part of the register affected by the emulated instruction */
506507
regs->ax &= ~mask;
@@ -729,7 +730,7 @@ static bool tdx_map_gpa(phys_addr_t start, phys_addr_t end, bool enc)
729730
.r13 = end - start };
730731

731732
u64 map_fail_paddr;
732-
u64 ret = __tdx_hypercall_ret(&args);
733+
u64 ret = __tdx_hypercall(&args);
733734

734735
if (ret != TDVMCALL_STATUS_RETRY)
735736
return !ret;

arch/x86/hyperv/ivm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ static void hv_tdx_msr_read(u64 msr, u64 *val)
404404
.r12 = msr,
405405
};
406406

407-
u64 ret = __tdx_hypercall_ret(&args);
407+
u64 ret = __tdx_hypercall(&args);
408408

409409
if (WARN_ONCE(ret, "Failed to emulate MSR read: %lld\n", ret))
410410
*val = 0;
@@ -420,7 +420,7 @@ u64 hv_tdx_hypercall(u64 control, u64 param1, u64 param2)
420420
args.rdx = param1;
421421
args.r8 = param2;
422422

423-
(void)__tdx_hypercall_ret(&args);
423+
(void)__tdx_hypercall(&args);
424424

425425
return args.r11;
426426
}

0 commit comments

Comments
 (0)