Skip to content

Commit 8999ad9

Browse files
committed
Merge tag 'x86_tdx_for_6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 TDX updates from Dave Hansen: "The majority of this is a rework of the assembly and C wrappers that are used to talk to the TDX module and VMM. This is a nice cleanup in general but is also clearing the way for using this code when Linux is the TDX VMM. There are also some tidbits to make TDX guests play nicer with Hyper-V and to take advantage the hardware TSC. Summary: - Refactor and clean up TDX hypercall/module call infrastructure - Handle retrying/resuming page conversion hypercalls - Make sure to use the (shockingly) reliable TSC in TDX guests" [ TLA reminder: TDX is "Trust Domain Extensions", Intel's guest VM confidentiality technology ] * tag 'x86_tdx_for_6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/tdx: Mark TSC reliable x86/tdx: Fix __noreturn build warning around __tdx_hypercall_failed() x86/virt/tdx: Make TDX_MODULE_CALL handle SEAMCALL #UD and #GP x86/virt/tdx: Wire up basic SEAMCALL functions x86/tdx: Remove 'struct tdx_hypercall_args' x86/tdx: Reimplement __tdx_hypercall() using TDX_MODULE_CALL asm x86/tdx: Make TDX_HYPERCALL asm similar to TDX_MODULE_CALL x86/tdx: Extend TDX_MODULE_CALL to support more TDCALL/SEAMCALL leafs x86/tdx: Pass TDCALL/SEAMCALL input/output registers via a structure x86/tdx: Rename __tdx_module_call() to __tdcall() x86/tdx: Make macros of TDCALLs consistent with the spec x86/tdx: Skip saving output regs when SEAMCALL fails with VMFailInvalid x86/tdx: Zero out the missing RSI in TDX_HYPERCALL macro x86/tdx: Retry partially-completed page conversion hypercalls
2 parents f00593e + 9ee4318 commit 8999ad9

File tree

16 files changed

+491
-366
lines changed

16 files changed

+491
-366
lines changed

arch/x86/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,6 +1940,18 @@ config X86_USER_SHADOW_STACK
19401940

19411941
If unsure, say N.
19421942

1943+
config INTEL_TDX_HOST
1944+
bool "Intel Trust Domain Extensions (TDX) host support"
1945+
depends on CPU_SUP_INTEL
1946+
depends on X86_64
1947+
depends on KVM_INTEL
1948+
help
1949+
Intel Trust Domain Extensions (TDX) protects guest VMs from malicious
1950+
host and certain physical attacks. This option enables necessary TDX
1951+
support in the host kernel to run confidential VMs.
1952+
1953+
If unsure, say N.
1954+
19431955
config EFI
19441956
bool "EFI runtime service support"
19451957
depends on ACPI

arch/x86/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,8 @@ archheaders:
253253

254254
libs-y += arch/x86/lib/
255255

256+
core-y += arch/x86/virt/
257+
256258
# drivers-y are linked after core-y
257259
drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/
258260
drivers-$(CONFIG_PCI) += arch/x86/pci/

arch/x86/boot/compressed/tdx.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,23 @@ void __tdx_hypercall_failed(void)
1818

