[RFC PATCH 00/22] KVM: apply chainsaw to struct kvm_mmu

From: Paolo Bonzini

Date: Mon May 11 2026 - 11:12:38 EST


The kvm_mmu is a "god data structure" that includes three different
tasks: describing the guest page table's format, walking the guest
page tables and building the page tables. This means that the
(already poorly named) nested_mmu is only used in part, since it
has no page tables to construct.

Furthermore, some parts are reused across guest and host page
tables (such as the reserved bits detector) but others are not;
for example permission_fault is replaced by simplified code such as
is_executable_pte().

This series cleans this up by splitting kvm_mmu in three parts:

- kvm_pagewalk is the page table walker. There are two of them
per vCPU, cpu_walk and tdp_walk. walk_mmu is *always* replaced
by cpu_walk no matter if running an L1 or L2 guest, unlike in the
current code that moves it between root_mmu and nested_mmu.

- kvm_mmu retains the page table building functionality. It uses
a page table walker to build shadow pages; that is always cpu_walk
for root_mmu or tdp_walk for guest_mmu.

- kvm_page_format allows KVM to operate on PTEs that already exist.
Both kvm_pagewalk and kvm_mmu have their own kvm_page_format, though
at least for now kvm_mmu only uses it for reserved bit checks.

This is in general an interesting cleanup, not least because it reduces
the confusion between guest_mmu and nested_mmu. See for example the
comment "Exempt nested MMUs" which actually exempts guest_mmu. While I'm
not going as far as renaming guest_mmu, there is indeed less confusion
due nested_mmu coming before the introduction of guest_mmu and stealing
the obvious name. However, the last patch also shows the code reuse
benefits can be used for new features too.

By adapting the permission_fault() machinery and using it to test SPTEs
against struct kvm_page_fault, it makes it possible to support SPTEs
that have XS!=XU; these were not supported yet by KVM, but could now be
added via memory attributes.

I'm posting this as RFC to give an early preview of this, while trying
to sort out David's reported issue with MBEC. It's tested very lightly;
in particular, right now npt=0 seems broken for Linux guests and I also
have not tried Intel or 32-bit hosts at all.

Paolo

ps: part of the work was done with help from AI, especially for the more
mechanical patches. However all the planning of each commit was
done by me and I used the LLM essentially as a "natural language
Coccinelle" (e.g., "move gva_to_gpa from struct kvm_mmu to struct
kvm_pagewalk. if the function that calls it has a variable of
type kvm_pagewalk, use it instead of mmu->w"). Since there's
really just one way to do the work given the prompts that I used,
I still consider even the individual patches to be assisted by LLMs
and not generated. Alas, the patches were created prior to
the introduction of Documentation/process/coding-assistants.rst;
if required, I can go back and try to figure out which of the
refactoring patches were done this way.


Paolo Bonzini (22):
KVM: x86: remove nested_mmu from mmu_is_nested()
KVM: x86: move pdptrs out of the MMU
KVM: x86: check that kvm_handle_invpcid is only invoked with shadow
paging
KVM: x86/hyperv: remove unnecessary mmu_is_nested() check
KVM: x86/mmu: introduce struct kvm_pagewalk
KVM: x86/mmu: move get_guest_pgd to struct kvm_pagewalk
KVM: x86/mmu: move gva_to_gpa to struct kvm_pagewalk
KVM: x86/mmu: move get_pdptr to struct kvm_pagewalk
KVM: x86/mmu: move inject_page_fault to struct kvm_pagewalk
KVM: x86/mmu: move CPU-related fields to struct kvm_pagewalk
KVM: x86/mmu: change CPU-role accessor fields to take struct
kvm_pagewalk
KVM: x86/mmu: move remaining permission fields to struct kvm_pagewalk
KVM: x86/mmu: pass struct kvm_pagewalk to kvm_mmu_invalidate_addr
KVM: x86/mmu: change walk_mmu to struct kvm_pagewalk
KVM: x86/mmu: change nested_mmu.w to nested_cpu_walk
KVM: x86/mmu: make cpu_walk a value
KVM: x86/mmu: pull struct kvm_pagewalk out of struct kvm_mmu
KVM: x86/mmu: cleanup functions that initialize shadow MMU
KVM: x86/mmu: pull page format to a new struct
KVM: x86/mmu: merge struct rsvd_bits_validate into struct
kvm_page_format
KVM: x86/mmu: parameterize update_permission_bitmask()
KVM: x86/mmu: use kvm_page_format to test SPTEs

arch/x86/include/asm/kvm_host.h | 75 +++---
arch/x86/kvm/hyperv.c | 7 +-
arch/x86/kvm/kvm_cache_regs.h | 4 +-
arch/x86/kvm/mmu.h | 31 +--
arch/x86/kvm/mmu/mmu.c | 411 +++++++++++++++-----------------
arch/x86/kvm/mmu/paging_tmpl.h | 88 +++----
arch/x86/kvm/mmu/spte.c | 4 +-
arch/x86/kvm/mmu/spte.h | 64 ++---
arch/x86/kvm/mmu/tdp_mmu.c | 3 +-
arch/x86/kvm/svm/nested.c | 22 +-
arch/x86/kvm/svm/svm.c | 2 +-
arch/x86/kvm/vmx/nested.c | 29 ++-
arch/x86/kvm/vmx/vmx.c | 22 +-
arch/x86/kvm/x86.c | 67 +++---
arch/x86/kvm/x86.h | 2 +-
15 files changed, 411 insertions(+), 420 deletions(-)

--
2.52.0