Skip to contentSkip to conversation

x86/sev: Fix RMPOPT enablement on non-RMPOPT configs

PATCH In review Ashish Kalra 6 participants 25 messages Oct 28 – Nov 4

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

v4 cover x86/sev: Fix RMPOPT enablement on non-RMPOPT configs

From: Ashish Kalra <[email protected]>

Two fixes for the RMPOPT series, both for configurations where the RMPOPT CPUID bit is advertised but RMPOPT is not actually usable:

Patch 1 clears X86_FEATURE_RMPOPT when the platform advertises segmented RMP but the firmware has it disabled (contiguous RMP) - otherwise RMPOPT_BASE is programmed and RMPOPT issued, which #GP on a contiguous RMP.

Patch 2 sets up RMPOPT only on an active SNP host by moving the soft-init (workqueue setup and the "optimizations enabled" message) into snp_rmptable_init(), so it no longer runs on systems where SNP is not enabled (e.g. disabled in the BIOS).

v4:
- Patch 1: drop the inline comment on the common fall-through clear (the rationale is in the commit message), and reword the commit message so RMPOPT_BASE programming is no longer attributed to the "RMPOPT initcall". No functional change; Tom's Reviewed-by retained.
- Patch 2: instead of gating rmpopt_init() on CC_ATTR_HOST_SEV_SNP, move the RMPOPT soft-init into snp_rmptable_init(), which runs only once the host RMP table is established (CC_ATTR_HOST_SEV_SNP guaranteed). rmpopt_init() keeps its X86_FEATURE_RMPOPT-only gate and drops the device_initcall.

v3:
- Patch 2: gate rmpopt_init() on cc_platform_has(CC_ATTR_HOST_SEV_SNP) instead of the X86_FEATURE_SEV_SNP CPUID bit. SNP can be disabled after feature detection (e.g. when AMD IOMMU init fails to enable it), which clears CC_ATTR_HOST_SEV_SNP but leaves the CPUID bit set; CC_ATTR_HOST_SEV_SNP reflects the final host state and matches the gate in snp_enable_rmpopt().

v2:
- Patch 1: expand the commit message to spell out the CPUID-advertise vs firmware-enable distinction and how the configuration arises; drop the trailing sentence; add Tom's Reviewed-by.
- Patch 2: rather than moving the announcement to snp_enable_rmpopt(), gate rmpopt_init() on an SNP host and keep the message there (Tom).

Ashish Kalra (2):
x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware x86/sev: Set up RMPOPT only on an active SNP host

 arch/x86/virt/svm/sev.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

base-commit: 250ee734115bca1c1f7a38d838909aa83cce87ae

Signature · 1 line
2.43.0
#1 lore raw

PATCH v4 1/2 x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

From: Ashish Kalra <[email protected]>

Segmented RMP has two independent states: the CPU *advertises* support via the X86_FEATURE_SEGMENTED_RMP CPUID bit, and the firmware *enables* it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. A platform can advertise segmented RMP (CPUID bit set) while the firmware leaves it disabled (SEG_RMP_ENABLED clear) -- e.g. through a BIOS option to disable Segmented RMP -- in which case the system runs with a contiguous RMP.

snp_probe_rmptable_info() clears X86_FEATURE_RMPOPT only when the CPU does not advertise segmented RMP, or when the segmented RMP table probe fails. It misses the advertised-but-firmware-disabled case: that path falls through to the contiguous probe with X86_FEATURE_RMPOPT still set.

X86_FEATURE_RMPOPT is a CPUID bit advertised independently of whether segmented RMP is enabled, but RMPOPT requires an enabled segmented RMP. With the capability left set, RMPOPT_BASE is programmed and the RMPOPT instruction issued, both of which #GP on a contiguous RMP:

unchecked MSR access error: WRMSR to 0xc0010139 ...

  general protection fault ... snp_enable_rmpopt

Clear X86_FEATURE_RMPOPT on the common contiguous fall-through so it covers both "segmented RMP not supported" and "segmented RMP supported but disabled by firmware".

Fixes 15d974be0a3b ("x86/sev: Initialize RMPOPT configuration MSRs")
---
 arch/x86/virt/svm/sev.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/virt/svm/sev.c +2 -2
index bd70c4d0b774..cd0412b9d251 100644
@@ -827,10 +827,10 @@ bool snp_probe_rmptable_info(void)
 			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 			return false;
 		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 	}
 
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+
 	return probe_contiguous_rmptable_info();
 }
 
Signature · 1 line
2.43.0
Reviewed-by Tested-by on v4 1/2
#2 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 22 lines

From: Ashish Kalra <[email protected]>

