1/* SPDX-License-Identifier: GPL-2.0 2 * 3 * arch/sh/lib/mcount.S 4 * 5 * Copyright (C) 2008, 2009 Paul Mundt 6 * Copyright (C) 2008, 2009 Matt Fleming 7 */ 8#include <asm/ftrace.h> 9#include <asm/thread_info.h> 10#include <asm/asm-offsets.h> 11 12#define MCOUNT_ENTER() \ 13 mov.l r4, @-r15; \ 14 mov.l r5, @-r15; \ 15 mov.l r6, @-r15; \ 16 mov.l r7, @-r15; \ 17 sts.l pr, @-r15; \ 18 \ 19 mov.l @(20,r15),r4; \ 20 sts pr, r5 21 22#define MCOUNT_LEAVE() \ 23 lds.l @r15+, pr; \ 24 mov.l @r15+, r7; \ 25 mov.l @r15+, r6; \ 26 mov.l @r15+, r5; \ 27 rts; \ 28 mov.l @r15+, r4 29 30#ifdef CONFIG_STACK_DEBUG 31/* 32 * Perform diagnostic checks on the state of the kernel stack. 33 * 34 * Check for stack overflow. If there is less than 1KB free 35 * then it has overflowed. 36 * 37 * Make sure the stack pointer contains a valid address. Valid 38 * addresses for kernel stacks are anywhere after the bss 39 * (after __bss_stop) and anywhere in init_thread_union (init_stack). 40 */ 41#define STACK_CHECK() \ 42 mov #(THREAD_SIZE >> 10), r0; \ 43 shll8 r0; \ 44 shll2 r0; \ 45 \ 46 /* r1 = sp & (THREAD_SIZE - 1) */ \ 47 mov #-1, r1; \ 48 add r0, r1; \ 49 and r15, r1; \ 50 \ 51 mov #TI_SIZE, r3; \ 52 mov #(STACK_WARN >> 8), r2; \ 53 shll8 r2; \ 54 add r3, r2; \ 55 \ 56 /* Is the stack overflowing? */ \ 57 cmp/hi r2, r1; \ 58 bf stack_panic; \ 59 \ 60 /* If sp > __bss_stop then we're OK. */ \ 61 mov.l .L_ebss, r1; \ 62 cmp/hi r1, r15; \ 63 bt 1f; \ 64 \ 65 /* If sp < init_stack, we're not OK. */ \ 66 mov.l .L_init_thread_union, r1; \ 67 cmp/hs r1, r15; \ 68 bf stack_panic; \ 69 \ 70 /* If sp > init_stack && sp < __bss_stop, not OK. */ \ 71 add r0, r1; \ 72 cmp/hs r1, r15; \ 73 bt stack_panic; \ 741: 75#else 76#define STACK_CHECK() 77#endif /* CONFIG_STACK_DEBUG */ 78 79 .align 2 80 .globl _mcount 81 .type _mcount,@function 82 .globl mcount 83 .type mcount,@function 84_mcount: 85mcount: 86 STACK_CHECK() 87 88#ifndef CONFIG_FUNCTION_TRACER 89 rts 90 nop 91#else 92 MCOUNT_ENTER() 93 94#ifdef CONFIG_DYNAMIC_FTRACE 95 .globl mcount_call 96mcount_call: 97 mov.l .Lftrace_stub, r6 98#else 99 mov.l .Lftrace_trace_function, r6 100 mov.l ftrace_stub, r7 101 cmp/eq r6, r7 102 bt skip_trace 103 mov.l @r6, r6 104#endif 105 106 jsr @r6 107 nop 108 109#ifdef CONFIG_FUNCTION_GRAPH_TRACER 110 mov.l .Lftrace_graph_return, r6 111 mov.l .Lftrace_stub, r7 112 cmp/eq r6, r7 113 bt 1f 114 115 mov.l .Lftrace_graph_caller, r0 116 jmp @r0 117 nop 118 1191: 120 mov.l .Lftrace_graph_entry, r6 121 mov.l .Lftrace_graph_entry_stub, r7 122 cmp/eq r6, r7 123 bt skip_trace 124 125 mov.l .Lftrace_graph_caller, r0 126 jmp @r0 127 nop 128 129 .align 2 130.Lftrace_graph_return: 131 .long ftrace_graph_return 132.Lftrace_graph_entry: 133 .long ftrace_graph_entry 134.Lftrace_graph_entry_stub: 135 .long ftrace_graph_entry_stub 136.Lftrace_graph_caller: 137 .long ftrace_graph_caller 138#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 139 140 .globl skip_trace 141skip_trace: 142 MCOUNT_LEAVE() 143 144 .align 2 145.Lftrace_trace_function: 146 .long ftrace_trace_function 147 148#ifdef CONFIG_DYNAMIC_FTRACE 149#ifdef CONFIG_FUNCTION_GRAPH_TRACER 150/* 151 * NOTE: Do not move either ftrace_graph_call or ftrace_caller 152 * as this will affect the calculation of GRAPH_INSN_OFFSET. 153 */ 154 .globl ftrace_graph_call 155ftrace_graph_call: 156 mov.l .Lskip_trace, r0 157 jmp @r0 158 nop 159 160 .align 2 161.Lskip_trace: 162 .long skip_trace 163#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 164 165 .globl ftrace_caller 166ftrace_caller: 167 MCOUNT_ENTER() 168 169 .globl ftrace_call 170ftrace_call: 171 mov.l .Lftrace_stub, r6 172 jsr @r6 173 nop 174 175#ifdef CONFIG_FUNCTION_GRAPH_TRACER 176 bra ftrace_graph_call 177 nop 178#else 179 MCOUNT_LEAVE() 180#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 181#endif /* CONFIG_DYNAMIC_FTRACE */ 182 183 .align 2 184 185/* 186 * NOTE: From here on the locations of the .Lftrace_stub label and 187 * ftrace_stub itself are fixed. Adding additional data here will skew 188 * the displacement for the memory table and break the block replacement. 189 * Place new labels either after the ftrace_stub body, or before 190 * ftrace_caller. You have been warned. 191 */ 192.Lftrace_stub: 193 .long ftrace_stub 194 195 .globl ftrace_stub 196ftrace_stub: 197 rts 198 nop 199 200#ifdef CONFIG_FUNCTION_GRAPH_TRACER 201 .globl ftrace_graph_caller 202ftrace_graph_caller: 203 mov.l 2f, r1 204 jmp @r1 205 nop 2061: 207 /* 208 * MCOUNT_ENTER() pushed 5 registers onto the stack, so 209 * the stack address containing our return address is 210 * r15 + 20. 211 */ 212 mov #20, r0 213 add r15, r0 214 mov r0, r4 215 216 mov.l .Lprepare_ftrace_return, r0 217 jsr @r0 218 nop 219 220 MCOUNT_LEAVE() 221 222 .align 2 2232: .long skip_trace 224.Lprepare_ftrace_return: 225 .long prepare_ftrace_return 226 227 .globl return_to_handler 228return_to_handler: 229 /* 230 * Save the return values. 231 */ 232 mov.l r0, @-r15 233 mov.l r1, @-r15 234 235 mov #0, r4 236 237 mov.l .Lftrace_return_to_handler, r0 238 jsr @r0 239 nop 240 241 /* 242 * The return value from ftrace_return_handler has the real 243 * address that we should return to. 244 */ 245 lds r0, pr 246 mov.l @r15+, r1 247 rts 248 mov.l @r15+, r0 249 250 251 .align 2 252.Lftrace_return_to_handler: 253 .long ftrace_return_to_handler 254#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 255#endif /* CONFIG_FUNCTION_TRACER */ 256 257#ifdef CONFIG_STACK_DEBUG 258 .globl stack_panic 259stack_panic: 260 mov.l .Ldump_stack, r0 261 jsr @r0 262 nop 263 264 mov.l .Lpanic, r0 265 jsr @r0 266 mov.l .Lpanic_s, r4 267 268 rts 269 nop 270 271 .align 2 272.L_init_thread_union: 273 .long init_thread_union 274.L_ebss: 275 .long __bss_stop 276.Lpanic: 277 .long panic 278.Lpanic_s: 279 .long .Lpanic_str 280.Ldump_stack: 281 .long dump_stack 282 283 .section .rodata 284 .align 2 285.Lpanic_str: 286 .string "Stack error" 287#endif /* CONFIG_STACK_DEBUG */ 288