[PATCH v14 3/5] x86/sev: Initialize RMPOPT configuration MSRs
From: Ashish Kalra <Ashish.Kalra@amd.com>
Date: 2026-09-10 22:00:18
Also in:
kvm, linux-crypto, lkml
Subsystem:
amd cryptographic coprocessor (ccp) driver, amd cryptographic coprocessor (ccp) driver - sev support, crypto api, the rest, x86 architecture (32-bit and 64-bit) · Maintainers:
Tom Lendacky, John Allen, Ashish Kalra, Herbert Xu, "David S. Miller", Linus Torvalds, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen
From: Ashish Kalra <ashish.kalra@amd.com>
The new RMPOPT instruction helps manage per-CPU RMP optimization
structures inside the CPU. It takes a 1GB-aligned physical address
and either returns the status of the optimizations or tries to enable
the optimizations.
Per-CPU RMPOPT tables support at most 2 TB of addressable memory for
RMP optimizations.
Initialize the per-CPU RMPOPT table base to the starting physical
address. This enables RMP optimization for up to 2 TB of system RAM on
all CPUs.
Additionally, add support to setup and enable RMPOPT once SNP is
enabled and initialized.
Suggested-by: Thomas Lendacky <thomas.lendacky@amd.com>
Suggested-by: Dave Hansen <dave.hansen@linux.intel.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
v14: rmpopt_disable() and the RMPOPT_BASE teardown were removed from this
patch (the disable path is reworked in the next patch, and the MSRs are
now left in place on shutdown). Dropped Reviewed-by: Dave Hansen and
Tom Lendacky due to this rework.
arch/x86/include/asm/msr-index.h | 3 +++
arch/x86/include/asm/sev.h | 2 ++
arch/x86/virt/svm/sev.c | 46 ++++++++++++++++++++++++++++----
drivers/crypto/ccp/sev-dev.c | 2 ++
4 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 3a8e51a0c9e8..1635e2e1c576 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h@@ -761,6 +761,9 @@ #define MSR_AMD64_SEG_RMP_ENABLED_BIT 0 #define MSR_AMD64_SEG_RMP_ENABLED BIT_ULL(MSR_AMD64_SEG_RMP_ENABLED_BIT) #define MSR_AMD64_RMP_SEGMENT_SHIFT(x) (((x) & GENMASK_ULL(13, 8)) >> 8) +#define MSR_AMD64_RMPOPT_BASE 0xc0010139 +#define MSR_AMD64_RMPOPT_ENABLE_BIT 0 +#define MSR_AMD64_RMPOPT_ENABLE BIT_ULL(MSR_AMD64_RMPOPT_ENABLE_BIT) #define MSR_SVSM_CAA 0xc001f000
diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h
index 9e7a077c445d..5638d09b5132 100644
--- a/arch/x86/include/asm/sev.h
+++ b/arch/x86/include/asm/sev.h@@ -662,6 +662,7 @@ static inline void snp_leak_pages(u64 pfn, unsigned int pages) __snp_leak_pages(pfn, pages, true); } int snp_prepare(void); +void snp_setup_rmpopt(void); void snp_shutdown(void); #else static inline bool snp_probe_rmptable_info(void) { return false; }
@@ -680,6 +681,7 @@ static inline void snp_leak_pages(u64 pfn, unsigned int npages) {} static inline void kdump_sev_callback(void) { } static inline void snp_fixup_e820_tables(void) {} static inline int snp_prepare(void) { return -ENODEV; } +static inline void snp_setup_rmpopt(void) {} static inline void snp_shutdown(void) {} #endif
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 558f7924a3f8..a059327dc107 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c@@ -124,6 +124,8 @@ static void *rmp_bookkeeping __ro_after_init; static u64 probed_rmp_base, probed_rmp_size; +static phys_addr_t rmpopt_pa_start; + static LIST_HEAD(snp_leaked_pages_list); static DEFINE_SPINLOCK(snp_leaked_pages_list_lock);
@@ -575,6 +577,32 @@ void snp_shutdown(void) } EXPORT_SYMBOL_FOR_MODULES(snp_shutdown, "ccp"); +static bool rmpopt_capable(void) +{ + return cpu_feature_enabled(X86_FEATURE_RMPOPT) && + cc_platform_has(CC_ATTR_HOST_SEV_SNP); +} + +void snp_setup_rmpopt(void) +{ + u64 rmpopt_base; + int cpu; + + if (!rmpopt_capable()) + return; + + rmpopt_pa_start = ALIGN_DOWN(PFN_PHYS(min_low_pfn), SZ_1G); + rmpopt_base = rmpopt_pa_start | MSR_AMD64_RMPOPT_ENABLE; + + /* + * Per-CPU RMPOPT tables cover at most 2 TB. Program each core's + * RMPOPT_BASE with the start of RAM to optimize up to 2 TB. + */ + for_each_cpu(cpu, cpu_primary_thread_mask) + wrmsrq_on_cpu(cpu, MSR_AMD64_RMPOPT_BASE, rmpopt_base); +} +EXPORT_SYMBOL_FOR_MODULES(snp_setup_rmpopt, "ccp"); + /* * Do the necessary preparations which are verified by the firmware as * described in the SNP_INIT_EX firmware command description in the SNP
@@ -699,13 +727,21 @@ static bool probe_segmented_rmptable_info(void) bool snp_probe_rmptable_info(void) { - if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) + if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) { rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg); - if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) - return probe_segmented_rmptable_info(); - else - return probe_contiguous_rmptable_info(); + if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) + return probe_segmented_rmptable_info(); + } + + /* + * Segmented RMP is either not supported on the platform or is + * disabled by the firmware. RMPOPT is not supported without + * segmented RMP. + */ + setup_clear_cpu_cap(X86_FEATURE_RMPOPT); + + return probe_contiguous_rmptable_info(); } /*
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index f833cb7e4da3..287a8345854b 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c@@ -1663,6 +1663,8 @@ static int __sev_snp_init_locked(int *error, unsigned int max_snp_asid) sev_es_tmr_size = SNP_TMR_SIZE; + snp_setup_rmpopt(); + return 0; }
--
2.43.0