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