Commit | Line | Data |
---|---|---|
59bd54a8 KS |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (C) 2021-2022 Intel Corporation */ | |
3 | ||
4 | #undef pr_fmt | |
5 | #define pr_fmt(fmt) "tdx: " fmt | |
6 | ||
7 | #include <linux/cpufeature.h> | |
41394e33 | 8 | #include <asm/coco.h> |
59bd54a8 KS |
9 | #include <asm/tdx.h> |
10 | ||
41394e33 KS |
11 | /* TDX module Call Leaf IDs */ |
12 | #define TDX_GET_INFO 1 | |
13 | ||
eb94f1b6 KS |
14 | /* |
15 | * Wrapper for standard use of __tdx_hypercall with no output aside from | |
16 | * return code. | |
17 | */ | |
18 | static inline u64 _tdx_hypercall(u64 fn, u64 r12, u64 r13, u64 r14, u64 r15) | |
19 | { | |
20 | struct tdx_hypercall_args args = { | |
21 | .r10 = TDX_HYPERCALL_STANDARD, | |
22 | .r11 = fn, | |
23 | .r12 = r12, | |
24 | .r13 = r13, | |
25 | .r14 = r14, | |
26 | .r15 = r15, | |
27 | }; | |
28 | ||
29 | return __tdx_hypercall(&args, 0); | |
30 | } | |
31 | ||
32 | /* Called from __tdx_hypercall() for unrecoverable failure */ | |
33 | void __tdx_hypercall_failed(void) | |
34 | { | |
35 | panic("TDVMCALL failed. TDX module bug?"); | |
36 | } | |
37 | ||
41394e33 KS |
38 | /* |
39 | * Used for TDX guests to make calls directly to the TD module. This | |
40 | * should only be used for calls that have no legitimate reason to fail | |
41 | * or where the kernel can not survive the call failing. | |
42 | */ | |
43 | static inline void tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, | |
44 | struct tdx_module_output *out) | |
45 | { | |
46 | if (__tdx_module_call(fn, rcx, rdx, r8, r9, out)) | |
47 | panic("TDCALL %lld failed (Buggy TDX module!)\n", fn); | |
48 | } | |
49 | ||
50 | static u64 get_cc_mask(void) | |
51 | { | |
52 | struct tdx_module_output out; | |
53 | unsigned int gpa_width; | |
54 | ||
55 | /* | |
56 | * TDINFO TDX module call is used to get the TD execution environment | |
57 | * information like GPA width, number of available vcpus, debug mode | |
58 | * information, etc. More details about the ABI can be found in TDX | |
59 | * Guest-Host-Communication Interface (GHCI), section 2.4.2 TDCALL | |
60 | * [TDG.VP.INFO]. | |
61 | * | |
62 | * The GPA width that comes out of this call is critical. TDX guests | |
63 | * can not meaningfully run without it. | |
64 | */ | |
65 | tdx_module_call(TDX_GET_INFO, 0, 0, 0, 0, &out); | |
66 | ||
67 | gpa_width = out.rcx & GENMASK(5, 0); | |
68 | ||
69 | /* | |
70 | * The highest bit of a guest physical address is the "sharing" bit. | |
71 | * Set it for shared pages and clear it for private pages. | |
72 | */ | |
73 | return BIT_ULL(gpa_width - 1); | |
74 | } | |
75 | ||
59bd54a8 KS |
76 | void __init tdx_early_init(void) |
77 | { | |
41394e33 | 78 | u64 cc_mask; |
59bd54a8 KS |
79 | u32 eax, sig[3]; |
80 | ||
81 | cpuid_count(TDX_CPUID_LEAF_ID, 0, &eax, &sig[0], &sig[2], &sig[1]); | |
82 | ||
83 | if (memcmp(TDX_IDENT, sig, sizeof(sig))) | |
84 | return; | |
85 | ||
86 | setup_force_cpu_cap(X86_FEATURE_TDX_GUEST); | |
87 | ||
41394e33 KS |
88 | cc_set_vendor(CC_VENDOR_INTEL); |
89 | cc_mask = get_cc_mask(); | |
90 | cc_set_mask(cc_mask); | |
91 | ||
65fab5bc KS |
92 | /* |
93 | * All bits above GPA width are reserved and kernel treats shared bit | |
94 | * as flag, not as part of physical address. | |
95 | * | |
96 | * Adjust physical mask to only cover valid GPA bits. | |
97 | */ | |
98 | physical_mask &= cc_mask - 1; | |
99 | ||
59bd54a8 KS |
100 | pr_info("Guest detected\n"); |
101 | } |