Skip to content

Commit 527a534

Browse files
kirylhansendc
authored andcommitted
x86/tdx: Provide common base for SEAMCALL and TDCALL C wrappers
Secure Arbitration Mode (SEAM) is an extension of VMX architecture. It defines a new VMX root operation (SEAM VMX root) and a new VMX non-root operation (SEAM VMX non-root) which are both isolated from the legacy VMX operation where the host kernel runs. A CPU-attested software module (called 'TDX module') runs in SEAM VMX root to manage and protect VMs running in SEAM VMX non-root. SEAM VMX root is also used to host another CPU-attested software module (called 'P-SEAMLDR') to load and update the TDX module. Host kernel transits to either P-SEAMLDR or TDX module via the new SEAMCALL instruction, which is essentially a VMExit from VMX root mode to SEAM VMX root mode. SEAMCALLs are leaf functions defined by P-SEAMLDR and TDX module around the new SEAMCALL instruction. A guest kernel can also communicate with TDX module via TDCALL instruction. TDCALLs and SEAMCALLs use an ABI different from the x86-64 system-v ABI. RAX is used to carry both the SEAMCALL leaf function number (input) and the completion status (output). Additional GPRs (RCX, RDX, R8-R11) may be further used as both input and output operands in individual leaf. TDCALL and SEAMCALL share the same ABI and require the largely same code to pass down arguments and retrieve results. Define an assembly macro that can be used to implement C wrapper for both TDCALL and SEAMCALL. Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Kirill A. Shutemov <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Dave Hansen <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 59bd54a commit 527a534

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

arch/x86/include/asm/tdx.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,38 @@
44
#define _ASM_X86_TDX_H
55

66
#include <linux/init.h>
7+
#include <linux/bits.h>
78

89
#define TDX_CPUID_LEAF_ID 0x21
910
#define TDX_IDENT "IntelTDX "
1011

12+
/*
13+
* SW-defined error codes.
14+
*
15+
* Bits 47:40 == 0xFF indicate Reserved status code class that never used by
16+
* TDX module.
17+
*/
18+
#define TDX_ERROR _BITUL(63)
19+
#define TDX_SW_ERROR (TDX_ERROR | GENMASK_ULL(47, 40))
20+
#define TDX_SEAMCALL_VMFAILINVALID (TDX_SW_ERROR | _UL(0xFFFF0000))
21+
22+
#ifndef __ASSEMBLY__
23+
24+
/*
25+
* Used to gather the output registers values of the TDCALL and SEAMCALL
26+
* instructions when requesting services from the TDX module.
27+
*
28+
* This is a software only structure and not part of the TDX module/VMM ABI.
29+
*/
30+
struct tdx_module_output {
31+
u64 rcx;
32+
u64 rdx;
33+
u64 r8;
34+
u64 r9;
35+
u64 r10;
36+
u64 r11;
37+
};
38+
1139
#ifdef CONFIG_INTEL_TDX_GUEST
1240

1341
void __init tdx_early_init(void);
@@ -18,4 +46,5 @@ static inline void tdx_early_init(void) { };
1846

1947
#endif /* CONFIG_INTEL_TDX_GUEST */
2048

49+
#endif /* !__ASSEMBLY__ */
2150
#endif /* _ASM_X86_TDX_H */

arch/x86/kernel/asm-offsets.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <asm/bootparam.h>
1919
#include <asm/suspend.h>
2020
#include <asm/tlbflush.h>
21+
#include <asm/tdx.h>
2122

2223
#ifdef CONFIG_XEN
2324
#include <xen/interface/xen.h>
@@ -65,6 +66,14 @@ static void __used common(void)
6566
OFFSET(XEN_vcpu_info_arch_cr2, vcpu_info, arch.cr2);
6667
#endif
6768

69+
BLANK();
70+
OFFSET(TDX_MODULE_rcx, tdx_module_output, rcx);
71+
OFFSET(TDX_MODULE_rdx, tdx_module_output, rdx);
72+
OFFSET(TDX_MODULE_r8, tdx_module_output, r8);
73+
OFFSET(TDX_MODULE_r9, tdx_module_output, r9);
74+
OFFSET(TDX_MODULE_r10, tdx_module_output, r10);
75+
OFFSET(TDX_MODULE_r11, tdx_module_output, r11);
76+
6877
BLANK();
6978
OFFSET(BP_scratch, boot_params, scratch);
7079
OFFSET(BP_secure_boot, boot_params, secure_boot);

