Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
  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
 20enum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE;
 21u64 cc_mask __ro_after_init;
 22
 23static struct cc_attr_flags {
 24	__u64 host_sev_snp	: 1,
 25	      __resv		: 63;
 26} cc_flags;
 27
 28static 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 */
 46static __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
 70static 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
112bool 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}
123EXPORT_SYMBOL_GPL(cc_platform_has);
124
125u64 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
147u64 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}
162EXPORT_SYMBOL_GPL(cc_mkdec);
163
164static 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
175void 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
186static 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
197void 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}
1