Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[pandora-kernel.git] / arch / sh / kernel / ftrace.c
index 4c32474..066f37d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Matt Fleming <mjf@gentoo.org>
+ * Copyright (C) 2008 Matt Fleming <matt@console-pimps.org>
  * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org>
  *
  * Code for replacing ftrace calls with jumps.
 #include <asm/ftrace.h>
 #include <asm/cacheflush.h>
 
-static unsigned char ftrace_nop[] = {
-       0x09, 0x00,             /* nop */
-       0x09, 0x00,             /* nop */
-};
-
 static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
 
-unsigned char *ftrace_nop_replace(void)
+static unsigned char ftrace_nop[4];
+/*
+ * If we're trying to nop out a call to a function, we instead
+ * place a call to the address after the memory table.
+ *
+ * 8c011060 <a>:
+ * 8c011060:       02 d1           mov.l   8c01106c <a+0xc>,r1
+ * 8c011062:       22 4f           sts.l   pr,@-r15
+ * 8c011064:       02 c7           mova    8c011070 <a+0x10>,r0
+ * 8c011066:       2b 41           jmp     @r1
+ * 8c011068:       2a 40           lds     r0,pr
+ * 8c01106a:       09 00           nop
+ * 8c01106c:       68 24           .word 0x2468     <--- ip
+ * 8c01106e:       1d 8c           .word 0x8c1d
+ * 8c011070:       26 4f           lds.l   @r15+,pr <--- ip + MCOUNT_INSN_SIZE
+ *
+ * We write 0x8c011070 to 0x8c01106c so that on entry to a() we branch
+ * past the _mcount call and continue executing code like normal.
+ */
+static unsigned char *ftrace_nop_replace(unsigned long ip)
 {
+       __raw_writel(ip + MCOUNT_INSN_SIZE, ftrace_nop);
        return ftrace_nop;
 }
 
-static int is_sh_nop(unsigned char *ip)
-{
-       return strncmp(ip, ftrace_nop, sizeof(ftrace_nop));
-}
-
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
 {
        /* Place the address in the memory table. */
-       if (addr == CALLER_ADDR)
-               __raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code);
-       else
-               __raw_writel(addr, ftrace_replaced_code);
+       __raw_writel(addr, ftrace_replaced_code);
 
        /*
         * No locking needed, this must be called via kstop_machine
@@ -51,7 +58,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
        return ftrace_replaced_code;
 }
 
-int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
+static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
                       unsigned char *new_code)
 {
        unsigned char replaced[MCOUNT_INSN_SIZE];
@@ -66,13 +73,6 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
         * kstop_machine, or before SMP starts.
         */
 
-       /*
-        * If we're trying to nop out a call to a function, we instead
-        * place a call to the address after the memory table.
-        */
-       if (is_sh_nop(new_code) == 0)
-               __raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code);
-
        /* read the text we want to modify */
        if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
                return -EFAULT;
@@ -92,13 +92,13 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-       unsigned long ip = (unsigned long)(&ftrace_call);
+       unsigned long ip = (unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET;
        unsigned char old[MCOUNT_INSN_SIZE], *new;
 
-       memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE);
+       memcpy(old, (unsigned char *)ip, MCOUNT_INSN_SIZE);
        new = ftrace_call_replace(ip, (unsigned long)func);
 
-       return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new);
+       return ftrace_modify_code(ip, old, new);
 }
 
 int ftrace_make_nop(struct module *mod,
@@ -108,7 +108,7 @@ int ftrace_make_nop(struct module *mod,
        unsigned long ip = rec->ip;
 
        old = ftrace_call_replace(ip, addr);
-       new = ftrace_nop_replace();
+       new = ftrace_nop_replace(ip);
 
        return ftrace_modify_code(rec->ip, old, new);
 }
@@ -118,7 +118,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        unsigned char *new, *old;
        unsigned long ip = rec->ip;
 
-       old = ftrace_nop_replace();
+       old = ftrace_nop_replace(ip);
        new = ftrace_call_replace(ip, addr);
 
        return ftrace_modify_code(rec->ip, old, new);