arch/x86/virt/vmx/tdx/tdxcall.S

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#include <asm/asm-offsets.h>
3+
#include <asm/tdx.h>
4+
5+
/*
6+
* TDCALL and SEAMCALL are supported in Binutils >= 2.36.
7+
*/
8+
#define tdcall .byte 0x66,0x0f,0x01,0xcc
9+
#define seamcall .byte 0x66,0x0f,0x01,0xcf
10+
11+
/*
12+
* TDX_MODULE_CALL - common helper macro for both
13+
* TDCALL and SEAMCALL instructions.
14+
*
15+
* TDCALL - used by TDX guests to make requests to the
16+
* TDX module and hypercalls to the VMM.
17+
* SEAMCALL - used by TDX hosts to make requests to the
18+
* TDX module.
19+
*/
20+
.macro TDX_MODULE_CALL host:req
21+
/*
22+
* R12 will be used as temporary storage for struct tdx_module_output
23+
* pointer. Since R12-R15 registers are not used by TDCALL/SEAMCALL
24+
* services supported by this function, it can be reused.
25+
*/
26+
27+
/* Callee saved, so preserve it */
28+
push %r12
29+
30+
/*
31+
* Push output pointer to stack.
32+
* After the operation, it will be fetched into R12 register.
33+
*/
34+
push %r9
35+
36+
/* Mangle function call ABI into TDCALL/SEAMCALL ABI: */
37+
/* Move Leaf ID to RAX */
38+
mov %rdi, %rax
39+
/* Move input 4 to R9 */
40+
mov %r8, %r9
41+
/* Move input 3 to R8 */
42+
mov %rcx, %r8
43+
/* Move input 1 to RCX */
44+
mov %rsi, %rcx
45+
/* Leave input param 2 in RDX */
46+
47+
.if \host
48+
seamcall
49+
/*
50+
* SEAMCALL instruction is essentially a VMExit from VMX root
51+
* mode to SEAM VMX root mode. VMfailInvalid (CF=1) indicates
52+
* that the targeted SEAM firmware is not loaded or disabled,
53+
* or P-SEAMLDR is busy with another SEAMCALL. %rax is not
54+
* changed in this case.
55+
*
56+
* Set %rax to TDX_SEAMCALL_VMFAILINVALID for VMfailInvalid.
57+
* This value will never be used as actual SEAMCALL error code as
58+
* it is from the Reserved status code class.
59+
*/
60+
jnc .Lno_vmfailinvalid
61+
mov $TDX_SEAMCALL_VMFAILINVALID, %rax
62+
.Lno_vmfailinvalid:
63+
64+
.else
65+
tdcall
66+
.endif
67+
68+
/*
69+
* Fetch output pointer from stack to R12 (It is used
70+
* as temporary storage)
71+
*/
72+
pop %r12
73+
74+
/*
75+
* Since this macro can be invoked with NULL as an output pointer,
76+
* check if caller provided an output struct before storing output
77+
* registers.
78+
*
79+
* Update output registers, even if the call failed (RAX != 0).
80+
* Other registers may contain details of the failure.
81+
*/
82+
test %r12, %r12
83+
jz .Lno_output_struct
84+
85+
/* Copy result registers to output struct: */
86+
movq %rcx, TDX_MODULE_rcx(%r12)
87+
movq %rdx, TDX_MODULE_rdx(%r12)
88+
movq %r8, TDX_MODULE_r8(%r12)
89+
movq %r9, TDX_MODULE_r9(%r12)
90+
movq %r10, TDX_MODULE_r10(%r12)
91+
movq %r11, TDX_MODULE_r11(%r12)
92+
93+
.Lno_output_struct:
94+
/* Restore the state of R12 register */
95+
pop %r12
96+
.endm

0 commit comments

Comments
 (0)