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