[PATCH 11/20] x86/tdx: Rewrite tdx_panic() without __tdx_hypercall()

Kirill A. Shutemov
2024-05-17T14:20:01Z

tdx_panic() uses REPORT_FATAL_ERROR hypercall to deliver panic message
in ealy boot. Rewrite it without using __tdx_hypercall().

REPORT_FATAL_ERROR hypercall is special. It uses pretty much all
available registers to pass down the error message. TDVMCALL macros are
not usable here.

Implement the hypercall directly in assembly.

It cuts code bloat substantially:

Function old new delta
tdx_panic 222 59 -163

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
---
arch/x86/coco/tdx/tdcall.S | 28 ++++++++++++++++++++++++++++
arch/x86/coco/tdx/tdx.c | 31 +++----------------------------
arch/x86/include/asm/tdx.h | 2 ++
tools/objtool/noreturns.h | 1 +
4 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/arch/x86/coco/tdx/tdcall.S b/arch/x86/coco/tdx/tdcall.S
index 12185fbd33ba..269e5789672a 100644
--- a/arch/x86/coco/tdx/tdcall.S
+++ b/arch/x86/coco/tdx/tdcall.S
@@ -110,3 +110,31 @@ SYM_FUNC_START(tdvmcall_trampoline)
ud2
SYM_FUNC_END(tdvmcall_trampoline)
.popsection
+
+SYM_FUNC_START(tdvmcall_report_fatal_error)
+ movq $TDX_HYPERCALL_STANDARD, %r10
+ movq $TDVMCALL_REPORT_FATAL_ERROR, %r11
+ movq %rdi, %r12
+ movq $0, %r13
+
+ movq %rsi, %rcx
+
+ /* Order according to the GHCI */
+ movq 0*8(%rcx), %r14
+ movq 1*8(%rcx), %r15
+ movq 2*8(%rcx), %rbx
+ movq 3*8(%rcx), %rdi
+ movq 4*8(%rcx), %rsi
+ movq 5*8(%rcx), %r8
+ movq 6*8(%rcx), %r9
+ movq 7*8(%rcx), %rdx
+
+ movq $TDG_VP_VMCALL, %rax
+ movq $(TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \
+ TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15), \
+ %rcx
+
+ tdcall
+
+ ud2
+SYM_FUNC_END(tdvmcall_report_fatal_error)
diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 3f0be1d3cccb..b7299e668564 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -157,37 +157,12 @@ EXPORT_SYMBOL_GPL(tdx_hcall_get_quote);

static void __noreturn tdx_panic(const char *msg)
{
- struct tdx_module_args args = {
- .r10 = TDX_HYPERCALL_STANDARD,
- .r11 = TDVMCALL_REPORT_FATAL_ERROR,
- .r12 = 0, /* Error code: 0 is Panic */
- };
- union {
- /* Define register order according to the GHCI */
- struct { u64 r14, r15, rbx, rdi, rsi, r8, r9, rdx; };
-
- char str[64];
- } message;
+ char str[64];

/* VMM assumes '\0' in byte 65, if the message took all 64 bytes */
- strtomem_pad(message.str, msg, '\0');
+ strtomem_pad(str, msg, '\0');

- args.r8 = message.r8;
- args.r9 = message.r9;
- args.r14 = message.r14;
- args.r15 = message.r15;
- args.rdi = message.rdi;
- args.rsi = message.rsi;
- args.rbx = message.rbx;
- args.rdx = message.rdx;
-
- /*
- * This hypercall should never return and it is not safe
- * to keep the guest running. Call it forever if it
- * happens to return.
- */
- while (1)
- __tdx_hypercall(&args);
+ tdvmcall_report_fatal_error(0, str);
}

/*
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index eba178996d84..f67e5e6b66ad 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -54,6 +54,8 @@ struct ve_info {

void __init tdx_early_init(void);

+void __noreturn tdvmcall_report_fatal_error(u64 error_code, const char str[64]);
+
void tdx_get_ve_info(struct ve_info *ve);

bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve);
diff --git a/tools/objtool/noreturns.h b/tools/objtool/noreturns.h
index 7ebf29c91184..0670cacf0734 100644
--- a/tools/objtool/noreturns.h
+++ b/tools/objtool/noreturns.h
@@ -39,6 +39,7 @@ NORETURN(sev_es_terminate)
NORETURN(snp_abort)
NORETURN(start_kernel)
NORETURN(stop_this_cpu)
+NORETURN(tdvmcall_report_fatal_error)
NORETURN(usercopy_abort)
NORETURN(x86_64_start_kernel)
NORETURN(x86_64_start_reservations)
--
2.43.0