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 struct cc_attr_flags { 24 __u64 host_sev_snp : 1, 25 __resv : 63; 26 } cc_flags; 27 28 static bool noinstr intel_cc_platform_has(enum cc_attr attr) 29 { 30 switch (attr) { 31 case CC_ATTR_GUEST_UNROLL_STRING_IO: 32 case CC_ATTR_GUEST_MEM_ENCRYPT: 33 case CC_ATTR_MEM_ENCRYPT: 34 return true; 35 default: 36 return false; 37 } 38 } 39 40 /* 41 * Handle the SEV-SNP vTOM case where sme_me_mask is zero, and 42 * the other levels of SME/SEV functionality, including C-bit 43 * based SEV-SNP, are not enabled. 44 */ 45 static __maybe_unused __always_inline bool amd_cc_platform_vtom(enum cc_attr attr) 46 { 47 switch (attr) { 48 case CC_ATTR_GUEST_MEM_ENCRYPT: 49 case CC_ATTR_MEM_ENCRYPT: 50 return true; 51 default: 52 return false; 53 } 54 } 55 56 /* 57 * SME and SEV are very similar but they are not the same, so there are 58 * times that the kernel will need to distinguish between SME and SEV. The 59 * cc_platform_has() function is used for this. When a distinction isn't 60 * needed, the CC_ATTR_MEM_ENCRYPT attribute can be used. 61 * 62 * The trampoline code is a good example for this requirement. Before 63 * paging is activated, SME will access all memory as decrypted, but SEV 64 * will access all memory as encrypted. So, when APs are being brought 65 * up under SME the trampoline area cannot be encrypted, whereas under SEV 66 * the trampoline area must be encrypted. 67 */ 68 static bool noinstr amd_cc_platform_has(enum cc_attr attr) 69 { 70 #ifdef CONFIG_AMD_MEM_ENCRYPT 71 72 if (sev_status & MSR_AMD64_SNP_VTOM) 73 return amd_cc_platform_vtom(attr); 74 75 switch (attr) { 76 case CC_ATTR_MEM_ENCRYPT: 77 return sme_me_mask; 78 79 case CC_ATTR_HOST_MEM_ENCRYPT: 80 return sme_me_mask && !(sev_status & MSR_AMD64_SEV_ENABLED); 81 82 case CC_ATTR_GUEST_MEM_ENCRYPT: 83 return sev_status & MSR_AMD64_SEV_ENABLED; 84 85 case CC_ATTR_GUEST_STATE_ENCRYPT: 86 return sev_status & MSR_AMD64_SEV_ES_ENABLED; 87 88 /* 89 * With SEV, the rep string I/O instructions need to be unrolled 90 * but SEV-ES supports them through the #VC handler. 91 */ 92 case CC_ATTR_GUEST_UNROLL_STRING_IO: 93 return (sev_status & MSR_AMD64_SEV_ENABLED) && 94 !(sev_status & MSR_AMD64_SEV_ES_ENABLED); 95 96 case CC_ATTR_GUEST_SEV_SNP: 97 return sev_status & MSR_AMD64_SEV_SNP_ENABLED; 98 99 case CC_ATTR_GUEST_SNP_SECURE_TSC: 100 return sev_status & MSR_AMD64_SNP_SECURE_TSC; 101 102 case CC_ATTR_HOST_SEV_SNP: 103 return cc_flags.host_sev_snp; 104 105 default: 106 return false; 107 } 108 #else 109 return false; 110 #endif 111 } 112 113 bool noinstr cc_platform_has(enum cc_attr attr) 114 { 115 switch (cc_vendor) { 116 case CC_VENDOR_AMD: 117 return amd_cc_platform_has(attr); 118 case CC_VENDOR_INTEL: 119 return intel_cc_platform_has(attr); 120 default: 121 return false; 122 } 123 } 124 EXPORT_SYMBOL_GPL(cc_platform_has); 125 126 u64 cc_mkenc(u64 val) 127 { 128 /* 129 * Both AMD and Intel use a bit in the page table to indicate 130 * encryption status of the page. 131 * 132 * - for AMD, bit *set* means the page is encrypted 133 * - for AMD with vTOM and for Intel, *clear* means encrypted 134 */ 135 switch (cc_vendor) { 136 case CC_VENDOR_AMD: 137 if (sev_status & MSR_AMD64_SNP_VTOM) 138 return val & ~cc_mask; 139 else 140 return val | cc_mask; 141 case CC_VENDOR_INTEL: 142 return val & ~cc_mask; 143 default: 144 return val; 145 } 146 } 147 148 u64 cc_mkdec(u64 val) 149 { 150 /* See comment in cc_mkenc() */ 151 switch (cc_vendor) { 152 case CC_VENDOR_AMD: 153 if (sev_status & MSR_AMD64_SNP_VTOM) 154 return val | cc_mask; 155 else 156 return val & ~cc_mask; 157 case CC_VENDOR_INTEL: 158 return val | cc_mask; 159 default: 160 return val; 161 } 162 } 163 EXPORT_SYMBOL_GPL(cc_mkdec); 164 165 static void amd_cc_platform_clear(enum cc_attr attr) 166 { 167 switch (attr) { 168 case CC_ATTR_HOST_SEV_SNP: 169 cc_flags.host_sev_snp = 0; 170 break; 171 default: 172 break; 173 } 174 } 175 176 void cc_platform_clear(enum cc_attr attr) 177 { 178 switch (cc_vendor) { 179 case CC_VENDOR_AMD: 180 amd_cc_platform_clear(attr); 181 break; 182 default: 183 break; 184 } 185 } 186 187 static void amd_cc_platform_set(enum cc_attr attr) 188 { 189 switch (attr) { 190 case CC_ATTR_HOST_SEV_SNP: 191 cc_flags.host_sev_snp = 1; 192 break; 193 default: 194 break; 195 } 196 } 197 198 void cc_platform_set(enum cc_attr attr) 199 { 200 switch (cc_vendor) { 201 case CC_VENDOR_AMD: 202 amd_cc_platform_set(attr); 203 break; 204 default: 205 break; 206 } 207 } 208 209 __init void cc_random_init(void) 210 { 211 /* 212 * The seed is 32 bytes (in units of longs), which is 256 bits, which 213 * is the security level that the RNG is targeting. 214 */ 215 unsigned long rng_seed[32 / sizeof(long)]; 216 size_t i, longs; 217 218 if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT)) 219 return; 220 221 /* 222 * Since the CoCo threat model includes the host, the only reliable 223 * source of entropy that can be neither observed nor manipulated is 224 * RDRAND. Usually, RDRAND failure is considered tolerable, but since 225 * CoCo guests have no other unobservable source of entropy, it's 226 * important to at least ensure the RNG gets some initial random seeds. 227 */ 228 for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) { 229 longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i); 230 231 /* 232 * A zero return value means that the guest doesn't have RDRAND 233 * or the CPU is physically broken, and in both cases that 234 * means most crypto inside of the CoCo instance will be 235 * broken, defeating the purpose of CoCo in the first place. So 236 * just panic here because it's absolutely unsafe to continue 237 * executing. 238 */ 239 if (longs == 0) 240 panic("RDRAND is defective."); 241 } 242 add_device_randomness(rng_seed, sizeof(rng_seed)); 243 memzero_explicit(rng_seed, sizeof(rng_seed)); 244 } 245