Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[cascardo/linux.git] / arch / mips / kernel / ftrace.c
index 8b65387..937c54b 100644 (file)
@@ -63,7 +63,7 @@ static inline int in_kernel_space(unsigned long ip)
        ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK)))
 
 static unsigned int insn_jal_ftrace_caller __read_mostly;
-static unsigned int insn_lui_v1_hi16_mcount __read_mostly;
+static unsigned int insn_la_mcount[2] __read_mostly;
 static unsigned int insn_j_ftrace_graph_caller __maybe_unused __read_mostly;
 
 static inline void ftrace_dyn_arch_init_insns(void)
@@ -71,10 +71,10 @@ static inline void ftrace_dyn_arch_init_insns(void)
        u32 *buf;
        unsigned int v1;
 
-       /* lui v1, hi16_mcount */
+       /* la v1, _mcount */
        v1 = 3;
-       buf = (u32 *)&insn_lui_v1_hi16_mcount;
-       UASM_i_LA_mostly(&buf, v1, MCOUNT_ADDR);
+       buf = (u32 *)&insn_la_mcount[0];
+       UASM_i_LA(&buf, v1, MCOUNT_ADDR);
 
        /* jal (ftrace_caller + 8), jump over the first two instruction */
        buf = (u32 *)&insn_jal_ftrace_caller;
@@ -111,14 +111,47 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
                                unsigned int new_code2)
 {
        int faulted;
+       mm_segment_t old_fs;
 
        safe_store_code(new_code1, ip, faulted);
        if (unlikely(faulted))
                return -EFAULT;
-       safe_store_code(new_code2, ip + 4, faulted);
+
+       ip += 4;
+       safe_store_code(new_code2, ip, faulted);
        if (unlikely(faulted))
                return -EFAULT;
+
+       ip -= 4;
+       old_fs = get_fs();
+       set_fs(get_ds());
        flush_icache_range(ip, ip + 8);
+       set_fs(old_fs);
+
+       return 0;
+}
+
+static int ftrace_modify_code_2r(unsigned long ip, unsigned int new_code1,
+                                unsigned int new_code2)
+{
+       int faulted;
+       mm_segment_t old_fs;
+
+       ip += 4;
+       safe_store_code(new_code2, ip, faulted);
+       if (unlikely(faulted))
+               return -EFAULT;
+
+       ip -= 4;
+       safe_store_code(new_code1, ip, faulted);
+       if (unlikely(faulted))
+               return -EFAULT;
+
+       old_fs = get_fs();
+       set_fs(get_ds());
+       flush_icache_range(ip, ip + 8);
+       set_fs(old_fs);
+
        return 0;
 }
 #endif
@@ -130,13 +163,14 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
  *
  * move at, ra
  * jal _mcount         --> nop
+ *  sub sp, sp, 8      --> nop  (CONFIG_32BIT)
  *
  * 2. For modules:
  *
  * 2.1 For KBUILD_MCOUNT_RA_ADDRESS and CONFIG_32BIT
  *
  * lui v1, hi_16bit_of_mcount       --> b 1f (0x10000005)
- * addiu v1, v1, low_16bit_of_mcount
+ * addiu v1, v1, low_16bit_of_mcount --> nop  (CONFIG_32BIT)
  * move at, ra
  * move $12, ra_address
  * jalr v1
@@ -145,7 +179,7 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
  * 2.2 For the Other situations
  *
  * lui v1, hi_16bit_of_mcount       --> b 1f (0x10000004)
- * addiu v1, v1, low_16bit_of_mcount
+ * addiu v1, v1, low_16bit_of_mcount --> nop  (CONFIG_32BIT)
  * move at, ra
  * jalr v1
  *  nop | move $12, ra_address | sub sp, sp, 8
@@ -184,10 +218,14 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        unsigned int new;
        unsigned long ip = rec->ip;
 
-       new = in_kernel_space(ip) ? insn_jal_ftrace_caller :
-               insn_lui_v1_hi16_mcount;
+       new = in_kernel_space(ip) ? insn_jal_ftrace_caller : insn_la_mcount[0];
 
+#ifdef CONFIG_64BIT
        return ftrace_modify_code(ip, new);
+#else
+       return ftrace_modify_code_2r(ip, new, in_kernel_space(ip) ?
+                                               INSN_NOP : insn_la_mcount[1]);
+#endif
 }
 
 #define FTRACE_CALL_IP ((unsigned long)(&ftrace_call))