Segmented RMP has two independent states: the CPU *advertises* support via the X86_FEATURE_SEGMENTED_RMP CPUID bit, and the firmware *enables* it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. A platform can advertise segmented RMP (CPUID bit set) while the firmware leaves it disabled (SEG_RMP_ENABLED clear) -- e.g. through a BIOS option to disable Segmented RMP -- in which case the system runs with a contiguous RMP.

snp_probe_rmptable_info() clears X86_FEATURE_RMPOPT only when the CPU does not advertise segmented RMP, or when the segmented RMP table probe fails. It misses the advertised-but-firmware-disabled case: that path falls through to the contiguous probe with X86_FEATURE_RMPOPT still set.

X86_FEATURE_RMPOPT is a CPUID bit advertised independently of whether segmented RMP is enabled, but RMPOPT requires an enabled segmented RMP. With the capability left set, RMPOPT_BASE is programmed and the RMPOPT instruction issued, both of which #GP on a contiguous RMP:

unchecked MSR access error: WRMSR to 0xc0010139 ...

  general protection fault ... snp_enable_rmpopt
Quoted 7 lines

Clear X86_FEATURE_RMPOPT on the common contiguous fall-through so it covers both "segmented RMP not supported" and "segmented RMP supported but disabled by firmware".

Fixes 15d974be0a3b ("x86/sev: Initialize RMPOPT configuration MSRs")
Quoted 25 lines
---
 arch/x86/virt/svm/sev.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/virt/svm/sev.c +2 -3
index bd70c4d0b774..cd0412b9d251 100644
@@ -827,10 +827,10 @@ bool snp_probe_rmptable_info(void)
                        setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
                        return false;
                }
-       } else {
-               setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
        }
 
+       setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+
        return probe_contiguous_rmptable_info();
 }
 
--

2.43.0

maintainer
#3 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

In reply to Ashish Kalra

Ok,

pls check if this works too:

From: Ashish Kalra <[email protected]>
Date: Wed, 28 Oct 2026 19:49:22 +0000
Subject: [PATCH] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Segmented RMP support is advertised via X86_FEATURE_SEGMENTED_RMP, and the firmware enables it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. The latter can be cleared in platform BIOS by the user, in which case the system runs in contiguous RMP setting.

snp_probe_rmptable_info() does not clear X86_FEATURE_RMPOPT in the advertised-but-firmware-disabled case.

As a result, this does not prevent snp_enable_rmpopt() from trying to program MSR_AMD64_RMPOPT_BASE, which raises a #GP on the MSR access.

Make sure X86_FEATURE_RMPOPT is cleared in all cases where segmented RMP is not enabled.

[ bp:
- Put the commit message on Ozempic
- Flip the logic in the function so that the segmented RMP disabled case goes first and the flow gets simpler this way. ]

---
 arch/x86/virt/svm/sev.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)
arch/x86/virt/svm/sev.c +10 -11
index bd70c4d0b774..ff6d17795054 100644
@@ -817,21 +817,20 @@ static bool probe_segmented_rmptable_info(void)
 
 bool snp_probe_rmptable_info(void)
 {
-	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
-		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
+		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
+		return probe_contiguous_rmptable_info();
+	}
 
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+	rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
+		if (probe_segmented_rmptable_info())
+			return true;
 	}
 
