summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <maz@kernel.org>2020-10-26 09:51:09 +0000
committerMarc Zyngier <maz@kernel.org>2020-10-29 19:49:02 +0000
commit28e81c6270b3d0e9faadd565f314ad9ac8256620 (patch)
tree0ecf256edc134a02c827573c6260bf08d2595e7e
parent4e5dc64c43192b4fd4c96ac150a8f013065f5f5b (diff)
downloadlinux-stable-28e81c6270b3d0e9faadd565f314ad9ac8256620.tar.gz
linux-stable-28e81c6270b3d0e9faadd565f314ad9ac8256620.tar.bz2
linux-stable-28e81c6270b3d0e9faadd565f314ad9ac8256620.zip
KVM: arm64: Don't corrupt tpidr_el2 on failed HVC call
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
-rw-r--r--arch/arm64/kvm/hyp/nvhe/hyp-init.S23
1 files changed, 16 insertions, 7 deletions
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
index 47224dc62c51..b11a9d7db677 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
@@ -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