[RFC PATCH v2 06/69] KVM: TDX: add a helper function for kvm to call seamcall

From: isaku . yamahata
Date: Fri Jul 02 2021 - 18:08:18 EST


From: Isaku Yamahata <isaku.yamahata@xxxxxxxxx>

Add a helper function for kvm to call seamcall and a helper macro to check
its return value. The later patches will use them.

Co-developed-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxx>
Signed-off-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxx>
Signed-off-by: Isaku Yamahata <isaku.yamahata@xxxxxxxxx>
---
arch/x86/kernel/asm-offsets_64.c | 15 ++++++++
arch/x86/kvm/Makefile | 1 +
arch/x86/kvm/vmx/seamcall.S | 64 ++++++++++++++++++++++++++++++++
arch/x86/kvm/vmx/seamcall.h | 47 +++++++++++++++++++++++
4 files changed, 127 insertions(+)
create mode 100644 arch/x86/kvm/vmx/seamcall.S
create mode 100644 arch/x86/kvm/vmx/seamcall.h

diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index b14533af7676..c5908bcf3055 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -9,6 +9,11 @@
#include <asm/kvm_para.h>
#endif

+#ifdef CONFIG_KVM_INTEL_TDX
+#include <linux/kvm_types.h>
+#include "../kvm/vmx/tdx_arch.h"
+#endif
+
int main(void)
{
#ifdef CONFIG_PARAVIRT
@@ -25,6 +30,16 @@ int main(void)
BLANK();
#endif

+#ifdef CONFIG_KVM_INTEL_TDX
+ OFFSET(TDX_SEAM_rcx, tdx_ex_ret, rcx);
+ OFFSET(TDX_SEAM_rdx, tdx_ex_ret, rdx);
+ OFFSET(TDX_SEAM_r8, tdx_ex_ret, r8);
+ OFFSET(TDX_SEAM_r9, tdx_ex_ret, r9);
+ OFFSET(TDX_SEAM_r10, tdx_ex_ret, r10);
+ OFFSET(TDX_SEAM_r11, tdx_ex_ret, r11);
+ BLANK();
+#endif
+
#define ENTRY(entry) OFFSET(pt_regs_ ## entry, pt_regs, entry)
ENTRY(bx);
ENTRY(cx);
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile
index c589db5d91b3..60f3e90fef8b 100644
--- a/arch/x86/kvm/Makefile
+++ b/arch/x86/kvm/Makefile
@@ -24,6 +24,7 @@ kvm-$(CONFIG_KVM_XEN) += xen.o
kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
vmx/evmcs.o vmx/nested.o vmx/posted_intr.o
kvm-intel-$(CONFIG_X86_SGX_KVM) += vmx/sgx.o
+kvm-intel-$(CONFIG_KVM_INTEL_TDX) += vmx/seamcall.o

kvm-amd-y += svm/svm.o svm/vmenter.o svm/pmu.o svm/nested.o svm/avic.o svm/sev.o

diff --git a/arch/x86/kvm/vmx/seamcall.S b/arch/x86/kvm/vmx/seamcall.S
new file mode 100644
index 000000000000..08bb2b29deb7
--- /dev/null
+++ b/arch/x86/kvm/vmx/seamcall.S
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* ASM helper to call SEAMCALL for P-SEAMLDR, TDX module */
+
+#include <linux/linkage.h>
+
+#include <asm/alternative.h>
+#include <asm/asm-offsets.h>
+#include <asm/frame.h>
+#include <asm/asm.h>
+
+#include "seamcall.h"
+
+/*
+ * __seamcall - helper function to invoke SEAMCALL to request service
+ * of TDX module for KVM.
+ *
+ * @op (RDI) SEAMCALL leaf ID
+ * @rcx (RSI) input 1 (optional based on leaf ID)
+ * @rdx (RDX) input 2 (optional based on leaf ID)
+ * @r8 (RCX) input 3 (optional based on leaf ID)
+ * @r9 (R8) input 4 (optional based on leaf ID)
+ * @r10 (R9) input 5 (optional based on leaf ID)
+ * @ex stack pointer to struct tdx_ex_ret. optional return value stored.
+ *
+ * @return RAX: completion code of P-SEAMLDR or TDX module
+ * 0 on success, non-0 on failure
+ * trapnumber on fault
+ */
+SYM_FUNC_START(__seamcall)
+ FRAME_BEGIN
+
+ /* shuffle registers from function call ABI to SEAMCALL ABI. */
+ movq %r9, %r10
+ movq %r8, %r9
+ movq %rcx, %r8
+ /* %rdx doesn't need shuffle. */
+ movq %rsi, %rcx
+ movq %rdi, %rax
+
+.Lseamcall:
+ seamcall
+ jmp .Lseamcall_ret
+.Lspurious_fault:
+ call kvm_spurious_fault
+.Lseamcall_ret:
+
+ movq (FRAME_OFFSET + 8)(%rsp), %rdi
+ testq %rdi, %rdi
+ jz 1f
+
+ /* If ex is non-NULL, store extra return values into it. */
+ movq %rcx, TDX_SEAM_rcx(%rdi)
+ movq %rdx, TDX_SEAM_rdx(%rdi)
+ movq %r8, TDX_SEAM_r8(%rdi)
+ movq %r9, TDX_SEAM_r9(%rdi)
+ movq %r10, TDX_SEAM_r10(%rdi)
+ movq %r11, TDX_SEAM_r11(%rdi)
+
+1:
+ FRAME_END
+ ret
+
+ _ASM_EXTABLE(.Lseamcall, .Lspurious_fault)
+SYM_FUNC_END(__seamcall)
diff --git a/arch/x86/kvm/vmx/seamcall.h b/arch/x86/kvm/vmx/seamcall.h
new file mode 100644
index 000000000000..a318940f62ed
--- /dev/null
+++ b/arch/x86/kvm/vmx/seamcall.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_VMX_SEAMCALL_H
+#define __KVM_VMX_SEAMCALL_H
+
+#ifdef __ASSEMBLY__
+
+#define seamcall .byte 0x66, 0x0f, 0x01, 0xcf
+
+#else
+
+#ifndef seamcall
+struct tdx_ex_ret;
+asmlinkage u64 __seamcall(u64 op, u64 rcx, u64 rdx, u64 r8, u64 r9, u64 r10,
+ struct tdx_ex_ret *ex);
+
+#define seamcall(op, rcx, rdx, r8, r9, r10, ex) \
+ __seamcall(SEAMCALL_##op, (rcx), (rdx), (r8), (r9), (r10), (ex))
+#endif
+
+static inline void __pr_seamcall_error(u64 op, const char *op_str,
+ u64 err, struct tdx_ex_ret *ex)
+{
+ pr_err_ratelimited("SEAMCALL[%s] failed on cpu %d: 0x%llx\n",
+ op_str, smp_processor_id(), (err));
+ if (ex)
+ pr_err_ratelimited(
+ "RCX 0x%llx, RDX 0x%llx, R8 0x%llx, R9 0x%llx, R10 0x%llx, R11 0x%llx\n",
+ (ex)->rcx, (ex)->rdx, (ex)->r8, (ex)->r9, (ex)->r10,
+ (ex)->r11);
+}
+
+#define pr_seamcall_error(op, err, ex) \
+ __pr_seamcall_error(SEAMCALL_##op, #op, (err), (ex))
+
+/* ex is a pointer to struct tdx_ex_ret or NULL. */
+#define TDX_ERR(err, op, ex) \
+({ \
+ u64 __ret_warn_on = WARN_ON_ONCE(err); \
+ \
+ if (unlikely(__ret_warn_on)) \
+ pr_seamcall_error(op, err, ex); \
+ __ret_warn_on; \
+})
+
+#endif
+
+#endif /* __KVM_VMX_SEAMCALL_H */
--
2.25.1