GNU Linux-libre 6.8.9-gnu
[releases.git] / arch / x86 / coco / core.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Confidential Computing Platform Capability checks
4  *
5  * Copyright (C) 2021 Advanced Micro Devices, Inc.
6  * Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
7  *
8  * Author: Tom Lendacky <thomas.lendacky@amd.com>
9  */
10
11 #include <linux/export.h>
12 #include <linux/cc_platform.h>
13 #include <linux/string.h>
14 #include <linux/random.h>
15
16 #include <asm/archrandom.h>
17 #include <asm/coco.h>
18 #include <asm/processor.h>
19
20 enum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE;
21 u64 cc_mask __ro_after_init;
22
23 static bool noinstr intel_cc_platform_has(enum cc_attr attr)
24 {
25         switch (attr) {
26         case CC_ATTR_GUEST_UNROLL_STRING_IO:
27         case CC_ATTR_HOTPLUG_DISABLED:
28         case CC_ATTR_GUEST_MEM_ENCRYPT:
29         case CC_ATTR_MEM_ENCRYPT:
30                 return true;
31         default:
32                 return false;
33         }
34 }
35
36 /*
37  * Handle the SEV-SNP vTOM case where sme_me_mask is zero, and
38  * the other levels of SME/SEV functionality, including C-bit
39  * based SEV-SNP, are not enabled.
40  */
41 static __maybe_unused __always_inline bool amd_cc_platform_vtom(enum cc_attr attr)
42 {
43         switch (attr) {
44         case CC_ATTR_GUEST_MEM_ENCRYPT:
45         case CC_ATTR_MEM_ENCRYPT:
46                 return true;
47         default:
48                 return false;
49         }
50 }
51
52 /*
53  * SME and SEV are very similar but they are not the same, so there are
54  * times that the kernel will need to distinguish between SME and SEV. The
55  * cc_platform_has() function is used for this.  When a distinction isn't
56  * needed, the CC_ATTR_MEM_ENCRYPT attribute can be used.
57  *
58  * The trampoline code is a good example for this requirement.  Before
59  * paging is activated, SME will access all memory as decrypted, but SEV
60  * will access all memory as encrypted.  So, when APs are being brought
61  * up under SME the trampoline area cannot be encrypted, whereas under SEV
62  * the trampoline area must be encrypted.
63  */
64
65 static bool noinstr amd_cc_platform_has(enum cc_attr attr)
66 {
67 #ifdef CONFIG_AMD_MEM_ENCRYPT
68
69         if (sev_status & MSR_AMD64_SNP_VTOM)
70                 return amd_cc_platform_vtom(attr);
71
72         switch (attr) {
73         case CC_ATTR_MEM_ENCRYPT:
74                 return sme_me_mask;
75
76         case CC_ATTR_HOST_MEM_ENCRYPT:
77                 return sme_me_mask && !(sev_status & MSR_AMD64_SEV_ENABLED);
78
79         case CC_ATTR_GUEST_MEM_ENCRYPT:
80                 return sev_status & MSR_AMD64_SEV_ENABLED;
81
82         case CC_ATTR_GUEST_STATE_ENCRYPT:
83                 return sev_status & MSR_AMD64_SEV_ES_ENABLED;
84
85         /*
86          * With SEV, the rep string I/O instructions need to be unrolled
87          * but SEV-ES supports them through the #VC handler.
88          */
89         case CC_ATTR_GUEST_UNROLL_STRING_IO:
90                 return (sev_status & MSR_AMD64_SEV_ENABLED) &&
91                         !(sev_status & MSR_AMD64_SEV_ES_ENABLED);
92
93         case CC_ATTR_GUEST_SEV_SNP:
94                 return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
95
96         default:
97                 return false;
98         }
99 #else
100         return false;
101 #endif
102 }
103
104 bool noinstr cc_platform_has(enum cc_attr attr)
105 {
106         switch (cc_vendor) {
107         case CC_VENDOR_AMD:
108                 return amd_cc_platform_has(attr);
109         case CC_VENDOR_INTEL:
110                 return intel_cc_platform_has(attr);
111         default:
112                 return false;
113         }
114 }
115 EXPORT_SYMBOL_GPL(cc_platform_has);
116
117 u64 cc_mkenc(u64 val)
118 {
119         /*
120          * Both AMD and Intel use a bit in the page table to indicate
121          * encryption status of the page.
122          *
123          * - for AMD, bit *set* means the page is encrypted
124          * - for AMD with vTOM and for Intel, *clear* means encrypted
125          */
126         switch (cc_vendor) {
127         case CC_VENDOR_AMD:
128                 if (sev_status & MSR_AMD64_SNP_VTOM)
129                         return val & ~cc_mask;
130                 else
131                         return val | cc_mask;
132         case CC_VENDOR_INTEL:
133                 return val & ~cc_mask;
134         default:
135                 return val;
136         }
137 }
138
139 u64 cc_mkdec(u64 val)
140 {
141         /* See comment in cc_mkenc() */
142         switch (cc_vendor) {
143         case CC_VENDOR_AMD:
144                 if (sev_status & MSR_AMD64_SNP_VTOM)
145                         return val | cc_mask;
146                 else
147                         return val & ~cc_mask;
148         case CC_VENDOR_INTEL:
149                 return val | cc_mask;
150         default:
151                 return val;
152         }
153 }
154 EXPORT_SYMBOL_GPL(cc_mkdec);
155
156 __init void cc_random_init(void)
157 {
158         /*
159          * The seed is 32 bytes (in units of longs), which is 256 bits, which
160          * is the security level that the RNG is targeting.
161          */
162         unsigned long rng_seed[32 / sizeof(long)];
163         size_t i, longs;
164
165         if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
166                 return;
167
168         /*
169          * Since the CoCo threat model includes the host, the only reliable
170          * source of entropy that can be neither observed nor manipulated is
171          * RDRAND. Usually, RDRAND failure is considered tolerable, but since
172          * CoCo guests have no other unobservable source of entropy, it's
173          * important to at least ensure the RNG gets some initial random seeds.
174          */
175         for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) {
176                 longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i);
177
178                 /*
179                  * A zero return value means that the guest doesn't have RDRAND
180                  * or the CPU is physically broken, and in both cases that
181                  * means most crypto inside of the CoCo instance will be
182                  * broken, defeating the purpose of CoCo in the first place. So
183                  * just panic here because it's absolutely unsafe to continue
184                  * executing.
185                  */
186                 if (longs == 0)
187                         panic("RDRAND is defective.");
188         }
189         add_device_randomness(rng_seed, sizeof(rng_seed));
190         memzero_explicit(rng_seed, sizeof(rng_seed));
191 }