From: Ashish Kalra The RMPOPT table is a per-CPU table which indicates whether 1GB regions of physical memory are entirely hypervisor-owned. 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 disable 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 disable the RMPOPT optimizations for the affected 1GB regions. When guests are torn down, their pages are converted back to shared, so those regions may become eligible for RMPOPT optimization again. Without some intervention, all RMP optimizations would eventually be lost, so re-optimize all of physical memory on SNP guest teardown by calling snp_enable_rmpopt(). snp_enable_rmpopt() performs the re-optimization after a delay, using mod_delayed_work() so that the delay timer is reset on each call. This batches multiple guest terminations into a single pass: the re-optimization runs 10 seconds after the *last* 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. Guest teardown is currently the only event that returns guest memory to hypervisor ownership: SNP guests do not support ballooning or memory hotplug, so pages freed during a guest's lifetime remain guest-owned. It is therefore the only point at which memory becomes eligible for RMP re-optimization, which is why re-optimization is driven by guest teardown rather than by a periodic scan. Reviewed-by: Ackerley Tng Reviewed-by: Tom Lendacky Reviewed-by: Dave Hansen Signed-off-by: Ashish Kalra --- Changes in v15: - Call snp_enable_rmpopt() on guest teardown instead of a separate snp_rmpopt_all_physmem(); the delayed re-optimization now lives in snp_enable_rmpopt(). arch/x86/kvm/svm/sev.c | 2 ++ arch/x86/virt/svm/sev.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 5705723f1f41..4d5e30af1ade 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -3032,6 +3032,8 @@ void sev_vm_destroy(struct kvm *kvm) */ if (snp_decommission_context(kvm)) return; + + snp_enable_rmpopt(); } else { sev_unbind_asid(kvm, sev->handle); } diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c index bd97135cacc2..13d9acb319aa 100644 --- a/arch/x86/virt/svm/sev.c +++ b/arch/x86/virt/svm/sev.c @@ -702,7 +702,7 @@ void snp_enable_rmpopt(void) pr_info_once("RMPOPT optimizations enabled\n"); } -EXPORT_SYMBOL_FOR_MODULES(snp_enable_rmpopt, "ccp"); +EXPORT_SYMBOL_FOR_MODULES(snp_enable_rmpopt, "ccp,kvm-amd"); /* * Do the necessary preparations which are verified by the firmware as -- 2.43.0