xref: /optee_os/core/arch/arm/kernel/unwind_arm32.c (revision 02d307b7db909c7973fd54431c9bb7335f103ede)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2923c1f34SJens Wiklander /*
3923c1f34SJens Wiklander  * Copyright 2015 Linaro Limited
4923c1f34SJens Wiklander  * Copyright 2013-2014 Andrew Turner.
5923c1f34SJens Wiklander  * Copyright 2013-2014 Ian Lepore.
6923c1f34SJens Wiklander  * Copyright 2013-2014 Rui Paulo.
7923c1f34SJens Wiklander  * Copyright 2013 Eitan Adler.
8923c1f34SJens Wiklander  * All rights reserved.
9923c1f34SJens Wiklander  *
10923c1f34SJens Wiklander  * Redistribution and use in source and binary forms, with or without
11923c1f34SJens Wiklander  * modification, are permitted provided that the following conditions are
12923c1f34SJens Wiklander  * met:
13923c1f34SJens Wiklander  *
14923c1f34SJens Wiklander  *  1. Redistributions of source code must retain the above copyright
15923c1f34SJens Wiklander  *     notice, this list of conditions and the following disclaimer.
16923c1f34SJens Wiklander  *  2. Redistributions in binary form must reproduce the above copyright
17923c1f34SJens Wiklander  *     notice, this list of conditions and the following disclaimer in the
18923c1f34SJens Wiklander  *     documentation and/or other materials provided with the distribution.
19923c1f34SJens Wiklander  *
20923c1f34SJens Wiklander  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21923c1f34SJens Wiklander  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22923c1f34SJens Wiklander  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23923c1f34SJens Wiklander  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
24923c1f34SJens Wiklander  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25923c1f34SJens Wiklander  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26923c1f34SJens Wiklander  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27923c1f34SJens Wiklander  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28923c1f34SJens Wiklander  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29923c1f34SJens Wiklander  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30923c1f34SJens Wiklander  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31923c1f34SJens Wiklander  */
32923c1f34SJens Wiklander 
33a681fabaSJerome Forissier #include <arm.h>
34e4c86a07SJens Wiklander #include <kernel/linker.h>
35*02d307b7SJerome Forissier #include <kernel/thread.h>
36923c1f34SJens Wiklander #include <kernel/unwind.h>
37923c1f34SJens Wiklander #include <trace.h>
38*02d307b7SJerome Forissier #include <unw/unwind.h>
39a367dcbbSJerome Forissier 
40a367dcbbSJerome Forissier #include "unwind_private.h"
41923c1f34SJens Wiklander 
42923c1f34SJens Wiklander /* The register names */
43923c1f34SJens Wiklander #define	FP	11
44923c1f34SJens Wiklander #define	SP	13
45923c1f34SJens Wiklander #define	LR	14
46923c1f34SJens Wiklander #define	PC	15
47923c1f34SJens Wiklander 
find_exidx(vaddr_t addr __unused,vaddr_t * idx_start,vaddr_t * idx_end)48*02d307b7SJerome Forissier bool find_exidx(vaddr_t addr __unused, vaddr_t *idx_start, vaddr_t *idx_end)
49923c1f34SJens Wiklander {
50*02d307b7SJerome Forissier 	*idx_start = (vaddr_t)__exidx_start;
51*02d307b7SJerome Forissier 	*idx_end = (vaddr_t)__exidx_end;
52af8149deSJens Wiklander 	return true;
53af8149deSJens Wiklander }
54af8149deSJens Wiklander 
unw_get_kernel_stack(void)55a367dcbbSJerome Forissier vaddr_t *unw_get_kernel_stack(void)
56a367dcbbSJerome Forissier {
57a367dcbbSJerome Forissier 	size_t n = 0;
58a367dcbbSJerome Forissier 	size_t size = 0;
59a367dcbbSJerome Forissier 	size_t exidx_sz = 0;
60a367dcbbSJerome Forissier 	vaddr_t *tmp = NULL;
61a367dcbbSJerome Forissier 	vaddr_t *addr = NULL;
62b5ca5ba1SJerome Forissier 	struct unwind_state_arm32 state = { };
63a367dcbbSJerome Forissier 	vaddr_t stack = thread_stack_start();
64a367dcbbSJerome Forissier 	size_t stack_size = thread_stack_size();
65a367dcbbSJerome Forissier 
66a367dcbbSJerome Forissier 	if (SUB_OVERFLOW((vaddr_t)__exidx_end, (vaddr_t)__exidx_start,
67a367dcbbSJerome Forissier 			 &exidx_sz))
68a367dcbbSJerome Forissier 		return NULL;
69a367dcbbSJerome Forissier 
70a367dcbbSJerome Forissier 	/* r7: Thumb-style frame pointer */
71a367dcbbSJerome Forissier 	state.registers[7] = read_r7();
72a367dcbbSJerome Forissier 	/* r11: ARM-style frame pointer */
73a367dcbbSJerome Forissier 	state.registers[FP] = read_fp();
74a367dcbbSJerome Forissier 	state.registers[SP] = read_sp();
75a367dcbbSJerome Forissier 	state.registers[LR] = read_lr();
7619b3fe6cSAngelina Zhao 
7719b3fe6cSAngelina Zhao 	/*
7819b3fe6cSAngelina Zhao 	 * Add 4 to make sure that we have an address well inside this function.
7919b3fe6cSAngelina Zhao 	 * This is needed because we're subtracting 2 from PC when calling
8019b3fe6cSAngelina Zhao 	 * find_index() above. See a comment there for more details.
8119b3fe6cSAngelina Zhao 	 */
8219b3fe6cSAngelina Zhao 	state.registers[PC] = (uint32_t)unw_get_kernel_stack + 4;
83a367dcbbSJerome Forissier 
84*02d307b7SJerome Forissier 	while (unwind_stack_arm32(&state, stack, stack_size)) {
85a367dcbbSJerome Forissier 		tmp = unw_grow(addr, &size, (n + 1) * sizeof(vaddr_t));
86a367dcbbSJerome Forissier 		if (!tmp)
87a367dcbbSJerome Forissier 			goto err;
88a367dcbbSJerome Forissier 		addr = tmp;
89a367dcbbSJerome Forissier 		addr[n] = state.registers[PC];
90a367dcbbSJerome Forissier 		n++;
91a367dcbbSJerome Forissier 	}
92a367dcbbSJerome Forissier 
93a367dcbbSJerome Forissier 	if (addr) {
94a367dcbbSJerome Forissier 		tmp = unw_grow(addr, &size, (n + 1) * sizeof(vaddr_t));
95a367dcbbSJerome Forissier 		if (!tmp)
96a367dcbbSJerome Forissier 			goto err;
97a367dcbbSJerome Forissier 		addr = tmp;
98a367dcbbSJerome Forissier 		addr[n] = 0;
99a367dcbbSJerome Forissier 	}
100a367dcbbSJerome Forissier 
101a367dcbbSJerome Forissier 	return addr;
102a367dcbbSJerome Forissier err:
103a367dcbbSJerome Forissier 	EMSG("Out of memory");
104a367dcbbSJerome Forissier 	return NULL;
105a367dcbbSJerome Forissier }
106*02d307b7SJerome Forissier 
107*02d307b7SJerome Forissier #if (TRACE_LEVEL > 0)
print_kernel_stack(void)108*02d307b7SJerome Forissier void print_kernel_stack(void)
109*02d307b7SJerome Forissier {
110*02d307b7SJerome Forissier 	struct unwind_state_arm32 state = { };
111*02d307b7SJerome Forissier 	vaddr_t stack_start = 0;
112*02d307b7SJerome Forissier 	vaddr_t stack_end = 0;
113*02d307b7SJerome Forissier 
114*02d307b7SJerome Forissier 	/* r7: Thumb-style frame pointer */
115*02d307b7SJerome Forissier 	state.registers[7] = read_r7();
116*02d307b7SJerome Forissier 	/* r11: ARM-style frame pointer */
117*02d307b7SJerome Forissier 	state.registers[FP] = read_fp();
118*02d307b7SJerome Forissier 	state.registers[SP] = read_sp();
119*02d307b7SJerome Forissier 	state.registers[LR] = read_lr();
120*02d307b7SJerome Forissier 
121*02d307b7SJerome Forissier 	/*
122*02d307b7SJerome Forissier 	 * Add 4 to make sure that we have an address well inside this function.
123*02d307b7SJerome Forissier 	 * This is needed because we're subtracting 2 from PC when calling
124*02d307b7SJerome Forissier 	 * find_index() above. See a comment there for more details.
125*02d307b7SJerome Forissier 	 */
126*02d307b7SJerome Forissier 	state.registers[PC] = (uint32_t)print_kernel_stack + 4;
127*02d307b7SJerome Forissier 
128*02d307b7SJerome Forissier 	trace_printf_helper_raw(TRACE_ERROR, true,
129*02d307b7SJerome Forissier 				"TEE load address @ %#"PRIxVA, VCORE_START_VA);
130*02d307b7SJerome Forissier 	get_stack_hard_limits(&stack_start, &stack_end);
131*02d307b7SJerome Forissier 	print_stack_arm32(&state, stack_start, stack_end - stack_start);
132*02d307b7SJerome Forissier }
133a367dcbbSJerome Forissier #endif
134