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 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 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) 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