-	return probe_contiguous_rmptable_info();
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+	return false;
 }
 
 /*
Signature · 7 lines
2.53.0

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Reviewed-by
#4 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Hello Boris,

Quoted 4 lines · Borislav Petkov

Segmented RMP support is advertised via X86_FEATURE_SEGMENTED_RMP, and the firmware enables it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. The latter can be cleared in platform BIOS by the user, in which case the system runs in contiguous RMP setting.

nit. In the latter case, SNP is disabled entirely in bsp_determine_snp and the system won't continue with contiguous RMP.

Quoted 14 lines

snp_probe_rmptable_info() does not clear X86_FEATURE_RMPOPT in the advertised-but-firmware-disabled case.

As a result, this does not prevent snp_enable_rmpopt() from trying to program MSR_AMD64_RMPOPT_BASE, which raises a #GP on the MSR access.

Make sure X86_FEATURE_RMPOPT is cleared in all cases where segmented RMP is not enabled.

[ bp:
- Put the commit message on Ozempic
- Flip the logic in the function so that the segmented RMP disabled case goes first and the flow gets simpler this way. ]

Quoted 4 lines

Feel free to include:

Quoted 40 lines
---
 arch/x86/virt/svm/sev.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)
arch/x86/virt/svm/sev.c +10 -11
index bd70c4d0b774..ff6d17795054 100644
@@ -817,21 +817,20 @@ static bool probe_segmented_rmptable_info(void)
 
 bool snp_probe_rmptable_info(void)
 {
-	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
-		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
+		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
+		return probe_contiguous_rmptable_info();
+	}
 
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+	rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
+		if (probe_segmented_rmptable_info())
+			return true;
 	}
 
-	return probe_contiguous_rmptable_info();
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+	return false;
 }
 
 /*
Signature · 2 lines
Thanks and Regards,
Prateek
maintainer
#5 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 8 lines · K Prateek Nayak
Quoted 4 lines · Borislav Petkov

Segmented RMP support is advertised via X86_FEATURE_SEGMENTED_RMP, and the firmware enables it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. The latter can be cleared in platform BIOS by the user, in which case the system runs in contiguous RMP setting.

nit. In the latter case, SNP is disabled entirely in bsp_determine_snp and the system won't continue with contiguous RMP.

Ah, true, good catch.

Thx.

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
#6 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

In reply to K Prateek Nayak
Quoted 10 lines · K Prateek Nayak

Hello Boris,

Quoted 4 lines · Borislav Petkov

Segmented RMP support is advertised via X86_FEATURE_SEGMENTED_RMP, and the firmware enables it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. The latter can be cleared in platform BIOS by the user, in which case the system runs in contiguous RMP setting.

nit. In the latter case, SNP is disabled entirely in bsp_determine_snp and the system won't continue with contiguous RMP.

Heh, I don't think that is a nit, it is broken.

I think the code as it was read fine, but that's just my opinion.

Thanks,
Tom

Quoted 65 lines
Quoted 15 lines

snp_probe_rmptable_info() does not clear X86_FEATURE_RMPOPT in the advertised-but-firmware-disabled case.

As a result, this does not prevent snp_enable_rmpopt() from trying to program MSR_AMD64_RMPOPT_BASE, which raises a #GP on the MSR access.

Make sure X86_FEATURE_RMPOPT is cleared in all cases where segmented RMP is not enabled.

[ bp:
- Put the commit message on Ozempic
- Flip the logic in the function so that the segmented RMP disabled case goes first and the flow gets simpler this way. ]

Quoted 4 lines

Feel free to include:

Quoted 40 lines
---
 arch/x86/virt/svm/sev.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)
arch/x86/virt/svm/sev.c +10 -11
index bd70c4d0b774..ff6d17795054 100644
@@ -817,21 +817,20 @@ static bool probe_segmented_rmptable_info(void)
 
 bool snp_probe_rmptable_info(void)
 {
-	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
-		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
+		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
+		return probe_contiguous_rmptable_info();
+	}
 
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+	rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
+		if (probe_segmented_rmptable_info())
+			return true;
 	}
 
-	return probe_contiguous_rmptable_info();
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+	return false;
 }
 
 /*
maintainer
#7 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 3 lines · Tom Lendacky

Heh, I don't think that is a nit, it is broken.

I think the code as it was read fine, but that's just my opinion.

Lemme see if you like this more (pasting it in applied form because the diff is unreadable):

bool snp_probe_rmptable_info(void)

{
        if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
                goto out;
        
        rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
        if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
                if (probe_segmented_rmptable_info())
                        return true;
        }       

out:

        setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
        return probe_contiguous_rmptable_info();
}

No repeated code, no if-else conditionals, just what needs to happen.

Thx.

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
#8 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Hello Boris,

Quoted 19 lines · Borislav Petkov
Quoted 3 lines · Tom Lendacky

Heh, I don't think that is a nit, it is broken.

I think the code as it was read fine, but that's just my opinion.

Lemme see if you like this more (pasting it in applied form because the diff is unreadable):

bool snp_probe_rmptable_info(void)

{
        if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
                goto out;
        
        rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
        if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
                if (probe_segmented_rmptable_info())
                        return true;
        }       
Quoted 6 lines

out:

        setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
        return probe_contiguous_rmptable_info();
}

No repeated code, no if-else conditionals, just what needs to happen.

The original patch returns false if segmented RMP is enabled but probe_segmented_rmptable_info() fails, your version falls through to probe_contiguous_rmptable_info() instead.

I believe it makes sense to keep the return false there: on a segmented RMP enabled platform the RMP is segmented, not contiguous, so the contiguous probe shouldn't run.

That's why i think the original patch looks fine to me.

Thanks,
Ashish

Quoted 3 lines

Thx.

maintainer
#9 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 7 lines · Ashish

The original patch returns false if segmented RMP is enabled but probe_segmented_rmptable_info() fails, your version falls through to probe_contiguous_rmptable_info() instead.

I believe it makes sense to keep the return false there: on a segmented RMP enabled platform the RMP is segmented, not contiguous, so the contiguous probe shouldn't run.

That simplifies the code even more:

bool snp_probe_rmptable_info(void)

{
        if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
                goto out;

        rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
        if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
                return probe_segmented_rmptable_info();

out:

        setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
        return probe_contiguous_rmptable_info();
}

Along with the below, which should have happened too:

1. RMPOPT depends on SEV_SNP, ofc. This would make sure RMPOPT is cleared everytime SNP is cleared, as it should be.

2. snp_enable_rmpopt() needs to check SNP first, ofc, and then RMPOPT.

arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +2 -2
index ff6d17795054..a47b812b2ea3 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)

---

here's the full diff. Have a look pls and let me know what else I am missing:

---

arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +9 -14
index bd70c4d0b774..a47b812b2ea3 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
@@ -817,20 +817,15 @@ static bool probe_segmented_rmptable_info(void)
 
 bool snp_probe_rmptable_info(void)
 {
-	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
-		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
-
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
+	if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
+		goto out;
 
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-	}
+	rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
+		return probe_segmented_rmptable_info();
 
+out:
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 	return probe_contiguous_rmptable_info();
 }
 

---

Thx.

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
#10 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 21 lines · Borislav Petkov
Quoted 7 lines · Ashish

The original patch returns false if segmented RMP is enabled but probe_segmented_rmptable_info() fails, your version falls through to probe_contiguous_rmptable_info() instead.

I believe it makes sense to keep the return false there: on a segmented RMP enabled platform the RMP is segmented, not contiguous, so the contiguous probe shouldn't run.

That simplifies the code even more:

bool snp_probe_rmptable_info(void)

{
        if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
                goto out;

        rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
        if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
                return probe_segmented_rmptable_info();

out:

Quoted 9 lines
        setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
        return probe_contiguous_rmptable_info();
}

Along with the below, which should have happened too:

1. RMPOPT depends on SEV_SNP, ofc. This would make sure RMPOPT is cleared everytime SNP is cleared, as it should be.

Yes, that is a good point, but do note that the cpuid-dep only fires when the SEV_SNP CPUID bit is cleared though, and the IOMMU "can't enable SNP" path clears only CC_ATTR_HOST_SEV_SNP, not the CPUID bit.

Quoted 1 line

2. snp_enable_rmpopt() needs to check SNP first, ofc, and then RMPOPT.

Yes.

Quoted 85 lines
arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +2 -3
index ff6d17795054..a47b812b2ea3 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
 
---

here's the full diff. Have a look pls and let me know what else I am missing:

---

arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +4 -14
index bd70c4d0b774..a47b812b2ea3 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
@@ -817,20 +817,15 @@ static bool probe_segmented_rmptable_info(void)
 
 bool snp_probe_rmptable_info(void)
 {
-	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
-		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
-
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
+	if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
+		goto out;
 
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-	}

arch/x86/virt/svm/sev.c static bool probe_segmented_rmptable_info(void)

Quoted 10 lines
arch/x86/virt/svm/sev.c +5 -1
+	rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
+		return probe_segmented_rmptable_info();
 
+out:
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 	return probe_contiguous_rmptable_info();
 }
 
---

Looks good, the simplification is nice. Two things worth noting:

1). With the leaner snp_probe_rmptable_info(), a probe_segmented_rmptable_info() failure no longer clears RMPOPT inline — it now relies on the new {RMPOPT, SEV_SNP} dep: the false return (from probe_segmented_rmptable_info()) makes bsp_determine_snp() clear SEV_SNP, which clears RMPOPT.

2). As i mentioned above, the cpuid-dep only fires when the SEV_SNP CPUID bit is cleared though, and the IOMMU "can't enable SNP" path clears only CC_ATTR_HOST_SEV_SNP, not the CPUID bit. So we still need the rmpopt_init() (in patch 2 of this series) move into snp_rmptable_init() to avoid announcing RMPOPT / allocating the workqueue on a host where the IOMMU turned SNP off — this dep doesn't cover that case.

Rest looks right.

Thanks,
Ashish

Quoted 3 lines

Thx.

maintainer
#11 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 3 lines · Ashish

As i mentioned above, the cpuid-dep only fires when the SEV_SNP CPUID bit is cleared though, and the IOMMU "can't enable SNP" path clears only CC_ATTR_HOST_SEV_SNP, not the CPUID bit.

I believe the IOMMU path is too late in the boot for the CPUID bit anyway.

Quoted 3 lines

So we still need the rmpopt_init() (in patch 2 of this series) move into snp_rmptable_init() to avoid announcing RMPOPT / allocating the workqueue on a host where the IOMMU turned SNP off — this dep doesn't cover that case.

Sure.

Lemme put everything into a proper patch now.

Thx.

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
#12 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

In reply to Borislav Petkov
Quoted 20 lines · Borislav Petkov
Quoted 7 lines · Ashish

The original patch returns false if segmented RMP is enabled but probe_segmented_rmptable_info() fails, your version falls through to probe_contiguous_rmptable_info() instead.

I believe it makes sense to keep the return false there: on a segmented RMP enabled platform the RMP is segmented, not contiguous, so the contiguous probe shouldn't run.

That simplifies the code even more:

bool snp_probe_rmptable_info(void)

{
        if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
                goto out;

        rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
        if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
                return probe_segmented_rmptable_info();
Quoted 3 lines

out:

        setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
        return probe_contiguous_rmptable_info();

The current code clears X86_FEATURE_RMPOPT when probe_segmented_rmptable_info() fails. The above code doesn't. But since SNP will be disabled on failure of snp_probe_rmptable_info(), I guess it doesn't matter. In which case you can eliminate the goto by doing:

	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();
	}

	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
	return probe_contiguous_rmptable_info();

Which looks pretty clean.

Thanks,
Tom

		> }
Quoted 105 lines

Along with the below, which should have happened too:

1. RMPOPT depends on SEV_SNP, ofc. This would make sure RMPOPT is cleared everytime SNP is cleared, as it should be.

2. snp_enable_rmpopt() needs to check SNP first, ofc, and then RMPOPT.

arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +2 -3
index ff6d17795054..a47b812b2ea3 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
 
---

here's the full diff. Have a look pls and let me know what else I am missing:

---

arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +9 -15
index bd70c4d0b774..a47b812b2ea3 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
@@ -817,20 +817,15 @@ static bool probe_segmented_rmptable_info(void)
 
 bool snp_probe_rmptable_info(void)
 {
-	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
-		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
-
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
+	if (!cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP))
+		goto out;
 
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-	}
+	rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
+	if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
+		return probe_segmented_rmptable_info();
 
+out:
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 	return probe_contiguous_rmptable_info();
 }
 
---

Thx.

maintainer
#13 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 2 lines · Tom Lendacky

The current code clears X86_FEATURE_RMPOPT when probe_segmented_rmptable_info() fails. The above code doesn't.

See the hunk in cpuid-deps.c

Quoted 14 lines

But since SNP will be disabled on failure of snp_probe_rmptable_info(), I guess it doesn't matter. In which case you can eliminate the goto by doing:

	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();
	}

	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
	return probe_contiguous_rmptable_info();
Quoted 1 line

Which looks pretty clean.

Yap.

Quoted 9 lines

arch/x86/kernel/cpu/cpuid-deps.c static const struct cpuid_dep cpuid_deps[] = { · line 96

Quoted 9 lines
arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },

This hunk.

Signature · 4 lines
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
#14 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 17 lines · Borislav Petkov
Quoted 2 lines · Tom Lendacky

The current code clears X86_FEATURE_RMPOPT when probe_segmented_rmptable_info() fails. The above code doesn't.

See the hunk in cpuid-deps.c

Quoted 11 lines

But since SNP will be disabled on failure of snp_probe_rmptable_info(), I guess it doesn't matter. In which case you can eliminate the goto by doing:

	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();
	}
Quoted 6 lines
Quoted 4 lines
	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
	return probe_contiguous_rmptable_info();

Which looks pretty clean.

Yap.

LGTM, tested on HW.

Thanks,
Ashish

Quoted 13 lines
Quoted 10 lines

arch/x86/kernel/cpu/cpuid-deps.c static const struct cpuid_dep cpuid_deps[] = { · line 96

Quoted 10 lines
arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },

This hunk.

maintainer
#15 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 1 line · Ashish

LGTM, tested on HW.

Ok, thanks.

This below is what I have now, and the code looks a lot better. If there are no more complaints and it looks like what you tested, you can wait for me to push out the two patches and then you can test tip:x86/urgent again.

Thx.

---
From: Ashish Kalra <[email protected]>
Date: Wed, 28 Oct 2026 19:49:22 +0000
Subject: [PATCH] x86/sev: Clear RMPOPT when segmented RMP is disabled by
firmware

Segmented RMP support is advertised via X86_FEATURE_SEGMENTED_RMP, and the firmware enables it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. The latter can be cleared in platform BIOS by the user, in which case the system runs in contiguous RMP setting.

snp_probe_rmptable_info() does not clear X86_FEATURE_RMPOPT in the advertised-but-firmware-disabled case.

As a result, this does not prevent snp_enable_rmpopt() from trying to program MSR_AMD64_RMPOPT_BASE, which raises a #GP on the MSR access.

Make sure X86_FEATURE_RMPOPT is cleared in all cases where segmented RMP is not enabled.

[ bp:
- Put the commit message on Ozempic
- Simplify snp_probe_rmptable_info()
- Fix feature check order in snp_enable_rmpopt()
- Add RMPOPT feature dependency on SEV_SNP ]

---
 arch/x86/kernel/cpu/cpuid-deps.c |  1 +
 arch/x86/virt/svm/sev.c          | 17 +++++------------
 2 files changed, 6 insertions(+), 12 deletions(-)
arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +5 -12
index bd70c4d0b774..417e6a41ac60 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
@@ -819,18 +819,11 @@ bool snp_probe_rmptable_info(void)
 {
 	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
 		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
-
-		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);
+		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
+			return probe_segmented_rmptable_info();
 	}
 
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 	return probe_contiguous_rmptable_info();
 }
 
Signature · 7 lines
2.53.0

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
#16 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

arch/x86/virt/svm/sev.c void snp_enable_rmpopt(void) · line 673

Quoted 11 lines · Borislav Petkov
arch/x86/virt/svm/sev.c +1 -1
index bd70c4d0b774..417e6a41ac60 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;

nit. We should check CC_ATTR_HOST_SEV_SNP in rmpopt_init() too now to prevent an unnecessary workqueue allocation if probe_segmented_rmptable_info() failed early.

Since it doesn't change anything functionally, maybe Ashish can do it as a part of his mutil-node optimization series.

Quoted 6 lines
arch/x86/virt/svm/sev.c +1 -1
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
Signature · 2 lines
Thanks and Regards,
Prateek
#17 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 9 lines · K Prateek Nayak
Quoted 8 lines · Borislav Petkov
arch/x86/virt/svm/sev.c +0 -0
index bd70c4d0b774..417e6a41ac60 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
Quoted 7 lines

arch/x86/virt/svm/sev.c void snp_enable_rmpopt(void) · line 673

Quoted 3 lines
arch/x86/virt/svm/sev.c +1 -1
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;

nit. We should check CC_ATTR_HOST_SEV_SNP in rmpopt_init() too now to prevent an unnecessary workqueue allocation if probe_segmented_rmptable_info() failed early.

As rmpopt_init() is now called from snp_rmptable_init() (in patch 2/2), and there is already a CC_ATTR_HOST_SEV_SNP check in snp_rmptable_init(), there should be no need to check this in rmpopt_init().

Thanks,
Ashish

Quoted 11 lines

Since it doesn't change anything functionally, maybe Ashish can do it as a part of his mutil-node optimization series.

Quoted 6 lines
arch/x86/virt/svm/sev.c +1 -1
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
#18 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Hello Ashish,

Quoted 18 lines · Ashish
Quoted 9 lines · K Prateek Nayak
Quoted 8 lines · Borislav Petkov
arch/x86/virt/svm/sev.c +0 -0
index bd70c4d0b774..417e6a41ac60 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
Quoted 7 lines

arch/x86/virt/svm/sev.c void snp_enable_rmpopt(void) · line 673

Quoted 3 lines
arch/x86/virt/svm/sev.c +1 -1
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;

nit. We should check CC_ATTR_HOST_SEV_SNP in rmpopt_init() too now to prevent an unnecessary workqueue allocation if probe_segmented_rmptable_info() failed early.

Quoted 3 lines

As rmpopt_init() is now called from snp_rmptable_init() (in patch 2/2), and there is already a CC_ATTR_HOST_SEV_SNP check in snp_rmptable_init(), there should be no need to check this in rmpopt_init().

True that! I forgot the second patch existed (facepalm). Sorry for the noise.

Signature · 2 lines
Thanks and Regards,
Prateek
#19 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

In reply to Borislav Petkov
Quoted 87 lines · Borislav Petkov
Quoted 1 line · Ashish

LGTM, tested on HW.

Ok, thanks.

This below is what I have now, and the code looks a lot better. If there are no more complaints and it looks like what you tested, you can wait for me to push out the two patches and then you can test tip:x86/urgent again.

Thx.

---
From: Ashish Kalra <[email protected]>
Date: Wed, 28 Oct 2026 19:49:22 +0000
Subject: [PATCH] x86/sev: Clear RMPOPT when segmented RMP is disabled by
firmware

Segmented RMP support is advertised via X86_FEATURE_SEGMENTED_RMP, and the firmware enables it via MSR_AMD64_RMP_CFG[SEG_RMP_ENABLED]. The latter can be cleared in platform BIOS by the user, in which case the system runs in contiguous RMP setting.

snp_probe_rmptable_info() does not clear X86_FEATURE_RMPOPT in the advertised-but-firmware-disabled case.

As a result, this does not prevent snp_enable_rmpopt() from trying to program MSR_AMD64_RMPOPT_BASE, which raises a #GP on the MSR access.

Make sure X86_FEATURE_RMPOPT is cleared in all cases where segmented RMP is not enabled.

[ bp:
- Put the commit message on Ozempic
- Simplify snp_probe_rmptable_info()
- Fix feature check order in snp_enable_rmpopt()
- Add RMPOPT feature dependency on SEV_SNP ]

---
 arch/x86/kernel/cpu/cpuid-deps.c |  1 +
 arch/x86/virt/svm/sev.c          | 17 +++++------------
 2 files changed, 6 insertions(+), 12 deletions(-)
arch/x86/kernel/cpu/cpuid-deps.c +1 -0
index 99801e844b30..acbcec394ef1 100644
@@ -93,6 +93,7 @@ static const struct cpuid_dep cpuid_deps[] = {
 	{ X86_FEATURE_SPEC_CTRL_SSBD,		X86_FEATURE_SPEC_CTRL },
 	{ X86_FEATURE_LASS,			X86_FEATURE_SMAP      },
 	{ X86_FEATURE_INVLPGB,			X86_FEATURE_PCID      },
+	{ X86_FEATURE_RMPOPT,			X86_FEATURE_SEV_SNP   },
 	{}
 };
 
arch/x86/virt/svm/sev.c +2 -10
index bd70c4d0b774..417e6a41ac60 100644
@@ -669,10 +669,10 @@ void snp_enable_rmpopt(void)
 	u64 base;
 	int cpu;
 
-	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
+	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
 		return;
 
-	if (!cc_platform_has(CC_ATTR_HOST_SEV_SNP))
+	if (!cpu_feature_enabled(X86_FEATURE_RMPOPT))
 		return;
 
 	if (!rmpopt_soft_init)
@@ -819,18 +819,11 @@ bool snp_probe_rmptable_info(void)
 {
 	if (cpu_feature_enabled(X86_FEATURE_SEGMENTED_RMP)) {
 		rdmsrq(MSR_AMD64_RMP_CFG, rmp_cfg);
-
-		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED) {
-			if (probe_segmented_rmptable_info())
-				return true;
-
-			setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
-			return false;
-		}

arch/x86/virt/svm/sev.c bool snp_probe_rmptable_info(void) · line 829

Quoted 10 lines
arch/x86/virt/svm/sev.c +3 -2
-	} else {
-		setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
+		if (rmp_cfg & MSR_AMD64_SEG_RMP_ENABLED)
+			return probe_segmented_rmptable_info();
 	}
 
+	setup_clear_cpu_cap(X86_FEATURE_RMPOPT);
 	return probe_contiguous_rmptable_info();
 }
 

LGTM.

I'll wait for you to push to tip:x86/urgent and re-test there.

Thanks,
Ashish

author Tested-by
#21 lore raw

Re: [PATCH v4 1/2] x86/sev: Clear RMPOPT when segmented RMP is disabled by firmware

Quoted 9 lines · Borislav Petkov
Quoted 1 line · Ashish

I'll wait for you to push to tip:x86/urgent and re-test there.

With patch 2 ontop:

https://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git/log/?h=rc1%2brmp

Thx.

Both patches look good — the commit-log cleanups and the [ bp: ] changes are fine with me, no further comments.

Tested on an SNP host: segmented and contiguous RMP, SNP enabled and disabled, and an SNP guest boot — all work as expected.

Will re-confirm on tip:x86/urgent once it lands there.

Thanks,
Ashish

#22 lore raw

PATCH v4 2/2 x86/sev: Set up RMPOPT only on an active SNP host

In reply to Ashish Kalra

From: Ashish Kalra <[email protected]>

rmpopt_init() allocates the RMPOPT workqueue and prints "RMPOPT optimizations enabled", gated only on X86_FEATURE_RMPOPT - a CPUID bit advertised independently of whether SNP is active. As a device_initcall it runs on every system with that bit, so on a host where SNP is not enabled (disabled in the BIOS, or AMD IOMMU initialization fails to bring it up) the workqueue is allocated and the message is printed at boot even though RMPOPT is never used: snp_enable_rmpopt() bails out on a non-SNP host.

Rather than add an explicit SNP-host gate to the initcall, set RMPOPT up where the host SNP state is established. Call rmpopt_init() from the tail of snp_rmptable_init(), which runs only once the host RMP table has been set up and CC_ATTR_HOST_SEV_SNP is guaranteed (it WARN_ON_ONCE()s otherwise), and drop the device_initcall. rmpopt_init() keeps its original X86_FEATURE_RMPOPT-only gate and no longer needs a separate SNP-host check.

This is soft initialization only - the workqueue and the announcement; the actual RMPOPT_BASE programming is still done later by snp_enable_rmpopt(), which re-checks X86_FEATURE_RMPOPT, CC_ATTR_HOST_SEV_SNP and rmpopt_soft_init. An rmpopt_init() failure is non-fatal to SNP and is intentionally ignored by snp_rmptable_init().

Fixes c6c6f156d192 ("x86/sev: Perform RMP optimizations asynchronously")
---
 arch/x86/virt/svm/sev.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/virt/svm/sev.c +2 -1
index cd0412b9d251..39d3943cdc49 100644
@@ -662,7 +662,6 @@ static int __init rmpopt_init(void)
 
 	return 0;
 }
-device_initcall(rmpopt_init);
 
 void snp_enable_rmpopt(void)
 {
@@ -726,6 +725,8 @@ int __init snp_rmptable_init(void)
 	 */
 	crash_kexec_post_notifiers = true;
 
