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