xref: /optee_os/core/arch/arm/kernel/abort.c (revision 325d496372fce39d1e3c3aa07da6ee80523797e8)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
216841254SJens Wiklander /*
393dc6b29SJens Wiklander  * Copyright (c) 2015-2022, Linaro Limited
416841254SJens Wiklander  */
516841254SJens Wiklander 
6bce4951cSJens Wiklander #include <arm.h>
716841254SJens Wiklander #include <kernel/abort.h>
824d52e47SJerome Forissier #include <kernel/linker.h>
916841254SJens Wiklander #include <kernel/misc.h>
1016841254SJens Wiklander #include <kernel/panic.h>
11bce4951cSJens Wiklander #include <kernel/tee_ta_manager.h>
127e399f9bSJens Wiklander #include <kernel/thread_private.h>
1315ba8c1fSJens Wiklander #include <kernel/user_mode_ctx.h>
14f7a5c21eSJerome Forissier #include <memtag.h>
1516841254SJens Wiklander #include <mm/core_mmu.h>
1616841254SJens Wiklander #include <mm/tee_pager.h>
1716841254SJens Wiklander #include <trace.h>
1802d307b7SJerome Forissier #include <unw/unwind.h>
1916841254SJens Wiklander 
2029e63291SJens Wiklander enum fault_type {
21d0e3efa6SJens Wiklander 	FAULT_TYPE_USER_MODE_PANIC,
22d0e3efa6SJens Wiklander 	FAULT_TYPE_USER_MODE_VFP,
2329e63291SJens Wiklander 	FAULT_TYPE_PAGEABLE,
2429e63291SJens Wiklander 	FAULT_TYPE_IGNORE,
25*325d4963SGatien Chevallier 	FAULT_TYPE_EXTERNAL_ABORT,
2616841254SJens Wiklander };
2716841254SJens Wiklander 
2831a29642SJerome Forissier #ifdef CFG_UNWIND
2931a29642SJerome Forissier 
3023cf8945SJens Wiklander #ifdef ARM32
3131a29642SJerome Forissier /*
3231a29642SJerome Forissier  * Kernel or user mode unwind (32-bit execution state).
3331a29642SJerome Forissier  */
__print_stack_unwind(struct abort_info * ai)3423cf8945SJens Wiklander static void __print_stack_unwind(struct abort_info *ai)
3531a29642SJerome Forissier {
36c9826bf5SJens Wiklander 	struct unwind_state_arm32 state = { };
37935ac3ecSJens Wiklander 	uint32_t mode = ai->regs->spsr & CPSR_MODE_MASK;
38c9826bf5SJens Wiklander 	uint32_t sp = 0;
39c9826bf5SJens Wiklander 	uint32_t lr = 0;
4031a29642SJerome Forissier 
41c9826bf5SJens Wiklander 	assert(!abort_is_user_exception(ai));
42923c1f34SJens Wiklander 
43c9826bf5SJens Wiklander 	if (mode == CPSR_MODE_SYS) {
44935ac3ecSJens Wiklander 		sp = ai->regs->usr_sp;
45935ac3ecSJens Wiklander 		lr = ai->regs->usr_lr;
46935ac3ecSJens Wiklander 	} else {
47935ac3ecSJens Wiklander 		sp = read_mode_sp(mode);
48935ac3ecSJens Wiklander 		lr = read_mode_lr(mode);
49935ac3ecSJens Wiklander 	}
50935ac3ecSJens Wiklander 
51923c1f34SJens Wiklander 	memset(&state, 0, sizeof(state));
52923c1f34SJens Wiklander 	state.registers[0] = ai->regs->r0;
53923c1f34SJens Wiklander 	state.registers[1] = ai->regs->r1;
54923c1f34SJens Wiklander 	state.registers[2] = ai->regs->r2;
55923c1f34SJens Wiklander 	state.registers[3] = ai->regs->r3;
56923c1f34SJens Wiklander 	state.registers[4] = ai->regs->r4;
57923c1f34SJens Wiklander 	state.registers[5] = ai->regs->r5;
58923c1f34SJens Wiklander 	state.registers[6] = ai->regs->r6;
59923c1f34SJens Wiklander 	state.registers[7] = ai->regs->r7;
60923c1f34SJens Wiklander 	state.registers[8] = ai->regs->r8;
61923c1f34SJens Wiklander 	state.registers[9] = ai->regs->r9;
62923c1f34SJens Wiklander 	state.registers[10] = ai->regs->r10;
63923c1f34SJens Wiklander 	state.registers[11] = ai->regs->r11;
64935ac3ecSJens Wiklander 	state.registers[13] = sp;
65935ac3ecSJens Wiklander 	state.registers[14] = lr;
66923c1f34SJens Wiklander 	state.registers[15] = ai->pc;
67923c1f34SJens Wiklander 
6802d307b7SJerome Forissier 	print_stack_arm32(&state, thread_stack_start(), thread_stack_size());
6931a29642SJerome Forissier }
70923c1f34SJens Wiklander #endif /* ARM32 */
7123cf8945SJens Wiklander 
72923c1f34SJens Wiklander #ifdef ARM64
73c9826bf5SJens Wiklander /* Kernel mode unwind (64-bit execution state) */
__print_stack_unwind(struct abort_info * ai)7423cf8945SJens Wiklander static void __print_stack_unwind(struct abort_info *ai)
75923c1f34SJens Wiklander {
76c9826bf5SJens Wiklander 	struct unwind_state_arm64 state = {
77c9826bf5SJens Wiklander 		.pc = ai->regs->elr,
78c9826bf5SJens Wiklander 		.fp = ai->regs->x29,
79c9826bf5SJens Wiklander 	};
8031a29642SJerome Forissier 
81e6f01334SJerome Forissier 	print_stack_arm64(&state, thread_stack_start(), thread_stack_size());
8231a29642SJerome Forissier }
83923c1f34SJens Wiklander #endif /*ARM64*/
84923c1f34SJens Wiklander 
8523cf8945SJens Wiklander #else /* CFG_UNWIND */
__print_stack_unwind(struct abort_info * ai __unused)8623cf8945SJens Wiklander static void __print_stack_unwind(struct abort_info *ai __unused)
87923c1f34SJens Wiklander {
88923c1f34SJens Wiklander }
8931a29642SJerome Forissier #endif /* CFG_UNWIND */
90923c1f34SJens Wiklander 
abort_type_to_str(uint32_t abort_type)913276098dSJerome Forissier static __maybe_unused const char *abort_type_to_str(uint32_t abort_type)
9216841254SJens Wiklander {
9329e63291SJens Wiklander 	if (abort_type == ABORT_TYPE_DATA)
9416841254SJens Wiklander 		return "data";
9529e63291SJens Wiklander 	if (abort_type == ABORT_TYPE_PREFETCH)
9616841254SJens Wiklander 		return "prefetch";
9716841254SJens Wiklander 	return "undef";
9816841254SJens Wiklander }
9916841254SJens Wiklander 
fault_to_str(uint32_t abort_type,uint32_t fault_descr)1000b94897eSJens Wiklander static __maybe_unused const char *fault_to_str(uint32_t abort_type,
1010b94897eSJens Wiklander 			uint32_t fault_descr)
102f2930adaSJerome Forissier {
1030b94897eSJens Wiklander 	/* fault_descr is only valid for data or prefetch abort */
1040b94897eSJens Wiklander 	if (abort_type != ABORT_TYPE_DATA && abort_type != ABORT_TYPE_PREFETCH)
1050b94897eSJens Wiklander 		return "";
106f2930adaSJerome Forissier 
107f2930adaSJerome Forissier 	switch (core_mmu_get_fault_type(fault_descr)) {
108f2930adaSJerome Forissier 	case CORE_MMU_FAULT_ALIGNMENT:
109f2930adaSJerome Forissier 		return " (alignment fault)";
110f2930adaSJerome Forissier 	case CORE_MMU_FAULT_TRANSLATION:
111f2930adaSJerome Forissier 		return " (translation fault)";
112f2930adaSJerome Forissier 	case CORE_MMU_FAULT_READ_PERMISSION:
113f2930adaSJerome Forissier 		return " (read permission fault)";
114f2930adaSJerome Forissier 	case CORE_MMU_FAULT_WRITE_PERMISSION:
115f2930adaSJerome Forissier 		return " (write permission fault)";
116fb873b88SJens Wiklander 	case CORE_MMU_FAULT_TAG_CHECK:
117fb873b88SJens Wiklander 		return " (tag check fault)";
118*325d4963SGatien Chevallier 	case CORE_MMU_FAULT_SYNC_EXTERNAL:
119*325d4963SGatien Chevallier 		return " (Synchronous external abort)";
120*325d4963SGatien Chevallier 	case CORE_MMU_FAULT_ASYNC_EXTERNAL:
121*325d4963SGatien Chevallier 		return " (Asynchronous external abort)";
122f2930adaSJerome Forissier 	default:
123f2930adaSJerome Forissier 		return "";
124f2930adaSJerome Forissier 	}
125f2930adaSJerome Forissier }
126f2930adaSJerome Forissier 
127935ac3ecSJens Wiklander static __maybe_unused void
__print_abort_info(struct abort_info * ai __maybe_unused,const char * ctx __maybe_unused)128935ac3ecSJens Wiklander __print_abort_info(struct abort_info *ai __maybe_unused,
1293276098dSJerome Forissier 		   const char *ctx __maybe_unused)
13016841254SJens Wiklander {
131c0bc8d0eSJens Wiklander 	__maybe_unused size_t core_pos = 0;
132935ac3ecSJens Wiklander #ifdef ARM32
133935ac3ecSJens Wiklander 	uint32_t mode = ai->regs->spsr & CPSR_MODE_MASK;
134c0bc8d0eSJens Wiklander 	__maybe_unused uint32_t sp = 0;
135c0bc8d0eSJens Wiklander 	__maybe_unused uint32_t lr = 0;
136935ac3ecSJens Wiklander 
137935ac3ecSJens Wiklander 	if (mode == CPSR_MODE_USR || mode == CPSR_MODE_SYS) {
138935ac3ecSJens Wiklander 		sp = ai->regs->usr_sp;
139935ac3ecSJens Wiklander 		lr = ai->regs->usr_lr;
140c0bc8d0eSJens Wiklander 		core_pos = thread_get_tsd()->abort_core;
141935ac3ecSJens Wiklander 	} else {
142935ac3ecSJens Wiklander 		sp = read_mode_sp(mode);
143935ac3ecSJens Wiklander 		lr = read_mode_lr(mode);
144c0bc8d0eSJens Wiklander 		core_pos = get_core_pos();
145935ac3ecSJens Wiklander 	}
146935ac3ecSJens Wiklander #endif /*ARM32*/
147c0bc8d0eSJens Wiklander #ifdef ARM64
148c0bc8d0eSJens Wiklander 	if (abort_is_user_exception(ai))
149c0bc8d0eSJens Wiklander 		core_pos = thread_get_tsd()->abort_core;
150c0bc8d0eSJens Wiklander 	else
151c0bc8d0eSJens Wiklander 		core_pos = get_core_pos();
152c0bc8d0eSJens Wiklander #endif /*ARM64*/
153935ac3ecSJens Wiklander 
1541bc08befSJerome Forissier 	EMSG_RAW("");
155f7a5c21eSJerome Forissier 	if (IS_ENABLED(CFG_MEMTAG))
156f7a5c21eSJerome Forissier 		EMSG_RAW("%s %s-abort at address 0x%" PRIxVA
157f7a5c21eSJerome Forissier 			 " [tagged 0x%" PRIxVA "]%s", ctx,
158f7a5c21eSJerome Forissier 			 abort_type_to_str(ai->abort_type),
159f7a5c21eSJerome Forissier 			 memtag_strip_tag_vaddr((void *)ai->va), ai->va,
160f7a5c21eSJerome Forissier 			 fault_to_str(ai->abort_type, ai->fault_descr));
161f7a5c21eSJerome Forissier 	else
162f7a5c21eSJerome Forissier 		EMSG_RAW("%s %s-abort at address 0x%" PRIxVA "%s", ctx,
163f7a5c21eSJerome Forissier 			 abort_type_to_str(ai->abort_type), ai->va,
1640b94897eSJens Wiklander 			 fault_to_str(ai->abort_type, ai->fault_descr));
16516841254SJens Wiklander #ifdef ARM32
1661bc08befSJerome Forissier 	EMSG_RAW(" fsr 0x%08x  ttbr0 0x%08x  ttbr1 0x%08x  cidr 0x%X",
16716841254SJens Wiklander 		 ai->fault_descr, read_ttbr0(), read_ttbr1(),
16816841254SJens Wiklander 		 read_contextidr());
1691bc08befSJerome Forissier 	EMSG_RAW(" cpu #%zu          cpsr 0x%08x",
170c0bc8d0eSJens Wiklander 		 core_pos, ai->regs->spsr);
1711bc08befSJerome Forissier 	EMSG_RAW(" r0 0x%08x      r4 0x%08x    r8 0x%08x   r12 0x%08x",
17216841254SJens Wiklander 		 ai->regs->r0, ai->regs->r4, ai->regs->r8, ai->regs->ip);
1731bc08befSJerome Forissier 	EMSG_RAW(" r1 0x%08x      r5 0x%08x    r9 0x%08x    sp 0x%08x",
174935ac3ecSJens Wiklander 		 ai->regs->r1, ai->regs->r5, ai->regs->r9, sp);
1751bc08befSJerome Forissier 	EMSG_RAW(" r2 0x%08x      r6 0x%08x   r10 0x%08x    lr 0x%08x",
176935ac3ecSJens Wiklander 		 ai->regs->r2, ai->regs->r6, ai->regs->r10, lr);
1771bc08befSJerome Forissier 	EMSG_RAW(" r3 0x%08x      r7 0x%08x   r11 0x%08x    pc 0x%08x",
17816841254SJens Wiklander 		 ai->regs->r3, ai->regs->r7, ai->regs->r11, ai->pc);
17916841254SJens Wiklander #endif /*ARM32*/
18016841254SJens Wiklander #ifdef ARM64
1811bc08befSJerome Forissier 	EMSG_RAW(" esr 0x%08x  ttbr0 0x%08" PRIx64 "   ttbr1 0x%08" PRIx64
1821bc08befSJerome Forissier 		 "   cidr 0x%X", ai->fault_descr, read_ttbr0_el1(),
1831bc08befSJerome Forissier 		 read_ttbr1_el1(), read_contextidr_el1());
1841bc08befSJerome Forissier 	EMSG_RAW(" cpu #%zu          cpsr 0x%08x",
185c0bc8d0eSJens Wiklander 		 core_pos, (uint32_t)ai->regs->spsr);
18616841254SJens Wiklander 	EMSG_RAW(" x0  %016" PRIx64 " x1  %016" PRIx64,
18716841254SJens Wiklander 		 ai->regs->x0, ai->regs->x1);
18816841254SJens Wiklander 	EMSG_RAW(" x2  %016" PRIx64 " x3  %016" PRIx64,
18916841254SJens Wiklander 		 ai->regs->x2, ai->regs->x3);
19016841254SJens Wiklander 	EMSG_RAW(" x4  %016" PRIx64 " x5  %016" PRIx64,
19116841254SJens Wiklander 		 ai->regs->x4, ai->regs->x5);
19216841254SJens Wiklander 	EMSG_RAW(" x6  %016" PRIx64 " x7  %016" PRIx64,
19316841254SJens Wiklander 		 ai->regs->x6, ai->regs->x7);
19416841254SJens Wiklander 	EMSG_RAW(" x8  %016" PRIx64 " x9  %016" PRIx64,
19516841254SJens Wiklander 		 ai->regs->x8, ai->regs->x9);
19616841254SJens Wiklander 	EMSG_RAW(" x10 %016" PRIx64 " x11 %016" PRIx64,
19716841254SJens Wiklander 		 ai->regs->x10, ai->regs->x11);
19816841254SJens Wiklander 	EMSG_RAW(" x12 %016" PRIx64 " x13 %016" PRIx64,
19916841254SJens Wiklander 		 ai->regs->x12, ai->regs->x13);
20016841254SJens Wiklander 	EMSG_RAW(" x14 %016" PRIx64 " x15 %016" PRIx64,
20116841254SJens Wiklander 		 ai->regs->x14, ai->regs->x15);
20216841254SJens Wiklander 	EMSG_RAW(" x16 %016" PRIx64 " x17 %016" PRIx64,
20316841254SJens Wiklander 		 ai->regs->x16, ai->regs->x17);
20416841254SJens Wiklander 	EMSG_RAW(" x18 %016" PRIx64 " x19 %016" PRIx64,
20516841254SJens Wiklander 		 ai->regs->x18, ai->regs->x19);
20616841254SJens Wiklander 	EMSG_RAW(" x20 %016" PRIx64 " x21 %016" PRIx64,
20716841254SJens Wiklander 		 ai->regs->x20, ai->regs->x21);
20816841254SJens Wiklander 	EMSG_RAW(" x22 %016" PRIx64 " x23 %016" PRIx64,
20916841254SJens Wiklander 		 ai->regs->x22, ai->regs->x23);
21016841254SJens Wiklander 	EMSG_RAW(" x24 %016" PRIx64 " x25 %016" PRIx64,
21116841254SJens Wiklander 		 ai->regs->x24, ai->regs->x25);
21216841254SJens Wiklander 	EMSG_RAW(" x26 %016" PRIx64 " x27 %016" PRIx64,
21316841254SJens Wiklander 		 ai->regs->x26, ai->regs->x27);
21416841254SJens Wiklander 	EMSG_RAW(" x28 %016" PRIx64 " x29 %016" PRIx64,
21516841254SJens Wiklander 		 ai->regs->x28, ai->regs->x29);
21616841254SJens Wiklander 	EMSG_RAW(" x30 %016" PRIx64 " elr %016" PRIx64,
21716841254SJens Wiklander 		 ai->regs->x30, ai->regs->elr);
21816841254SJens Wiklander 	EMSG_RAW(" sp_el0 %016" PRIx64, ai->regs->sp_el0);
21916841254SJens Wiklander #endif /*ARM64*/
22016841254SJens Wiklander }
22116841254SJens Wiklander 
22231a29642SJerome Forissier /*
22331a29642SJerome Forissier  * Print abort info and (optionally) stack dump to the console
224c0bc8d0eSJens Wiklander  * @ai kernel-mode abort info.
22531a29642SJerome Forissier  * @stack_dump true to show a stack trace
22631a29642SJerome Forissier  */
__abort_print(struct abort_info * ai,bool stack_dump)22731a29642SJerome Forissier static void __abort_print(struct abort_info *ai, bool stack_dump)
22831a29642SJerome Forissier {
229c0bc8d0eSJens Wiklander 	assert(!abort_is_user_exception(ai));
23031a29642SJerome Forissier 
2311bc08befSJerome Forissier 	__print_abort_info(ai, "Core");
23216841254SJens Wiklander 
23324d52e47SJerome Forissier 	if (stack_dump) {
23424d52e47SJerome Forissier 		trace_printf_helper_raw(TRACE_ERROR, true,
23524d52e47SJerome Forissier 					"TEE load address @ %#"PRIxVA,
23624d52e47SJerome Forissier 					VCORE_START_VA);
23723cf8945SJens Wiklander 		__print_stack_unwind(ai);
23831a29642SJerome Forissier 	}
23924d52e47SJerome Forissier }
24031a29642SJerome Forissier 
abort_print(struct abort_info * ai)24131a29642SJerome Forissier void abort_print(struct abort_info *ai)
24216841254SJens Wiklander {
24331a29642SJerome Forissier 	__abort_print(ai, false);
24416841254SJens Wiklander }
24516841254SJens Wiklander 
abort_print_error(struct abort_info * ai)246923c1f34SJens Wiklander void abort_print_error(struct abort_info *ai)
24716841254SJens Wiklander {
24831a29642SJerome Forissier 	__abort_print(ai, true);
24916841254SJens Wiklander }
25016841254SJens Wiklander 
251c0bc8d0eSJens Wiklander /* This function must be called from a normal thread */
abort_print_current_ts(void)2524e994fd8SJelle Sels void abort_print_current_ts(void)
253c0bc8d0eSJens Wiklander {
254c0bc8d0eSJens Wiklander 	struct thread_specific_data *tsd = thread_get_tsd();
255c0bc8d0eSJens Wiklander 	struct abort_info ai = { };
25600b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_current_session();
257c0bc8d0eSJens Wiklander 
258c0bc8d0eSJens Wiklander 	ai.abort_type = tsd->abort_type;
259c0bc8d0eSJens Wiklander 	ai.fault_descr = tsd->abort_descr;
260c0bc8d0eSJens Wiklander 	ai.va = tsd->abort_va;
261c0bc8d0eSJens Wiklander 	ai.pc = tsd->abort_regs.elr;
262c0bc8d0eSJens Wiklander 	ai.regs = &tsd->abort_regs;
263c0bc8d0eSJens Wiklander 
264d0e3efa6SJens Wiklander 	if (ai.abort_type != ABORT_TYPE_USER_MODE_PANIC)
265d0e3efa6SJens Wiklander 		__print_abort_info(&ai, "User mode");
2668e64b181SJens Wiklander 
2678e64b181SJens Wiklander 	s->ctx->ops->dump_state(s->ctx);
2688e64b181SJens Wiklander 
269099918f6SSumit Garg #if defined(CFG_FTRACE_SUPPORT)
270099918f6SSumit Garg 	if (s->ctx->ops->dump_ftrace) {
271099918f6SSumit Garg 		s->fbuf = NULL;
272153479acSJens Wiklander 		s->ctx->ops->dump_ftrace(s->ctx);
273c0bc8d0eSJens Wiklander 	}
274099918f6SSumit Garg #endif
275099918f6SSumit Garg }
276c0bc8d0eSJens Wiklander 
save_abort_info_in_tsd(struct abort_info * ai)277c0bc8d0eSJens Wiklander static void save_abort_info_in_tsd(struct abort_info *ai)
278c0bc8d0eSJens Wiklander {
279c0bc8d0eSJens Wiklander 	struct thread_specific_data *tsd = thread_get_tsd();
280c0bc8d0eSJens Wiklander 
281c0bc8d0eSJens Wiklander 	tsd->abort_type = ai->abort_type;
282c0bc8d0eSJens Wiklander 	tsd->abort_descr = ai->fault_descr;
283c0bc8d0eSJens Wiklander 	tsd->abort_va = ai->va;
284c0bc8d0eSJens Wiklander 	tsd->abort_regs = *ai->regs;
285c0bc8d0eSJens Wiklander 	tsd->abort_core = get_core_pos();
286c0bc8d0eSJens Wiklander }
287c0bc8d0eSJens Wiklander 
28816841254SJens Wiklander #ifdef ARM32
set_abort_info(uint32_t abort_type,struct thread_abort_regs * regs,struct abort_info * ai)28916841254SJens Wiklander static void set_abort_info(uint32_t abort_type, struct thread_abort_regs *regs,
29029e63291SJens Wiklander 		struct abort_info *ai)
29116841254SJens Wiklander {
29216841254SJens Wiklander 	switch (abort_type) {
29329e63291SJens Wiklander 	case ABORT_TYPE_DATA:
29416841254SJens Wiklander 		ai->fault_descr = read_dfsr();
29516841254SJens Wiklander 		ai->va = read_dfar();
29616841254SJens Wiklander 		break;
29729e63291SJens Wiklander 	case ABORT_TYPE_PREFETCH:
29816841254SJens Wiklander 		ai->fault_descr = read_ifsr();
29916841254SJens Wiklander 		ai->va = read_ifar();
30016841254SJens Wiklander 		break;
30116841254SJens Wiklander 	default:
30216841254SJens Wiklander 		ai->fault_descr = 0;
30316841254SJens Wiklander 		ai->va = regs->elr;
30416841254SJens Wiklander 		break;
30516841254SJens Wiklander 	}
30616841254SJens Wiklander 	ai->abort_type = abort_type;
30716841254SJens Wiklander 	ai->pc = regs->elr;
30816841254SJens Wiklander 	ai->regs = regs;
30916841254SJens Wiklander }
31016841254SJens Wiklander #endif /*ARM32*/
31116841254SJens Wiklander 
31216841254SJens Wiklander #ifdef ARM64
set_abort_info(uint32_t abort_type __unused,struct thread_abort_regs * regs,struct abort_info * ai)31316841254SJens Wiklander static void set_abort_info(uint32_t abort_type __unused,
31429e63291SJens Wiklander 		struct thread_abort_regs *regs, struct abort_info *ai)
31516841254SJens Wiklander {
31616841254SJens Wiklander 	ai->fault_descr = read_esr_el1();
31716841254SJens Wiklander 	switch ((ai->fault_descr >> ESR_EC_SHIFT) & ESR_EC_MASK) {
31816841254SJens Wiklander 	case ESR_EC_IABT_EL0:
31916841254SJens Wiklander 	case ESR_EC_IABT_EL1:
32029e63291SJens Wiklander 		ai->abort_type = ABORT_TYPE_PREFETCH;
32116841254SJens Wiklander 		ai->va = read_far_el1();
32216841254SJens Wiklander 		break;
32316841254SJens Wiklander 	case ESR_EC_DABT_EL0:
32416841254SJens Wiklander 	case ESR_EC_DABT_EL1:
32516841254SJens Wiklander 	case ESR_EC_SP_ALIGN:
32629e63291SJens Wiklander 		ai->abort_type = ABORT_TYPE_DATA;
32716841254SJens Wiklander 		ai->va = read_far_el1();
32816841254SJens Wiklander 		break;
32916841254SJens Wiklander 	default:
33029e63291SJens Wiklander 		ai->abort_type = ABORT_TYPE_UNDEF;
33116841254SJens Wiklander 		ai->va = regs->elr;
33216841254SJens Wiklander 	}
33316841254SJens Wiklander 	ai->pc = regs->elr;
33416841254SJens Wiklander 	ai->regs = regs;
33516841254SJens Wiklander }
33616841254SJens Wiklander #endif /*ARM64*/
33716841254SJens Wiklander 
33816841254SJens Wiklander #ifdef ARM32
handle_user_mode_panic(struct abort_info * ai)339d0e3efa6SJens Wiklander static void handle_user_mode_panic(struct abort_info *ai)
34016841254SJens Wiklander {
34116841254SJens Wiklander 	/*
34216841254SJens Wiklander 	 * It was a user exception, stop user execution and return
34316841254SJens Wiklander 	 * to TEE Core.
34416841254SJens Wiklander 	 */
34516841254SJens Wiklander 	ai->regs->r0 = TEE_ERROR_TARGET_DEAD;
34616841254SJens Wiklander 	ai->regs->r1 = true;
34716841254SJens Wiklander 	ai->regs->r2 = 0xdeadbeef;
34816841254SJens Wiklander 	ai->regs->elr = (uint32_t)thread_unwind_user_mode;
349935ac3ecSJens Wiklander 	ai->regs->spsr &= CPSR_FIA;
35016841254SJens Wiklander 	ai->regs->spsr &= ~CPSR_MODE_MASK;
35116841254SJens Wiklander 	ai->regs->spsr |= CPSR_MODE_SVC;
35216841254SJens Wiklander 	/* Select Thumb or ARM mode */
35316841254SJens Wiklander 	if (ai->regs->elr & 1)
35416841254SJens Wiklander 		ai->regs->spsr |= CPSR_T;
35516841254SJens Wiklander 	else
35616841254SJens Wiklander 		ai->regs->spsr &= ~CPSR_T;
35716841254SJens Wiklander }
35816841254SJens Wiklander #endif /*ARM32*/
35916841254SJens Wiklander 
36016841254SJens Wiklander #ifdef ARM64
handle_user_mode_panic(struct abort_info * ai)361d0e3efa6SJens Wiklander static void handle_user_mode_panic(struct abort_info *ai)
36216841254SJens Wiklander {
36393dc6b29SJens Wiklander 	struct thread_ctx *tc __maybe_unused = NULL;
36493dc6b29SJens Wiklander 	uint32_t daif = 0;
3650e84f8acSJens Wiklander 	uint32_t pan_bit = 0;
36616841254SJens Wiklander 
36716841254SJens Wiklander 	/*
36816841254SJens Wiklander 	 * It was a user exception, stop user execution and return
36916841254SJens Wiklander 	 * to TEE Core.
37016841254SJens Wiklander 	 */
37116841254SJens Wiklander 	ai->regs->x0 = TEE_ERROR_TARGET_DEAD;
37216841254SJens Wiklander 	ai->regs->x1 = true;
37316841254SJens Wiklander 	ai->regs->x2 = 0xdeadbeef;
37416841254SJens Wiklander 	ai->regs->elr = (vaddr_t)thread_unwind_user_mode;
37516841254SJens Wiklander 	ai->regs->sp_el0 = thread_get_saved_thread_sp();
37616841254SJens Wiklander 
37793dc6b29SJens Wiklander #if defined(CFG_CORE_PAUTH)
37893dc6b29SJens Wiklander 	/*
37993dc6b29SJens Wiklander 	 * We're going to return to the privileged core thread, update the
38093dc6b29SJens Wiklander 	 * APIA key to match the key used by the thread.
38193dc6b29SJens Wiklander 	 */
38293dc6b29SJens Wiklander 	tc = threads + thread_get_id();
38393dc6b29SJens Wiklander 	ai->regs->apiakey_hi = tc->keys.apia_hi;
38493dc6b29SJens Wiklander 	ai->regs->apiakey_lo = tc->keys.apia_lo;
38593dc6b29SJens Wiklander #endif
38693dc6b29SJens Wiklander 
3870e84f8acSJens Wiklander 	if (IS_ENABLED(CFG_PAN) && feat_pan_implemented() && read_pan())
3880e84f8acSJens Wiklander 		pan_bit = SPSR_64_PAN;
38916841254SJens Wiklander 	daif = (ai->regs->spsr >> SPSR_32_AIF_SHIFT) & SPSR_32_AIF_MASK;
39016841254SJens Wiklander 	/* XXX what about DAIF_D? */
3910e84f8acSJens Wiklander 	ai->regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, daif) |
3920e84f8acSJens Wiklander 			 pan_bit;
39316841254SJens Wiklander }
39416841254SJens Wiklander #endif /*ARM64*/
39516841254SJens Wiklander 
3960de9a5fbSJens Wiklander #ifdef CFG_WITH_VFP
handle_user_mode_vfp(void)397d0e3efa6SJens Wiklander static void handle_user_mode_vfp(void)
3980de9a5fbSJens Wiklander {
39900b3b9a2SJens Wiklander 	struct ts_session *s = ts_get_current_session();
4000de9a5fbSJens Wiklander 
40115ba8c1fSJens Wiklander 	thread_user_enable_vfp(&to_user_mode_ctx(s->ctx)->vfp);
4020de9a5fbSJens Wiklander }
4030de9a5fbSJens Wiklander #endif /*CFG_WITH_VFP*/
4040de9a5fbSJens Wiklander 
4056fbac37eSJens Wiklander #ifdef CFG_WITH_USER_TA
40616841254SJens Wiklander #ifdef ARM32
40716841254SJens Wiklander /* Returns true if the exception originated from user mode */
abort_is_user_exception(struct abort_info * ai)40879c1dec7SJens Wiklander bool abort_is_user_exception(struct abort_info *ai)
40916841254SJens Wiklander {
41016841254SJens Wiklander 	return (ai->regs->spsr & ARM32_CPSR_MODE_MASK) == ARM32_CPSR_MODE_USR;
41116841254SJens Wiklander }
41216841254SJens Wiklander #endif /*ARM32*/
41316841254SJens Wiklander 
41416841254SJens Wiklander #ifdef ARM64
41516841254SJens Wiklander /* Returns true if the exception originated from user mode */
abort_is_user_exception(struct abort_info * ai)41679c1dec7SJens Wiklander bool abort_is_user_exception(struct abort_info *ai)
41716841254SJens Wiklander {
41816841254SJens Wiklander 	uint32_t spsr = ai->regs->spsr;
41916841254SJens Wiklander 
42016841254SJens Wiklander 	if (spsr & (SPSR_MODE_RW_32 << SPSR_MODE_RW_SHIFT))
42116841254SJens Wiklander 		return true;
42216841254SJens Wiklander 	if (((spsr >> SPSR_64_MODE_EL_SHIFT) & SPSR_64_MODE_EL_MASK) ==
42316841254SJens Wiklander 	    SPSR_64_MODE_EL0)
42416841254SJens Wiklander 		return true;
42516841254SJens Wiklander 	return false;
42616841254SJens Wiklander }
42716841254SJens Wiklander #endif /*ARM64*/
4286fbac37eSJens Wiklander #else /*CFG_WITH_USER_TA*/
abort_is_user_exception(struct abort_info * ai __unused)42979c1dec7SJens Wiklander bool abort_is_user_exception(struct abort_info *ai __unused)
4306fbac37eSJens Wiklander {
4316fbac37eSJens Wiklander 	return false;
4326fbac37eSJens Wiklander }
4336fbac37eSJens Wiklander #endif /*CFG_WITH_USER_TA*/
43416841254SJens Wiklander 
4356fbac37eSJens Wiklander #if defined(CFG_WITH_VFP) && defined(CFG_WITH_USER_TA)
4360de9a5fbSJens Wiklander #ifdef ARM32
is_vfp_fault(struct abort_info * ai)4370de9a5fbSJens Wiklander static bool is_vfp_fault(struct abort_info *ai)
4380de9a5fbSJens Wiklander {
4390de9a5fbSJens Wiklander 	if ((ai->abort_type != ABORT_TYPE_UNDEF) || vfp_is_enabled())
4400de9a5fbSJens Wiklander 		return false;
4410de9a5fbSJens Wiklander 
442405c67d3SJens Wiklander 	/*
443405c67d3SJens Wiklander 	 * Not entirely accurate, but if it's a truly undefined instruction
444405c67d3SJens Wiklander 	 * we'll end up in this function again, except this time
445405c67d3SJens Wiklander 	 * vfp_is_enabled() so we'll return false.
446405c67d3SJens Wiklander 	 */
447405c67d3SJens Wiklander 	return true;
4480de9a5fbSJens Wiklander }
4490de9a5fbSJens Wiklander #endif /*ARM32*/
4500de9a5fbSJens Wiklander 
4510de9a5fbSJens Wiklander #ifdef ARM64
is_vfp_fault(struct abort_info * ai)4520de9a5fbSJens Wiklander static bool is_vfp_fault(struct abort_info *ai)
4530de9a5fbSJens Wiklander {
4540de9a5fbSJens Wiklander 	switch ((ai->fault_descr >> ESR_EC_SHIFT) & ESR_EC_MASK) {
4550de9a5fbSJens Wiklander 	case ESR_EC_FP_ASIMD:
4560de9a5fbSJens Wiklander 	case ESR_EC_AARCH32_FP:
4570de9a5fbSJens Wiklander 	case ESR_EC_AARCH64_FP:
4580de9a5fbSJens Wiklander 		return true;
4590de9a5fbSJens Wiklander 	default:
4600de9a5fbSJens Wiklander 		return false;
4610de9a5fbSJens Wiklander 	}
4620de9a5fbSJens Wiklander }
4630de9a5fbSJens Wiklander #endif /*ARM64*/
4646fbac37eSJens Wiklander #else /*CFG_WITH_VFP && CFG_WITH_USER_TA*/
is_vfp_fault(struct abort_info * ai __unused)4656fbac37eSJens Wiklander static bool is_vfp_fault(struct abort_info *ai __unused)
4666fbac37eSJens Wiklander {
4676fbac37eSJens Wiklander 	return false;
4686fbac37eSJens Wiklander }
4696fbac37eSJens Wiklander #endif  /*CFG_WITH_VFP && CFG_WITH_USER_TA*/
4700de9a5fbSJens Wiklander 
abort_is_write_fault(struct abort_info * ai)4715c1334faSJens Wiklander bool abort_is_write_fault(struct abort_info *ai)
4725c1334faSJens Wiklander {
4735c1334faSJens Wiklander #ifdef ARM32
4745c1334faSJens Wiklander 	unsigned int write_not_read = 11;
4755c1334faSJens Wiklander #endif
4765c1334faSJens Wiklander #ifdef ARM64
4775c1334faSJens Wiklander 	unsigned int write_not_read = 6;
4785c1334faSJens Wiklander #endif
4795c1334faSJens Wiklander 
4805c1334faSJens Wiklander 	return ai->abort_type == ABORT_TYPE_DATA &&
4815c1334faSJens Wiklander 	       (ai->fault_descr & BIT(write_not_read));
4825c1334faSJens Wiklander }
4835c1334faSJens Wiklander 
get_fault_type(struct abort_info * ai)48429e63291SJens Wiklander static enum fault_type get_fault_type(struct abort_info *ai)
48516841254SJens Wiklander {
48679c1dec7SJens Wiklander 	if (abort_is_user_exception(ai)) {
4870de9a5fbSJens Wiklander 		if (is_vfp_fault(ai))
488d0e3efa6SJens Wiklander 			return FAULT_TYPE_USER_MODE_VFP;
48979c1dec7SJens Wiklander #ifndef CFG_WITH_PAGER
490d0e3efa6SJens Wiklander 		return FAULT_TYPE_USER_MODE_PANIC;
49179c1dec7SJens Wiklander #endif
49216841254SJens Wiklander 	}
49316841254SJens Wiklander 
494935ac3ecSJens Wiklander 	if (thread_is_from_abort_mode()) {
49529e63291SJens Wiklander 		abort_print_error(ai);
4968c9d9445SEtienne Carriere 		panic("[abort] abort in abort handler (trap CPU)");
49716841254SJens Wiklander 	}
49816841254SJens Wiklander 
49929e63291SJens Wiklander 	if (ai->abort_type == ABORT_TYPE_UNDEF) {
50079c1dec7SJens Wiklander 		if (abort_is_user_exception(ai))
501d0e3efa6SJens Wiklander 			return FAULT_TYPE_USER_MODE_PANIC;
50229e63291SJens Wiklander 		abort_print_error(ai);
5038c9d9445SEtienne Carriere 		panic("[abort] undefined abort (trap CPU)");
50416841254SJens Wiklander 	}
50516841254SJens Wiklander 
50616841254SJens Wiklander 	switch (core_mmu_get_fault_type(ai->fault_descr)) {
50716841254SJens Wiklander 	case CORE_MMU_FAULT_ALIGNMENT:
50879c1dec7SJens Wiklander 		if (abort_is_user_exception(ai))
509d0e3efa6SJens Wiklander 			return FAULT_TYPE_USER_MODE_PANIC;
51029e63291SJens Wiklander 		abort_print_error(ai);
5118c9d9445SEtienne Carriere 		panic("[abort] alignement fault!  (trap CPU)");
51216841254SJens Wiklander 		break;
51316841254SJens Wiklander 
51416841254SJens Wiklander 	case CORE_MMU_FAULT_ACCESS_BIT:
51579c1dec7SJens Wiklander 		if (abort_is_user_exception(ai))
516d0e3efa6SJens Wiklander 			return FAULT_TYPE_USER_MODE_PANIC;
51729e63291SJens Wiklander 		abort_print_error(ai);
5188c9d9445SEtienne Carriere 		panic("[abort] access bit fault!  (trap CPU)");
51916841254SJens Wiklander 		break;
52016841254SJens Wiklander 
52116841254SJens Wiklander 	case CORE_MMU_FAULT_DEBUG_EVENT:
522c0bc8d0eSJens Wiklander 		if (!abort_is_user_exception(ai))
52329e63291SJens Wiklander 			abort_print(ai);
52429e63291SJens Wiklander 		DMSG("[abort] Ignoring debug event!");
52529e63291SJens Wiklander 		return FAULT_TYPE_IGNORE;
52616841254SJens Wiklander 
52716841254SJens Wiklander 	case CORE_MMU_FAULT_TRANSLATION:
52816841254SJens Wiklander 	case CORE_MMU_FAULT_WRITE_PERMISSION:
52916841254SJens Wiklander 	case CORE_MMU_FAULT_READ_PERMISSION:
53029e63291SJens Wiklander 		return FAULT_TYPE_PAGEABLE;
53116841254SJens Wiklander 
53216841254SJens Wiklander 	case CORE_MMU_FAULT_ASYNC_EXTERNAL:
533*325d4963SGatien Chevallier 	case CORE_MMU_FAULT_SYNC_EXTERNAL:
534c0bc8d0eSJens Wiklander 		if (!abort_is_user_exception(ai))
53529e63291SJens Wiklander 			abort_print(ai);
536*325d4963SGatien Chevallier 		DMSG("[abort]%s", fault_to_str(ai->abort_type,
537*325d4963SGatien Chevallier 					       ai->fault_descr));
538*325d4963SGatien Chevallier 		return FAULT_TYPE_EXTERNAL_ABORT;
53916841254SJens Wiklander 
540fb873b88SJens Wiklander 	case CORE_MMU_FAULT_TAG_CHECK:
541fb873b88SJens Wiklander 		if (abort_is_user_exception(ai))
542fb873b88SJens Wiklander 			return FAULT_TYPE_USER_MODE_PANIC;
543fb873b88SJens Wiklander 		abort_print_error(ai);
544fb873b88SJens Wiklander 		panic("[abort] Tag check fault! (trap CPU)");
545fb873b88SJens Wiklander 		break;
546fb873b88SJens Wiklander 
54716841254SJens Wiklander 	case CORE_MMU_FAULT_OTHER:
54816841254SJens Wiklander 	default:
549c0bc8d0eSJens Wiklander 		if (!abort_is_user_exception(ai))
55029e63291SJens Wiklander 			abort_print(ai);
55129e63291SJens Wiklander 		DMSG("[abort] Unhandled fault!");
55229e63291SJens Wiklander 		return FAULT_TYPE_IGNORE;
55316841254SJens Wiklander 	}
55416841254SJens Wiklander }
55516841254SJens Wiklander 
abort_handler(uint32_t abort_type,struct thread_abort_regs * regs)55629e63291SJens Wiklander void abort_handler(uint32_t abort_type, struct thread_abort_regs *regs)
55716841254SJens Wiklander {
55829e63291SJens Wiklander 	struct abort_info ai;
55979c1dec7SJens Wiklander 	bool handled;
56016841254SJens Wiklander 
56116841254SJens Wiklander 	set_abort_info(abort_type, regs, &ai);
56216841254SJens Wiklander 
56329e63291SJens Wiklander 	switch (get_fault_type(&ai)) {
56429e63291SJens Wiklander 	case FAULT_TYPE_IGNORE:
56516841254SJens Wiklander 		break;
566d0e3efa6SJens Wiklander 	case FAULT_TYPE_USER_MODE_PANIC:
56779c1dec7SJens Wiklander 		DMSG("[abort] abort in User mode (TA will panic)");
568c0bc8d0eSJens Wiklander 		save_abort_info_in_tsd(&ai);
5690de9a5fbSJens Wiklander 		vfp_disable();
570d0e3efa6SJens Wiklander 		handle_user_mode_panic(&ai);
57116841254SJens Wiklander 		break;
572*325d4963SGatien Chevallier 	case FAULT_TYPE_EXTERNAL_ABORT:
573*325d4963SGatien Chevallier #ifdef CFG_EXTERNAL_ABORT_PLAT_HANDLER
574*325d4963SGatien Chevallier 		/* Allow platform-specific handling */
575*325d4963SGatien Chevallier 		plat_external_abort_handler(&ai);
576*325d4963SGatien Chevallier #endif
577*325d4963SGatien Chevallier 		break;
5780de9a5fbSJens Wiklander #ifdef CFG_WITH_VFP
579d0e3efa6SJens Wiklander 	case FAULT_TYPE_USER_MODE_VFP:
580d0e3efa6SJens Wiklander 		handle_user_mode_vfp();
5810de9a5fbSJens Wiklander 		break;
5820de9a5fbSJens Wiklander #endif
58329e63291SJens Wiklander 	case FAULT_TYPE_PAGEABLE:
58416841254SJens Wiklander 	default:
58540004d9aSJens Wiklander 		if (thread_get_id_may_fail() < 0) {
58640004d9aSJens Wiklander 			abort_print_error(&ai);
58740004d9aSJens Wiklander 			panic("abort outside thread context");
58840004d9aSJens Wiklander 		}
5890de9a5fbSJens Wiklander 		thread_kernel_save_vfp();
59079c1dec7SJens Wiklander 		handled = tee_pager_handle_fault(&ai);
5910de9a5fbSJens Wiklander 		thread_kernel_restore_vfp();
59279c1dec7SJens Wiklander 		if (!handled) {
593c0bc8d0eSJens Wiklander 			if (!abort_is_user_exception(&ai)) {
59479c1dec7SJens Wiklander 				abort_print_error(&ai);
5958c9d9445SEtienne Carriere 				panic("unhandled pageable abort");
596c0bc8d0eSJens Wiklander 			}
59779c1dec7SJens Wiklander 			DMSG("[abort] abort in User mode (TA will panic)");
598c0bc8d0eSJens Wiklander 			save_abort_info_in_tsd(&ai);
59979c1dec7SJens Wiklander 			vfp_disable();
600d0e3efa6SJens Wiklander 			handle_user_mode_panic(&ai);
60179c1dec7SJens Wiklander 		}
60216841254SJens Wiklander 		break;
60316841254SJens Wiklander 	}
60416841254SJens Wiklander }
605