1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * linux/arch/unicore32/lib/backtrace.S 4 * 5 * Code specific to PKUnity SoC and UniCore ISA 6 * 7 * Copyright (C) 2001-2010 GUAN Xue-tao 8 */ 9#include <linux/linkage.h> 10#include <asm/assembler.h> 11 .text 12 13@ fp is 0 or stack frame 14 15#define frame v4 16#define sv_fp v5 17#define sv_pc v6 18#define offset v8 19 20ENTRY(__backtrace) 21 mov r0, fp 22 23ENTRY(c_backtrace) 24 25#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) 26 mov pc, lr 27ENDPROC(__backtrace) 28ENDPROC(c_backtrace) 29#else 30 stm.w (v4 - v8, lr), [sp-] @ Save an extra register 31 @ so we have a location... 32 mov.a frame, r0 @ if frame pointer is zero 33 beq no_frame @ we have no stack frames 34 351: stm.w (pc), [sp-] @ calculate offset of PC stored 36 ldw.w r0, [sp]+, #4 @ by stmfd for this CPU 37 adr r1, 1b 38 sub offset, r0, r1 39 40/* 41 * Stack frame layout: 42 * optionally saved caller registers (r4 - r10) 43 * saved fp 44 * saved sp 45 * saved lr 46 * frame => saved pc 47 * optionally saved arguments (r0 - r3) 48 * saved sp => <next word> 49 * 50 * Functions start with the following code sequence: 51 * mov ip, sp 52 * stm.w (r0 - r3), [sp-] (optional) 53 * corrected pc => stm.w sp, (..., fp, ip, lr, pc) 54 */ 55for_each_frame: 56 571001: ldw sv_pc, [frame+], #0 @ get saved pc 581002: ldw sv_fp, [frame+], #-12 @ get saved fp 59 60 sub sv_pc, sv_pc, offset @ Correct PC for prefetching 61 621003: ldw r2, [sv_pc+], #-4 @ if stmfd sp, {args} exists, 63 ldw r3, .Ldsi+4 @ adjust saved 'pc' back one 64 cxor.a r3, r2 >> #14 @ instruction 65 beq 201f 66 sub r0, sv_pc, #4 @ allow for mov 67 b 202f 68201: 69 sub r0, sv_pc, #8 @ allow for mov + stmia 70202: 71 ldw r1, [frame+], #-4 @ get saved lr 72 mov r2, frame 73 b.l dump_backtrace_entry 74 75 ldw r1, [sv_pc+], #-4 @ if stmfd sp, {args} exists, 76 ldw r3, .Ldsi+4 77 cxor.a r3, r1 >> #14 78 bne 1004f 79 ldw r0, [frame+], #-8 @ get sp 80 sub r0, r0, #4 @ point at the last arg 81 b.l .Ldumpstm @ dump saved registers 82 831004: ldw r1, [sv_pc+], #0 @ if stmfd {, fp, ip, lr, pc} 84 ldw r3, .Ldsi @ instruction exists, 85 cxor.a r3, r1 >> #14 86 bne 201f 87 sub r0, frame, #16 88 b.l .Ldumpstm @ dump saved registers 89201: 90 cxor.a sv_fp, #0 @ zero saved fp means 91 beq no_frame @ no further frames 92 93 csub.a sv_fp, frame @ next frame must be 94 mov frame, sv_fp @ above the current frame 95 bua for_each_frame 96 971006: adr r0, .Lbad 98 mov r1, frame 99 b.l printk 100no_frame: ldm.w (v4 - v8, pc), [sp]+ 101ENDPROC(__backtrace) 102ENDPROC(c_backtrace) 103 104 .pushsection __ex_table,"a" 105 .align 3 106 .long 1001b, 1006b 107 .long 1002b, 1006b 108 .long 1003b, 1006b 109 .long 1004b, 1006b 110 .popsection 111 112#define instr v4 113#define reg v5 114#define stack v6 115 116.Ldumpstm: stm.w (instr, reg, stack, v7, lr), [sp-] 117 mov stack, r0 118 mov instr, r1 119 mov reg, #14 120 mov v7, #0 1211: mov r3, #1 122 csub.a reg, #8 123 bne 201f 124 sub reg, reg, #3 125201: 126 cand.a instr, r3 << reg 127 beq 2f 128 add v7, v7, #1 129 cxor.a v7, #6 130 cmoveq v7, #1 131 cmoveq r1, #'\n' 132 cmovne r1, #' ' 133 ldw.w r3, [stack]+, #-4 134 mov r2, reg 135 csub.a r2, #8 136 bsl 201f 137 sub r2, r2, #3 138201: 139 cand.a instr, #0x40 @ if H is 1, high 16 regs 140 beq 201f 141 add r2, r2, #0x10 @ so r2 need add 16 142201: 143 adr r0, .Lfp 144 b.l printk 1452: sub.a reg, reg, #1 146 bns 1b 147 cxor.a v7, #0 148 beq 201f 149 adr r0, .Lcr 150 b.l printk 151201: ldm.w (instr, reg, stack, v7, pc), [sp]+ 152 153.Lfp: .asciz "%cr%d:%08x" 154.Lcr: .asciz "\n" 155.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" 156 .align 157.Ldsi: .word 0x92eec000 >> 14 @ stm.w sp, (... fp, ip, lr, pc) 158 .word 0x92e10000 >> 14 @ stm.w sp, () 159 160#endif 161