[PATCH v11 5/6] x86/sev: Add interface to re-enable RMP optimizations.
Ashish Kalra <[email protected]> Mon, 27 Jul 2026 19:05:54 +0000
| Newsgroups | dev.linux.lists.linux-coco,org.kernel.vger.kvm,org.kernel.vger.linux-crypto,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <afc058ce32417dc45e3f7cd9536d0fafafcacb4b.1784844080.git.ashish.kalra@amd.com> |
From: Ashish Kalra <[email protected]> RMPOPT table is a per-CPU table which indicates if 1GB regions of physical memory are entirely hypervisor-owned or not. When performing host memory accesses in hypervisor mode as well as non-SNP guest mode, the processor may consult the RMPOPT table to potentially skip an RMP access and improve performance. Normal guest events clear RMP optimizations: pages are converted from shared to private as SNP guests are launched, and large pages are split and collapsed during guest operation -- both clear the RMPOPT optimizations for the affected 1GB regions. Conversely, guest pages are converted back to shared during SNP guest termination, so those regions may become eligible for RMPOPT optimization again. Without some intervention, all RMP optimizations would eventually be lost. Add an interface to re-optimize all of physical memory. The interface uses mod_delayed_work() instead of queue_delayed_work() so that the delay timer is reset on each call. This provides proper batching semantics: re-optimization runs 10 seconds after the *last* VM termination rather than after the first. mod_delayed_work() also re-queues work that is already in-flight, so a re-scan request during an active scan is not silently dropped. Reviewed-by: Ackerley Tng <[email protected]> Signed-off-by: Ashish Kalra <[email protected]> --- arch/x86/include/asm/sev.h | 2 ++ arch/x86/virt/svm/sev.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/arch/x86/include/asm/sev.h b/arch/x86/include/asm/sev.h index 6fd72a44a51e..09b1c5d33790 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_rmpopt_all_physmem(void); void snp_setup_rmpopt(void); void snp_shutdown(void); #else @@ -681,6 +682,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_rmpopt_all_physmem(void) {} 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 04b19e64f832..291a360291eb 100644 --- a/arch/x86/virt/svm/sev.c +++ b/arch/x86/virt/svm/sev.c @@ -710,6 +710,21 @@ static void rmpopt_work_handler(struct work_struct *work) free_cpumask_var(follower_mask); } +void snp_rmpopt_all_physmem(void) +{ + if (!rmpopt_capable()) + return; + + guard(mutex)(&rmpopt_wq_mutex); + + if (!rmpopt_wq) + return; + + mod_delayed_work(rmpopt_wq, &rmpopt_delayed_work, + msecs_to_jiffies(RMPOPT_WORK_TIMEOUT)); +} +EXPORT_SYMBOL_FOR_MODULES(snp_rmpopt_all_physmem, "kvm-amd"); + void snp_setup_rmpopt(void) { u64 rmpopt_base; -- 2.43.0