Re: [PATCH v16 3/5] x86/sev: Initialize RMPOPT configuration MSRs

From: Borislav Petkov

Date: Fri Sep 18 2026 - 14:01:55 EST


On Wed, Sep 16, 2026 at 10:14:52PM +0000, Ashish Kalra wrote:
> Changes in v15:
> - Rename snp_setup_rmpopt() to snp_enable_rmpopt().
> - Program each core's RMPOPT_BASE only when it is not already set.
> arch/x86/include/asm/msr-index.h | 3 ++
> arch/x86/include/asm/sev.h | 2 +
> arch/x86/virt/svm/sev.c | 66 +++++++++++++++++++++++++++++---
> drivers/crypto/ccp/sev-dev.c | 2 +
> 4 files changed, 68 insertions(+), 5 deletions(-)

Did some scrubbing:

commit 61132258c7a139a9533ae24b056a099184b70e50 (HEAD -> refs/heads/tip-x86-sev)
Author: Ashish Kalra <ashish.kalra@xxxxxxx>
Date: Wed Sep 16 22:14:52 2026 +0000

x86/sev: Initialize RMPOPT configuration MSRs

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.

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 because this is the maximum the RMPOPT tables support.

The RMPOPT_BASE MSR can only be written after SNP is enabled, so the
enabling runs from the ccp SNP init path (and again on guest teardown)
rather than from an initcall. This is also in line with the intention to
not enable SNP by default but enable it on demand, when the ccp module
is loaded.

RMPOPT_BASE is programmed on all primary threads. RMPOPT_EN cannot be
cleared while SNP is enabled, and CPU hotplug is disabled while SNP is
active, so once programmed the MSRs stay set on all CPUs until SNP is
disabled. A set RMPOPT_EN on the local CPU therefore means the
programming has already been done and thus it can be skipped.

[ bp:
- Massage commit message
- move enabling logic into the commit message
- zap unnecessary comments
- cleanup ]

Suggested-by: Thomas Lendacky <thomas.lendacky@xxxxxxx>
Suggested-by: Dave Hansen <dave.hansen@xxxxxxxxxxxxxxx>
Signed-off-by: Ashish Kalra <ashish.kalra@xxxxxxx>
Signed-off-by: Borislav Petkov (AMD) <bp@xxxxxxxxx>
Reviewed-by: Tom Lendacky <thomas.lendacky@xxxxxxx>
Link: https://patch.msgid.link/7fdf0f5b1be4b561c884c5200d6606a947cbc09d.1789594774.git.ashish.kalra@xxxxxxx

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..fa81aa004e8b 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_enable_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_enable_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..1fecd246ce5f 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,34 @@ 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_enable_rmpopt(void)
+{
+ u64 base;
+ int cpu;
+
+ if (!rmpopt_capable())
+ return;
+
+ rmpopt_pa_start = ALIGN_DOWN(PFN_PHYS(min_low_pfn), SZ_1G);
+
+ /*
+ * 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.
+ */
+ rdmsrq(MSR_AMD64_RMPOPT_BASE, base);
+ if (!(base & MSR_AMD64_RMPOPT_ENABLE))
+ for_each_cpu(cpu, cpu_primary_thread_mask)
+ wrmsrq_on_cpu(cpu, MSR_AMD64_RMPOPT_BASE,
+ rmpopt_pa_start | MSR_AMD64_RMPOPT_ENABLE);
+}
+EXPORT_SYMBOL_FOR_MODULES(snp_enable_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 +729,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) {
+ if (probe_segmented_rmptable_info())
+ return true;
+
+ setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+ return false;
+ }
+ } else {
+ 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..5c996ab63895 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_enable_rmpopt();
+
return 0;
}

--
Regards/Gruss,
Boris.

https://people.kernel.org/tglx/notes-about-netiquette