+	rmpopt_init();
+
 	return 0;
 }
 
Signature · 1 line
2.43.0
Reviewed-by on v4 2/2
#23 lore raw

Re: [PATCH v4 2/2] x86/sev: Set up RMPOPT only on an active SNP host

Quoted 26 lines

From: Ashish Kalra <[email protected]>

rmpopt_init() allocates the RMPOPT workqueue and prints "RMPOPT optimizations enabled", gated only on X86_FEATURE_RMPOPT - a CPUID bit advertised independently of whether SNP is active. As a device_initcall it runs on every system with that bit, so on a host where SNP is not enabled (disabled in the BIOS, or AMD IOMMU initialization fails to bring it up) the workqueue is allocated and the message is printed at boot even though RMPOPT is never used: snp_enable_rmpopt() bails out on a non-SNP host.

Rather than add an explicit SNP-host gate to the initcall, set RMPOPT up where the host SNP state is established. Call rmpopt_init() from the tail of snp_rmptable_init(), which runs only once the host RMP table has been set up and CC_ATTR_HOST_SEV_SNP is guaranteed (it WARN_ON_ONCE()s otherwise), and drop the device_initcall. rmpopt_init() keeps its original X86_FEATURE_RMPOPT-only gate and no longer needs a separate SNP-host check.

