2 * Copyright (C) 2012 - Virtual Open Systems and Columbia University
3 * Author: Christoffer Dall <c.dall@virtualopensystems.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License, version 2, as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <linux/arm-smccc.h>
20 #include <linux/linkage.h>
21 #include <asm/kvm_arm.h>
22 #include <asm/kvm_asm.h>
27 .pushsection .hyp.text, "ax"
30 mrc p15, 4, \reg, c13, c0, 2 @ HTPIDR
33 /********************************************************************
34 * Hypervisor exception vector and handlers
37 * The KVM/ARM Hypervisor ABI is defined as follows:
39 * Entry to Hyp mode from the host kernel will happen _only_ when an HVC
40 * instruction is issued since all traps are disabled when running the host
41 * kernel as per the Hyp-mode initialization at boot time.
43 * HVC instructions cause a trap to the vector page + offset 0x14 (see hyp_hvc
44 * below) when the HVC instruction is called from SVC mode (i.e. a guest or the
45 * host kernel) and they cause a trap to the vector page + offset 0x8 when HVC
46 * instructions are called from within Hyp-mode.
48 * Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
49 * Switching to Hyp mode is done through a simple HVC #0 instruction. The
50 * exception vector code will check that the HVC comes from VMID==0.
51 * - r0 contains a pointer to a HYP function
52 * - r1, r2, and r3 contain arguments to the above function.
53 * - The HYP function will be called with its arguments in r0, r1 and r2.
54 * On HYP function return, we return directly to SVC.
56 * Note that the above is used to execute code in Hyp-mode from a host-kernel
57 * point of view, and is a different concept from performing a world-switch and
58 * executing guest code SVC mode (with a VMID != 0).
63 .global __kvm_hyp_vector
65 @ Hyp-mode exception vector
75 #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
77 __kvm_hyp_vector_ic_inv:
78 .global __kvm_hyp_vector_ic_inv
81 * We encode the exception entry in the bottom 3 bits of
82 * SP, and we have to guarantee to be 8 bytes aligned.
84 W(add) sp, sp, #1 /* Reset 7 */
85 W(add) sp, sp, #1 /* Undef 6 */
86 W(add) sp, sp, #1 /* Syscall 5 */
87 W(add) sp, sp, #1 /* Prefetch abort 4 */
88 W(add) sp, sp, #1 /* Data abort 3 */
89 W(add) sp, sp, #1 /* HVC 2 */
90 W(add) sp, sp, #1 /* IRQ 1 */
93 mcr p15, 0, r0, c7, c5, 0 /* ICIALLU */
99 __kvm_hyp_vector_bp_inv:
100 .global __kvm_hyp_vector_bp_inv
103 * We encode the exception entry in the bottom 3 bits of
104 * SP, and we have to guarantee to be 8 bytes aligned.
106 W(add) sp, sp, #1 /* Reset 7 */
107 W(add) sp, sp, #1 /* Undef 6 */
108 W(add) sp, sp, #1 /* Syscall 5 */
109 W(add) sp, sp, #1 /* Prefetch abort 4 */
110 W(add) sp, sp, #1 /* Data abort 3 */
111 W(add) sp, sp, #1 /* HVC 2 */
112 W(add) sp, sp, #1 /* IRQ 1 */
115 mcr p15, 0, r0, c7, c5, 6 /* BPIALL */
120 #ifdef CONFIG_THUMB2_KERNEL
122 * Yet another silly hack: Use VPIDR as a temp register.
123 * Thumb2 is really a pain, as SP cannot be used with most
124 * of the bitwise instructions. The vect_br macro ensures
125 * things gets cleaned-up.
127 mcr p15, 4, r0, c0, c0, 0 /* VPIDR */
133 mrc p15, 4, r0, c0, c0, 0 /* VPIDR */
134 mrc p15, 0, r2, c0, c0, 0 /* MIDR */
135 mcr p15, 4, r2, c0, c0, 0 /* VPIDR */
138 .macro vect_br val, targ
139 ARM( eor sp, sp, #\val )
141 ARM( eorne sp, sp, #\val )
143 THUMB( cmp r1, #\val )
144 THUMB( popeq {r1, r2} )
159 .macro invalid_vector label, cause
161 \label: mov r0, #\cause
165 invalid_vector hyp_reset ARM_EXCEPTION_RESET
166 invalid_vector hyp_undef ARM_EXCEPTION_UNDEFINED
167 invalid_vector hyp_svc ARM_EXCEPTION_SOFTWARE
168 invalid_vector hyp_pabt ARM_EXCEPTION_PREF_ABORT
169 invalid_vector hyp_fiq ARM_EXCEPTION_FIQ
171 ENTRY(__hyp_do_panic)
173 bic lr, lr, #MODE_MASK
174 orr lr, lr, #SVC_MODE
175 THUMB( orr lr, lr, #PSR_T_BIT )
179 ldr lr, =kvm_call_hyp
182 ENDPROC(__hyp_do_panic)
186 * Getting here is either because of a trap from a guest,
187 * or from executing HVC from the host kernel, which means
188 * "do something in Hyp mode".
192 @ Check syndrome register
193 mrc p15, 4, r1, c5, c2, 0 @ HSR
194 lsr r0, r1, #HSR_EC_SHIFT
196 bne guest_trap @ Not HVC instr.
199 * Let's check if the HVC came from VMID 0 and allow simple
202 mrrc p15, 6, r0, r2, c2
206 bne guest_hvc_trap @ Guest called HVC
209 * Getting here means host called HVC, we shift parameters and branch
215 * Check if we have a kernel function, which is guaranteed to be
216 * bigger than the maximum hyp stub hypercall
218 cmp r0, #HVC_STUB_HCALL_NR
222 * Not a kernel function, treat it as a stub hypercall.
223 * Compute the physical address for __kvm_handle_stub_hvc
224 * (as the code lives in the idmaped page) and branch there.
225 * We hijack ip (r12) as a tmp register.
228 ldr r1, =kimage_voffset
230 ldr ip, =__kvm_handle_stub_hvc
238 * Pushing r2 here is just a way of keeping the stack aligned to
239 * 8 bytes on any path that can trigger a HYP exception. Here,
240 * we may well be about to jump into the guest, and the guest
241 * exit would otherwise be badly decoded by our fancy
242 * "decode-exception-without-a-branch" code...
252 blx lr @ Call the HYP function
258 movw r2, #:lower16:ARM_SMCCC_ARCH_WORKAROUND_1
259 movt r2, #:upper16:ARM_SMCCC_ARCH_WORKAROUND_1
260 ldr r0, [sp] @ Guest's r0
266 @ r1 = HSR value (perfectly predictable)
267 @ r2 = ARM_SMCCC_ARCH_WORKAROUND_1
272 load_vcpu r0 @ Load VCPU pointer to r0
275 @ Check for a VFP access
276 lsr r1, r1, #HSR_EC_SHIFT
277 cmp r1, #HSR_EC_CP_0_13
278 beq __vfp_guest_restore
281 mov r1, #ARM_EXCEPTION_HVC
286 mov r1, #ARM_EXCEPTION_IRQ
287 load_vcpu r0 @ Load VCPU pointer to r0
293 ldr r1, =abort_guest_exit_start
294 THUMB( add r1, r1, #1)
296 ldrne r1, =abort_guest_exit_end
297 THUMB( addne r1, r1, #1)
302 orr r0, r0, #(1 << ARM_EXIT_WITH_ABORT_BIT)