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