xref: /openbmc/linux/arch/x86/coco/core.c (revision 86aa961bb4619a68077ebeba21c52e9ba0eab43d)
161983110SKirill A. Shutemov // SPDX-License-Identifier: GPL-2.0-only
261983110SKirill A. Shutemov /*
361983110SKirill A. Shutemov  * Confidential Computing Platform Capability checks
461983110SKirill A. Shutemov  *
561983110SKirill A. Shutemov  * Copyright (C) 2021 Advanced Micro Devices, Inc.
6*453b5f2dSJason A. Donenfeld  * Copyright (C) 2024 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
761983110SKirill A. Shutemov  *
861983110SKirill A. Shutemov  * Author: Tom Lendacky <thomas.lendacky@amd.com>
961983110SKirill A. Shutemov  */
1061983110SKirill A. Shutemov 
1161983110SKirill A. Shutemov #include <linux/export.h>
1261983110SKirill A. Shutemov #include <linux/cc_platform.h>
13*453b5f2dSJason A. Donenfeld #include <linux/string.h>
14*453b5f2dSJason A. Donenfeld #include <linux/random.h>
1561983110SKirill A. Shutemov 
16*453b5f2dSJason A. Donenfeld #include <asm/archrandom.h>
17655a0fa3SKirill A. Shutemov #include <asm/coco.h>
1861983110SKirill A. Shutemov #include <asm/processor.h>
1961983110SKirill A. Shutemov 
20da86eb96SBorislav Petkov (AMD) enum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE;
210982fd6bSArd Biesheuvel u64 cc_mask __ro_after_init;
22655a0fa3SKirill A. Shutemov 
intel_cc_platform_has(enum cc_attr attr)231eaf282eSBorislav Petkov (AMD) static bool noinstr intel_cc_platform_has(enum cc_attr attr)
2461983110SKirill A. Shutemov {
2503149948SKuppuswamy Sathyanarayanan 	switch (attr) {
2603149948SKuppuswamy Sathyanarayanan 	case CC_ATTR_GUEST_UNROLL_STRING_IO:
27bae1a962SKuppuswamy Sathyanarayanan 	case CC_ATTR_HOTPLUG_DISABLED:
287dbde763SKirill A. Shutemov 	case CC_ATTR_GUEST_MEM_ENCRYPT:
29968b4931SKirill A. Shutemov 	case CC_ATTR_MEM_ENCRYPT:
3003149948SKuppuswamy Sathyanarayanan 		return true;
3103149948SKuppuswamy Sathyanarayanan 	default:
3261983110SKirill A. Shutemov 		return false;
3361983110SKirill A. Shutemov 	}
3403149948SKuppuswamy Sathyanarayanan }
3561983110SKirill A. Shutemov 
3661983110SKirill A. Shutemov /*
37812b0597SMichael Kelley  * Handle the SEV-SNP vTOM case where sme_me_mask is zero, and
38812b0597SMichael Kelley  * the other levels of SME/SEV functionality, including C-bit
39812b0597SMichael Kelley  * based SEV-SNP, are not enabled.
40812b0597SMichael Kelley  */
amd_cc_platform_vtom(enum cc_attr attr)411eaf282eSBorislav Petkov (AMD) static __maybe_unused __always_inline bool amd_cc_platform_vtom(enum cc_attr attr)
42812b0597SMichael Kelley {
43812b0597SMichael Kelley 	switch (attr) {
44812b0597SMichael Kelley 	case CC_ATTR_GUEST_MEM_ENCRYPT:
45812b0597SMichael Kelley 	case CC_ATTR_MEM_ENCRYPT:
46812b0597SMichael Kelley 		return true;
47812b0597SMichael Kelley 	default:
48812b0597SMichael Kelley 		return false;
49812b0597SMichael Kelley 	}
50812b0597SMichael Kelley }
51812b0597SMichael Kelley 
52812b0597SMichael Kelley /*
5361983110SKirill A. Shutemov  * SME and SEV are very similar but they are not the same, so there are
5461983110SKirill A. Shutemov  * times that the kernel will need to distinguish between SME and SEV. The
5561983110SKirill A. Shutemov  * cc_platform_has() function is used for this.  When a distinction isn't
5661983110SKirill A. Shutemov  * needed, the CC_ATTR_MEM_ENCRYPT attribute can be used.
5761983110SKirill A. Shutemov  *
5861983110SKirill A. Shutemov  * The trampoline code is a good example for this requirement.  Before
5961983110SKirill A. Shutemov  * paging is activated, SME will access all memory as decrypted, but SEV
6061983110SKirill A. Shutemov  * will access all memory as encrypted.  So, when APs are being brought
6161983110SKirill A. Shutemov  * up under SME the trampoline area cannot be encrypted, whereas under SEV
6261983110SKirill A. Shutemov  * the trampoline area must be encrypted.
6361983110SKirill A. Shutemov  */
64812b0597SMichael Kelley 
amd_cc_platform_has(enum cc_attr attr)651eaf282eSBorislav Petkov (AMD) static bool noinstr amd_cc_platform_has(enum cc_attr attr)
6661983110SKirill A. Shutemov {
6761983110SKirill A. Shutemov #ifdef CONFIG_AMD_MEM_ENCRYPT
68812b0597SMichael Kelley 
69812b0597SMichael Kelley 	if (sev_status & MSR_AMD64_SNP_VTOM)
70812b0597SMichael Kelley 		return amd_cc_platform_vtom(attr);
71812b0597SMichael Kelley 
7261983110SKirill A. Shutemov 	switch (attr) {
7361983110SKirill A. Shutemov 	case CC_ATTR_MEM_ENCRYPT:
7461983110SKirill A. Shutemov 		return sme_me_mask;
7561983110SKirill A. Shutemov 
7661983110SKirill A. Shutemov 	case CC_ATTR_HOST_MEM_ENCRYPT:
7761983110SKirill A. Shutemov 		return sme_me_mask && !(sev_status & MSR_AMD64_SEV_ENABLED);
7861983110SKirill A. Shutemov 
7961983110SKirill A. Shutemov 	case CC_ATTR_GUEST_MEM_ENCRYPT:
8061983110SKirill A. Shutemov 		return sev_status & MSR_AMD64_SEV_ENABLED;
8161983110SKirill A. Shutemov 
8261983110SKirill A. Shutemov 	case CC_ATTR_GUEST_STATE_ENCRYPT:
8361983110SKirill A. Shutemov 		return sev_status & MSR_AMD64_SEV_ES_ENABLED;
8461983110SKirill A. Shutemov 
8561983110SKirill A. Shutemov 	/*
8661983110SKirill A. Shutemov 	 * With SEV, the rep string I/O instructions need to be unrolled
8761983110SKirill A. Shutemov 	 * but SEV-ES supports them through the #VC handler.
8861983110SKirill A. Shutemov 	 */
8961983110SKirill A. Shutemov 	case CC_ATTR_GUEST_UNROLL_STRING_IO:
9061983110SKirill A. Shutemov 		return (sev_status & MSR_AMD64_SEV_ENABLED) &&
9161983110SKirill A. Shutemov 			!(sev_status & MSR_AMD64_SEV_ES_ENABLED);
9261983110SKirill A. Shutemov 
93f742b90eSBrijesh Singh 	case CC_ATTR_GUEST_SEV_SNP:
94f742b90eSBrijesh Singh 		return sev_status & MSR_AMD64_SEV_SNP_ENABLED;
95f742b90eSBrijesh Singh 
9661983110SKirill A. Shutemov 	default:
9761983110SKirill A. Shutemov 		return false;
9861983110SKirill A. Shutemov 	}
9961983110SKirill A. Shutemov #else
10061983110SKirill A. Shutemov 	return false;
10161983110SKirill A. Shutemov #endif
10261983110SKirill A. Shutemov }
10361983110SKirill A. Shutemov 
cc_platform_has(enum cc_attr attr)1041eaf282eSBorislav Petkov (AMD) bool noinstr cc_platform_has(enum cc_attr attr)
10561983110SKirill A. Shutemov {
1063d91c537SBorislav Petkov (AMD) 	switch (cc_vendor) {
107655a0fa3SKirill A. Shutemov 	case CC_VENDOR_AMD:
10861983110SKirill A. Shutemov 		return amd_cc_platform_has(attr);
109655a0fa3SKirill A. Shutemov 	case CC_VENDOR_INTEL:
110655a0fa3SKirill A. Shutemov 		return intel_cc_platform_has(attr);
111655a0fa3SKirill A. Shutemov 	default:
11261983110SKirill A. Shutemov 		return false;
11361983110SKirill A. Shutemov 	}
114655a0fa3SKirill A. Shutemov }
11561983110SKirill A. Shutemov EXPORT_SYMBOL_GPL(cc_platform_has);
116655a0fa3SKirill A. Shutemov 
cc_mkenc(u64 val)117b577f542SKirill A. Shutemov u64 cc_mkenc(u64 val)
118b577f542SKirill A. Shutemov {
11941394e33SKirill A. Shutemov 	/*
12041394e33SKirill A. Shutemov 	 * Both AMD and Intel use a bit in the page table to indicate
12141394e33SKirill A. Shutemov 	 * encryption status of the page.
12241394e33SKirill A. Shutemov 	 *
12341394e33SKirill A. Shutemov 	 * - for AMD, bit *set* means the page is encrypted
124812b0597SMichael Kelley 	 * - for AMD with vTOM and for Intel, *clear* means encrypted
12541394e33SKirill A. Shutemov 	 */
1263d91c537SBorislav Petkov (AMD) 	switch (cc_vendor) {
127b577f542SKirill A. Shutemov 	case CC_VENDOR_AMD:
128812b0597SMichael Kelley 		if (sev_status & MSR_AMD64_SNP_VTOM)
129812b0597SMichael Kelley 			return val & ~cc_mask;
130812b0597SMichael Kelley 		else
131b577f542SKirill A. Shutemov 			return val | cc_mask;
13241394e33SKirill A. Shutemov 	case CC_VENDOR_INTEL:
13341394e33SKirill A. Shutemov 		return val & ~cc_mask;
134b577f542SKirill A. Shutemov 	default:
135b577f542SKirill A. Shutemov 		return val;
136b577f542SKirill A. Shutemov 	}
137b577f542SKirill A. Shutemov }
138b577f542SKirill A. Shutemov 
cc_mkdec(u64 val)139b577f542SKirill A. Shutemov u64 cc_mkdec(u64 val)
140b577f542SKirill A. Shutemov {
14141394e33SKirill A. Shutemov 	/* See comment in cc_mkenc() */
1423d91c537SBorislav Petkov (AMD) 	switch (cc_vendor) {
143b577f542SKirill A. Shutemov 	case CC_VENDOR_AMD:
144812b0597SMichael Kelley 		if (sev_status & MSR_AMD64_SNP_VTOM)
145812b0597SMichael Kelley 			return val | cc_mask;
146812b0597SMichael Kelley 		else
147b577f542SKirill A. Shutemov 			return val & ~cc_mask;
14841394e33SKirill A. Shutemov 	case CC_VENDOR_INTEL:
14941394e33SKirill A. Shutemov 		return val | cc_mask;
150b577f542SKirill A. Shutemov 	default:
151b577f542SKirill A. Shutemov 		return val;
152b577f542SKirill A. Shutemov 	}
153b577f542SKirill A. Shutemov }
154b577f542SKirill A. Shutemov EXPORT_SYMBOL_GPL(cc_mkdec);
155*453b5f2dSJason A. Donenfeld 
cc_random_init(void)156*453b5f2dSJason A. Donenfeld __init void cc_random_init(void)
157*453b5f2dSJason A. Donenfeld {
158*453b5f2dSJason A. Donenfeld 	/*
159*453b5f2dSJason A. Donenfeld 	 * The seed is 32 bytes (in units of longs), which is 256 bits, which
160*453b5f2dSJason A. Donenfeld 	 * is the security level that the RNG is targeting.
161*453b5f2dSJason A. Donenfeld 	 */
162*453b5f2dSJason A. Donenfeld 	unsigned long rng_seed[32 / sizeof(long)];
163*453b5f2dSJason A. Donenfeld 	size_t i, longs;
164*453b5f2dSJason A. Donenfeld 
165*453b5f2dSJason A. Donenfeld 	if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))
166*453b5f2dSJason A. Donenfeld 		return;
167*453b5f2dSJason A. Donenfeld 
168*453b5f2dSJason A. Donenfeld 	/*
169*453b5f2dSJason A. Donenfeld 	 * Since the CoCo threat model includes the host, the only reliable
170*453b5f2dSJason A. Donenfeld 	 * source of entropy that can be neither observed nor manipulated is
171*453b5f2dSJason A. Donenfeld 	 * RDRAND. Usually, RDRAND failure is considered tolerable, but since
172*453b5f2dSJason A. Donenfeld 	 * CoCo guests have no other unobservable source of entropy, it's
173*453b5f2dSJason A. Donenfeld 	 * important to at least ensure the RNG gets some initial random seeds.
174*453b5f2dSJason A. Donenfeld 	 */
175*453b5f2dSJason A. Donenfeld 	for (i = 0; i < ARRAY_SIZE(rng_seed); i += longs) {
176*453b5f2dSJason A. Donenfeld 		longs = arch_get_random_longs(&rng_seed[i], ARRAY_SIZE(rng_seed) - i);
177*453b5f2dSJason A. Donenfeld 
178*453b5f2dSJason A. Donenfeld 		/*
179*453b5f2dSJason A. Donenfeld 		 * A zero return value means that the guest doesn't have RDRAND
180*453b5f2dSJason A. Donenfeld 		 * or the CPU is physically broken, and in both cases that
181*453b5f2dSJason A. Donenfeld 		 * means most crypto inside of the CoCo instance will be
182*453b5f2dSJason A. Donenfeld 		 * broken, defeating the purpose of CoCo in the first place. So
183*453b5f2dSJason A. Donenfeld 		 * just panic here because it's absolutely unsafe to continue
184*453b5f2dSJason A. Donenfeld 		 * executing.
185*453b5f2dSJason A. Donenfeld 		 */
186*453b5f2dSJason A. Donenfeld 		if (longs == 0)
187*453b5f2dSJason A. Donenfeld 			panic("RDRAND is defective.");
188*453b5f2dSJason A. Donenfeld 	}
189*453b5f2dSJason A. Donenfeld 	add_device_randomness(rng_seed, sizeof(rng_seed));
190*453b5f2dSJason A. Donenfeld 	memzero_explicit(rng_seed, sizeof(rng_seed));
191*453b5f2dSJason A. Donenfeld }
192