KVM: arm64: Don't corrupt tpidr_el2 on failed HVC call
authorMarc Zyngier <maz@kernel.org>
Mon, 26 Oct 2020 09:51:09 +0000 (09:51 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 29 Oct 2020 19:49:02 +0000 (19:49 +0000)
The hyp-init code starts by stashing a register in TPIDR_EL2
in in order to free a register. This happens no matter if the
HVC call is legal or not.

Although nothing wrong seems to come out of it, it feels odd
to alter the EL2 state for something that eventually returns
an error.

Instead, use the fact that we know exactly which bits of the
__kvm_hyp_init call are non-zero to perform the check with
a series of EOR/ROR instructions, combined with a build-time
check that the value is the one we expect.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20201026095116.72051-2-maz@kernel.org
arch/arm64/kvm/hyp/nvhe/hyp-init.S

index 47224dc62c51f5c9df1061ecf49665ea6cbc6e72..b11a9d7db677db887f306d4f801a2bdb37cdcb1d 100644 (file)
@@ -57,16 +57,25 @@ __do_hyp_init:
        cmp     x0, #HVC_STUB_HCALL_NR
        b.lo    __kvm_handle_stub_hvc
 
-       /* Set tpidr_el2 for use by HYP to free a register */
-       msr     tpidr_el2, x2
-
-       mov     x2, #KVM_HOST_SMCCC_FUNC(__kvm_hyp_init)
-       cmp     x0, x2
-       b.eq    1f
+       // We only actively check bits [24:31], and everything
+       // else has to be zero, which we check at build time.
+#if (KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) & 0xFFFFFFFF00FFFFFF)
+#error Unexpected __KVM_HOST_SMCCC_FUNC___kvm_hyp_init value
+#endif
+
+       ror     x0, x0, #24
+       eor     x0, x0, #((KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) >> 24) & 0xF)
+       ror     x0, x0, #4
+       eor     x0, x0, #((KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) >> 28) & 0xF)
+       cbz     x0, 1f
        mov     x0, #SMCCC_RET_NOT_SUPPORTED
        eret
 
-1:     phys_to_ttbr x0, x1
+1:
+       /* Set tpidr_el2 for use by HYP to free a register */
+       msr     tpidr_el2, x2
+
+       phys_to_ttbr x0, x1
 alternative_if ARM64_HAS_CNP
        orr     x0, x0, #TTBR_CNP_BIT
 alternative_else_nop_endif