On Tue, Jun 02, 2026 at 12:42:13PM +0530, Naveen N Rao (AMD) wrote:
> KVM commit 66155de93bcf ("KVM: x86: Disallow read-only memslots for
> SEV-ES and SEV-SNP (and TDX)"), and the subsequent commit d30d9ee94cc0
> ("KVM: x86: Only advertise KVM_CAP_READONLY_MEM when supported by VM")
> stopped advertising KVM_CAP_READONLY_MEM support for encrypted guests
> (KVM_X86_SEV_ES_VM and KVM_X86_SNP_VM), but not for KVM_X86_DEFAULT_VM
> type SEV-ES guests. As a result of this, it is no longer possible to
> start SEV-ES guests with any SEV feature enabled (in particular,
> debug-swap) with pflash devices.
>
> This is an issue since SEV-ES guests have historically used pflash
> devices for OVMF. Guests on older KVM+Qemu are able to enable debug-swap
> while using pflash devices, so work around the KVM limitation by
> switching to using a VMA-based write protection. This allows
> well-behaved SEV-ES guests to continue to work with pflash devices and
> enable debug-swap. Mis-behaving guests trying to write to the protected
> OVMF area will be killed.
>
> Enable VMA protection and set the memory to be RO when adding the KVM
> memory slot. Because pflash devices support command-mode, change VMA
> protection to RW when tearing down the KVM memory slot. KVM
> SEV_LAUNCH_UPDATE also requires memory to be RW, so disable the
> protection when calling that.
>
> Print a warning when switching to VMA-based protection so that it is
> clear that KVM itself isn't supporting readonly memory, and that a
> workaround is in place. Users can plan on switching to using '-bios'.
>
> Finally, drop the check rejecting SEV-ES guests with SEV features so
> that debug-swap can be enabled.
>
>
> Signed-off-by: Naveen N Rao (AMD) <[email protected]>
> ---
> Background discussion on this issue:
> http://lore.kernel.org/r/[email protected]
>
> This series depends on VMSA features support:
> http://lore.kernel.org/r/[email protected]
>
...
> @@ -2024,6 +2018,15 @@ static int
> sev_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
> return -1;
> }
>
> + /*
> + * Use VMA-based protection for SEV-ES guests that enable any
> + * SEV feature, since KVM does not advertise readonly memory
> + * support for non-default type SEV guests.
> + */
> + if (sev_es_enabled() && SEV_COMMON(cgs)->sev_features) {
> + kvm_enable_ro_mem_vma_protection();
> + }
> +
Manali reported that -bios no longer works due to this change. That's
because we enable protection for all SEV-ES guests here. A simple fix is
to move this to where we throw the warning for pflash today (diff
below).
It looks like we will need an additional change for kernel-hashes since
that also calls into sev_encrypt_flash(), so we need to move calls to
mprotect to the OVMF caller. The diff below also addresses that.
I will wait for some feedback on this patch/approach before posting the
next version.
- Naveen
---
hw/i386/pc_sysfw.c | 1 +
hw/i386/pc_sysfw_ovmf.c | 8 ++++++++
target/i386/sev.c | 15 ---------------
3 files changed, 9 insertions(+), 15 deletions(-)
diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c
index 9590458e00c5..41da3685b98f 100644
--- a/hw/i386/pc_sysfw.c
+++ b/hw/i386/pc_sysfw.c
@@ -257,6 +257,7 @@ void pc_system_firmware_init(PCMachineState *pcms,
if (sev_es_enabled() && !sev_snp_enabled()) {
warn_report("pflash not supported with SEV-ES guests, "
"attempting VMA based protection");
+ kvm_enable_ro_mem_vma_protection();
} else {
/*
* Older KVM cannot execute from device memory. So, flash
diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c
index 2f7d15c9f3eb..d7a2e36aa736 100644
--- a/hw/i386/pc_sysfw_ovmf.c
+++ b/hw/i386/pc_sysfw_ovmf.c
@@ -30,6 +30,7 @@
#include "cpu.h"
#include "target/i386/sev.h"
#include "kvm/tdx.h"
+#include "system/kvm.h"
#define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d"
@@ -184,7 +185,14 @@ void x86_firmware_configure(hwaddr gpa, void *ptr, int
size)
exit(1);
}
+ /*
+ * KVM requires these pages to be RW for SEV_LAUNCH_UPDATE_DATA,
+ * so remove VMA RO protection if any, for the duration of
+ * sev_encrypt_flash().
+ */
+ kvm_set_memory_readwrite(ptr, size);
sev_encrypt_flash(gpa, ptr, size, &error_fatal);
+ kvm_set_memory_readonly(ptr, size);
} else if (is_tdx_vm()) {
ret = tdx_parse_tdvf(ptr, size);
if (ret) {
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0876e7c1fa1e..dc8851a12927 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -2018,15 +2018,6 @@ static int sev_kvm_init(ConfidentialGuestSupport *cgs,
Error **errp)
return -1;
}
- /*
- * Use VMA-based protection for SEV-ES guests that enable any
- * SEV feature, since KVM does not advertise readonly memory
- * support for non-default type SEV guests.
- */
- if (sev_es_enabled() && SEV_COMMON(cgs)->sev_features) {
- kvm_enable_ro_mem_vma_protection();
- }
-
if (!cgs->ready) {
/*
* SEV uses these notifiers to register/pin pages prior to guest use,
@@ -2114,13 +2105,7 @@ sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t
len, Error **errp)
if (sev_check_state(sev_common, SEV_STATE_LAUNCH_UPDATE)) {
int ret;
- /*
- * KVM requires these pages to be RW, so remove VMA RO protection
- * for the duration of SEV_LAUNCH_UPDATE if using SEV features.
- */
- kvm_set_memory_readwrite(ptr, len);
ret = klass->launch_update_data(sev_common, gpa, ptr, len, errp);
- kvm_set_memory_readonly(ptr, len);
if (ret < 0) {
return ret;
}
--