]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: arm64: nv: Trap debug registers when in hyp context
authorOliver Upton <oliver.upton@linux.dev>
Wed, 17 Sep 2025 20:31:24 +0000 (13:31 -0700)
committerMarc Zyngier <maz@kernel.org>
Thu, 18 Sep 2025 15:46:20 +0000 (16:46 +0100)
In case you haven't realized it yet, the architecture is _slightly_
broken in the context of nested virt. Here we have another example of
FEAT_NV2 redirecting a sysreg (MDSCR_EL1) to memory that actually
affects execution at vEL2.

Fortunately, MDCR_EL2.TDA provides the necessary traps to hide this
mess at the expense of unnecessarily trapping the breakpoint/watchpoint
registers. Yes, FEAT_FGT gives us a precise trap but let's just opt for
obvious correctness to start.

Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_nested.h
arch/arm64/kvm/debug.c
arch/arm64/kvm/nested.c

index 7fd76f41c296af8a785ac0bed3b2561fcacdbebb..cd3ab06abdca48c17e6fe3d40c7f4478fff5abf5 100644 (file)
@@ -83,6 +83,8 @@ extern void check_nested_vcpu_requests(struct kvm_vcpu *vcpu);
 extern void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu);
 extern void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu);
 
+extern void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu);
+
 struct kvm_s2_trans {
        phys_addr_t output;
        unsigned long block_size;
index 381382c19fe4741980c79b08bbdab6a1bcd825ad..fc275335c0ee9c2073bbb970f8478e1434d2b05f 100644 (file)
@@ -56,6 +56,9 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu)
        if (!kvm_guest_owns_debug_regs(vcpu))
                vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
 
+       if (vcpu_has_nv(vcpu))
+               kvm_nested_setup_mdcr_el2(vcpu);
+
        /* Write MDCR_EL2 directly if we're already at EL2 */
        if (has_vhe())
                write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
index 77db81bae86f9b1b4f34d63069a3bdebf03190ef..9559c64e7e0c01f7a43451759a6a7e05a95f6899 100644 (file)
@@ -1796,3 +1796,14 @@ void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu)
        if (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING)))
                kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu));
 }
+
+void kvm_nested_setup_mdcr_el2(struct kvm_vcpu *vcpu)
+{
+       /*
+        * In yet another example where FEAT_NV2 is fscking broken, accesses
+        * to MDSCR_EL1 are redirected to the VNCR despite having an effect
+        * at EL2. Use a big hammer to apply sanity.
+        */
+       if (is_hyp_ctxt(vcpu))
+               vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA;
+}