xref: /optee_os/core/arch/arm/kernel/abort.c (revision 16841254c18912671256ad8c2cfe921a73b3e354)
1 /*
2  * Copyright (c) 2015, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <kernel/abort.h>
29 #include <kernel/misc.h>
30 #include <kernel/tee_ta_manager.h>
31 #include <kernel/panic.h>
32 #include <mm/core_mmu.h>
33 #include <mm/tee_pager.h>
34 #include <trace.h>
35 #include <arm.h>
36 
37 enum tee_pager_fault_type {
38 	TEE_PAGER_FAULT_TYPE_USER_TA_PANIC,
39 	TEE_PAGER_FAULT_TYPE_PAGEABLE,
40 	TEE_PAGER_FAULT_TYPE_IGNORE,
41 };
42 
43 static __unused const char *abort_type_to_str(uint32_t abort_type)
44 {
45 	if (abort_type == THREAD_ABORT_DATA)
46 		return "data";
47 	if (abort_type == THREAD_ABORT_PREFETCH)
48 		return "prefetch";
49 	return "undef";
50 }
51 
52 static __unused void tee_pager_print_detailed_abort(
53 				struct tee_pager_abort_info *ai __unused,
54 				const char *ctx __unused)
55 {
56 	EMSG_RAW("\n");
57 	EMSG_RAW("%s %s-abort at address 0x%" PRIxVA "\n",
58 		ctx, abort_type_to_str(ai->abort_type), ai->va);
59 #ifdef ARM32
60 	EMSG_RAW(" fsr 0x%08x  ttbr0 0x%08x  ttbr1 0x%08x  cidr 0x%X\n",
61 		 ai->fault_descr, read_ttbr0(), read_ttbr1(),
62 		 read_contextidr());
63 	EMSG_RAW(" cpu #%zu          cpsr 0x%08x\n",
64 		 get_core_pos(), ai->regs->spsr);
65 	EMSG_RAW(" r0 0x%08x      r4 0x%08x    r8 0x%08x   r12 0x%08x\n",
66 		 ai->regs->r0, ai->regs->r4, ai->regs->r8, ai->regs->ip);
67 	EMSG_RAW(" r1 0x%08x      r5 0x%08x    r9 0x%08x    sp 0x%08x\n",
68 		 ai->regs->r1, ai->regs->r5, ai->regs->r9,
69 		 read_mode_sp(ai->regs->spsr & CPSR_MODE_MASK));
70 	EMSG_RAW(" r2 0x%08x      r6 0x%08x   r10 0x%08x    lr 0x%08x\n",
71 		 ai->regs->r2, ai->regs->r6, ai->regs->r10,
72 		 read_mode_lr(ai->regs->spsr & CPSR_MODE_MASK));
73 	EMSG_RAW(" r3 0x%08x      r7 0x%08x   r11 0x%08x    pc 0x%08x\n",
74 		 ai->regs->r3, ai->regs->r7, ai->regs->r11, ai->pc);
75 #endif /*ARM32*/
76 #ifdef ARM64
77 	EMSG_RAW(" esr 0x%08x  ttbr0 0x%08" PRIx64 "   ttbr1 0x%08" PRIx64 "   cidr 0x%X\n",
78 		 ai->fault_descr, read_ttbr0_el1(), read_ttbr1_el1(),
79 		 read_contextidr_el1());
80 	EMSG_RAW(" cpu #%zu          cpsr 0x%08x\n",
81 		 get_core_pos(), (uint32_t)ai->regs->spsr);
82 	EMSG_RAW("x0  %016" PRIx64 " x1  %016" PRIx64,
83 		 ai->regs->x0, ai->regs->x1);
84 	EMSG_RAW("x2  %016" PRIx64 " x3  %016" PRIx64,
85 		 ai->regs->x2, ai->regs->x3);
86 	EMSG_RAW("x4  %016" PRIx64 " x5  %016" PRIx64,
87 		 ai->regs->x4, ai->regs->x5);
88 	EMSG_RAW("x6  %016" PRIx64 " x7  %016" PRIx64,
89 		 ai->regs->x6, ai->regs->x7);
90 	EMSG_RAW("x8  %016" PRIx64 " x9  %016" PRIx64,
91 		 ai->regs->x8, ai->regs->x9);
92 	EMSG_RAW("x10 %016" PRIx64 " x11 %016" PRIx64,
93 		 ai->regs->x10, ai->regs->x11);
94 	EMSG_RAW("x12 %016" PRIx64 " x13 %016" PRIx64,
95 		 ai->regs->x12, ai->regs->x13);
96 	EMSG_RAW("x14 %016" PRIx64 " x15 %016" PRIx64,
97 		 ai->regs->x14, ai->regs->x15);
98 	EMSG_RAW("x16 %016" PRIx64 " x17 %016" PRIx64,
99 		 ai->regs->x16, ai->regs->x17);
100 	EMSG_RAW("x18 %016" PRIx64 " x19 %016" PRIx64,
101 		 ai->regs->x18, ai->regs->x19);
102 	EMSG_RAW("x20 %016" PRIx64 " x21 %016" PRIx64,
103 		 ai->regs->x20, ai->regs->x21);
104 	EMSG_RAW("x22 %016" PRIx64 " x23 %016" PRIx64,
105 		 ai->regs->x22, ai->regs->x23);
106 	EMSG_RAW("x24 %016" PRIx64 " x25 %016" PRIx64,
107 		 ai->regs->x24, ai->regs->x25);
108 	EMSG_RAW("x26 %016" PRIx64 " x27 %016" PRIx64,
109 		 ai->regs->x26, ai->regs->x27);
110 	EMSG_RAW("x28 %016" PRIx64 " x29 %016" PRIx64,
111 		 ai->regs->x28, ai->regs->x29);
112 	EMSG_RAW("x30 %016" PRIx64 " elr %016" PRIx64,
113 		 ai->regs->x30, ai->regs->elr);
114 	EMSG_RAW("sp_el0 %016" PRIx64, ai->regs->sp_el0);
115 #endif /*ARM64*/
116 }
117 
118 static void tee_pager_print_user_abort(struct tee_pager_abort_info *ai __unused)
119 {
120 #ifdef CFG_TEE_CORE_TA_TRACE
121 	tee_pager_print_detailed_abort(ai, "user TA");
122 	tee_ta_dump_current();
123 #endif
124 }
125 
126 void tee_pager_print_abort(struct tee_pager_abort_info *ai __unused)
127 {
128 #if (TRACE_LEVEL >= TRACE_INFO)
129 	tee_pager_print_detailed_abort(ai, "core");
130 #endif /*TRACE_LEVEL >= TRACE_DEBUG*/
131 }
132 
133 
134 
135 void tee_pager_print_error_abort(struct tee_pager_abort_info *ai __unused)
136 {
137 #if (TRACE_LEVEL >= TRACE_INFO)
138 	/* full verbose log at DEBUG level */
139 	tee_pager_print_detailed_abort(ai, "core");
140 #else
141 #ifdef ARM32
142 	EMSG("%s-abort at 0x%" PRIxVA "\n"
143 	     "FSR 0x%x PC 0x%x TTBR0 0x%X CONTEXIDR 0x%X\n"
144 	     "CPUID 0x%x CPSR 0x%x (read from SPSR)",
145 	     abort_type_to_str(ai->abort_type),
146 	     ai->va, ai->fault_descr, ai->pc, read_ttbr0(), read_contextidr(),
147 	     read_mpidr(), read_spsr());
148 #endif /*ARM32*/
149 #ifdef ARM64
150 	EMSG("%s-abort at 0x%" PRIxVA "\n"
151 	     "ESR 0x%x PC 0x%x TTBR0 0x%" PRIx64 " CONTEXIDR 0x%X\n"
152 	     "CPUID 0x%" PRIx64 " CPSR 0x%x (read from SPSR)",
153 	     abort_type_to_str(ai->abort_type),
154 	     ai->va, ai->fault_descr, ai->pc, read_ttbr0_el1(),
155 	     read_contextidr_el1(),
156 	     read_mpidr_el1(), (uint32_t)ai->regs->spsr);
157 #endif /*ARM64*/
158 #endif /*TRACE_LEVEL >= TRACE_DEBUG*/
159 }
160 
161 #ifdef ARM32
162 static void set_abort_info(uint32_t abort_type, struct thread_abort_regs *regs,
163 		struct tee_pager_abort_info *ai)
164 {
165 	switch (abort_type) {
166 	case THREAD_ABORT_DATA:
167 		ai->fault_descr = read_dfsr();
168 		ai->va = read_dfar();
169 		break;
170 	case THREAD_ABORT_PREFETCH:
171 		ai->fault_descr = read_ifsr();
172 		ai->va = read_ifar();
173 		break;
174 	default:
175 		ai->fault_descr = 0;
176 		ai->va = regs->elr;
177 		break;
178 	}
179 	ai->abort_type = abort_type;
180 	ai->pc = regs->elr;
181 	ai->regs = regs;
182 }
183 #endif /*ARM32*/
184 
185 #ifdef ARM64
186 static void set_abort_info(uint32_t abort_type __unused,
187 		struct thread_abort_regs *regs, struct tee_pager_abort_info *ai)
188 {
189 	ai->fault_descr = read_esr_el1();
190 	switch ((ai->fault_descr >> ESR_EC_SHIFT) & ESR_EC_MASK) {
191 	case ESR_EC_IABT_EL0:
192 	case ESR_EC_IABT_EL1:
193 		ai->abort_type = THREAD_ABORT_PREFETCH;
194 		ai->va = read_far_el1();
195 		break;
196 	case ESR_EC_DABT_EL0:
197 	case ESR_EC_DABT_EL1:
198 	case ESR_EC_SP_ALIGN:
199 		ai->abort_type = THREAD_ABORT_DATA;
200 		ai->va = read_far_el1();
201 		break;
202 	default:
203 		ai->abort_type = THREAD_ABORT_UNDEF;
204 		ai->va = regs->elr;
205 	}
206 	ai->pc = regs->elr;
207 	ai->regs = regs;
208 }
209 #endif /*ARM64*/
210 
211 #ifdef ARM32
212 static void handle_user_ta_panic(struct tee_pager_abort_info *ai)
213 {
214 	/*
215 	 * It was a user exception, stop user execution and return
216 	 * to TEE Core.
217 	 */
218 	ai->regs->r0 = TEE_ERROR_TARGET_DEAD;
219 	ai->regs->r1 = true;
220 	ai->regs->r2 = 0xdeadbeef;
221 	ai->regs->elr = (uint32_t)thread_unwind_user_mode;
222 	ai->regs->spsr = read_cpsr();
223 	ai->regs->spsr &= ~CPSR_MODE_MASK;
224 	ai->regs->spsr |= CPSR_MODE_SVC;
225 	ai->regs->spsr &= ~CPSR_FIA;
226 	ai->regs->spsr |= read_spsr() & CPSR_FIA;
227 	/* Select Thumb or ARM mode */
228 	if (ai->regs->elr & 1)
229 		ai->regs->spsr |= CPSR_T;
230 	else
231 		ai->regs->spsr &= ~CPSR_T;
232 }
233 #endif /*ARM32*/
234 
235 #ifdef ARM64
236 static void handle_user_ta_panic(struct tee_pager_abort_info *ai)
237 {
238 	uint32_t daif;
239 
240 	/*
241 	 * It was a user exception, stop user execution and return
242 	 * to TEE Core.
243 	 */
244 	ai->regs->x0 = TEE_ERROR_TARGET_DEAD;
245 	ai->regs->x1 = true;
246 	ai->regs->x2 = 0xdeadbeef;
247 	ai->regs->elr = (vaddr_t)thread_unwind_user_mode;
248 	ai->regs->sp_el0 = thread_get_saved_thread_sp();
249 
250 	daif = (ai->regs->spsr >> SPSR_32_AIF_SHIFT) & SPSR_32_AIF_MASK;
251 	/* XXX what about DAIF_D? */
252 	ai->regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, daif);
253 }
254 #endif /*ARM64*/
255 
256 #ifdef ARM32
257 /* Returns true if the exception originated from user mode */
258 static bool tee_pager_is_user_exception(struct tee_pager_abort_info *ai)
259 {
260 	return (ai->regs->spsr & ARM32_CPSR_MODE_MASK) == ARM32_CPSR_MODE_USR;
261 }
262 #endif /*ARM32*/
263 
264 #ifdef ARM64
265 /* Returns true if the exception originated from user mode */
266 static bool tee_pager_is_user_exception(struct tee_pager_abort_info *ai)
267 {
268 	uint32_t spsr = ai->regs->spsr;
269 
270 	if (spsr & (SPSR_MODE_RW_32 << SPSR_MODE_RW_SHIFT))
271 		return true;
272 	if (((spsr >> SPSR_64_MODE_EL_SHIFT) & SPSR_64_MODE_EL_MASK) ==
273 	    SPSR_64_MODE_EL0)
274 		return true;
275 	return false;
276 }
277 #endif /*ARM64*/
278 
279 #ifdef ARM32
280 /* Returns true if the exception originated from abort mode */
281 static bool tee_pager_is_abort_in_abort_handler(struct tee_pager_abort_info *ai)
282 {
283 	return (ai->regs->spsr & ARM32_CPSR_MODE_MASK) == ARM32_CPSR_MODE_ABT;
284 }
285 #endif /*ARM32*/
286 
287 #ifdef ARM64
288 /* Returns true if the exception originated from abort mode */
289 static bool tee_pager_is_abort_in_abort_handler(
290 		struct tee_pager_abort_info *ai __unused)
291 {
292 	return false;
293 }
294 #endif /*ARM64*/
295 
296 
297 
298 static enum tee_pager_fault_type tee_pager_get_fault_type(
299 		struct tee_pager_abort_info *ai)
300 {
301 	if (tee_pager_is_user_exception(ai)) {
302 		tee_pager_print_user_abort(ai);
303 		DMSG("[TEE_PAGER] abort in User mode (TA will panic)");
304 		return TEE_PAGER_FAULT_TYPE_USER_TA_PANIC;
305 	}
306 
307 	if (tee_pager_is_abort_in_abort_handler(ai)) {
308 		tee_pager_print_error_abort(ai);
309 		EMSG("[PAGER] abort in abort handler (trap CPU)");
310 		panic();
311 	}
312 
313 	if (ai->abort_type == THREAD_ABORT_UNDEF) {
314 		tee_pager_print_error_abort(ai);
315 		EMSG("[TEE_PAGER] undefined abort (trap CPU)");
316 		panic();
317 	}
318 
319 	switch (core_mmu_get_fault_type(ai->fault_descr)) {
320 	case CORE_MMU_FAULT_ALIGNMENT:
321 		tee_pager_print_error_abort(ai);
322 		EMSG("[TEE_PAGER] alignement fault!  (trap CPU)");
323 		panic();
324 		break;
325 
326 	case CORE_MMU_FAULT_ACCESS_BIT:
327 		tee_pager_print_error_abort(ai);
328 		EMSG("[TEE_PAGER] access bit fault!  (trap CPU)");
329 		panic();
330 		break;
331 
332 	case CORE_MMU_FAULT_DEBUG_EVENT:
333 		tee_pager_print_abort(ai);
334 		DMSG("[TEE_PAGER] Ignoring debug event!");
335 		return TEE_PAGER_FAULT_TYPE_IGNORE;
336 
337 	case CORE_MMU_FAULT_TRANSLATION:
338 	case CORE_MMU_FAULT_WRITE_PERMISSION:
339 	case CORE_MMU_FAULT_READ_PERMISSION:
340 		return TEE_PAGER_FAULT_TYPE_PAGEABLE;
341 
342 	case CORE_MMU_FAULT_ASYNC_EXTERNAL:
343 		tee_pager_print_abort(ai);
344 		DMSG("[TEE_PAGER] Ignoring async external abort!");
345 		return TEE_PAGER_FAULT_TYPE_IGNORE;
346 
347 	case CORE_MMU_FAULT_OTHER:
348 	default:
349 		tee_pager_print_abort(ai);
350 		DMSG("[TEE_PAGER] Unhandled fault!");
351 		return TEE_PAGER_FAULT_TYPE_IGNORE;
352 	}
353 }
354 
355 void tee_pager_abort_handler(uint32_t abort_type,
356 			struct thread_abort_regs *regs)
357 {
358 	struct tee_pager_abort_info ai;
359 
360 	set_abort_info(abort_type, regs, &ai);
361 
362 	switch (tee_pager_get_fault_type(&ai)) {
363 	case TEE_PAGER_FAULT_TYPE_IGNORE:
364 		break;
365 	case TEE_PAGER_FAULT_TYPE_USER_TA_PANIC:
366 		handle_user_ta_panic(&ai);
367 		break;
368 	case TEE_PAGER_FAULT_TYPE_PAGEABLE:
369 	default:
370 		tee_pager_handle_fault(&ai);
371 		break;
372 	}
373 }
374 
375 
376