linux/arch/blackfin/kernel/ftrace-entry.S
<<
>>
Prefs
   1/*
   2 * mcount and friends -- ftrace stuff
   3 *
   4 * Copyright (C) 2009 Analog Devices Inc.
   5 * Licensed under the GPL-2 or later.
   6 */
   7
   8#include <linux/linkage.h>
   9#include <asm/ftrace.h>
  10
  11.text
  12
  13/* GCC will have called us before setting up the function prologue, so we
  14 * can clobber the normal scratch registers, but we need to make sure to
  15 * save/restore the registers used for argument passing (R0-R2) in case
  16 * the profiled function is using them.  With data registers, R3 is the
  17 * only one we can blow away.  With pointer registers, we have P0-P2.
  18 *
  19 * Upon entry, the RETS will point to the top of the current profiled
  20 * function.  And since GCC pushed the previous RETS for us, the previous
  21 * function will be waiting there.  mmmm pie.
  22 */
  23ENTRY(__mcount)
  24        /* save third function arg early so we can do testing below */
  25        [--sp] = r2;
  26
  27        /* load the function pointer to the tracer */
  28        p0.l = _ftrace_trace_function;
  29        p0.h = _ftrace_trace_function;
  30        r3 = [p0];
  31
  32        /* optional micro optimization: don't call the stub tracer */
  33        r2.l = _ftrace_stub;
  34        r2.h = _ftrace_stub;
  35        cc = r2 == r3;
  36        if ! cc jump .Ldo_trace;
  37
  38#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  39        /* if the ftrace_graph_return function pointer is not set to
  40         * the ftrace_stub entry, call prepare_ftrace_return().
  41         */
  42        p0.l = _ftrace_graph_return;
  43        p0.h = _ftrace_graph_return;
  44        r3 = [p0];
  45        cc = r2 == r3;
  46        if ! cc jump _ftrace_graph_caller;
  47
  48        /* similarly, if the ftrace_graph_entry function pointer is not
  49         * set to the ftrace_graph_entry_stub entry, ...
  50         */
  51        p0.l = _ftrace_graph_entry;
  52        p0.h = _ftrace_graph_entry;
  53        r2.l = _ftrace_graph_entry_stub;
  54        r2.h = _ftrace_graph_entry_stub;
  55        r3 = [p0];
  56        cc = r2 == r3;
  57        if ! cc jump _ftrace_graph_caller;
  58#endif
  59
  60        r2 = [sp++];
  61        rts;
  62
  63.Ldo_trace:
  64
  65        /* save first/second function arg and the return register */
  66        [--sp] = r0;
  67        [--sp] = r1;
  68        [--sp] = rets;
  69
  70        /* setup the tracer function */
  71        p0 = r3;
  72
  73        /* function_trace_call(unsigned long ip, unsigned long parent_ip):
  74         *  ip: this point was called by ...
  75         *  parent_ip: ... this function
  76         * the ip itself will need adjusting for the mcount call
  77         */
  78        r0 = rets;
  79        r1 = [sp + 16]; /* skip the 4 local regs on stack */
  80        r0 += -MCOUNT_INSN_SIZE;
  81
  82        /* call the tracer */
  83        call (p0);
  84
  85        /* restore state and get out of dodge */
  86.Lfinish_trace:
  87        rets = [sp++];
  88        r1 = [sp++];
  89        r0 = [sp++];
  90        r2 = [sp++];
  91
  92.globl _ftrace_stub
  93_ftrace_stub:
  94        rts;
  95ENDPROC(__mcount)
  96
  97#ifdef CONFIG_FUNCTION_GRAPH_TRACER
  98/* The prepare_ftrace_return() function is similar to the trace function
  99 * except it takes a pointer to the location of the frompc.  This is so
 100 * the prepare_ftrace_return() can hijack it temporarily for probing
 101 * purposes.
 102 */
 103ENTRY(_ftrace_graph_caller)
 104        /* save first/second function arg and the return register */
 105        [--sp] = r0;
 106        [--sp] = r1;
 107        [--sp] = rets;
 108
 109        /* prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) */
 110        r0 = sp;
 111        r1 = rets;
 112        r0 += 16;       /* skip the 4 local regs on stack */
 113        r1 += -MCOUNT_INSN_SIZE;
 114        call _prepare_ftrace_return;
 115
 116        jump .Lfinish_trace;
 117ENDPROC(_ftrace_graph_caller)
 118
 119/* Undo the rewrite caused by ftrace_graph_caller().  The common function
 120 * ftrace_return_to_handler() will return the original rets so we can
 121 * restore it and be on our way.
 122 */
 123ENTRY(_return_to_handler)
 124        /* make sure original return values are saved */
 125        [--sp] = p0;
 126        [--sp] = r0;
 127        [--sp] = r1;
 128
 129        /* get original return address */
 130        call _ftrace_return_to_handler;
 131        rets = r0;
 132
 133        /* anomaly 05000371 - make sure we have at least three instructions
 134         * between rets setting and the return
 135         */
 136        r1 = [sp++];
 137        r0 = [sp++];
 138        p0 = [sp++];
 139        rts;
 140ENDPROC(_return_to_handler)
 141#endif
 142