Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / arch / unicore32 / lib / backtrace.S
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
20 ENTRY(__backtrace)
21                 mov     r0, fp
22
23 ENTRY(c_backtrace)
24
25 #if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
26                 mov     pc, lr
27 ENDPROC(__backtrace)
28 ENDPROC(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
35 1:              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  */
55 for_each_frame:
56
57 1001:           ldw     sv_pc, [frame+], #0     @ get saved pc
58 1002:           ldw     sv_fp, [frame+], #-12   @ get saved fp
59
60                 sub     sv_pc, sv_pc, offset    @ Correct PC for prefetching
61
62 1003:           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
68 201:
69                 sub     r0, sv_pc, #8           @ allow for mov + stmia
70 202:
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
83 1004:           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
89 201:
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
97 1006:           adr     r0, .Lbad
98                 mov     r1, frame
99                 b.l     printk
100 no_frame:       ldm.w   (v4 - v8, pc), [sp]+
101 ENDPROC(__backtrace)
102 ENDPROC(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
121 1:              mov     r3, #1
122                 csub.a  reg, #8
123                 bne     201f
124                 sub     reg, reg, #3
125 201:
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
138 201:
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
142 201:
143                 adr     r0, .Lfp
144                 b.l     printk
145 2:              sub.a   reg, reg, #1
146                 bns     1b
147                 cxor.a  v7, #0
148                 beq     201f
149                 adr     r0, .Lcr
150                 b.l     printk
151 201:            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