1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2015 Linaro Limited
4  * Copyright 2013-2014 Andrew Turner.
5  * Copyright 2013-2014 Ian Lepore.
6  * Copyright 2013-2014 Rui Paulo.
7  * Copyright 2013 Eitan Adler.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are
12  * met:
13  *
14  *  1. Redistributions of source code must retain the above copyright
15  *     notice, this list of conditions and the following disclaimer.
16  *  2. Redistributions in binary form must reproduce the above copyright
17  *     notice, this list of conditions and the following disclaimer in the
18  *     documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <arm.h>
34 #include <kernel/linker.h>
35 #include <kernel/thread.h>
36 #include <kernel/unwind.h>
37 #include <trace.h>
38 #include <unw/unwind.h>
39 
40 #include "unwind_private.h"
41 
42 /* The register names */
43 #define	FP	11
44 #define	SP	13
45 #define	LR	14
46 #define	PC	15
47 
find_exidx(vaddr_t addr __unused,vaddr_t * idx_start,vaddr_t * idx_end)48 bool find_exidx(vaddr_t addr __unused, vaddr_t *idx_start, vaddr_t *idx_end)
49 {
50 	*idx_start = (vaddr_t)__exidx_start;
51 	*idx_end = (vaddr_t)__exidx_end;
52 	return true;
53 }
54 
unw_get_kernel_stack(void)55 vaddr_t *unw_get_kernel_stack(void)
56 {
57 	size_t n = 0;
58 	size_t size = 0;
59 	size_t exidx_sz = 0;
60 	vaddr_t *tmp = NULL;
61 	vaddr_t *addr = NULL;
62 	struct unwind_state_arm32 state = { };
63 	vaddr_t stack = thread_stack_start();
64 	size_t stack_size = thread_stack_size();
65 
66 	if (SUB_OVERFLOW((vaddr_t)__exidx_end, (vaddr_t)__exidx_start,
67 			 &exidx_sz))
68 		return NULL;
69 
70 	/* r7: Thumb-style frame pointer */
71 	state.registers[7] = read_r7();
72 	/* r11: ARM-style frame pointer */
73 	state.registers[FP] = read_fp();
74 	state.registers[SP] = read_sp();
75 	state.registers[LR] = read_lr();
76 
77 	/*
78 	 * Add 4 to make sure that we have an address well inside this function.
79 	 * This is needed because we're subtracting 2 from PC when calling
80 	 * find_index() above. See a comment there for more details.
81 	 */
82 	state.registers[PC] = (uint32_t)unw_get_kernel_stack + 4;
83 
84 	while (unwind_stack_arm32(&state, stack, stack_size)) {
85 		tmp = unw_grow(addr, &size, (n + 1) * sizeof(vaddr_t));
86 		if (!tmp)
87 			goto err;
88 		addr = tmp;
89 		addr[n] = state.registers[PC];
90 		n++;
91 	}
92 
93 	if (addr) {
94 		tmp = unw_grow(addr, &size, (n + 1) * sizeof(vaddr_t));
95 		if (!tmp)
96 			goto err;
97 		addr = tmp;
98 		addr[n] = 0;
99 	}
100 
101 	return addr;
102 err:
103 	EMSG("Out of memory");
104 	return NULL;
105 }
106 
107 #if (TRACE_LEVEL > 0)
print_kernel_stack(void)108 void print_kernel_stack(void)
109 {
110 	struct unwind_state_arm32 state = { };
111 	vaddr_t stack_start = 0;
112 	vaddr_t stack_end = 0;
113 
114 	/* r7: Thumb-style frame pointer */
115 	state.registers[7] = read_r7();
116 	/* r11: ARM-style frame pointer */
117 	state.registers[FP] = read_fp();
118 	state.registers[SP] = read_sp();
119 	state.registers[LR] = read_lr();
120 
121 	/*
122 	 * Add 4 to make sure that we have an address well inside this function.
123 	 * This is needed because we're subtracting 2 from PC when calling
124 	 * find_index() above. See a comment there for more details.
125 	 */
126 	state.registers[PC] = (uint32_t)print_kernel_stack + 4;
127 
128 	trace_printf_helper_raw(TRACE_ERROR, true,
129 				"TEE load address @ %#"PRIxVA, VCORE_START_VA);
130 	get_stack_hard_limits(&stack_start, &stack_end);
131 	print_stack_arm32(&state, stack_start, stack_end - stack_start);
132 }
133 #endif
134