[PATCH 00/14] KVM: arm64: Recursive NV support

Marc Zyngier
2025-02-15T15:02:02Z

This is probably the most interesting bit of the whole NV adventure.
So far, everything else has been a walk in the park, but this one is
where the real fun takes place.

With FEAT_NV2, most of the NV support revolves around tricking a guest
into accessing memory while it tries to access system registers. The
hypervisor's job is to handle the context switch of the actual
registers with the state in memory as needed.

This memory (which we call the VNCR page) lives at an EL2 VA, and is
therefore accessed out of context by the EL1 guest hypervisor.

So far, so good. But what does it mean to virtualise VNCR itself?

It means that when L1 has a prepared a VNCR page for L2, we must map
it in the L0 EL2, and allow L2 to magically access it. Isn't that fun?
To some extent. But there's more!

Having that L0 mapping on behalf of L1 comes with strings attached. It
means that we must be prepared for this page to become inaccessible,
which can happen for a variety of reasons:

- paged out from the host (MMU notifiers)

- unmapped from L1 EL2 stage-1

- permission changes in L1 EL2 stage-1

And in case you're wondering, yes, all of these have TLB invalidation
in common. That's because performing this mapping is akin to
allocating a "SW managed" TLB for L1's VNCR page.

This is what the bulk of this series is about: TLB management for VNCR
pages, and making sure we have the correct page at the right time.

From an implementation perspective, it isn't that complicated, as it
plugs into the existing NV artillery (TLBI, AT, MMU notifiers). Of
course, nothing is optimised, because we're not at this stage yet. I
have plans to make this better (i.e. fewer TLBIs, which implies fewer
traps when nesting), but that's future work.

But this is functional enough that I can run an L4 guest on my QC
box. Slowly.

Patches on top of -rc2. The full integration is, as always, in my
kvm-arm64/nv-next branch.

Marc Zyngier (14):
arm64: sysreg: Add layout for VNCR_EL2
KVM: arm64: nv: Allocate VNCR page when required
KVM: arm64: nv: Extract translation helper from the AT code
KVM: arm64: nv: Snapshot S1 ASID tagging information during walk
KVM: arm64: nv: Move TLBI range decoding to a helper
KVM: arm64: nv: Don't adjust PSTATE.M when L2 is nesting
KVM: arm64: nv: Add pseudo-TLB backing VNCR_EL2
KVM: arm64: nv: Add userspace and guest handling of VNCR_EL2
KVM: arm64: nv: Handle VNCR_EL2-triggered faults
KVM: arm64: nv: Handle mapping of VNCR_EL2 at EL2
KVM: arm64: nv: Handle VNCR_EL2 invalidation from MMU notifiers
KVM: arm64: nv: Program host's VNCR_EL2 to the fixmap address
KVM: arm64: nv: Add S1 TLB invalidation primitive for VNCR_EL2
KVM: arm64: nv: Plumb TLBI S1E2 into system instruction dispatch

arch/arm64/include/asm/esr.h | 2 +
arch/arm64/include/asm/fixmap.h | 6 +
arch/arm64/include/asm/kvm_host.h | 13 +
arch/arm64/include/asm/kvm_nested.h | 100 +++++
arch/arm64/include/asm/sysreg.h | 1 -
arch/arm64/kvm/arm.c | 6 +
arch/arm64/kvm/at.c | 123 +++---
arch/arm64/kvm/handle_exit.c | 1 +
arch/arm64/kvm/hyp/vhe/switch.c | 47 ++-
arch/arm64/kvm/nested.c | 608 +++++++++++++++++++++++++++-
arch/arm64/kvm/reset.c | 2 +
arch/arm64/kvm/sys_regs.c | 135 +++---
arch/arm64/tools/sysreg | 6 +
13 files changed, 921 insertions(+), 129 deletions(-)

--
2.39.2