1*d0df954bSJoseph Chen // SPDX-License-Identifier: BSD-2-Clause 2*d0df954bSJoseph Chen /* 3*d0df954bSJoseph Chen * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd 4*d0df954bSJoseph Chen * 5*d0df954bSJoseph Chen * This file is taken and modified from the OP-TEE project. 6*d0df954bSJoseph Chen */ 7*d0df954bSJoseph Chen 8*d0df954bSJoseph Chen #include <common.h> 9*d0df954bSJoseph Chen #include <stacktrace.h> 10*d0df954bSJoseph Chen #include <asm/sections.h> 11*d0df954bSJoseph Chen 12*d0df954bSJoseph Chen DECLARE_GLOBAL_DATA_PTR; 13*d0df954bSJoseph Chen 14*d0df954bSJoseph Chen /* The register names */ 15*d0df954bSJoseph Chen #define FP 11 16*d0df954bSJoseph Chen #define SP 13 17*d0df954bSJoseph Chen #define LR 14 18*d0df954bSJoseph Chen #define PC 15 19*d0df954bSJoseph Chen 20*d0df954bSJoseph Chen /* 21*d0df954bSJoseph Chen * Definitions for the instruction interpreter. 22*d0df954bSJoseph Chen * 23*d0df954bSJoseph Chen * The ARM EABI specifies how to perform the frame unwinding in the 24*d0df954bSJoseph Chen * Exception Handling ABI for the ARM Architecture document. To perform 25*d0df954bSJoseph Chen * the unwind we need to know the initial frame pointer, stack pointer, 26*d0df954bSJoseph Chen * link register and program counter. We then find the entry within the 27*d0df954bSJoseph Chen * index table that points to the function the program counter is within. 28*d0df954bSJoseph Chen * This gives us either a list of three instructions to process, a 31-bit 29*d0df954bSJoseph Chen * relative offset to a table of instructions, or a value telling us 30*d0df954bSJoseph Chen * we can't unwind any further. 31*d0df954bSJoseph Chen * 32*d0df954bSJoseph Chen * When we have the instructions to process we need to decode them 33*d0df954bSJoseph Chen * following table 4 in section 9.3. This describes a collection of bit 34*d0df954bSJoseph Chen * patterns to encode that steps to take to update the stack pointer and 35*d0df954bSJoseph Chen * link register to the correct values at the start of the function. 36*d0df954bSJoseph Chen */ 37*d0df954bSJoseph Chen 38*d0df954bSJoseph Chen /* A special case when we are unable to unwind past this function */ 39*d0df954bSJoseph Chen #define EXIDX_CANTUNWIND 1 40*d0df954bSJoseph Chen 41*d0df954bSJoseph Chen /* 42*d0df954bSJoseph Chen * Entry types. 43*d0df954bSJoseph Chen * These are the only entry types that have been seen in the kernel. 44*d0df954bSJoseph Chen */ 45*d0df954bSJoseph Chen #define ENTRY_MASK 0xff000000 46*d0df954bSJoseph Chen #define ENTRY_ARM_SU16 0x80000000 47*d0df954bSJoseph Chen #define ENTRY_ARM_LU16 0x81000000 48*d0df954bSJoseph Chen 49*d0df954bSJoseph Chen /* Instruction masks. */ 50*d0df954bSJoseph Chen #define INSN_VSP_MASK 0xc0 51*d0df954bSJoseph Chen #define INSN_VSP_SIZE_MASK 0x3f 52*d0df954bSJoseph Chen #define INSN_STD_MASK 0xf0 53*d0df954bSJoseph Chen #define INSN_STD_DATA_MASK 0x0f 54*d0df954bSJoseph Chen #define INSN_POP_TYPE_MASK 0x08 55*d0df954bSJoseph Chen #define INSN_POP_COUNT_MASK 0x07 56*d0df954bSJoseph Chen #define INSN_VSP_LARGE_INC_MASK 0xff 57*d0df954bSJoseph Chen 58*d0df954bSJoseph Chen /* Instruction definitions */ 59*d0df954bSJoseph Chen #define INSN_VSP_INC 0x00 60*d0df954bSJoseph Chen #define INSN_VSP_DEC 0x40 61*d0df954bSJoseph Chen #define INSN_POP_MASKED 0x80 62*d0df954bSJoseph Chen #define INSN_VSP_REG 0x90 63*d0df954bSJoseph Chen #define INSN_POP_COUNT 0xa0 64*d0df954bSJoseph Chen #define INSN_FINISH 0xb0 65*d0df954bSJoseph Chen #define INSN_POP_REGS 0xb1 66*d0df954bSJoseph Chen #define INSN_VSP_LARGE_INC 0xb2 67*d0df954bSJoseph Chen 68*d0df954bSJoseph Chen #define SHIFT_U32(v, shift) ((uint32_t)(v) << (shift)) 69*d0df954bSJoseph Chen 70*d0df954bSJoseph Chen /* The state of the unwind process (32-bit mode) */ 71*d0df954bSJoseph Chen struct unwind_state_arm32 { 72*d0df954bSJoseph Chen uint32_t registers[16]; 73*d0df954bSJoseph Chen uint32_t start_pc; 74*d0df954bSJoseph Chen ulong insn; 75*d0df954bSJoseph Chen unsigned int entries; 76*d0df954bSJoseph Chen unsigned int byte; 77*d0df954bSJoseph Chen uint16_t update_mask; 78*d0df954bSJoseph Chen }; 79*d0df954bSJoseph Chen 80*d0df954bSJoseph Chen /* An item in the exception index table */ 81*d0df954bSJoseph Chen struct unwind_idx { 82*d0df954bSJoseph Chen uint32_t offset; 83*d0df954bSJoseph Chen uint32_t insn; 84*d0df954bSJoseph Chen }; 85*d0df954bSJoseph Chen 86*d0df954bSJoseph Chen static __always_inline uint32_t read_pc(void) 87*d0df954bSJoseph Chen { 88*d0df954bSJoseph Chen uint32_t val; 89*d0df954bSJoseph Chen 90*d0df954bSJoseph Chen asm volatile ("adr %0, ." : "=r" (val)); 91*d0df954bSJoseph Chen return val; 92*d0df954bSJoseph Chen } 93*d0df954bSJoseph Chen 94*d0df954bSJoseph Chen static __always_inline uint32_t read_sp(void) 95*d0df954bSJoseph Chen { 96*d0df954bSJoseph Chen uint32_t val; 97*d0df954bSJoseph Chen 98*d0df954bSJoseph Chen asm volatile ("mov %0, sp" : "=r" (val)); 99*d0df954bSJoseph Chen return val; 100*d0df954bSJoseph Chen } 101*d0df954bSJoseph Chen 102*d0df954bSJoseph Chen static __always_inline uint32_t read_lr(void) 103*d0df954bSJoseph Chen { 104*d0df954bSJoseph Chen uint32_t val; 105*d0df954bSJoseph Chen 106*d0df954bSJoseph Chen asm volatile ("mov %0, lr" : "=r" (val)); 107*d0df954bSJoseph Chen return val; 108*d0df954bSJoseph Chen } 109*d0df954bSJoseph Chen 110*d0df954bSJoseph Chen static __always_inline uint32_t read_fp(void) 111*d0df954bSJoseph Chen { 112*d0df954bSJoseph Chen uint32_t val; 113*d0df954bSJoseph Chen 114*d0df954bSJoseph Chen asm volatile ("mov %0, fp" : "=r" (val)); 115*d0df954bSJoseph Chen return val; 116*d0df954bSJoseph Chen } 117*d0df954bSJoseph Chen 118*d0df954bSJoseph Chen static __always_inline uint32_t read_r7(void) 119*d0df954bSJoseph Chen { 120*d0df954bSJoseph Chen uint32_t val; 121*d0df954bSJoseph Chen 122*d0df954bSJoseph Chen asm volatile ("mov %0, r7" : "=r" (val)); 123*d0df954bSJoseph Chen return val; 124*d0df954bSJoseph Chen } 125*d0df954bSJoseph Chen 126*d0df954bSJoseph Chen static bool copy_in(void *dst, const void *src, size_t n, bool kernel_data) 127*d0df954bSJoseph Chen { 128*d0df954bSJoseph Chen if (!kernel_data) 129*d0df954bSJoseph Chen return false; 130*d0df954bSJoseph Chen 131*d0df954bSJoseph Chen memcpy(dst, src, n); 132*d0df954bSJoseph Chen 133*d0df954bSJoseph Chen return true; 134*d0df954bSJoseph Chen } 135*d0df954bSJoseph Chen 136*d0df954bSJoseph Chen /* Expand a 31-bit signed value to a 32-bit signed value */ 137*d0df954bSJoseph Chen static int32_t expand_prel31(uint32_t prel31) 138*d0df954bSJoseph Chen { 139*d0df954bSJoseph Chen return prel31 | SHIFT_U32(prel31 & BIT(30), 1); 140*d0df954bSJoseph Chen } 141*d0df954bSJoseph Chen 142*d0df954bSJoseph Chen /* 143*d0df954bSJoseph Chen * Perform a binary search of the index table to find the function 144*d0df954bSJoseph Chen * with the largest address that doesn't exceed addr. 145*d0df954bSJoseph Chen */ 146*d0df954bSJoseph Chen static struct unwind_idx *find_index(uint32_t addr, ulong exidx, 147*d0df954bSJoseph Chen size_t exidx_sz) 148*d0df954bSJoseph Chen { 149*d0df954bSJoseph Chen ulong idx_start, idx_end; 150*d0df954bSJoseph Chen unsigned int min, mid, max; 151*d0df954bSJoseph Chen struct unwind_idx *start; 152*d0df954bSJoseph Chen struct unwind_idx *item; 153*d0df954bSJoseph Chen int32_t prel31_addr; 154*d0df954bSJoseph Chen ulong func_addr; 155*d0df954bSJoseph Chen 156*d0df954bSJoseph Chen start = (struct unwind_idx *)exidx; 157*d0df954bSJoseph Chen idx_start = exidx; 158*d0df954bSJoseph Chen idx_end = exidx + exidx_sz; 159*d0df954bSJoseph Chen 160*d0df954bSJoseph Chen min = 0; 161*d0df954bSJoseph Chen max = (idx_end - idx_start) / sizeof(struct unwind_idx); 162*d0df954bSJoseph Chen 163*d0df954bSJoseph Chen while (min != max) { 164*d0df954bSJoseph Chen mid = min + (max - min + 1) / 2; 165*d0df954bSJoseph Chen 166*d0df954bSJoseph Chen item = &start[mid]; 167*d0df954bSJoseph Chen 168*d0df954bSJoseph Chen prel31_addr = expand_prel31(item->offset); 169*d0df954bSJoseph Chen func_addr = (ulong)&item->offset + prel31_addr; 170*d0df954bSJoseph Chen 171*d0df954bSJoseph Chen if (func_addr <= addr) { 172*d0df954bSJoseph Chen min = mid; 173*d0df954bSJoseph Chen } else { 174*d0df954bSJoseph Chen max = mid - 1; 175*d0df954bSJoseph Chen } 176*d0df954bSJoseph Chen } 177*d0df954bSJoseph Chen 178*d0df954bSJoseph Chen return &start[min]; 179*d0df954bSJoseph Chen } 180*d0df954bSJoseph Chen 181*d0df954bSJoseph Chen /* Reads the next byte from the instruction list */ 182*d0df954bSJoseph Chen static bool unwind_exec_read_byte(struct unwind_state_arm32 *state, 183*d0df954bSJoseph Chen uint32_t *ret_insn, bool kernel_stack) 184*d0df954bSJoseph Chen { 185*d0df954bSJoseph Chen uint32_t insn; 186*d0df954bSJoseph Chen 187*d0df954bSJoseph Chen if (!copy_in(&insn, (void *)state->insn, sizeof(insn), kernel_stack)) 188*d0df954bSJoseph Chen return false; 189*d0df954bSJoseph Chen 190*d0df954bSJoseph Chen /* Read the unwind instruction */ 191*d0df954bSJoseph Chen *ret_insn = (insn >> (state->byte * 8)) & 0xff; 192*d0df954bSJoseph Chen 193*d0df954bSJoseph Chen /* Update the location of the next instruction */ 194*d0df954bSJoseph Chen if (state->byte == 0) { 195*d0df954bSJoseph Chen state->byte = 3; 196*d0df954bSJoseph Chen state->insn += sizeof(uint32_t); 197*d0df954bSJoseph Chen state->entries--; 198*d0df954bSJoseph Chen } else { 199*d0df954bSJoseph Chen state->byte--; 200*d0df954bSJoseph Chen } 201*d0df954bSJoseph Chen 202*d0df954bSJoseph Chen return true; 203*d0df954bSJoseph Chen } 204*d0df954bSJoseph Chen 205*d0df954bSJoseph Chen static bool pop_vsp(uint32_t *reg, ulong *vsp, bool kernel_stack, 206*d0df954bSJoseph Chen ulong stack, size_t stack_size) 207*d0df954bSJoseph Chen { 208*d0df954bSJoseph Chen if (*vsp > gd->start_addr_sp || 209*d0df954bSJoseph Chen *vsp < gd->start_addr_sp - CONFIG_SYS_STACK_SIZE) 210*d0df954bSJoseph Chen return false; 211*d0df954bSJoseph Chen 212*d0df954bSJoseph Chen if (!copy_in(reg, (void *)*vsp, sizeof(*reg), kernel_stack)) 213*d0df954bSJoseph Chen return false; 214*d0df954bSJoseph Chen 215*d0df954bSJoseph Chen (*vsp) += sizeof(*reg); 216*d0df954bSJoseph Chen 217*d0df954bSJoseph Chen return true; 218*d0df954bSJoseph Chen } 219*d0df954bSJoseph Chen 220*d0df954bSJoseph Chen /* Executes the next instruction on the list */ 221*d0df954bSJoseph Chen static bool unwind_exec_insn(struct unwind_state_arm32 *state, 222*d0df954bSJoseph Chen bool kernel_stack, ulong stack, 223*d0df954bSJoseph Chen size_t stack_size) 224*d0df954bSJoseph Chen { 225*d0df954bSJoseph Chen uint32_t insn; 226*d0df954bSJoseph Chen ulong vsp = state->registers[SP]; 227*d0df954bSJoseph Chen int update_vsp = 0; 228*d0df954bSJoseph Chen 229*d0df954bSJoseph Chen /* Read the next instruction */ 230*d0df954bSJoseph Chen if (!unwind_exec_read_byte(state, &insn, kernel_stack)) 231*d0df954bSJoseph Chen return false; 232*d0df954bSJoseph Chen 233*d0df954bSJoseph Chen if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) { 234*d0df954bSJoseph Chen state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 235*d0df954bSJoseph Chen 236*d0df954bSJoseph Chen } else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) { 237*d0df954bSJoseph Chen state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 238*d0df954bSJoseph Chen 239*d0df954bSJoseph Chen } else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) { 240*d0df954bSJoseph Chen uint32_t mask; 241*d0df954bSJoseph Chen unsigned int reg; 242*d0df954bSJoseph Chen 243*d0df954bSJoseph Chen /* Load the mask */ 244*d0df954bSJoseph Chen if (!unwind_exec_read_byte(state, &mask, kernel_stack)) 245*d0df954bSJoseph Chen return false; 246*d0df954bSJoseph Chen mask |= (insn & INSN_STD_DATA_MASK) << 8; 247*d0df954bSJoseph Chen 248*d0df954bSJoseph Chen /* We have a refuse to unwind instruction */ 249*d0df954bSJoseph Chen if (mask == 0) 250*d0df954bSJoseph Chen return false; 251*d0df954bSJoseph Chen 252*d0df954bSJoseph Chen /* Update SP */ 253*d0df954bSJoseph Chen update_vsp = 1; 254*d0df954bSJoseph Chen 255*d0df954bSJoseph Chen /* Load the registers */ 256*d0df954bSJoseph Chen for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { 257*d0df954bSJoseph Chen if (mask & 1) { 258*d0df954bSJoseph Chen if (!pop_vsp(&state->registers[reg], &vsp, 259*d0df954bSJoseph Chen kernel_stack, stack, stack_size)) 260*d0df954bSJoseph Chen return false; 261*d0df954bSJoseph Chen state->update_mask |= 1 << reg; 262*d0df954bSJoseph Chen 263*d0df954bSJoseph Chen /* If we have updated SP kep its value */ 264*d0df954bSJoseph Chen if (reg == SP) 265*d0df954bSJoseph Chen update_vsp = 0; 266*d0df954bSJoseph Chen } 267*d0df954bSJoseph Chen } 268*d0df954bSJoseph Chen 269*d0df954bSJoseph Chen } else if ((insn & INSN_STD_MASK) == INSN_VSP_REG && 270*d0df954bSJoseph Chen ((insn & INSN_STD_DATA_MASK) != 13) && 271*d0df954bSJoseph Chen ((insn & INSN_STD_DATA_MASK) != 15)) { 272*d0df954bSJoseph Chen /* sp = register */ 273*d0df954bSJoseph Chen state->registers[SP] = 274*d0df954bSJoseph Chen state->registers[insn & INSN_STD_DATA_MASK]; 275*d0df954bSJoseph Chen 276*d0df954bSJoseph Chen } else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) { 277*d0df954bSJoseph Chen unsigned int count, reg; 278*d0df954bSJoseph Chen 279*d0df954bSJoseph Chen /* Read how many registers to load */ 280*d0df954bSJoseph Chen count = insn & INSN_POP_COUNT_MASK; 281*d0df954bSJoseph Chen 282*d0df954bSJoseph Chen /* Update sp */ 283*d0df954bSJoseph Chen update_vsp = 1; 284*d0df954bSJoseph Chen 285*d0df954bSJoseph Chen /* Pop the registers */ 286*d0df954bSJoseph Chen for (reg = 4; reg <= 4 + count; reg++) { 287*d0df954bSJoseph Chen if (!pop_vsp(&state->registers[reg], &vsp, 288*d0df954bSJoseph Chen kernel_stack, stack, stack_size)) 289*d0df954bSJoseph Chen return false; 290*d0df954bSJoseph Chen state->update_mask |= 1 << reg; 291*d0df954bSJoseph Chen } 292*d0df954bSJoseph Chen 293*d0df954bSJoseph Chen /* Check if we are in the pop r14 version */ 294*d0df954bSJoseph Chen if ((insn & INSN_POP_TYPE_MASK) != 0) { 295*d0df954bSJoseph Chen if (!pop_vsp(&state->registers[14], &vsp, kernel_stack, 296*d0df954bSJoseph Chen stack, stack_size)) 297*d0df954bSJoseph Chen return false; 298*d0df954bSJoseph Chen } 299*d0df954bSJoseph Chen 300*d0df954bSJoseph Chen } else if (insn == INSN_FINISH) { 301*d0df954bSJoseph Chen /* Stop processing */ 302*d0df954bSJoseph Chen state->entries = 0; 303*d0df954bSJoseph Chen 304*d0df954bSJoseph Chen } else if (insn == INSN_POP_REGS) { 305*d0df954bSJoseph Chen uint32_t mask; 306*d0df954bSJoseph Chen unsigned int reg; 307*d0df954bSJoseph Chen 308*d0df954bSJoseph Chen if (!unwind_exec_read_byte(state, &mask, kernel_stack)) 309*d0df954bSJoseph Chen return false; 310*d0df954bSJoseph Chen if (mask == 0 || (mask & 0xf0) != 0) 311*d0df954bSJoseph Chen return false; 312*d0df954bSJoseph Chen 313*d0df954bSJoseph Chen /* Update SP */ 314*d0df954bSJoseph Chen update_vsp = 1; 315*d0df954bSJoseph Chen 316*d0df954bSJoseph Chen /* Load the registers */ 317*d0df954bSJoseph Chen for (reg = 0; mask && reg < 4; mask >>= 1, reg++) { 318*d0df954bSJoseph Chen if (mask & 1) { 319*d0df954bSJoseph Chen if (!pop_vsp(&state->registers[reg], &vsp, 320*d0df954bSJoseph Chen kernel_stack, stack, stack_size)) 321*d0df954bSJoseph Chen return false; 322*d0df954bSJoseph Chen state->update_mask |= 1 << reg; 323*d0df954bSJoseph Chen } 324*d0df954bSJoseph Chen } 325*d0df954bSJoseph Chen 326*d0df954bSJoseph Chen } else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) { 327*d0df954bSJoseph Chen uint32_t uleb128; 328*d0df954bSJoseph Chen 329*d0df954bSJoseph Chen /* Read the increment value */ 330*d0df954bSJoseph Chen if (!unwind_exec_read_byte(state, &uleb128, kernel_stack)) 331*d0df954bSJoseph Chen return false; 332*d0df954bSJoseph Chen 333*d0df954bSJoseph Chen state->registers[SP] += 0x204 + (uleb128 << 2); 334*d0df954bSJoseph Chen 335*d0df954bSJoseph Chen } else { 336*d0df954bSJoseph Chen /* We hit a new instruction that needs to be implemented */ 337*d0df954bSJoseph Chen printf("Unhandled instruction %.2x\n", insn); 338*d0df954bSJoseph Chen return false; 339*d0df954bSJoseph Chen } 340*d0df954bSJoseph Chen 341*d0df954bSJoseph Chen if (update_vsp) 342*d0df954bSJoseph Chen state->registers[SP] = vsp; 343*d0df954bSJoseph Chen 344*d0df954bSJoseph Chen return true; 345*d0df954bSJoseph Chen } 346*d0df954bSJoseph Chen 347*d0df954bSJoseph Chen /* Performs the unwind of a function */ 348*d0df954bSJoseph Chen static bool unwind_tab(struct unwind_state_arm32 *state, bool kernel_stack, 349*d0df954bSJoseph Chen ulong stack, size_t stack_size) 350*d0df954bSJoseph Chen { 351*d0df954bSJoseph Chen uint32_t entry; 352*d0df954bSJoseph Chen uint32_t insn; 353*d0df954bSJoseph Chen 354*d0df954bSJoseph Chen /* Set PC to a known value */ 355*d0df954bSJoseph Chen state->registers[PC] = 0; 356*d0df954bSJoseph Chen 357*d0df954bSJoseph Chen if (!copy_in(&insn, (void *)state->insn, sizeof(insn), kernel_stack)) { 358*d0df954bSJoseph Chen printf("Bad insn addr %p", (void *)state->insn); 359*d0df954bSJoseph Chen return true; 360*d0df954bSJoseph Chen } 361*d0df954bSJoseph Chen 362*d0df954bSJoseph Chen /* Read the personality */ 363*d0df954bSJoseph Chen entry = insn & ENTRY_MASK; 364*d0df954bSJoseph Chen 365*d0df954bSJoseph Chen if (entry == ENTRY_ARM_SU16) { 366*d0df954bSJoseph Chen state->byte = 2; 367*d0df954bSJoseph Chen state->entries = 1; 368*d0df954bSJoseph Chen } else if (entry == ENTRY_ARM_LU16) { 369*d0df954bSJoseph Chen state->byte = 1; 370*d0df954bSJoseph Chen state->entries = ((insn >> 16) & 0xFF) + 1; 371*d0df954bSJoseph Chen } else { 372*d0df954bSJoseph Chen printf("Unknown entry: %x\n", entry); 373*d0df954bSJoseph Chen return true; 374*d0df954bSJoseph Chen } 375*d0df954bSJoseph Chen 376*d0df954bSJoseph Chen while (state->entries > 0) { 377*d0df954bSJoseph Chen if (!unwind_exec_insn(state, kernel_stack, stack, stack_size)) 378*d0df954bSJoseph Chen return true; 379*d0df954bSJoseph Chen } 380*d0df954bSJoseph Chen 381*d0df954bSJoseph Chen /* 382*d0df954bSJoseph Chen * The program counter was not updated, load it from the link register. 383*d0df954bSJoseph Chen */ 384*d0df954bSJoseph Chen if (state->registers[PC] == 0) { 385*d0df954bSJoseph Chen state->registers[PC] = state->registers[LR]; 386*d0df954bSJoseph Chen 387*d0df954bSJoseph Chen /* 388*d0df954bSJoseph Chen * If the program counter changed, flag it in the update mask. 389*d0df954bSJoseph Chen */ 390*d0df954bSJoseph Chen if (state->start_pc != state->registers[PC]) 391*d0df954bSJoseph Chen state->update_mask |= 1 << PC; 392*d0df954bSJoseph Chen 393*d0df954bSJoseph Chen /* Check again */ 394*d0df954bSJoseph Chen if (state->registers[PC] == 0) 395*d0df954bSJoseph Chen return true; 396*d0df954bSJoseph Chen } 397*d0df954bSJoseph Chen 398*d0df954bSJoseph Chen return false; 399*d0df954bSJoseph Chen } 400*d0df954bSJoseph Chen 401*d0df954bSJoseph Chen bool unwind_stack_arm32(struct unwind_state_arm32 *state, ulong exidx, 402*d0df954bSJoseph Chen size_t exidx_sz, bool kernel_stack, ulong stack, 403*d0df954bSJoseph Chen size_t stack_size) 404*d0df954bSJoseph Chen { 405*d0df954bSJoseph Chen struct unwind_idx *index; 406*d0df954bSJoseph Chen bool finished; 407*d0df954bSJoseph Chen 408*d0df954bSJoseph Chen if (!exidx_sz) 409*d0df954bSJoseph Chen return false; 410*d0df954bSJoseph Chen 411*d0df954bSJoseph Chen /* Reset the mask of updated registers */ 412*d0df954bSJoseph Chen state->update_mask = 0; 413*d0df954bSJoseph Chen 414*d0df954bSJoseph Chen /* The pc value is correct and will be overwritten, save it */ 415*d0df954bSJoseph Chen state->start_pc = state->registers[PC]; 416*d0df954bSJoseph Chen 417*d0df954bSJoseph Chen /* Find the item to run */ 418*d0df954bSJoseph Chen index = find_index(state->start_pc, exidx, exidx_sz); 419*d0df954bSJoseph Chen 420*d0df954bSJoseph Chen finished = false; 421*d0df954bSJoseph Chen if (index->insn != EXIDX_CANTUNWIND) { 422*d0df954bSJoseph Chen if (index->insn & (1U << 31)) { 423*d0df954bSJoseph Chen /* The data is within the instruction */ 424*d0df954bSJoseph Chen state->insn = (ulong)&index->insn; 425*d0df954bSJoseph Chen } else { 426*d0df954bSJoseph Chen /* A prel31 offset to the unwind table */ 427*d0df954bSJoseph Chen state->insn = (ulong)&index->insn + 428*d0df954bSJoseph Chen expand_prel31(index->insn); 429*d0df954bSJoseph Chen } 430*d0df954bSJoseph Chen 431*d0df954bSJoseph Chen /* Run the unwind function */ 432*d0df954bSJoseph Chen finished = unwind_tab(state, kernel_stack, stack, stack_size); 433*d0df954bSJoseph Chen } 434*d0df954bSJoseph Chen 435*d0df954bSJoseph Chen /* This is the top of the stack, finish */ 436*d0df954bSJoseph Chen if (index->insn == EXIDX_CANTUNWIND) 437*d0df954bSJoseph Chen finished = true; 438*d0df954bSJoseph Chen 439*d0df954bSJoseph Chen return !finished; 440*d0df954bSJoseph Chen } 441*d0df954bSJoseph Chen 442*d0df954bSJoseph Chen static uint32_t offset_prel31(uint32_t addr, int32_t offset) 443*d0df954bSJoseph Chen { 444*d0df954bSJoseph Chen return (addr + offset) & 0x7FFFFFFFUL; 445*d0df954bSJoseph Chen } 446*d0df954bSJoseph Chen 447*d0df954bSJoseph Chen int relocate_exidx(void *exidx, size_t exidx_sz, int32_t offset) 448*d0df954bSJoseph Chen { 449*d0df954bSJoseph Chen size_t num_items = exidx_sz / sizeof(struct unwind_idx); 450*d0df954bSJoseph Chen struct unwind_idx *start = (struct unwind_idx *)exidx; 451*d0df954bSJoseph Chen size_t n; 452*d0df954bSJoseph Chen 453*d0df954bSJoseph Chen for (n = 0; n < num_items; n++) { 454*d0df954bSJoseph Chen struct unwind_idx *item = &start[n]; 455*d0df954bSJoseph Chen 456*d0df954bSJoseph Chen if (item->offset & BIT(31)) 457*d0df954bSJoseph Chen return -EINVAL; 458*d0df954bSJoseph Chen 459*d0df954bSJoseph Chen /* Offset to the start of the function has to be adjusted */ 460*d0df954bSJoseph Chen item->offset = offset_prel31(item->offset, offset); 461*d0df954bSJoseph Chen 462*d0df954bSJoseph Chen if (item->insn == EXIDX_CANTUNWIND) 463*d0df954bSJoseph Chen continue; 464*d0df954bSJoseph Chen if (item->insn & BIT(31)) { 465*d0df954bSJoseph Chen /* insn is a table entry itself */ 466*d0df954bSJoseph Chen continue; 467*d0df954bSJoseph Chen } 468*d0df954bSJoseph Chen /* 469*d0df954bSJoseph Chen * insn is an offset to an entry in .ARM.extab so it has to be 470*d0df954bSJoseph Chen * adjusted 471*d0df954bSJoseph Chen */ 472*d0df954bSJoseph Chen item->insn = offset_prel31(item->insn, offset); 473*d0df954bSJoseph Chen } 474*d0df954bSJoseph Chen return 0; 475*d0df954bSJoseph Chen } 476*d0df954bSJoseph Chen 477*d0df954bSJoseph Chen void print_stack_arm32(struct unwind_state_arm32 *state, 478*d0df954bSJoseph Chen ulong exidx, size_t exidx_sz, bool kernel_stack, 479*d0df954bSJoseph Chen ulong stack, size_t stack_size) 480*d0df954bSJoseph Chen { 481*d0df954bSJoseph Chen ulong pc, lr; 482*d0df954bSJoseph Chen 483*d0df954bSJoseph Chen if (gd->flags & GD_FLG_RELOC) { 484*d0df954bSJoseph Chen pc = (ulong)state->registers[PC] - gd->reloc_off; 485*d0df954bSJoseph Chen lr = (ulong)state->registers[LR] - gd->reloc_off; 486*d0df954bSJoseph Chen } else { 487*d0df954bSJoseph Chen pc = (ulong)state->registers[PC]; 488*d0df954bSJoseph Chen lr = (ulong)state->registers[LR]; 489*d0df954bSJoseph Chen } 490*d0df954bSJoseph Chen 491*d0df954bSJoseph Chen printf("\nCall trace:\n"); 492*d0df954bSJoseph Chen printf(" PC: [< %08lx >]\n", pc); 493*d0df954bSJoseph Chen printf(" LR: [< %08lx >]\n", lr); 494*d0df954bSJoseph Chen 495*d0df954bSJoseph Chen printf("\nStack:\n"); 496*d0df954bSJoseph Chen do { 497*d0df954bSJoseph Chen if (gd->flags & GD_FLG_RELOC) 498*d0df954bSJoseph Chen pc = (ulong)state->registers[PC] - gd->reloc_off; 499*d0df954bSJoseph Chen else 500*d0df954bSJoseph Chen pc = (ulong)state->registers[PC]; 501*d0df954bSJoseph Chen 502*d0df954bSJoseph Chen printf(" [< %08lx >]\n", pc); 503*d0df954bSJoseph Chen } while (unwind_stack_arm32(state, exidx, exidx_sz, 504*d0df954bSJoseph Chen kernel_stack, stack, stack_size)); 505*d0df954bSJoseph Chen 506*d0df954bSJoseph Chen printf("\nNOTE: Please use ./scripts/stacktrace.sh to parse trace info\n"); 507*d0df954bSJoseph Chen } 508*d0df954bSJoseph Chen 509*d0df954bSJoseph Chen void dump_core_stack(struct pt_regs *regs) 510*d0df954bSJoseph Chen { 511*d0df954bSJoseph Chen struct unwind_state_arm32 state; 512*d0df954bSJoseph Chen ulong exidx = (ulong)__exidx_start; 513*d0df954bSJoseph Chen size_t exidx_sz = (ulong)__exidx_end - (ulong)__exidx_start; 514*d0df954bSJoseph Chen ulong stack = gd->start_addr_sp; 515*d0df954bSJoseph Chen size_t stack_size = CONFIG_SYS_STACK_SIZE; 516*d0df954bSJoseph Chen int i; 517*d0df954bSJoseph Chen 518*d0df954bSJoseph Chen /* Don't use memset(), which updates LR ! */ 519*d0df954bSJoseph Chen for (i = 0; i < 16; i++) 520*d0df954bSJoseph Chen state.registers[i] = 0; 521*d0df954bSJoseph Chen state.update_mask = 0; 522*d0df954bSJoseph Chen state.start_pc = 0; 523*d0df954bSJoseph Chen state.entries = 0; 524*d0df954bSJoseph Chen state.insn = 0; 525*d0df954bSJoseph Chen state.byte = 0; 526*d0df954bSJoseph Chen 527*d0df954bSJoseph Chen /* r7: Thumb-style frame pointer */ 528*d0df954bSJoseph Chen state.registers[7] = regs->ARM_r7; 529*d0df954bSJoseph Chen /* r11: ARM-style frame pointer */ 530*d0df954bSJoseph Chen state.registers[FP] = regs->ARM_ip; 531*d0df954bSJoseph Chen state.registers[SP] = regs->ARM_sp; 532*d0df954bSJoseph Chen state.registers[LR] = regs->ARM_lr; 533*d0df954bSJoseph Chen state.registers[PC] = regs->ARM_pc; 534*d0df954bSJoseph Chen 535*d0df954bSJoseph Chen print_stack_arm32(&state, exidx, exidx_sz, 536*d0df954bSJoseph Chen true, stack, stack_size); 537*d0df954bSJoseph Chen } 538*d0df954bSJoseph Chen 539*d0df954bSJoseph Chen void dump_stack(void) 540*d0df954bSJoseph Chen { 541*d0df954bSJoseph Chen struct pt_regs regs; 542*d0df954bSJoseph Chen 543*d0df954bSJoseph Chen regs.ARM_r7 = read_r7(); 544*d0df954bSJoseph Chen regs.ARM_ip = read_fp(); 545*d0df954bSJoseph Chen regs.ARM_sp = read_sp(); 546*d0df954bSJoseph Chen regs.ARM_lr = read_lr(); 547*d0df954bSJoseph Chen regs.ARM_pc = (uint32_t)dump_stack; 548*d0df954bSJoseph Chen 549*d0df954bSJoseph Chen dump_core_stack(®s); 550*d0df954bSJoseph Chen } 551