1919
static inline unsigned int tdx_io_in(int size, u16 port)
2020
{
21-
struct tdx_hypercall_args args = {
21+
struct tdx_module_args args = {
2222
.r10 = TDX_HYPERCALL_STANDARD,
2323
.r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION),
2424
.r12 = size,
2525
.r13 = 0,
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;
3333
}
3434

3535
static inline void tdx_io_out(int size, u16 port, u32 value)
3636
{
37-
struct tdx_hypercall_args args = {
37+
struct tdx_module_args args = {
3838
.r10 = TDX_HYPERCALL_STANDARD,
3939
.r11 = hcall_func(EXIT_REASON_IO_INSTRUCTION),
4040
.r12 = size,

arch/x86/coco/tdx/tdcall.S

Lines changed: 29 additions & 205 deletions
Original file line numberDiff line numberDiff line change
@@ -1,239 +1,63 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
#include <asm/asm-offsets.h>
33
#include <asm/asm.h>
4-
#include <asm/frame.h>
5-
#include <asm/unwind_hints.h>
64

75
#include <linux/linkage.h>
8-
#include <linux/bits.h>
96
#include <linux/errno.h>
107

118
#include "../../virt/vmx/tdx/tdxcall.S"
129

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-
4010
.section .noinstr.text, "ax"
4111

4212
/*
43-
* __tdx_module_call() - Used by TDX guests to request services from
44-
* the TDX module (does not include VMM services) using TDCALL instruction.
45-
*
46-
* Transforms function call register arguments into the TDCALL register ABI.
47-
* After TDCALL operation, TDX module output is saved in @out (if it is
48-
* provided by the user).
49-
*
50-
*-------------------------------------------------------------------------
51-
* TDCALL ABI:
52-
*-------------------------------------------------------------------------
53-
* Input Registers:
54-
*
55-
* RAX - TDCALL Leaf number.
56-
* RCX,RDX,R8-R9 - TDCALL Leaf specific input registers.
57-
*
58-
* Output Registers:
13+
* __tdcall() - Used by TDX guests to request services from the TDX
14+
* module (does not include VMM services) using TDCALL instruction.
5915
*
60-
* RAX - TDCALL instruction error code.
61-
* RCX,RDX,R8-R11 - TDCALL Leaf specific output registers.
16+
* __tdcall() function ABI:
6217
*
63-
*-------------------------------------------------------------------------
18+
* @fn (RDI) - TDCALL Leaf ID, moved to RAX
19+
* @args (RSI) - struct tdx_module_args for input
6420
*
65-
* __tdx_module_call() function ABI:
66-
*
67-
* @fn (RDI) - TDCALL Leaf ID, moved to RAX
68-
* @rcx (RSI) - Input parameter 1, moved to RCX
69-
* @rdx (RDX) - Input parameter 2, moved to RDX
70-
* @r8 (RCX) - Input parameter 3, moved to R8
71-
* @r9 (R8) - Input parameter 4, moved to R9
72-
*
73-
* @out (R9) - struct tdx_module_output pointer
74-
* stored temporarily in R12 (not
75-
* shared with the TDX module). It
76-
* can be NULL.
21+
* Only RCX/RDX/R8-R11 are used as input registers.
7722
*
7823
* Return status of TDCALL via RAX.
7924
*/
80-
SYM_FUNC_START(__tdx_module_call)
81-
FRAME_BEGIN
25+
SYM_FUNC_START(__tdcall)
8226
TDX_MODULE_CALL host=0
83-
FRAME_END
84-
RET
85-
SYM_FUNC_END(__tdx_module_call)
27+
SYM_FUNC_END(__tdcall)
8628

8729
/*
88-
* TDX_HYPERCALL - Make hypercalls to a TDX VMM using TDVMCALL leaf of TDCALL
89-
* instruction
90-
*
91-
* Transforms values in function call argument struct tdx_hypercall_args @args
92-
* into the TDCALL register ABI. After TDCALL operation, VMM output is saved
93-
* back in @args, if \ret is 1.
94-
*
95-
*-------------------------------------------------------------------------
96-
* TD VMCALL ABI:
97-
*-------------------------------------------------------------------------
98-
*
99-
* Input Registers:
30+
* __tdcall_ret() - Used by TDX guests to request services from the TDX
31+
* module (does not include VMM services) using TDCALL instruction, with
32+
* saving output registers to the 'struct tdx_module_args' used as input.
10033
*
101-
* RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
102-
* RCX - BITMAP which controls which part of TD Guest GPR
103-
* is passed as-is to the VMM and back.
104-
* R10 - Set 0 to indicate TDCALL follows standard TDX ABI
105-
* specification. Non zero value indicates vendor
106-
* specific ABI.
107-
* R11 - VMCALL sub function number
108-
* RBX, RDX, RDI, RSI - Used to pass VMCALL sub function specific arguments.
109-
* R8-R9, R12-R15 - Same as above.
34+
* __tdcall_ret() function ABI:
11035
*
111-
* Output Registers:
36+
* @fn (RDI) - TDCALL Leaf ID, moved to RAX
37+
* @args (RSI) - struct tdx_module_args for input and output
11238
*
113-
* RAX - TDCALL instruction status (Not related to hypercall
114-
* output).
115-
* RBX, RDX, RDI, RSI - Hypercall sub function specific output values.
116-
* R8-R15 - Same as above.
39+
* Only RCX/RDX/R8-R11 are used as input/output registers.
11740
*
41+
* Return status of TDCALL via RAX.
11842
*/
119-
.macro TDX_HYPERCALL ret:req
120-
FRAME_BEGIN
121-
122-
/* Save callee-saved GPRs as mandated by the x86_64 ABI */
123-
push %r15
124-
push %r14
125-
push %r13
126-
push %r12
127-
push %rbx
128-
129-
/* Free RDI to be used as TDVMCALL arguments */
130-
movq %rdi, %rax
131-
132-
/* Copy hypercall registers from arg struct: */
133-
movq TDX_HYPERCALL_r8(%rax), %r8
134-
movq TDX_HYPERCALL_r9(%rax), %r9
135-
movq TDX_HYPERCALL_r10(%rax), %r10
136-
movq TDX_HYPERCALL_r11(%rax), %r11
137-
movq TDX_HYPERCALL_r12(%rax), %r12
138-
movq TDX_HYPERCALL_r13(%rax), %r13
139-
movq TDX_HYPERCALL_r14(%rax), %r14
140-
movq TDX_HYPERCALL_r15(%rax), %r15
141-
movq TDX_HYPERCALL_rdi(%rax), %rdi
142-
movq TDX_HYPERCALL_rsi(%rax), %rsi
143-
movq TDX_HYPERCALL_rbx(%rax), %rbx
144-
movq TDX_HYPERCALL_rdx(%rax), %rdx
145-
146-
push %rax
147-
148-
/* Mangle function call ABI into TDCALL ABI: */
149-
/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
150-
xor %eax, %eax
151-
152-
movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
153-
154-
tdcall
155-
156-
/*
157-
* RAX!=0 indicates a failure of the TDVMCALL mechanism itself and that
158-
* something has gone horribly wrong with the TDX module.
159-
*
160-
* The return status of the hypercall operation is in a separate
161-
* register (in R10). Hypercall errors are a part of normal operation
162-
* and are handled by callers.
163-
*/
164-
testq %rax, %rax
165-
jne .Lpanic\@
166-
167-
pop %rax
168-
169-
.if \ret
170-
movq %r8, TDX_HYPERCALL_r8(%rax)
171-
movq %r9, TDX_HYPERCALL_r9(%rax)
172-
movq %r10, TDX_HYPERCALL_r10(%rax)
173-
movq %r11, TDX_HYPERCALL_r11(%rax)
174-
movq %r12, TDX_HYPERCALL_r12(%rax)
175-
movq %r13, TDX_HYPERCALL_r13(%rax)
176-
movq %r14, TDX_HYPERCALL_r14(%rax)
177-
movq %r15, TDX_HYPERCALL_r15(%rax)
178-
movq %rdi, TDX_HYPERCALL_rdi(%rax)
179-
movq %rsi, TDX_HYPERCALL_rsi(%rax)
180-
movq %rbx, TDX_HYPERCALL_rbx(%rax)
181-
movq %rdx, TDX_HYPERCALL_rdx(%rax)
182-
.endif
183-
184-
/* TDVMCALL leaf return code is in R10 */
185-
movq %r10, %rax
186-
187-
/*
188-
* Zero out registers exposed to the VMM to avoid speculative execution
189-
* with VMM-controlled values. This needs to include all registers
190-
* present in TDVMCALL_EXPOSE_REGS_MASK, except RBX, and R12-R15 which
191-
* will be restored.
192-
*/
193-
xor %r8d, %r8d
194-
xor %r9d, %r9d
195-
xor %r10d, %r10d
196-
xor %r11d, %r11d
197-
xor %rdi, %rdi
198-
xor %rdx, %rdx
199-
200-
/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
201-
pop %rbx
202-
pop %r12
203-
pop %r13
204-
pop %r14
205-
pop %r15
206-
207-
FRAME_END
208-
209-
RET
210-
.Lpanic\@:
211-
call __tdx_hypercall_failed
212-
/* __tdx_hypercall_failed never returns */
213-
REACHABLE
214-
jmp .Lpanic\@
215-
.endm
43+
SYM_FUNC_START(__tdcall_ret)
44+
TDX_MODULE_CALL host=0 ret=1
45+
SYM_FUNC_END(__tdcall_ret)
21646

21747
/*
48+
* __tdcall_saved_ret() - Used by TDX guests to request services from the
49+
* TDX module (including VMM services) using TDCALL instruction, with
50+
* saving output registers to the 'struct tdx_module_args' used as input.
21851
*
219-
* __tdx_hypercall() function ABI:
220-
*
221-
* @args (RDI) - struct tdx_hypercall_args for input
222-
*
223-
* On successful completion, return the hypercall error code.
224-
*/
225-
SYM_FUNC_START(__tdx_hypercall)
226-
TDX_HYPERCALL ret=0
227-
SYM_FUNC_END(__tdx_hypercall)
228-
229-
/*
52+
* __tdcall_saved_ret() function ABI:
23053
*
231-
* __tdx_hypercall_ret() function ABI:
54+
* @fn (RDI) - TDCALL leaf ID, moved to RAX
55+
* @args (RSI) - struct tdx_module_args for input/output
23256
*
233-
* @args (RDI) - struct tdx_hypercall_args for input and output
57+
* All registers in @args are used as input/output registers.
23458
*
23559
* On successful completion, return the hypercall error code.
23660
*/
237-
SYM_FUNC_START(__tdx_hypercall_ret)
238-
TDX_HYPERCALL ret=1
239-
SYM_FUNC_END(__tdx_hypercall_ret)
61+
SYM_FUNC_START(__tdcall_saved_ret)
62+
TDX_MODULE_CALL host=0 ret=1 saved=1
63+
SYM_FUNC_END(__tdcall_saved_ret)

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ static unsigned long try_accept_one(phys_addr_t start, unsigned long len,
55
enum pg_level pg_level)
66
{
77
unsigned long accept_size = page_level_size(pg_level);
8-
u64 tdcall_rcx;
8+
struct tdx_module_args args = {};
99
u8 page_size;
1010

1111
if (!IS_ALIGNED(start, accept_size))
@@ -34,8 +34,8 @@ static unsigned long try_accept_one(phys_addr_t start, unsigned long len,
3434
return 0;
3535
}
3636

37-
tdcall_rcx = start | page_size;
38-
if (__tdx_module_call(TDX_ACCEPT_PAGE, tdcall_rcx, 0, 0, 0, NULL))
37+
args.rcx = start | page_size;
38+
if (__tdcall(TDG_MEM_PAGE_ACCEPT, &args))
3939
return 0;
4040

4141
return accept_size;
@@ -45,7 +45,7 @@ bool tdx_accept_memory(phys_addr_t start, phys_addr_t end)
4545
{
4646
/*
4747
* For shared->private conversion, accept the page using
48-
* TDX_ACCEPT_PAGE TDX module call.
48+
* TDG_MEM_PAGE_ACCEPT TDX module call.
4949
*/
5050
while (start < end) {
5151
unsigned long len = end - start;
@@ -69,3 +69,23 @@ 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_module_args *args)
74+
{
75+
/*
76+
* For TDVMCALL explicitly set RCX to the bitmap of shared registers.
77+
* The caller isn't expected to set @args->rcx anyway.
78+
*/
79+
args->rcx = TDVMCALL_EXPOSE_REGS_MASK;
80+
81+
/*
82+
* Failure of __tdcall_saved_ret() indicates a failure of the TDVMCALL
83+
* mechanism itself and that something has gone horribly wrong with
84+
* the TDX module. __tdx_hypercall_failed() never returns.
85+
*/
86+
if (__tdcall_saved_ret(TDG_VP_VMCALL, args))
87+
__tdx_hypercall_failed();
88+
89+
/* TDVMCALL leaf return code is in R10 */
90+
return args->r10;
91+
}

0 commit comments

Comments
 (0)