From: David Woodhouse <[email protected]> Windows uses Virtualization Based Security for Credential Guard and friends, and enables it by default in current releases. A guest with VBS enabled runs its secure kernel in VTL1, a higher privilege level which the hypervisor has to keep isolated from the normal kernel in VTL0. KVM has no concept of that today, so Windows guests either lose VBS or emulate it with nested virtualization, which is slower and loses features.
There have been completely in-kernel implementations of VBS, which did unnatural things all within a single kvm_vcpu (four APICs, etc.) This is an attempt to build it more cleanly, more in userspace, based on KVM planes (https://lwn.net/Articles/1087590/). The behavioural reference was the in-kernel VSM implementation in the Nitro Hypervisor, complete with its latest compatibility fixes since it was last posted — largely turned into a bunch of kvm unit tests. The result boots Windows Server 2016 through 2025 with Credential Guard active, on both Intel and AMD hosts, with VTL1 protecting its memory from VTL0. With hibernate/resume tested, since that part has always been extra fun. For now I've structured the userspace part as a separable library which can be pulled into QEMU or other VMMs. Partly because QEMU doesn't want it when AI did the typing (but *might* tolerate it as an external library), and partly because I think it might make sense to have a more permissively licensed standard implementation for how KVM-based VMMs implement VSM, and have some input from the Microsoft side and some improved expectation that it'll *keep* working with Windows and not keep breaking for every new release. But that's a future conversation. For now I'm just preempting the question, "why does it look like that?". • https://git.infradead.org/?p=users/dwmw2/linux.git;a=shortlog;h=refs/heads/vsm • https://git.infradead.org/?p=users/dwmw2/qemu.git;a=shortlog;h=refs/heads/vsm • https://git.infradead.org/?p=users/dwmw2/kvm-unit-tests.git;a=shortlog;h=refs/heads/vsm Pulled into my base tree on v7.1-rc7 (not reposted here): • KVM planes itself (Jörg's latest from June) https://lore.kernel.org/kvm/[email protected]/ https://github.com/joergroedel/linux/tree/kvm-planes-v7.1 • Paolo's memory protection attributes v3 https://lore.kernel.org/kvm/[email protected]/ • Melody Wang's SEV-SNP #HV doorbell / Restricted Injection series https://lore.kernel.org/all/[email protected]/ • A few fixes to the above ride just above them in the git tree, each citing the report it addresses; not part of this posting Generic fixes and features in KVM before we get to VSM itself: • Userspace opt-in (KVM_CAP_PLANES) and plane run-state ioctls; MP state, guest-debug, KVM_TRANSLATE, SETUP_MCE and a filtered KVM_ENABLE_CAP on plane vCPU fds; unwind of a failed KVM_CREATE_PLANE • Plane mechanics: per-plane request fan-out, kicking the twin that is actually running, XCR0 and TSC matching shared across twins, runtime CPUID per plane, APICv inhibited while planes are enabled (for now). • Per-plane memory attributes and overlays, and instruction state on the memory-fault exit, for the VMM to build intercept messages from • Fixes found along the way: KVM_TRANSLATE reporting a real write-access walk, SVM keeping TPR[3:0] across exits without a guest CR8 write Finally we get to the actual Hyper-V VSM bits: • Hypercall forwarding to userspace (KVM_CAP_HYPERV_FORWARD_HCALL), with completion or injected #UD, for the VSM hypercalls KVM doesn't handle itself • HvCallVtlCall/HvCallVtlReturn switching between planes in the kernel; forced VTL entry gated on interrupt deliverability and re-armed when a plane suspends with IRR set • Per-plane Hyper-V state: GUEST_OS_ID/HYPERCALL MSRs, the reference TSC page, SynIC and event routing, TLB flushes • VTL register intercepts, including the descriptor-table load traps Credential Guard requires • The suspended-VP state (from Nikolas Wipper's series), refusal of SendIpi to a higher VTL, XMM fast hypercall output • Selftests for both halves; a hyperv_vsm suite for kvm-unit-tests covering VTL call/return, protections, intercepts and eventing follows separately The four WIP-marked patches need finishing and splitting; they are included because the series does not function without them. This is very much an RFC. Held back in the git tree for a follow-up posting: • KVM_TRANSLATE2 and the page-walker flags/status work (also Nikolas's), and the HvCallTranslateVirtualAddress handling built on it • TLB flush inhibit (TlbLocked) Not done at all yet: VINA, and migration of mid-VTL-switch state (the forced-entry and captured-register state has no GET/SET exposure). The interaction with SEV-SNP VMPLs, the other consumer of planes, is untested from this side. Mushahid also has a version which boots Windows 11 on arm64, which we'll reconcile when some of the dust settles. I think this will take a while to reconcile and merge, even after the base dependencies (planes, memattrs, etc.) are in. I'd like to start settling the basic functionality so we can start preparing to merge it in little pieces, if we can reach a general consensus. David Woodhouse (44): KVM: x86/mmu: Move ACC_* masks from spte.h to mmu.h KVM: x86: Let userspace opt in to multiple planes with KVM_CAP_PLANES KVM: selftests: Add x86 planes lifecycle test KVM: x86: hyper-v: Add KVM_CAP_HYPERV_FORWARD_HCALL KVM: selftests: Add Hyper-V hypercall forwarding test KVM: Add KVM_GET/SET_PLANE_RUN_STATE vCPU ioctls KVM: selftests: Cover plane run-state ioctls in planes_test KVM: x86: hyper-v: Let userspace fault a forwarded hypercall KVM: x86: Allow MP state ioctls on plane vCPU fds KVM: x86: Filter KVM_ENABLE_CAP on plane vCPU fds KVM: x86: initialise Hyper-V state on every plane vCPU KVM: implement per-plane memory attributes KVM: x86: hyper-v: bank GUEST_OS_ID and HYPERCALL MSRs per plane KVM: x86: hyper-v: bank the reference TSC page per plane KVM: x86: allow KVM_SET_GUEST_DEBUG on plane vCPU fds KVM: x86: hyper-v: flush the calling plane's TLB on flush hypercalls KVM: x86/mmu: free obsolete roots of all planes KVM: x86: hyperv: don't arm PV EOI for a higher plane's VP assist page KVM: x86: allow KVM_TRANSLATE on plane vCPU fds KVM: x86: hyper-v: handle VTL call/return in the kernel KVM: x86: load each plane twin while updating it after KVM_SET_CPUID WIP: userspace VTL interrupt entry and register intercepts WIP: KVM: x86: deliver events to suspended higher planes WIP: KVM: per-plane memory overlays, richer protection-fault exits WIP: KVM: x86: VSM event-delivery parity fixes from Windows boot triage KVM: planes: fan out per-plane requests to twin vCPUs KVM: x86: inhibit APICv when VM planes are enabled KVM: x86: hyperv: divert LLDT and LTR into register intercepts KVM: planes: Unwind published state on KVM_CREATE_PLANE failure KVM: planes: Kick the running twin's pCPU, not the request target's KVM: planes: Keep current_vcpu in sync in vcpu_load() KVM: x86: Report a real write-access walk from KVM_TRANSLATE KVM: planes: Share XCR0 across plane twins KVM: x86: hyperv: Refuse a synthetic IPI to a higher VTL KVM: x86: Gate forced VTL entry on interrupt deliverability KVM: selftests: Test a plane suspending with an undelivered interrupt KVM: x86: hyperv: Advertise XMM fast hypercall output KVM: SVM: Carry instruction state on reflected plane-protection faults KVM: SVM: Trap descriptor-table loads for VTL register intercepts KVM: SVM: Keep TPR[3:0] across exits without a guest CR8 write KVM: selftests: Add Hyper-V reference TSC page memory attribute test KVM: SVM: Hedge the v_tpr_entry comment KVM: Check every plane's protections before caching a gfn->hva KVM: planes: Annotate the lockless twin-publication protocol Mushahid Hussain (9): KVM: x86: Leave TSC matching to the plane 0 vCPUs KVM: x86: hyperv: Track the reference TSC page per plane KVM: x86: hyperv: Update the reference TSC page past protections KVM: x86: hyperv: Publish an added reference TSC page at once KVM: x86: hyperv: Harden the per-plane reference TSC page updates KVM: x86: Derive runtime CPUID bits from the executing plane KVM: selftests: Test hugepage sizing over mixed protection attributes KVM: x86: hyperv: Do not skip a moved vCPU when completing a hypercall KVM: x86: Allow KVM_X86_SETUP_MCE on plane vCPUs Nikolas Wipper (1): KVM: x86: Implement Hyper-V's vCPU suspended state Paolo Bonzini (1): KVM: selftests: Add VM plane infrastructure and tests Documentation/virt/kvm/api.rst | 241 ++++- arch/x86/hyperv/hv_apic.c | 3 +- arch/x86/include/asm/kvm-x86-ops.h | 1 + arch/x86/include/asm/kvm_host.h | 140 ++- arch/x86/kvm/cpuid.c | 139 ++- arch/x86/kvm/cpuid.h | 6 +- arch/x86/kvm/emulate.c | 21 + arch/x86/kvm/hyperv.c | 995 ++++++++++++++++-- arch/x86/kvm/hyperv.h | 37 +- arch/x86/kvm/kvm_emulate.h | 10 + arch/x86/kvm/lapic.c | 85 +- arch/x86/kvm/mmu.h | 14 + arch/x86/kvm/mmu/mmu.c | 131 ++- arch/x86/kvm/mmu/paging_tmpl.h | 7 +- arch/x86/kvm/mmu/spte.h | 14 - arch/x86/kvm/mmu/tdp_mmu.c | 23 +- arch/x86/kvm/svm/nested.c | 16 + arch/x86/kvm/svm/svm.c | 143 ++- arch/x86/kvm/svm/svm.h | 16 +- arch/x86/kvm/vmx/main.c | 13 +- arch/x86/kvm/vmx/nested.c | 1 + arch/x86/kvm/vmx/vmx.c | 118 ++- arch/x86/kvm/vmx/x86_ops.h | 1 + arch/x86/kvm/x86.c | 668 +++++++++++- include/hyperv/hvgdk_mini.h | 5 +- include/hyperv/hvhdk_mini.h | 3 +- include/linux/kvm_host.h | 149 ++- include/uapi/linux/kvm.h | 63 +- tools/include/uapi/linux/kvm.h | 54 +- tools/testing/selftests/kvm/Makefile.kvm | 7 + .../testing/selftests/kvm/include/kvm_util.h | 74 ++ .../selftests/kvm/include/x86/processor.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 85 +- .../testing/selftests/kvm/lib/x86/processor.c | 15 + .../testing/selftests/kvm/memory_attributes.c | 6 +- tools/testing/selftests/kvm/plane_test.c | 137 +++ .../selftests/kvm/x86/hyperv_forward_hcall.c | 144 +++ .../selftests/kvm/x86/hyperv_tsc_page_attrs.c | 129 +++ .../selftests/kvm/x86/memattr_hugepage_test.c | 132 +++ .../selftests/kvm/x86/plane_x86_test.c | 325 ++++++ tools/testing/selftests/kvm/x86/planes_test.c | 142 +++ .../selftests/kvm/x86/planes_vtl_entry_test.c | 188 ++++ virt/kvm/kvm_main.c | 699 +++++++++++- virt/kvm/pfncache.c | 3 +- 44 files changed, 4956 insertions(+), 248 deletions(-) create mode 100644 tools/testing/selftests/kvm/plane_test.c create mode 100644 tools/testing/selftests/kvm/x86/hyperv_forward_hcall.c create mode 100644 tools/testing/selftests/kvm/x86/hyperv_tsc_page_attrs.c create mode 100644 tools/testing/selftests/kvm/x86/memattr_hugepage_test.c create mode 100644 tools/testing/selftests/kvm/x86/plane_x86_test.c create mode 100644 tools/testing/selftests/kvm/x86/planes_test.c create mode 100644 tools/testing/selftests/kvm/x86/planes_vtl_entry_test.c -- 2.50.1

