// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2021-2022 Intel Corporation */ #undef pr_fmt #define pr_fmt(fmt) "tdx: " fmt #include #include #include /* 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); /* * All bits above GPA width are reserved and kernel treats shared bit * as flag, not as part of physical address. * * Adjust physical mask to only cover valid GPA bits. */ physical_mask &= cc_mask - 1; pr_info("Guest detected\n"); }