[PATCH 5/6] x86/sev: Use configfs to re-enable RMP optimizations.

From: Ashish Kalra

Date: Tue Feb 17 2026 - 15:13:35 EST


From: Ashish Kalra <ashish.kalra@xxxxxxx>

Use configfs as an interface to re-enable RMP optimizations at runtime

When SNP guests are launched, RMPUPDATE disables the corresponding
RMPOPT optimizations. Therefore, an interface is required to manually
re-enable RMP optimizations, as no mechanism currently exists to do so
during SNP guest cleanup.

Also select CONFIG_CONFIGFS_FS when host SEV or SNP support is enabled.

Suggested-by: Thomas Lendacky <thomas.lendacky@xxxxxxx>
Signed-off-by: Ashish Kalra <ashish.kalra@xxxxxxx>
---
arch/x86/kvm/Kconfig | 1 +
arch/x86/virt/svm/sev.c | 79 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+)

diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index d916bd766c94..8fb21893ec8c 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -164,6 +164,7 @@ config KVM_AMD_SEV
select HAVE_KVM_ARCH_GMEM_PREPARE
select HAVE_KVM_ARCH_GMEM_INVALIDATE
select HAVE_KVM_ARCH_GMEM_POPULATE
+ select CONFIGFS_FS
help
Provides support for launching encrypted VMs which use Secure
Encrypted Virtualization (SEV), Secure Encrypted Virtualization with
diff --git a/arch/x86/virt/svm/sev.c b/arch/x86/virt/svm/sev.c
index 713afcc2fab3..0f71a045e4aa 100644
--- a/arch/x86/virt/svm/sev.c
+++ b/arch/x86/virt/svm/sev.c
@@ -20,6 +20,7 @@
#include <linux/amd-iommu.h>
#include <linux/nospec.h>
#include <linux/kthread.h>
+#include <linux/configfs.h>

#include <asm/sev.h>
#include <asm/processor.h>
@@ -146,6 +147,10 @@ struct rmpopt_socket_config {
int current_node_idx;
};

+#define RMPOPT_CONFIGFS_NAME "rmpopt"
+
+static atomic_t rmpopt_in_progress = ATOMIC_INIT(0);
+
#undef pr_fmt
#define pr_fmt(fmt) "SEV-SNP: " fmt

@@ -581,6 +586,9 @@ static int rmpopt_kthread(void *__unused)
cond_resched();
}

+ /* Clear in_progress flag before going to sleep */
+ atomic_set(&rmpopt_in_progress, 0);
+
set_current_state(TASK_INTERRUPTIBLE);
schedule();
}
@@ -595,6 +603,75 @@ static void rmpopt_all_physmem(void)
wake_up_process(rmpopt_task);
}

+static ssize_t rmpopt_action_show(struct config_item *item, char *page)
+{
+ return sprintf(page, "RMP optimization in progress: %s\n",
+ atomic_read(&rmpopt_in_progress) == 1 ? "Yes" : "No");
+}
+
+static ssize_t rmpopt_action_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ int in_progress_flag, ret;
+ unsigned int action;
+
+ ret = kstrtouint(page, 10, &action);
+ if (ret)
+ return ret;
+
+ if (action == 1) {
+ /* perform RMP re-optimizations */
+ in_progress_flag = atomic_cmpxchg(&rmpopt_in_progress, 0, 1);
+ if (!in_progress_flag)
+ rmpopt_all_physmem();
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t rmpopt_description_show(struct config_item *item, char *page)
+{
+ return sprintf(page, "[RMPOPT]\n\necho 1 > action to perform RMP optimization.\n");
+}
+
+CONFIGFS_ATTR(rmpopt_, action);
+CONFIGFS_ATTR_RO(rmpopt_, description);
+
+static struct configfs_attribute *rmpopt_attrs[] = {
+ &rmpopt_attr_action,
+ &rmpopt_attr_description,
+ NULL,
+};
+
+static const struct config_item_type rmpopt_config_type = {
+ .ct_attrs = rmpopt_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem rmpopt_configfs = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = RMPOPT_CONFIGFS_NAME,
+ .ci_type = &rmpopt_config_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(rmpopt_configfs.su_mutex),
+};
+
+static int rmpopt_configfs_setup(void)
+{
+ int ret;
+
+ config_group_init(&rmpopt_configfs.su_group);
+ ret = configfs_register_subsystem(&rmpopt_configfs);
+ if (ret)
+ pr_err("Error %d while registering subsystem %s\n", ret, RMPOPT_CONFIGFS_NAME);
+
+ return ret;
+}
+
static void __configure_rmpopt(void *val)
{
u64 rmpopt_base = ((u64)val & PUD_MASK) | MSR_AMD64_RMPOPT_ENABLE;
@@ -770,6 +847,8 @@ static __init void configure_and_enable_rmpopt(void)
*/
rmpopt_all_physmem();

+ rmpopt_configfs_setup();
+
free_cpumask:
free_cpumask_var(primary_threads_cpulist);
}
--
2.43.0