KVM: arm64: Abstract the size of the HYP vectors pre-amble
authorJames Morse <james.morse@arm.com>
Tue, 18 Jun 2019 15:17:34 +0000 (16:17 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Fri, 5 Jul 2019 12:03:29 +0000 (13:03 +0100)
The EL2 vector hardening feature causes KVM to generate vectors for
each type of CPU present in the system. The generated sequences already
do some of the early guest-exit work (i.e. saving registers). To avoid
duplication the generated vectors branch to the original vector just
after the preamble. This size is hard coded.

Adding new instructions to the HYP vector causes strange side effects,
which are difficult to debug as the affected code is patched in at
runtime.

Add KVM_VECTOR_PREAMBLE to tell kvm_patch_vector_branch() how big
the preamble is. The valid_vect macro can then validate this at
build time.

Reviewed-by: Julien Thierry <julien.thierry@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
arch/arm64/include/asm/kvm_asm.h
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/kvm/va_layout.c

index 2ca437ef59faf5465bc95ff8e5a779477c3b8db3..388e1b520618a7712060331ac7787d2dae23f05b 100644 (file)
        {ARM_EXCEPTION_TRAP,            "TRAP"          },      \
        {ARM_EXCEPTION_HYP_GONE,        "HYP_GONE"      }
 
+/*
+ * Size of the HYP vectors preamble. kvm_patch_vector_branch() generates code
+ * that jumps over this.
+ */
+#define KVM_VECTOR_PREAMBLE    (1 * AARCH64_INSN_SIZE)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/mm.h>
index b8e045615961d5978c2893f5c2d4b2186fcd37c8..318a2f3996fc3c2fd6cd6046c2545108898cc306 100644 (file)
@@ -216,17 +216,32 @@ ENDPROC(\label)
 
        .align 11
 
+.macro check_preamble_length start, end
+/* kvm_patch_vector_branch() generates code that jumps over the preamble. */
+.if ((\end-\start) != KVM_VECTOR_PREAMBLE)
+       .error "KVM vector preamble length mismatch"
+.endif
+.endm
+
 .macro valid_vect target
        .align 7
+661:
        stp     x0, x1, [sp, #-16]!
+662:
        b       \target
+
+check_preamble_length 661b, 662b
 .endm
 
 .macro invalid_vect target
        .align 7
+661:
        b       \target
+662:
        ldp     x0, x1, [sp], #16
        b       \target
+
+check_preamble_length 661b, 662b
 .endm
 
 ENTRY(__kvm_hyp_vector)
@@ -271,7 +286,8 @@ ENDPROC(__kvm_hyp_vector)
  * movk        x0, #((addr >> 32) & 0xffff), lsl #32
  * br  x0
  *
- * Where addr = kern_hyp_va(__kvm_hyp_vector) + vector-offset + 4.
+ * Where:
+ * addr = kern_hyp_va(__kvm_hyp_vector) + vector-offset + KVM_VECTOR_PREAMBLE.
  * See kvm_patch_vector_branch for details.
  */
 alternative_cb kvm_patch_vector_branch
index 2947ab1b0fa5b768a519b48fa98cba75e96ce708..acd8084f1f2c1055adc0335d87644542018aa5da 100644 (file)
@@ -170,11 +170,10 @@ void kvm_patch_vector_branch(struct alt_instr *alt,
        addr |= ((u64)origptr & GENMASK_ULL(10, 7));
 
        /*
-        * Branch to the second instruction in the vectors in order to
-        * avoid the initial store on the stack (which we already
-        * perform in the hardening vectors).
+        * Branch over the preamble in order to avoid the initial store on
+        * the stack (which we already perform in the hardening vectors).
         */
-       addr += AARCH64_INSN_SIZE;
+       addr += KVM_VECTOR_PREAMBLE;
 
        /* stp x0, x1, [sp, #-16]! */
        insn = aarch64_insn_gen_load_store_pair(AARCH64_INSN_REG_0,