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


Reply via email to