[RFC PATCH v2 00/24] KVM: combined patchset for MBEC/GMET support

Paolo Bonzini posted 24 patches 6 days, 22 hours ago
Documentation/virt/kvm/x86/mmu.rst |  10 +-
arch/x86/include/asm/cpufeatures.h |   1 +
arch/x86/include/asm/kvm-x86-ops.h |   1 +
arch/x86/include/asm/kvm_host.h    |  45 +++++---
arch/x86/include/asm/svm.h         |   1 +
arch/x86/include/asm/vmx.h         |  14 ++-
arch/x86/kvm/mmu.h                 |  12 ++-
arch/x86/kvm/mmu/mmu.c             | 162 ++++++++++++++++++++---------
arch/x86/kvm/mmu/mmutrace.h        |  19 ++--
arch/x86/kvm/mmu/paging_tmpl.h     |  66 ++++++++----
arch/x86/kvm/mmu/spte.c            |  77 ++++++++------
arch/x86/kvm/mmu/spte.h            |  65 +++++++-----
arch/x86/kvm/mmu/tdp_mmu.c         |   6 +-
arch/x86/kvm/svm/nested.c          |  16 ++-
arch/x86/kvm/svm/svm.c             |  32 +++++-
arch/x86/kvm/svm/svm.h             |   1 +
arch/x86/kvm/vmx/capabilities.h    |  11 +-
arch/x86/kvm/vmx/common.h          |  20 ++--
arch/x86/kvm/vmx/hyperv_evmcs.h    |   1 +
arch/x86/kvm/vmx/main.c            |   9 ++
arch/x86/kvm/vmx/nested.c          |  25 ++++-
arch/x86/kvm/vmx/tdx.c             |   2 +-
arch/x86/kvm/vmx/vmx.c             |  29 +++++-
arch/x86/kvm/vmx/vmx.h             |   1 +
arch/x86/kvm/vmx/x86_ops.h         |   1 +
arch/x86/kvm/x86.c                 |   1 +
26 files changed, 437 insertions(+), 191 deletions(-)
[RFC PATCH v2 00/24] KVM: combined patchset for MBEC/GMET support
Posted by Paolo Bonzini 6 days, 22 hours ago
This series introduces support for two related features that Hyper-V uses
in its implementation of Virtual Secure Mode; these are Intel Mode-Based
Execute Control and AMD Guest Mode Execution Trap.

It's still RFC because it can definitely use more testing and review,
but I'm pretty confident with the overall shape and design.

Both MBEC and GMET allow more granular control over execute permissions,
with different levels of separation between supervisor and user mode.
MBEC provides support for separate supervisor and user-mode bits in the
PTEs; GMET instead lacks supervisor-mode only execution (with NX=0,
"both" is represented by U=0 and user-mode only by U=1).  GMET was
clearly inspired by SMEP though with some differences and annoyances.

The series was developed starting from Jon Kohler's earlier version at
https://lore.kernel.org/kvm/20251223054806.1611168-1-jon@nutanix.com/.
The difference is that I am starting this implementation from two
changes to core MMU code, even before looking at nested MBEC/GMET;
these are seemingly unnecessary for that goal but they make the actual
feature almost trivial to implement:

- first, I'm cleaning up the implementation of nVMX exec-only, by
  properly adding read permissions to the ACC_* constant and to the
  permission bitmask machinery.  Jon also had to add a fourth ACC_*
  bit, but used it only in the special case of nested MBEC; here
  instead ACC_READ_MASK is the normality, which simplifies testing
  a lot and removes gratuitous complexity.

- second, I'm enforcing that KVM runs with MBEC/GMET enabled even in
  non-nested mode, if it wants to provide the feature to nested
  hypervisors.  Initially I thought this would mostly simplify the
  testing; but it actually has a big effect on the code as well, because
  the creation of SPTEs now looks *exactly the same* for L1 and L2 guests;
  the difference lies only in the input access permissions.

Later patches have to use slightly different meanings for ACC_* in Intel
and AMD, but the differences are driven by whether the underlying SPTEs
have U/NX or XS/XU bits, and propagate from there.  In other words,
unlike the older ACC_USER_MASK hack these differences are backed by
concrete concepts of the page table format, and there is always a 1:1
mapping from ACC_* bits to PT_*_MASK or shadow_*_mask:

                            Intel                 AMD
     --------------------   -------------------   -------------------
     ACC_READ_MASK          PT_PRESENT_MASK       PT_PRESENT_MASK
     ACC_WRITE_MASK         PT_WRITABLE_MASK      PT_WRITABLE_MASK
     ACC_EXEC_MASK          shadow_xs_mask        shadow_nx_mask
     ACC_USER_MASK          ---                   shadow_user_mask
     ACC_USER_EXEC_MASK     shadow_xu_mask        ---

