Inter-revision diff: patch 3

Comparing v3 (message) to v5 (message)

--- v3
+++ v5
@@ -1,60 +1,258 @@
-Add CPU feature detection for Secure Encrypted Virtualization with
-Secure Nested Paging. This feature adds a strong memory integrity
-protection to help prevent malicious hypervisor-based attacks like
-data replay, memory re-mapping, and more.
+The memory integrity guarantees of SEV-SNP are enforced through a new
+structure called the Reverse Map Table (RMP). The RMP is a single data
+structure shared across the system that contains one entry for every 4K
+page of DRAM that may be used by SEV-SNP VMs. The goal of RMP is to
+track the owner of each page of memory. Pages of memory can be owned by
+the hypervisor, owned by a specific VM or owned by the AMD-SP. See APM2
+section 15.36.3 for more detail on RMP.
+
+The RMP table is used to enforce access control to memory. The table itself
+is not directly writable by the software. New CPU instructions (RMPUPDATE,
+PVALIDATE, RMPADJUST) are used to manipulate the RMP entries.
+
+Based on the platform configuration, the BIOS reserves the memory used
+for the RMP table. The start and end address of the RMP table must be
+queried by reading the RMP_BASE and RMP_END MSRs. If the RMP_BASE and
+RMP_END are not set then disable the SEV-SNP feature.
+
+The SEV-SNP feature is enabled only after the RMP table is successfully
+initialized.
 
 Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
 ---
