root/arch/microblaze/kernel/mcount.S
/*
 * Low-level ftrace handling
 *
 * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
 * Copyright (C) 2009 PetaLogix
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License. See the file COPYING in the main directory of this
 * archive for more details.
 */

#include <linux/linkage.h>

#define NOALIGN_ENTRY(name)     .globl name; name:

/* FIXME MS: I think that I don't need to save all regs */
#define SAVE_REGS               \
        addik   r1, r1, -120;   \
        swi     r2, r1, 4;      \
        swi     r3, r1, 8;      \
        swi     r4, r1, 12;     \
        swi     r5, r1, 116;    \
        swi     r6, r1, 16;     \
        swi     r7, r1, 20;     \
        swi     r8, r1, 24;     \
        swi     r9, r1, 28;     \
        swi     r10, r1, 32;    \
        swi     r11, r1, 36;    \
        swi     r12, r1, 40;    \
        swi     r13, r1, 44;    \
        swi     r14, r1, 48;    \
        swi     r16, r1, 52;    \
        swi     r17, r1, 56;    \
        swi     r18, r1, 60;    \
        swi     r19, r1, 64;    \
        swi     r20, r1, 68;    \
        swi     r21, r1, 72;    \
        swi     r22, r1, 76;    \
        swi     r23, r1, 80;    \
        swi     r24, r1, 84;    \
        swi     r25, r1, 88;    \
        swi     r26, r1, 92;    \
        swi     r27, r1, 96;    \
        swi     r28, r1, 100;   \
        swi     r29, r1, 104;   \
        swi     r30, r1, 108;   \
        swi     r31, r1, 112;

#define RESTORE_REGS            \
        lwi     r2, r1, 4;      \
        lwi     r3, r1, 8;      \
        lwi     r4, r1, 12;     \
        lwi     r5, r1, 116;    \
        lwi     r6, r1, 16;     \
        lwi     r7, r1, 20;     \
        lwi     r8, r1, 24;     \
        lwi     r9, r1, 28;     \
        lwi     r10, r1, 32;    \
        lwi     r11, r1, 36;    \
        lwi     r12, r1, 40;    \
        lwi     r13, r1, 44;    \
        lwi     r14, r1, 48;    \
        lwi     r16, r1, 52;    \
        lwi     r17, r1, 56;    \
        lwi     r18, r1, 60;    \
        lwi     r19, r1, 64;    \
        lwi     r20, r1, 68;    \
        lwi     r21, r1, 72;    \
        lwi     r22, r1, 76;    \
        lwi     r23, r1, 80;    \
        lwi     r24, r1, 84;    \
        lwi     r25, r1, 88;    \
        lwi     r26, r1, 92;    \
        lwi     r27, r1, 96;    \
        lwi     r28, r1, 100;   \
        lwi     r29, r1, 104;   \
        lwi     r30, r1, 108;   \
        lwi     r31, r1, 112;   \
        addik   r1, r1, 120;

ENTRY(ftrace_stub)
        rtsd    r15, 8;
        nop;

ENTRY(_mcount)
#ifdef CONFIG_DYNAMIC_FTRACE
ENTRY(ftrace_caller)
        /* MS: It is just barrier which is removed from C code */
        rtsd    r15, 8
        nop
#endif /* CONFIG_DYNAMIC_FTRACE */
        SAVE_REGS
        swi     r15, r1, 0;
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
#ifndef CONFIG_DYNAMIC_FTRACE
        lwi     r5, r0, ftrace_graph_return;
        addik   r6, r0, ftrace_stub; /* asm implementation */
        cmpu    r5, r5, r6; /* ftrace_graph_return != ftrace_stub */
        beqid   r5, end_graph_tracer;
        nop;

        lwi     r6, r0, ftrace_graph_entry;
        addik   r5, r0, ftrace_graph_entry_stub; /* implemented in C */
        cmpu    r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */
        beqid   r5, end_graph_tracer;
        nop;
#else /* CONFIG_DYNAMIC_FTRACE */
NOALIGN_ENTRY(ftrace_call_graph)
        /* MS: jump over graph function - replaced from C code */
        bri     end_graph_tracer
#endif /* CONFIG_DYNAMIC_FTRACE */
        addik   r5, r1, 120; /* MS: load parent addr */
        addik   r6, r15, 0; /* MS: load current function addr */
        bralid  r15, prepare_ftrace_return;
        nop;
        /* MS: graph was taken that's why - can jump over function trace */
        brid    end;
        nop;
end_graph_tracer:
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
#ifndef CONFIG_DYNAMIC_FTRACE
        /* MS: test function trace if is taken or not */
        lwi     r20, r0, ftrace_trace_function;
        addik   r6, r0, ftrace_stub;
        cmpu    r5, r20, r6; /* ftrace_trace_function != ftrace_stub */
        beqid   r5, end; /* MS: not taken -> jump over */
        nop;
#else /* CONFIG_DYNAMIC_FTRACE */
NOALIGN_ENTRY(ftrace_call)
/* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */
        nop
        nop
#endif /* CONFIG_DYNAMIC_FTRACE */
/* static normal trace */
        lwi     r6, r1, 120; /* MS: load parent addr */
        addik   r5, r15, -4; /* MS: load current function addr */
        /* MS: here is dependency on previous code */
        brald   r15, r20; /* MS: jump to ftrace handler */
        nop;
end:
        lwi     r15, r1, 0;
        RESTORE_REGS

        rtsd    r15, 8; /* MS: jump back */
        nop;

#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(return_to_handler)
        nop; /* MS: just barrier for rtsd r15, 8 */
        nop;
        SAVE_REGS
        swi     r15, r1, 0;

        /* MS: find out returning address */
        bralid  r15, ftrace_return_to_handler;
        nop;

        /* MS: return value from ftrace_return_to_handler is my returning addr
         * must be before restore regs because I have to restore r3 content */
        addik   r15, r3, 0;
        RESTORE_REGS

        rtsd    r15, 8; /* MS: jump back */
        nop;
#endif  /* CONFIG_FUNCTION_TRACER */