Guests communicate with VMMs with hypercalls. Historically, these are implemented using instructions that are known to cause VMEXITs like VMCALL, VMLAUNCH, etc. However, with TDX, VMEXITs no longer expose the guest state to the host. This prevents the old hypercall mechanisms from working. So, to communicate with VMM, TDX specification defines a new instruction called TDCALL. In a TDX based VM, since the VMM is an untrusted entity, an intermediary layer -- TDX module -- facilitates secure communication between the host and the guest. TDX module is loaded like a firmware into a special CPU mode called SEAM. TDX guests communicate with the TDX module using the TDCALL instruction. A guest uses TDCALL to communicate with both the TDX module and VMM. The value of the RAX register when executing the TDCALL instruction is used to determine the TDCALL type. A leaf of TDCALL used to communicate with the VMM is called TDVMCALL. Add generic interfaces to communicate with the TDX module and VMM (using the TDCALL instruction). __tdx_module_call() - Used to communicate with the TDX module (via TDCALL instruction). __tdx_hypercall() - Used by the guest to request services from the VMM (via TDVMCALL leaf of TDCALL). Also define an additional wrapper _tdx_hypercall(), which adds error handling support for the TDCALL failure. The __tdx_module_call() and __tdx_hypercall() helper functions are implemented in assembly in a .S file. The TDCALL ABI requires shuffling arguments in and out of registers, which proved to be awkward with inline assembly. Just like syscalls, not all TDVMCALL use cases need to use the same number of argument registers. The implementation here picks the current worst-case scenario for TDCALL (4 registers). For TDCALLs with fewer than 4 arguments, there will end up being a few superfluous (cheap) instructions. But, this approach maximizes code reuse. For registers used by the TDCALL instruction, please check TDX GHCI specification, the section titled "TDCALL instruction" and "TDG.VP.VMCALL Interface". Based on previous patch by Sean Christopherson. Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Tony Luck <tony.luck@intel.com> Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Borislav Petkov <bp@suse.de> Link: https://lkml.kernel.org/r/20220405232939.73860-4-kirill.shutemov@linux.intel.com
46 lines
945 B
C
46 lines
945 B
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (C) 2021-2022 Intel Corporation */
|
|
|
|
#undef pr_fmt
|
|
#define pr_fmt(fmt) "tdx: " fmt
|
|
|
|
#include <linux/cpufeature.h>
|
|
#include <asm/tdx.h>
|
|
|
|
/*
|
|
* Wrapper for standard use of __tdx_hypercall with no output aside from
|
|
* return code.
|
|
*/
|
|
static inline u64 _tdx_hypercall(u64 fn, u64 r12, u64 r13, u64 r14, u64 r15)
|
|
{
|
|
struct tdx_hypercall_args args = {
|
|
.r10 = TDX_HYPERCALL_STANDARD,
|
|
.r11 = fn,
|
|
.r12 = r12,
|
|
.r13 = r13,
|
|
.r14 = r14,
|
|
.r15 = r15,
|
|
};
|
|
|
|
return __tdx_hypercall(&args, 0);
|
|
}
|
|
|
|
/* Called from __tdx_hypercall() for unrecoverable failure */
|
|
void __tdx_hypercall_failed(void)
|
|
{
|
|
panic("TDVMCALL failed. TDX module bug?");
|
|
}
|
|
|
|
void __init tdx_early_init(void)
|
|
{
|
|
u32 eax, sig[3];
|
|
|
|
cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax, &sig[0], &sig[2], &sig[1]);
|
|
|
|
if (memcmp(TDX_IDENT, sig, sizeof(sig)))
|
|
return;
|
|
|
|
setup_force_cpu_cap(X86_FEATURE_TDX_GUEST);
|
|
|
|
pr_info("Guest detected\n");
|
|
}
|