Merge remote-tracking branch 'asoc/topic/rt5645' into asoc-next
[cascardo/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_dabt        ARM_EXCEPTION_DATA_ABORT
85         invalid_vector  hyp_fiq         ARM_EXCEPTION_FIQ
86
87 ENTRY(__hyp_do_panic)
88         mrs     lr, cpsr
89         bic     lr, lr, #MODE_MASK
90         orr     lr, lr, #SVC_MODE
91 THUMB(  orr     lr, lr, #PSR_T_BIT      )
92         msr     spsr_cxsf, lr
93         ldr     lr, =panic
94         msr     ELR_hyp, lr
95         ldr     lr, =kvm_call_hyp
96         clrex
97         eret
98 ENDPROC(__hyp_do_panic)
99
100 hyp_hvc:
101         /*
102          * Getting here is either because of a trap from a guest,
103          * or from executing HVC from the host kernel, which means
104          * "do something in Hyp mode".
105          */
106         push    {r0, r1, r2}
107
108         @ Check syndrome register
109         mrc     p15, 4, r1, c5, c2, 0   @ HSR
110         lsr     r0, r1, #HSR_EC_SHIFT
111         cmp     r0, #HSR_EC_HVC
112         bne     guest_trap              @ Not HVC instr.
113
114         /*
115          * Let's check if the HVC came from VMID 0 and allow simple
116          * switch to Hyp mode
117          */
118         mrrc    p15, 6, r0, r2, c2
119         lsr     r2, r2, #16
120         and     r2, r2, #0xff
121         cmp     r2, #0
122         bne     guest_trap              @ Guest called HVC
123
124         /*
125          * Getting here means host called HVC, we shift parameters and branch
126          * to Hyp function.
127          */
128         pop     {r0, r1, r2}
129
130         /* Check for __hyp_get_vectors */
131         cmp     r0, #-1
132         mrceq   p15, 4, r0, c12, c0, 0  @ get HVBAR
133         beq     1f
134
135         push    {lr}
136
137         mov     lr, r0
138         mov     r0, r1
139         mov     r1, r2
140         mov     r2, r3
141
142 THUMB(  orr     lr, #1)
143         blx     lr                      @ Call the HYP function
144
145         pop     {lr}
146 1:      eret
147
148 guest_trap:
149         load_vcpu r0                    @ Load VCPU pointer to r0
150
151 #ifdef CONFIG_VFPv3
152         @ Check for a VFP access
153         lsr     r1, r1, #HSR_EC_SHIFT
154         cmp     r1, #HSR_EC_CP_0_13
155         beq     __vfp_guest_restore
156 #endif
157
158         mov     r1, #ARM_EXCEPTION_HVC
159         b       __guest_exit
160
161 hyp_irq:
162         push    {r0, r1, r2}
163         mov     r1, #ARM_EXCEPTION_IRQ
164         load_vcpu r0                    @ Load VCPU pointer to r0
165         b       __guest_exit
166
167         .ltorg
168
169         .popsection