This is soft initialization only - the workqueue and the announcement; the actual RMPOPT_BASE programming is still done later by snp_enable_rmpopt(), which re-checks X86_FEATURE_RMPOPT, CC_ATTR_HOST_SEV_SNP and rmpopt_soft_init. An rmpopt_init() failure is non-fatal to SNP and is intentionally ignored by snp_rmptable_init().

Quoted 3 lines
Fixes c6c6f156d192 ("x86/sev: Perform RMP optimizations asynchronously")
Quoted 25 lines
---
  arch/x86/virt/svm/sev.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/virt/svm/sev.c +2 -1
index cd0412b9d251..39d3943cdc49 100644
@@ -662,7 +662,6 @@ static int __init rmpopt_init(void)
 
  	return 0;
  }
-device_initcall(rmpopt_init);
 
  void snp_enable_rmpopt(void)
  {
@@ -726,6 +725,8 @@ int __init snp_rmptable_init(void)
  	 */
  	crash_kexec_post_notifiers = true;
 
+	rmpopt_init();
+
  	return 0;
  }
 
Reviewed-by on v4 2/2
#24 lore raw

Re: [PATCH v4 2/2] x86/sev: Set up RMPOPT only on an active SNP host

In reply to Ashish Kalra
Quoted 25 lines · Ashish Kalra