- arch/x86/include/asm/cpufeatures.h       | 1 +
- arch/x86/kernel/cpu/amd.c                | 3 ++-
- tools/arch/x86/include/asm/cpufeatures.h | 1 +
- 3 files changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
-index ac37830ae941..433d00323b36 100644
---- a/arch/x86/include/asm/cpufeatures.h
-+++ b/arch/x86/include/asm/cpufeatures.h
-@@ -397,6 +397,7 @@
- #define X86_FEATURE_SEV			(19*32+ 1) /* AMD Secure Encrypted Virtualization */
- #define X86_FEATURE_VM_PAGE_FLUSH	(19*32+ 2) /* "" VM Page Flush MSR is supported */
- #define X86_FEATURE_SEV_ES		(19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
-+#define X86_FEATURE_SEV_SNP		(19*32+4)  /* AMD Secure Encrypted Virtualization - Secure Nested Paging */
- #define X86_FEATURE_SME_COHERENT	(19*32+10) /* "" AMD hardware-enforced cache coherency */
- 
+ arch/x86/include/asm/disabled-features.h |   8 +-
+ arch/x86/include/asm/msr-index.h         |   6 +
+ arch/x86/kernel/sev.c                    | 144 +++++++++++++++++++++++
+ 3 files changed, 157 insertions(+), 1 deletion(-)
+
+diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
+index 8f28fafa98b3..30a760e19c35 100644
+--- a/arch/x86/include/asm/disabled-features.h
++++ b/arch/x86/include/asm/disabled-features.h
+@@ -65,6 +65,12 @@
+ # define DISABLE_SGX	(1 << (X86_FEATURE_SGX & 31))
+ #endif
+ 
++#ifdef CONFIG_AMD_MEM_ENCRYPT
++# define DISABLE_SEV_SNP	0
++#else
++# define DISABLE_SEV_SNP	(1 << (X86_FEATURE_SEV_SNP & 31))
++#endif
++
  /*
-diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
-index 0adb0341cd7c..19567f976996 100644
---- a/arch/x86/kernel/cpu/amd.c
-+++ b/arch/x86/kernel/cpu/amd.c
-@@ -586,7 +586,7 @@ static void early_detect_mem_encrypt(struct cpuinfo_x86 *c)
- 	 *	      If BIOS has not enabled SME then don't advertise the
- 	 *	      SME feature (set in scattered.c).
- 	 *   For SEV: If BIOS has not enabled SEV then don't advertise the
--	 *            SEV and SEV_ES feature (set in scattered.c).
-+	 *            SEV, SEV_ES and SEV_SNP feature.
- 	 *
- 	 *   In all cases, since support for SME and SEV requires long mode,
- 	 *   don't advertise the feature under CONFIG_X86_32.
-@@ -618,6 +618,7 @@ static void early_detect_mem_encrypt(struct cpuinfo_x86 *c)
- clear_sev:
- 		setup_clear_cpu_cap(X86_FEATURE_SEV);
- 		setup_clear_cpu_cap(X86_FEATURE_SEV_ES);
-+		setup_clear_cpu_cap(X86_FEATURE_SEV_SNP);
- 	}
+  * Make sure to add features to the correct mask
+  */
+@@ -88,7 +94,7 @@
+ 			 DISABLE_ENQCMD)
+ #define DISABLED_MASK17	0
+ #define DISABLED_MASK18	0
+-#define DISABLED_MASK19	0
++#define DISABLED_MASK19	(DISABLE_SEV_SNP)
+ #define DISABLED_MASK_CHECK BUILD_BUG_ON_ZERO(NCAPINTS != 20)
+ 
+ #endif /* _ASM_X86_DISABLED_FEATURES_H */
+diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
+index 37589da0282e..410359a9512c 100644
+--- a/arch/x86/include/asm/msr-index.h
++++ b/arch/x86/include/asm/msr-index.h
+@@ -485,6 +485,8 @@
+ #define MSR_AMD64_SEV_ENABLED		BIT_ULL(MSR_AMD64_SEV_ENABLED_BIT)
+ #define MSR_AMD64_SEV_ES_ENABLED	BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT)
+ #define MSR_AMD64_SEV_SNP_ENABLED	BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)
++#define MSR_AMD64_RMP_BASE		0xc0010132
++#define MSR_AMD64_RMP_END		0xc0010133
+ 
+ #define MSR_AMD64_VIRT_SPEC_CTRL	0xc001011f
+ 
+@@ -542,6 +544,10 @@
+ #define MSR_AMD64_SYSCFG		0xc0010010
+ #define MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT	23
+ #define MSR_AMD64_SYSCFG_MEM_ENCRYPT	BIT_ULL(MSR_AMD64_SYSCFG_MEM_ENCRYPT_BIT)
++#define MSR_AMD64_SYSCFG_SNP_EN_BIT		24
++#define MSR_AMD64_SYSCFG_SNP_EN		BIT_ULL(MSR_AMD64_SYSCFG_SNP_EN_BIT)
++#define MSR_AMD64_SYSCFG_SNP_VMPL_EN_BIT	25
++#define MSR_AMD64_SYSCFG_SNP_VMPL_EN	BIT_ULL(MSR_AMD64_SYSCFG_SNP_VMPL_EN_BIT)
+ #define MSR_K8_INT_PENDING_MSG		0xc0010055
+ /* C1E active bits in int pending message */
+ #define K8_INTP_C1E_ACTIVE_MASK		0x18000000
+diff --git a/arch/x86/kernel/sev.c b/arch/x86/kernel/sev.c
+index ab17c93634e9..7936c8139c74 100644
+--- a/arch/x86/kernel/sev.c
++++ b/arch/x86/kernel/sev.c
+@@ -24,6 +24,8 @@
+ #include <linux/sev-guest.h>
+ #include <linux/platform_device.h>
+ #include <linux/io.h>
++#include <linux/cpumask.h>
++#include <linux/iommu.h>
+ 
+ #include <asm/cpu_entry_area.h>
+ #include <asm/stacktrace.h>
+@@ -40,11 +42,19 @@
+ #include <asm/efi.h>
+ #include <asm/cpuid.h>
+ #include <asm/setup.h>
++#include <asm/apic.h>
++#include <asm/iommu.h>
+ 
+ #include "sev-internal.h"
+ 
+ #define DR7_RESET_VALUE        0x400
+ 
++/*
++ * The first 16KB from the RMP_BASE is used by the processor for the
++ * bookkeeping, the range need to be added during the RMP entry lookup.
++ */
++#define RMPTABLE_CPU_BOOKKEEPING_SZ	0x4000
++
+ /* For early boot hypervisor communication in SEV-ES enabled guests */
+ static struct ghcb boot_ghcb_page __bss_decrypted __aligned(PAGE_SIZE);
+ 
+@@ -56,6 +66,9 @@ static struct ghcb __initdata *boot_ghcb;
+ 
+ static u64 snp_secrets_phys;
+ 
++static unsigned long rmptable_start __ro_after_init;
++static unsigned long rmptable_end __ro_after_init;
++
+ /* #VC handler runtime per-CPU data */
+ struct sev_es_runtime_data {
+ 	struct ghcb ghcb_page;
+@@ -2232,3 +2245,134 @@ static int __init add_snp_guest_request(void)
+ 	return 0;
  }
