162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Confidential Computing Platform Capability checks 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2021 Advanced Micro Devices, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Tom Lendacky <thomas.lendacky@amd.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/export.h> 1162306a36Sopenharmony_ci#include <linux/cc_platform.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/coco.h> 1462306a36Sopenharmony_ci#include <asm/processor.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cienum cc_vendor cc_vendor __ro_after_init = CC_VENDOR_NONE; 1762306a36Sopenharmony_cistatic u64 cc_mask __ro_after_init; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic bool noinstr intel_cc_platform_has(enum cc_attr attr) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci switch (attr) { 2262306a36Sopenharmony_ci case CC_ATTR_GUEST_UNROLL_STRING_IO: 2362306a36Sopenharmony_ci case CC_ATTR_HOTPLUG_DISABLED: 2462306a36Sopenharmony_ci case CC_ATTR_GUEST_MEM_ENCRYPT: 2562306a36Sopenharmony_ci case CC_ATTR_MEM_ENCRYPT: 2662306a36Sopenharmony_ci return true; 2762306a36Sopenharmony_ci default: 2862306a36Sopenharmony_ci return false; 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Handle the SEV-SNP vTOM case where sme_me_mask is zero, and 3462306a36Sopenharmony_ci * the other levels of SME/SEV functionality, including C-bit 3562306a36Sopenharmony_ci * based SEV-SNP, are not enabled. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistatic __maybe_unused __always_inline bool amd_cc_platform_vtom(enum cc_attr attr) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci switch (attr) { 4062306a36Sopenharmony_ci case CC_ATTR_GUEST_MEM_ENCRYPT: 4162306a36Sopenharmony_ci case CC_ATTR_MEM_ENCRYPT: 4262306a36Sopenharmony_ci return true; 4362306a36Sopenharmony_ci default: 4462306a36Sopenharmony_ci return false; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * SME and SEV are very similar but they are not the same, so there are 5062306a36Sopenharmony_ci * times that the kernel will need to distinguish between SME and SEV. The 5162306a36Sopenharmony_ci * cc_platform_has() function is used for this. When a distinction isn't 5262306a36Sopenharmony_ci * needed, the CC_ATTR_MEM_ENCRYPT attribute can be used. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * The trampoline code is a good example for this requirement. Before 5562306a36Sopenharmony_ci * paging is activated, SME will access all memory as decrypted, but SEV 5662306a36Sopenharmony_ci * will access all memory as encrypted. So, when APs are being brought 5762306a36Sopenharmony_ci * up under SME the trampoline area cannot be encrypted, whereas under SEV 5862306a36Sopenharmony_ci * the trampoline area must be encrypted. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic bool noinstr amd_cc_platform_has(enum cc_attr attr) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci#ifdef CONFIG_AMD_MEM_ENCRYPT 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (sev_status & MSR_AMD64_SNP_VTOM) 6662306a36Sopenharmony_ci return amd_cc_platform_vtom(attr); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci switch (attr) { 6962306a36Sopenharmony_ci case CC_ATTR_MEM_ENCRYPT: 7062306a36Sopenharmony_ci return sme_me_mask; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci case CC_ATTR_HOST_MEM_ENCRYPT: 7362306a36Sopenharmony_ci return sme_me_mask && !(sev_status & MSR_AMD64_SEV_ENABLED); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci case CC_ATTR_GUEST_MEM_ENCRYPT: 7662306a36Sopenharmony_ci return sev_status & MSR_AMD64_SEV_ENABLED; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci case CC_ATTR_GUEST_STATE_ENCRYPT: 7962306a36Sopenharmony_ci return sev_status & MSR_AMD64_SEV_ES_ENABLED; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* 8262306a36Sopenharmony_ci * With SEV, the rep string I/O instructions need to be unrolled 8362306a36Sopenharmony_ci * but SEV-ES supports them through the #VC handler. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci case CC_ATTR_GUEST_UNROLL_STRING_IO: 8662306a36Sopenharmony_ci return (sev_status & MSR_AMD64_SEV_ENABLED) && 8762306a36Sopenharmony_ci !(sev_status & MSR_AMD64_SEV_ES_ENABLED); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci case CC_ATTR_GUEST_SEV_SNP: 9062306a36Sopenharmony_ci return sev_status & MSR_AMD64_SEV_SNP_ENABLED; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci default: 9362306a36Sopenharmony_ci return false; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci#else 9662306a36Sopenharmony_ci return false; 9762306a36Sopenharmony_ci#endif 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cibool noinstr cc_platform_has(enum cc_attr attr) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci switch (cc_vendor) { 10362306a36Sopenharmony_ci case CC_VENDOR_AMD: 10462306a36Sopenharmony_ci return amd_cc_platform_has(attr); 10562306a36Sopenharmony_ci case CC_VENDOR_INTEL: 10662306a36Sopenharmony_ci return intel_cc_platform_has(attr); 10762306a36Sopenharmony_ci default: 10862306a36Sopenharmony_ci return false; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cc_platform_has); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciu64 cc_mkenc(u64 val) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Both AMD and Intel use a bit in the page table to indicate 11762306a36Sopenharmony_ci * encryption status of the page. 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * - for AMD, bit *set* means the page is encrypted 12062306a36Sopenharmony_ci * - for AMD with vTOM and for Intel, *clear* means encrypted 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci switch (cc_vendor) { 12362306a36Sopenharmony_ci case CC_VENDOR_AMD: 12462306a36Sopenharmony_ci if (sev_status & MSR_AMD64_SNP_VTOM) 12562306a36Sopenharmony_ci return val & ~cc_mask; 12662306a36Sopenharmony_ci else 12762306a36Sopenharmony_ci return val | cc_mask; 12862306a36Sopenharmony_ci case CC_VENDOR_INTEL: 12962306a36Sopenharmony_ci return val & ~cc_mask; 13062306a36Sopenharmony_ci default: 13162306a36Sopenharmony_ci return val; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciu64 cc_mkdec(u64 val) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci /* See comment in cc_mkenc() */ 13862306a36Sopenharmony_ci switch (cc_vendor) { 13962306a36Sopenharmony_ci case CC_VENDOR_AMD: 14062306a36Sopenharmony_ci if (sev_status & MSR_AMD64_SNP_VTOM) 14162306a36Sopenharmony_ci return val | cc_mask; 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci return val & ~cc_mask; 14462306a36Sopenharmony_ci case CC_VENDOR_INTEL: 14562306a36Sopenharmony_ci return val | cc_mask; 14662306a36Sopenharmony_ci default: 14762306a36Sopenharmony_ci return val; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(cc_mkdec); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci__init void cc_set_mask(u64 mask) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci cc_mask = mask; 15562306a36Sopenharmony_ci} 156