95a2faefc070f5c4b172c65dfdb5dd85b8b3df89
[muen/linux.git] / arch / arm / kvm / hyp / hyp-entry.S
1 /*
2  * Copyright (C) 2012 - Virtual Open Systems and Columbia University
3  * Author: Christoffer Dall <c.dall@virtualopensystems.com>
4  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <linux/linkage.h>
20 #include <asm/kvm_arm.h>
21 #include <asm/kvm_asm.h>
22
23         .arch_extension     virt
24
25         .text
26         .pushsection    .hyp.text, "ax"
27
28 .macro load_vcpu        reg
29         mrc     p15, 4, \reg, c13, c0, 2        @ HTPIDR
30 .endm
31
32 /********************************************************************
33  * Hypervisor exception vector and handlers
34  *
35  *
36  * The KVM/ARM Hypervisor ABI is defined as follows:
37  *
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.
41  *
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.
46  *
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.
54  *
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).
58  */
59
60         .align 5
61 __kvm_hyp_vector:
62         .global __kvm_hyp_vector
63
64         @ Hyp-mode exception vector
65         W(b)    hyp_reset
66         W(b)    hyp_undef
67         W(b)    hyp_svc
68         W(b)    hyp_pabt
69         W(b)    hyp_dabt
70         W(b)    hyp_hvc
71         W(b)    hyp_irq
72         W(b)    hyp_fiq
73
74 .macro invalid_vector label, cause
75         .align
76 \label: mov     r0, #\cause
77         b       __hyp_panic
78 .endm
79
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
85
86 ENTRY(__hyp_do_panic)
87         mrs     lr, cpsr
88         bic     lr, lr, #MODE_MASK
89         orr     lr, lr, #SVC_MODE
90 THUMB(  orr     lr, lr, #PSR_T_BIT      )
91         msr     spsr_cxsf, lr
92         ldr     lr, =panic
93         msr     ELR_hyp, lr
94         ldr     lr, =kvm_call_hyp
95         clrex
96         eret
97 ENDPROC(__hyp_do_panic)
98
99 hyp_hvc:
100         /*
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".
104          */
105         push    {r0, r1, r2}
106
107         @ Check syndrome register
108         mrc     p15, 4, r1, c5, c2, 0   @ HSR
109         lsr     r0, r1, #HSR_EC_SHIFT
110         cmp     r0, #HSR_EC_HVC
111         bne     guest_trap              @ Not HVC instr.
112
113         /*
114          * Let's check if the HVC came from VMID 0 and allow simple
115          * switch to Hyp mode
116          */
117         mrrc    p15, 6, r0, r2, c2
118         lsr     r2, r2, #16
119         and     r2, r2, #0xff
120         cmp     r2, #0
121         bne     guest_trap              @ Guest called HVC
122
123         /*
124          * Getting here means host called HVC, we shift parameters and branch
125          * to Hyp function.
126          */
127         pop     {r0, r1, r2}
128
129         /*
130          * Check if we have a kernel function, which is guaranteed to be
131          * bigger than the maximum hyp stub hypercall
132          */
133         cmp     r0, #HVC_STUB_HCALL_NR
134         bhs     1f
135
136         /*
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.
141          */
142         push    {r1}
143         ldr     r1, =kimage_voffset
144         ldr     r1, [r1]
145         ldr     ip, =__kvm_handle_stub_hvc
146         sub     ip, ip, r1
147         pop     {r1}
148
149         bx      ip
150
151 1:
152         push    {lr}
153
154         mov     lr, r0
155         mov     r0, r1
156         mov     r1, r2
157         mov     r2, r3
158
159 THUMB(  orr     lr, #1)
160         blx     lr                      @ Call the HYP function
161
162         pop     {lr}
163         eret
164
165 guest_trap:
166         load_vcpu r0                    @ Load VCPU pointer to r0
167
168 #ifdef CONFIG_VFPv3
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
173 #endif
174
175         mov     r1, #ARM_EXCEPTION_HVC
176         b       __guest_exit
177
178 hyp_irq:
179         push    {r0, r1, r2}
180         mov     r1, #ARM_EXCEPTION_IRQ
181         load_vcpu r0                    @ Load VCPU pointer to r0
182         b       __guest_exit
183
184 hyp_dabt:
185         push    {r0, r1}
186         mrs     r0, ELR_hyp
187         ldr     r1, =abort_guest_exit_start
188 THUMB(  add     r1, r1, #1)
189         cmp     r0, r1
190         ldrne   r1, =abort_guest_exit_end
191 THUMB(  addne   r1, r1, #1)
192         cmpne   r0, r1
193         pop     {r0, r1}
194         bne     __hyp_panic
195
196         orr     r0, r0, #(1 << ARM_EXIT_WITH_ABORT_BIT)
197         eret
198
199         .ltorg
200
201         .popsection