- 
-diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
-index cc96e26d69f7..e78ac4011ec8 100644
---- a/tools/arch/x86/include/asm/cpufeatures.h
-+++ b/tools/arch/x86/include/asm/cpufeatures.h
-@@ -390,6 +390,7 @@
- #define X86_FEATURE_SEV			(19*32+ 1) /* AMD Secure Encrypted Virtualization */
- #define X86_FEATURE_VM_PAGE_FLUSH	(19*32+ 2) /* "" VM Page Flush MSR is supported */
- #define X86_FEATURE_SEV_ES		(19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
-+#define X86_FEATURE_SEV_SNP		(19*32+4)  /* AMD Secure Encrypted Virtualization - Secure Nested Paging */
- #define X86_FEATURE_SME_COHERENT	(19*32+10) /* "" AMD hardware-enforced cache coherency */
- 
- /*
+ device_initcall(add_snp_guest_request);
++
++#undef pr_fmt
++#define pr_fmt(fmt)	"SEV-SNP: " fmt
++
++static int __snp_enable(unsigned int cpu)
++{
++	u64 val;
++
++	if (!cpu_feature_enabled(X86_FEATURE_SEV_SNP))
++		return 0;
++
++	rdmsrl(MSR_AMD64_SYSCFG, val);
++
++	val |= MSR_AMD64_SYSCFG_SNP_EN;
++	val |= MSR_AMD64_SYSCFG_SNP_VMPL_EN;
++
++	wrmsrl(MSR_AMD64_SYSCFG, val);
++
++	return 0;
++}
++
++static __init void snp_enable(void *arg)
++{
++	__snp_enable(smp_processor_id());
++}
++
++static bool get_rmptable_info(u64 *start, u64 *len)
++{
++	u64 calc_rmp_sz, rmp_sz, rmp_base, rmp_end, nr_pages;
++
++	rdmsrl(MSR_AMD64_RMP_BASE, rmp_base);
++	rdmsrl(MSR_AMD64_RMP_END, rmp_end);
++
++	if (!rmp_base || !rmp_end) {
++		pr_info("Memory for the RMP table has not been reserved by BIOS\n");
++		return false;
++	}
++
++	rmp_sz = rmp_end - rmp_base + 1;
++
++	/*
++	 * Calculate the amount the memory that must be reserved by the BIOS to
++	 * address the full system RAM. The reserved memory should also cover the
++	 * RMP table itself.
++	 *
++	 * See PPR Family 19h Model 01h, Revision B1 section 2.1.5.2 for more
++	 * information on memory requirement.
++	 */
++	nr_pages = totalram_pages();
++	calc_rmp_sz = (((rmp_sz >> PAGE_SHIFT) + nr_pages) << 4) + RMPTABLE_CPU_BOOKKEEPING_SZ;
++
++	if (calc_rmp_sz > rmp_sz) {
++		pr_info("Memory reserved for the RMP table does not cover full system RAM (expected 0x%llx got 0x%llx)\n",
++			calc_rmp_sz, rmp_sz);
++		return false;
++	}
++
++	*start = rmp_base;
++	*len = rmp_sz;
++
++	pr_info("RMP table physical address 0x%016llx - 0x%016llx\n", rmp_base, rmp_end);
++
++	return true;
++}
++
++static __init int __snp_rmptable_init(void)
++{
++	u64 rmp_base, sz;
++	void *start;
++	u64 val;
++
++	if (!get_rmptable_info(&rmp_base, &sz))
++		return 1;
++
++	start = memremap(rmp_base, sz, MEMREMAP_WB);
++	if (!start) {
++		pr_err("Failed to map RMP table 0x%llx+0x%llx\n", rmp_base, sz);
++		return 1;
++	}
++
++	/*
++	 * Check if SEV-SNP is already enabled, this can happen if we are coming from
++	 * kexec boot.
++	 */
++	rdmsrl(MSR_AMD64_SYSCFG, val);
++	if (val & MSR_AMD64_SYSCFG_SNP_EN)
++		goto skip_enable;
++
++	/* Initialize the RMP table to zero */
++	memset(start, 0, sz);
++
++	/* Flush the caches to ensure that data is written before SNP is enabled. */
++	wbinvd_on_all_cpus();
++
++	/* Enable SNP on all CPUs. */
++	on_each_cpu(snp_enable, NULL, 1);
++
++skip_enable:
++	rmptable_start = (unsigned long)start;
++	rmptable_end = rmptable_start + sz;
++
++	return 0;
++}
++
++static int __init snp_rmptable_init(void)
++{
++	if (!boot_cpu_has(X86_FEATURE_SEV_SNP))
++		return 0;
++
++	if (!iommu_sev_snp_supported())
++		goto nosnp;
++
++	if (__snp_rmptable_init())
++		goto nosnp;
++
++	cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/rmptable_init:online", __snp_enable, NULL);
++
++	return 0;
++
++nosnp:
++	setup_clear_cpu_cap(X86_FEATURE_SEV_SNP);
++	return 1;
++}
++
++/*
++ * This must be called after the PCI subsystem. This is because before enabling
++ * the SNP feature we need to ensure that IOMMU supports the SEV-SNP feature.
++ * The iommu_sev_snp_support() is used for checking the feature, and it is
++ * available after subsys_initcall().
++ */
++fs_initcall(snp_rmptable_init);
 -- 
 2.17.1
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help