As can be seen above, the Intel side needs a little work to split
shadow_x_mask and ACC_EXEC_MASK in two; now that there is an actual
ACC_READ_MASK to be used for exec-only pages, ACC_USER_MASK is unused
and can be reused as ACC_USER_EXEC_MASK.  ACC_EXEC_MASK is used for
kernel-mode execution and is tied to shadow_xs_mask (when MBEC is disabled
shadow_xs_mask == shadow_xu_mask, and ACC_USER_EXEC_MASK is computed but
ineffective).  update_permission_bitmask() precomputes all the necessary
conditions.  Note that with MBEC the user/supervisor distinction
depends on the U bit of the page tables rather than the CPL; processors
provide this information to the hypervisor through the "advanced EPT
violation vmexit info" feature, which is a requirement for KVM to use
MBEC, and kvm-intel.ko passes it to the MMU in PFERR_USER_MASK.

On the AMD side, the U bit maps to ACC_USER_MASK but nNPT adjusts the
permission bitmask to ignore it for reads and writes when GMET is active.
Despite the smaller scale of the changes compared to MBEC, there are some
changes to make to use GMET for L1 guests, because the page tables have
to be created with U=0.  This means that the root page has role.access !=
ACC_ALL and its permissions have to be propagated down.

In both cases, the complexity added to the core is limited in comparison
to the benefits of a pretty seamless nested support.

The former "smep_andnot_wp" bit of cpu_role.base, now named "cr4_smep",
is repurposed for nested TDP to indicate that MBEC/GMET is on.  The minor
pessimization for shadow page tables (toggling CR4.SMEP now always forces
building a separate version of the shadow page tables, even though that's
technically unnecessary if CR4.WP=1) is not really worth fretting about;
in practice, guests are not going to flip CR4.SMEP in a way that would
prevent efficient reuse of shadow page tables.

Patches 1-9 are general cleanups, mostly for MMU code.

Patches 10-17 are for Intel MBEC, with the first three covering
non-nested use.

Patches 18-24 are for AMD GMET, with 18/19/20/22 covering non-nested
use and the others covering nested virtualization.

(Patch 25 is a nice little hack that can be useful for testing).

Paolo


v1->v2:
- fix EXPORT_SYMBOL_FOR_KVM_INTERNAL goof
- drop bit 10 from FROZEN_SPTE, add static_assert to catch it [Kai]
- fix exit qualification for page table EPT violations [kvm-unit-tests]
- add XU to shadow_acc_track_mask
- propagate root_role->access also in shadow MMU direct_map()
- add requested access to kvm_mmu_spte_requested tracepoint
- include support for passing advanced EPT violation vmexit info to guest
- advanced EPT violation vmexit info is now required for nested MBEC
- fix nested MBEC to gate XS vs XU based on the U bit of paging structures
- drop SECONDARY_EXEC_MODE_BASED_EPT_EXEC if L1 does not set it
- add commit message to "KVM: nVMX: advertise MBEC to nested guests" [Jon]
- fix checkpatch.pl issues [Jon]
- drop gmet from /proc/cpuinfo [Borislav]
- fix running L1 without GMET



Jon Kohler (5):
  KVM: TDX/VMX: rework EPT_VIOLATION_EXEC_FOR_RING3_LIN into PROT_MASK
  KVM: x86/mmu: remove SPTE_PERM_MASK
  KVM: x86/mmu: free up bit 10 of PTEs in preparation for MBEC
  KVM: nVMX: advertise MBEC to nested guests
  KVM: nVMX: allow MBEC with EVMCS

Paolo Bonzini (20):
  KVM: x86/mmu: shuffle high bits of SPTEs in preparation for MBEC
  KVM: x86/mmu: remove SPTE_EPT_*
  KVM: x86/mmu: merge make_spte_{non,}executable
  KVM: x86/mmu: rename and clarify BYTE_MASK
  KVM: x86/mmu: introduce ACC_READ_MASK
  KVM: x86/mmu: separate more EPT/non-EPT permission_fault()
  KVM: x86/mmu: split XS/XU bits for EPT
  KVM: x86/mmu: move cr4_smep to base role
  KVM: VMX: enable use of MBEC
  KVM: nVMX: pass advanced EPT violation vmexit info to guest
  KVM: nVMX: pass PFERR_USER_MASK to MMU on EPT violations
  KVM: x86/mmu: add support for MBEC to EPT page table walks
  KVM: x86/mmu: propagate access mask from root pages down
  KVM: x86/mmu: introduce cpu_role bit for availability of PFEC.I/D
  KVM: SVM: add GMET bit definitions
  KVM: x86/mmu: add support for GMET to NPT page table walks
  KVM: SVM: enable GMET and set it in MMU role
  KVM: SVM: work around errata 1218
  KVM: nSVM: enable GMET for guests
  stats hack

 Documentation/virt/kvm/x86/mmu.rst |  10 +-
 arch/x86/include/asm/cpufeatures.h |   1 +
 arch/x86/include/asm/kvm-x86-ops.h |   1 +
 arch/x86/include/asm/kvm_host.h    |  45 +++++---
 arch/x86/include/asm/svm.h         |   1 +
 arch/x86/include/asm/vmx.h         |  14 ++-
 arch/x86/kvm/mmu.h                 |  12 ++-
 arch/x86/kvm/mmu/mmu.c             | 162 ++++++++++++++++++++---------
 arch/x86/kvm/mmu/mmutrace.h        |  19 ++--
 arch/x86/kvm/mmu/paging_tmpl.h     |  66 ++++++++----
 arch/x86/kvm/mmu/spte.c            |  77 ++++++++------
 arch/x86/kvm/mmu/spte.h            |  65 +++++++-----
 arch/x86/kvm/mmu/tdp_mmu.c         |   6 +-
 arch/x86/kvm/svm/nested.c          |  16 ++-
 arch/x86/kvm/svm/svm.c             |  32 +++++-
 arch/x86/kvm/svm/svm.h             |   1 +
 arch/x86/kvm/vmx/capabilities.h    |  11 +-
 arch/x86/kvm/vmx/common.h          |  20 ++--
 arch/x86/kvm/vmx/hyperv_evmcs.h    |   1 +
 arch/x86/kvm/vmx/main.c            |   9 ++
 arch/x86/kvm/vmx/nested.c          |  25 ++++-
 arch/x86/kvm/vmx/tdx.c             |   2 +-
 arch/x86/kvm/vmx/vmx.c             |  29 +++++-
 arch/x86/kvm/vmx/vmx.h             |   1 +
 arch/x86/kvm/vmx/x86_ops.h         |   1 +
 arch/x86/kvm/x86.c                 |   1 +
 26 files changed, 437 insertions(+), 191 deletions(-)

