diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2015-10-25 04:01:56 -0400 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2015-12-14 06:30:42 -0500 |
commit | 2b28162cf65a6fe1c93d172675e4f2792792f17e (patch) | |
tree | 27d32d87a38af2dd157b109d9de6dfef57e6c1cc /arch/arm64/kvm | |
parent | 5eec0a91e32a2862e86265532ae773820e0afd77 (diff) |
arm64: KVM: HYP mode entry points
Add the entry points for HYP mode (both for hypercalls and
exception handling).
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'arch/arm64/kvm')
-rw-r--r-- | arch/arm64/kvm/hyp/Makefile | 1 | ||||
-rw-r--r-- | arch/arm64/kvm/hyp/hyp-entry.S | 203 |
2 files changed, 204 insertions, 0 deletions
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index 1a529f5a4922..826032bc3945 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile | |||
@@ -11,3 +11,4 @@ obj-$(CONFIG_KVM_ARM_HOST) += entry.o | |||
11 | obj-$(CONFIG_KVM_ARM_HOST) += switch.o | 11 | obj-$(CONFIG_KVM_ARM_HOST) += switch.o |
12 | obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o | 12 | obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o |
13 | obj-$(CONFIG_KVM_ARM_HOST) += tlb.o | 13 | obj-$(CONFIG_KVM_ARM_HOST) += tlb.o |
14 | obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o | ||
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S new file mode 100644 index 000000000000..818731a5f61c --- /dev/null +++ b/arch/arm64/kvm/hyp/hyp-entry.S | |||
@@ -0,0 +1,203 @@ | |||
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> | ||
22 | #include <asm/asm-offsets.h> | ||
23 | #include <asm/cpufeature.h> | ||
24 | #include <asm/kvm_arm.h> | ||
25 | #include <asm/kvm_asm.h> | ||
26 | #include <asm/kvm_mmu.h> | ||
27 | |||
28 | .text | ||
29 | .pushsection .hyp.text, "ax" | ||
30 | |||
31 | .macro save_x0_to_x3 | ||
32 | stp x0, x1, [sp, #-16]! | ||
33 | stp x2, x3, [sp, #-16]! | ||
34 | .endm | ||
35 | |||
36 | .macro restore_x0_to_x3 | ||
37 | ldp x2, x3, [sp], #16 | ||
38 | ldp x0, x1, [sp], #16 | ||
39 | .endm | ||
40 | |||
41 | el1_sync: // Guest trapped into EL2 | ||
42 | save_x0_to_x3 | ||
43 | |||
44 | mrs x1, esr_el2 | ||
45 | lsr x2, x1, #ESR_ELx_EC_SHIFT | ||
46 | |||
47 | cmp x2, #ESR_ELx_EC_HVC64 | ||
48 | b.ne el1_trap | ||
49 | |||
50 | mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest | ||
51 | cbnz x3, el1_trap // called HVC | ||
52 | |||
53 | /* Here, we're pretty sure the host called HVC. */ | ||
54 | restore_x0_to_x3 | ||
55 | |||
56 | /* Check for __hyp_get_vectors */ | ||
57 | cbnz x0, 1f | ||
58 | mrs x0, vbar_el2 | ||
59 | b 2f | ||
60 | |||
61 | 1: stp lr, xzr, [sp, #-16]! | ||
62 | |||
63 | /* | ||
64 | * Compute the function address in EL2, and shuffle the parameters. | ||
65 | */ | ||
66 | kern_hyp_va x0 | ||
67 | mov lr, x0 | ||
68 | mov x0, x1 | ||
69 | mov x1, x2 | ||
70 | mov x2, x3 | ||
71 | blr lr | ||
72 | |||
73 | ldp lr, xzr, [sp], #16 | ||
74 | 2: eret | ||
75 | |||
76 | el1_trap: | ||
77 | /* | ||
78 | * x1: ESR | ||
79 | * x2: ESR_EC | ||
80 | */ | ||
81 | |||
82 | /* Guest accessed VFP/SIMD registers, save host, restore Guest */ | ||
83 | cmp x2, #ESR_ELx_EC_FP_ASIMD | ||
84 | b.eq __fpsimd_guest_restore | ||
85 | |||
86 | cmp x2, #ESR_ELx_EC_DABT_LOW | ||
87 | mov x0, #ESR_ELx_EC_IABT_LOW | ||
88 | ccmp x2, x0, #4, ne | ||
89 | b.ne 1f // Not an abort we care about | ||
90 | |||
91 | /* This is an abort. Check for permission fault */ | ||
92 | alternative_if_not ARM64_WORKAROUND_834220 | ||
93 | and x2, x1, #ESR_ELx_FSC_TYPE | ||
94 | cmp x2, #FSC_PERM | ||
95 | b.ne 1f // Not a permission fault | ||
96 | alternative_else | ||
97 | nop // Use the permission fault path to | ||
98 | nop // check for a valid S1 translation, | ||
99 | nop // regardless of the ESR value. | ||
100 | alternative_endif | ||
101 | |||
102 | /* | ||
103 | * Check for Stage-1 page table walk, which is guaranteed | ||
104 | * to give a valid HPFAR_EL2. | ||
105 | */ | ||
106 | tbnz x1, #7, 1f // S1PTW is set | ||
107 | |||
108 | /* Preserve PAR_EL1 */ | ||
109 | mrs x3, par_el1 | ||
110 | stp x3, xzr, [sp, #-16]! | ||
111 | |||
112 | /* | ||
113 | * Permission fault, HPFAR_EL2 is invalid. | ||
114 | * Resolve the IPA the hard way using the guest VA. | ||
115 | * Stage-1 translation already validated the memory access rights. | ||
116 | * As such, we can use the EL1 translation regime, and don't have | ||
117 | * to distinguish between EL0 and EL1 access. | ||
118 | */ | ||
119 | mrs x2, far_el2 | ||
120 | at s1e1r, x2 | ||
121 | isb | ||
122 | |||
123 | /* Read result */ | ||
124 | mrs x3, par_el1 | ||
125 | ldp x0, xzr, [sp], #16 // Restore PAR_EL1 from the stack | ||
126 | msr par_el1, x0 | ||
127 | tbnz x3, #0, 3f // Bail out if we failed the translation | ||
128 | ubfx x3, x3, #12, #36 // Extract IPA | ||
129 | lsl x3, x3, #4 // and present it like HPFAR | ||
130 | b 2f | ||
131 | |||
132 | 1: mrs x3, hpfar_el2 | ||
133 | mrs x2, far_el2 | ||
134 | |||
135 | 2: mrs x0, tpidr_el2 | ||
136 | str w1, [x0, #VCPU_ESR_EL2] | ||
137 | str x2, [x0, #VCPU_FAR_EL2] | ||
138 | str x3, [x0, #VCPU_HPFAR_EL2] | ||
139 | |||
140 | mov x1, #ARM_EXCEPTION_TRAP | ||
141 | b __guest_exit | ||
142 | |||
143 | /* | ||
144 | * Translation failed. Just return to the guest and | ||
145 | * let it fault again. Another CPU is probably playing | ||
146 | * behind our back. | ||
147 | */ | ||
148 | 3: restore_x0_to_x3 | ||
149 | |||
150 | eret | ||
151 | |||
152 | el1_irq: | ||
153 | save_x0_to_x3 | ||
154 | mrs x0, tpidr_el2 | ||
155 | mov x1, #ARM_EXCEPTION_IRQ | ||
156 | b __guest_exit | ||
157 | |||
158 | .macro invalid_vector label, target = __kvm_hyp_panic | ||
159 | .align 2 | ||
160 | \label: | ||
161 | b \target | ||
162 | ENDPROC(\label) | ||
163 | .endm | ||
164 | |||
165 | /* None of these should ever happen */ | ||
166 | invalid_vector el2t_sync_invalid | ||
167 | invalid_vector el2t_irq_invalid | ||
168 | invalid_vector el2t_fiq_invalid | ||
169 | invalid_vector el2t_error_invalid | ||
170 | invalid_vector el2h_sync_invalid | ||
171 | invalid_vector el2h_irq_invalid | ||
172 | invalid_vector el2h_fiq_invalid | ||
173 | invalid_vector el2h_error_invalid | ||
174 | invalid_vector el1_sync_invalid | ||
175 | invalid_vector el1_irq_invalid | ||
176 | invalid_vector el1_fiq_invalid | ||
177 | invalid_vector el1_error_invalid | ||
178 | |||
179 | .ltorg | ||
180 | |||
181 | .align 11 | ||
182 | |||
183 | ENTRY(__hyp_vector) | ||
184 | ventry el2t_sync_invalid // Synchronous EL2t | ||
185 | ventry el2t_irq_invalid // IRQ EL2t | ||
186 | ventry el2t_fiq_invalid // FIQ EL2t | ||
187 | ventry el2t_error_invalid // Error EL2t | ||
188 | |||
189 | ventry el2h_sync_invalid // Synchronous EL2h | ||
190 | ventry el2h_irq_invalid // IRQ EL2h | ||
191 | ventry el2h_fiq_invalid // FIQ EL2h | ||
192 | ventry el2h_error_invalid // Error EL2h | ||
193 | |||
194 | ventry el1_sync // Synchronous 64-bit EL1 | ||
195 | ventry el1_irq // IRQ 64-bit EL1 | ||
196 | ventry el1_fiq_invalid // FIQ 64-bit EL1 | ||
197 | ventry el1_error_invalid // Error 64-bit EL1 | ||
198 | |||
199 | ventry el1_sync // Synchronous 32-bit EL1 | ||
200 | ventry el1_irq // IRQ 32-bit EL1 | ||
201 | ventry el1_fiq_invalid // FIQ 32-bit EL1 | ||
202 | ventry el1_error_invalid // Error 32-bit EL1 | ||
203 | ENDPROC(__hyp_vector) | ||