Commit | Line | Data |
---|---|---|
2b28162c MZ |
1 | /* |
2 | * Copyright (C) 2015 - ARM Ltd | |
3 | * Author: Marc Zyngier <marc.zyngier@arm.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, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | ||
18 | #include <linux/linkage.h> | |
19 | ||
20 | #include <asm/alternative.h> | |
21 | #include <asm/assembler.h> | |
2b28162c MZ |
22 | #include <asm/cpufeature.h> |
23 | #include <asm/kvm_arm.h> | |
24 | #include <asm/kvm_asm.h> | |
25 | #include <asm/kvm_mmu.h> | |
26 | ||
27 | .text | |
28 | .pushsection .hyp.text, "ax" | |
29 | ||
30 | .macro save_x0_to_x3 | |
31 | stp x0, x1, [sp, #-16]! | |
32 | stp x2, x3, [sp, #-16]! | |
33 | .endm | |
34 | ||
35 | .macro restore_x0_to_x3 | |
36 | ldp x2, x3, [sp], #16 | |
37 | ldp x0, x1, [sp], #16 | |
38 | .endm | |
39 | ||
b81125c7 MZ |
40 | .macro do_el2_call |
41 | /* | |
42 | * Shuffle the parameters before calling the function | |
43 | * pointed to in x0. Assumes parameters in x[1,2,3]. | |
44 | */ | |
b81125c7 MZ |
45 | mov lr, x0 |
46 | mov x0, x1 | |
47 | mov x1, x2 | |
48 | mov x2, x3 | |
49 | blr lr | |
b81125c7 MZ |
50 | .endm |
51 | ||
52 | ENTRY(__vhe_hyp_call) | |
00a44cda | 53 | str lr, [sp, #-16]! |
b81125c7 | 54 | do_el2_call |
00a44cda | 55 | ldr lr, [sp], #16 |
b81125c7 MZ |
56 | /* |
57 | * We used to rely on having an exception return to get | |
58 | * an implicit isb. In the E2H case, we don't have it anymore. | |
59 | * rather than changing all the leaf functions, just do it here | |
60 | * before returning to the rest of the kernel. | |
61 | */ | |
62 | isb | |
63 | ret | |
64 | ENDPROC(__vhe_hyp_call) | |
65 | ||
2b28162c MZ |
66 | el1_sync: // Guest trapped into EL2 |
67 | save_x0_to_x3 | |
68 | ||
5f05a72a | 69 | alternative_if_not ARM64_HAS_VIRT_HOST_EXTN |
2b28162c | 70 | mrs x1, esr_el2 |
5f05a72a MZ |
71 | alternative_else |
72 | mrs x1, esr_el1 | |
73 | alternative_endif | |
2b28162c MZ |
74 | lsr x2, x1, #ESR_ELx_EC_SHIFT |
75 | ||
76 | cmp x2, #ESR_ELx_EC_HVC64 | |
77 | b.ne el1_trap | |
78 | ||
79 | mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest | |
80 | cbnz x3, el1_trap // called HVC | |
81 | ||
82 | /* Here, we're pretty sure the host called HVC. */ | |
83 | restore_x0_to_x3 | |
84 | ||
ad72e59f GL |
85 | cmp x0, #HVC_GET_VECTORS |
86 | b.ne 1f | |
2b28162c MZ |
87 | mrs x0, vbar_el2 |
88 | b 2f | |
89 | ||
b81125c7 | 90 | 1: |
2b28162c | 91 | /* |
b81125c7 | 92 | * Perform the EL2 call |
2b28162c MZ |
93 | */ |
94 | kern_hyp_va x0 | |
b81125c7 | 95 | do_el2_call |
2b28162c | 96 | |
2b28162c MZ |
97 | 2: eret |
98 | ||
99 | el1_trap: | |
100 | /* | |
101 | * x1: ESR | |
102 | * x2: ESR_EC | |
103 | */ | |
104 | ||
105 | /* Guest accessed VFP/SIMD registers, save host, restore Guest */ | |
106 | cmp x2, #ESR_ELx_EC_FP_ASIMD | |
107 | b.eq __fpsimd_guest_restore | |
108 | ||
5f05a72a | 109 | mrs x0, tpidr_el2 |
2b28162c MZ |
110 | mov x1, #ARM_EXCEPTION_TRAP |
111 | b __guest_exit | |
112 | ||
2b28162c MZ |
113 | el1_irq: |
114 | save_x0_to_x3 | |
115 | mrs x0, tpidr_el2 | |
116 | mov x1, #ARM_EXCEPTION_IRQ | |
117 | b __guest_exit | |
118 | ||
53fd5b64 MZ |
119 | ENTRY(__hyp_do_panic) |
120 | mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\ | |
121 | PSR_MODE_EL1h) | |
122 | msr spsr_el2, lr | |
123 | ldr lr, =panic | |
124 | msr elr_el2, lr | |
125 | eret | |
126 | ENDPROC(__hyp_do_panic) | |
127 | ||
128 | .macro invalid_vector label, target = __hyp_panic | |
2b28162c MZ |
129 | .align 2 |
130 | \label: | |
131 | b \target | |
132 | ENDPROC(\label) | |
133 | .endm | |
134 | ||
135 | /* None of these should ever happen */ | |
136 | invalid_vector el2t_sync_invalid | |
137 | invalid_vector el2t_irq_invalid | |
138 | invalid_vector el2t_fiq_invalid | |
139 | invalid_vector el2t_error_invalid | |
140 | invalid_vector el2h_sync_invalid | |
141 | invalid_vector el2h_irq_invalid | |
142 | invalid_vector el2h_fiq_invalid | |
143 | invalid_vector el2h_error_invalid | |
144 | invalid_vector el1_sync_invalid | |
145 | invalid_vector el1_irq_invalid | |
146 | invalid_vector el1_fiq_invalid | |
147 | invalid_vector el1_error_invalid | |
148 | ||
149 | .ltorg | |
150 | ||
151 | .align 11 | |
152 | ||
044ac37d | 153 | ENTRY(__kvm_hyp_vector) |
2b28162c MZ |
154 | ventry el2t_sync_invalid // Synchronous EL2t |
155 | ventry el2t_irq_invalid // IRQ EL2t | |
156 | ventry el2t_fiq_invalid // FIQ EL2t | |
157 | ventry el2t_error_invalid // Error EL2t | |
158 | ||
159 | ventry el2h_sync_invalid // Synchronous EL2h | |
160 | ventry el2h_irq_invalid // IRQ EL2h | |
161 | ventry el2h_fiq_invalid // FIQ EL2h | |
162 | ventry el2h_error_invalid // Error EL2h | |
163 | ||
164 | ventry el1_sync // Synchronous 64-bit EL1 | |
165 | ventry el1_irq // IRQ 64-bit EL1 | |
166 | ventry el1_fiq_invalid // FIQ 64-bit EL1 | |
167 | ventry el1_error_invalid // Error 64-bit EL1 | |
168 | ||
169 | ventry el1_sync // Synchronous 32-bit EL1 | |
170 | ventry el1_irq // IRQ 32-bit EL1 | |
171 | ventry el1_fiq_invalid // FIQ 32-bit EL1 | |
172 | ventry el1_error_invalid // Error 32-bit EL1 | |
044ac37d | 173 | ENDPROC(__kvm_hyp_vector) |