94 lines
2.3 KiB
C
94 lines
2.3 KiB
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/coco.h>
|
|
#include <asm/tdx.h>
|
|
|
|
/* TDX module Call Leaf IDs */
|
|
#define TDX_GET_INFO 1
|
|
|
|
/*
|
|
* 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?");
|
|
}
|
|
|
|
/*
|
|
* Used for TDX guests to make calls directly to the TD module. This
|
|
* should only be used for calls that have no legitimate reason to fail
|
|
* or where the kernel can not survive the call failing.
|
|
*/
|
|
static inline void tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9,
|
|
struct tdx_module_output *out)
|
|
{
|
|
if (__tdx_module_call(fn, rcx, rdx, r8, r9, out))
|
|
panic("TDCALL %lld failed (Buggy TDX module!)\n", fn);
|
|
}
|
|
|
|
static u64 get_cc_mask(void)
|
|
{
|
|
struct tdx_module_output out;
|
|
unsigned int gpa_width;
|
|
|
|
/*
|
|
* TDINFO TDX module call is used to get the TD execution environment
|
|
* information like GPA width, number of available vcpus, debug mode
|
|
* information, etc. More details about the ABI can be found in TDX
|
|
* Guest-Host-Communication Interface (GHCI), section 2.4.2 TDCALL
|
|
* [TDG.VP.INFO].
|
|
*
|
|
* The GPA width that comes out of this call is critical. TDX guests
|
|
* can not meaningfully run without it.
|
|
*/
|
|
tdx_module_call(TDX_GET_INFO, 0, 0, 0, 0, &out);
|
|
|
|
gpa_width = out.rcx & GENMASK(5, 0);
|
|
|
|
/*
|
|
* The highest bit of a guest physical address is the "sharing" bit.
|
|
* Set it for shared pages and clear it for private pages.
|
|
*/
|
|
return BIT_ULL(gpa_width - 1);
|
|
}
|
|
|
|
void __init tdx_early_init(void)
|
|
{
|
|
u64 cc_mask;
|
|
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);
|
|
|
|
cc_set_vendor(CC_VENDOR_INTEL);
|
|
cc_mask = get_cc_mask();
|
|
cc_set_mask(cc_mask);
|
|
|
|
pr_info("Guest detected\n");
|
|
}
|