-- 
2.53.0
Re: [RFC PATCH v2 00/24] KVM: combined patchset for MBEC/GMET support
Posted by Jon Kohler 3 days, 14 hours ago

> On Mar 26, 2026, at 2:16 PM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> 
> This series introduces support for two related features that Hyper-V uses
> in its implementation of Virtual Secure Mode; these are Intel Mode-Based
> Execute Control and AMD Guest Mode Execution Trap.
> 
> It's still RFC because it can definitely use more testing and review,
> but I'm pretty confident with the overall shape and design.

I've tested this on both Intel and AMD in our 6.18.y based tree and
everything works as expected, and we're very happy with performance
thus far. 

I've also ran the kvm-unit-tests series on both Intel/AMD and thats
also working as expected. I proposed a few more SVM tests off-list, so
we'll see if that helps increase coverage a pinch more.

Guest:
Windows 11 25H2 OS Build 26200.8037

AMD proc:
AMD EPYC 9745 (Turin/Zen5)

Intel proc:
Intel(R) Xeon(R) Gold 6426Y (SPR)

For this RFCv2 series:
Tested-By: Jon Kohler <jon@nutanix.com>

On the ecosystem enablement side, qemu has both mbec [1] and gmet [2];
however, they are not exposed via any model definitions (yet), so users
would need to manually enable them in the short term. I'll work up 
a patch to expose these via model definitions and propose that to the
list this week.

[1] https://github.com/qemu/qemu/commit/bfff4b2ae5452463ab8c14b4a8a020288b5ff5d8
[2] https://github.com/qemu/qemu/commit/746a823a17f25393cc8c0cd1257f6dcef757bc09

Re: [RFC PATCH v2 00/24] KVM: combined patchset for MBEC/GMET support
Posted by Paolo Bonzini 3 days, 6 hours ago
On Mon, Mar 30, 2026 at 4:28 AM Jon Kohler <jon@nutanix.com> wrote:
> For this RFCv2 series:
> Tested-By: Jon Kohler <jon@nutanix.com>

Great, thanks! FWIW I found a small hole (just by code inspection);
translate_nested_gpa is always setting PFERR_USER_MASK and therefore
always using XU (and always allowing execution for GMET). The fix is
not hard, basically translate_nested_gpa needs to become an entry in
the nested_ops and the callers need a little bit of adjustment to pass
more info down. Then the vendor code can do respectively:

    /*
     * MBEC differentiates based on the effective U/S bit of
     * the guest page tables; not the processor CPL.
     */
    access &= ~PFERR_USER_MASK;
    if ((pte_access & ACC_USER_MASK)
        && (access & PFERR_GUEST_FINAL_MASK))
        access |= PFERR_USER_MASK;

and

    /* Non-GMET walks are always user-walks */
    if (!(svm->nested.ctl.nested_ctl & SVM_NESTED_CTL_GMET_ENABLE))
        access |= PFERR_USER_MASK;

I'll post this after the series gets more review altogether.

> On the ecosystem enablement side, qemu has both mbec [1] and gmet [2];
> however, they are not exposed via any model definitions (yet), so users
> would need to manually enable them in the short term. I'll work up
> a patch to expose these via model definitions and propose that to the
> list this week.
>
> [1] https://github.com/qemu/qemu/commit/bfff4b2ae5452463ab8c14b4a8a020288b5ff5d8
> [2] https://github.com/qemu/qemu/commit/746a823a17f25393cc8c0cd1257f6dcef757bc09

Sounds good!

Paolo