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/linkage.h>
20 #include <asm/kvm_arm.h>
21 #include <asm/kvm_asm.h>
26 .pushsection .hyp.text, "ax"
29 mrc p15, 4, \reg, c13, c0, 2 @ HTPIDR
32 /********************************************************************
33 * Hypervisor exception vector and handlers
36 * The KVM/ARM Hypervisor ABI is defined as follows:
38 * Entry to Hyp mode from the host kernel will happen _only_ when an HVC
39 * instruction is issued since all traps are disabled when running the host
40 * kernel as per the Hyp-mode initialization at boot time.
42 * HVC instructions cause a trap to the vector page + offset 0x14 (see hyp_hvc
43 * below) when the HVC instruction is called from SVC mode (i.e. a guest or the
44 * host kernel) and they cause a trap to the vector page + offset 0x8 when HVC
45 * instructions are called from within Hyp-mode.
47 * Hyp-ABI: Calling HYP-mode functions from host (in SVC mode):
48 * Switching to Hyp mode is done through a simple HVC #0 instruction. The
49 * exception vector code will check that the HVC comes from VMID==0.
50 * - r0 contains a pointer to a HYP function
51 * - r1, r2, and r3 contain arguments to the above function.
52 * - The HYP function will be called with its arguments in r0, r1 and r2.
53 * On HYP function return, we return directly to SVC.
55 * Note that the above is used to execute code in Hyp-mode from a host-kernel
56 * point of view, and is a different concept from performing a world-switch and
57 * executing guest code SVC mode (with a VMID != 0).
62 .global __kvm_hyp_vector
64 @ Hyp-mode exception vector
74 .macro invalid_vector label, cause
76 \label: mov r0, #\cause
80 invalid_vector hyp_reset ARM_EXCEPTION_RESET
81 invalid_vector hyp_undef ARM_EXCEPTION_UNDEFINED
82 invalid_vector hyp_svc ARM_EXCEPTION_SOFTWARE
83 invalid_vector hyp_pabt ARM_EXCEPTION_PREF_ABORT
84 invalid_vector hyp_fiq ARM_EXCEPTION_FIQ
88 bic lr, lr, #MODE_MASK
90 THUMB( orr lr, lr, #PSR_T_BIT )
97 ENDPROC(__hyp_do_panic)
101 * Getting here is either because of a trap from a guest,
102 * or from executing HVC from the host kernel, which means
103 * "do something in Hyp mode".
107 @ Check syndrome register
108 mrc p15, 4, r1, c5, c2, 0 @ HSR
109 lsr r0, r1, #HSR_EC_SHIFT
111 bne guest_trap @ Not HVC instr.
114 * Let's check if the HVC came from VMID 0 and allow simple
117 mrrc p15, 6, r0, r2, c2
121 bne guest_trap @ Guest called HVC
124 * Getting here means host called HVC, we shift parameters and branch
130 * Check if we have a kernel function, which is guaranteed to be
131 * bigger than the maximum hyp stub hypercall
133 cmp r0, #HVC_STUB_HCALL_NR
137 * Not a kernel function, treat it as a stub hypercall.
138 * Compute the physical address for __kvm_handle_stub_hvc
139 * (as the code lives in the idmaped page) and branch there.
140 * We hijack ip (r12) as a tmp register.
143 ldr r1, =kimage_voffset
145 ldr ip, =__kvm_handle_stub_hvc
160 blx lr @ Call the HYP function
166 load_vcpu r0 @ Load VCPU pointer to r0
169 @ Check for a VFP access
170 lsr r1, r1, #HSR_EC_SHIFT
171 cmp r1, #HSR_EC_CP_0_13
172 beq __vfp_guest_restore
175 mov r1, #ARM_EXCEPTION_HVC
180 mov r1, #ARM_EXCEPTION_IRQ
181 load_vcpu r0 @ Load VCPU pointer to r0
187 ldr r1, =abort_guest_exit_start
188 THUMB( add r1, r1, #1)
190 ldrne r1, =abort_guest_exit_end
191 THUMB( addne r1, r1, #1)
196 orr r0, r0, #(1 << ARM_EXIT_WITH_ABORT_BIT)