From: Ashish Kalra <[email protected]>

rmpopt_init() allocates the RMPOPT workqueue and prints "RMPOPT optimizations enabled", gated only on X86_FEATURE_RMPOPT - a CPUID bit advertised independently of whether SNP is active. As a device_initcall it runs on every system with that bit, so on a host where SNP is not enabled (disabled in the BIOS, or AMD IOMMU initialization fails to bring it up) the workqueue is allocated and the message is printed at boot even though RMPOPT is never used: snp_enable_rmpopt() bails out on a non-SNP host.

Rather than add an explicit SNP-host gate to the initcall, set RMPOPT up where the host SNP state is established. Call rmpopt_init() from the tail of snp_rmptable_init(), which runs only once the host RMP table has been set up and CC_ATTR_HOST_SEV_SNP is guaranteed (it WARN_ON_ONCE()s otherwise), and drop the device_initcall. rmpopt_init() keeps its original X86_FEATURE_RMPOPT-only gate and no longer needs a separate SNP-host check.

This is soft initialization only - the workqueue and the announcement; the actual RMPOPT_BASE programming is still done later by snp_enable_rmpopt(), which re-checks X86_FEATURE_RMPOPT, CC_ATTR_HOST_SEV_SNP and rmpopt_soft_init. An rmpopt_init() failure is non-fatal to SNP and is intentionally ignored by snp_rmptable_init().

Quoted 3 lines
Fixes c6c6f156d192 ("x86/sev: Perform RMP optimizations asynchronously")
Quoted 25 lines
---
 arch/x86/virt/svm/sev.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/virt/svm/sev.c +2 -1
index cd0412b9d251..39d3943cdc49 100644
@@ -662,7 +662,6 @@ static int __init rmpopt_init(void)
 
 	return 0;
 }
-device_initcall(rmpopt_init);
 
 void snp_enable_rmpopt(void)
 {
@@ -726,6 +725,8 @@ int __init snp_rmptable_init(void)
 	 */
 	crash_kexec_post_notifiers = true;
 
+	rmpopt_init();
+
 	return 0;
 }