diff options
Diffstat (limited to 'arch/mips/kernel/ftrace.c')
| -rw-r--r-- | arch/mips/kernel/ftrace.c | 43 |
1 files changed, 22 insertions, 21 deletions
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 2625232bfe52..b15615b28569 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -37,10 +37,6 @@ void arch_ftrace_update_code(int command) ftrace_modify_all_code(command); } -#endif - -#ifdef CONFIG_DYNAMIC_FTRACE - #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ #define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */ #define JUMP_RANGE_MASK ((1UL << 28) - 1) @@ -58,10 +54,20 @@ static inline void ftrace_dyn_arch_init_insns(void) u32 *buf; unsigned int v1; - /* la v1, _mcount */ - v1 = 3; - buf = (u32 *)&insn_la_mcount[0]; - UASM_i_LA(&buf, v1, MCOUNT_ADDR); + /* If we are not in compat space, the number of generated + * instructions will exceed the maximum expected limit of 2. + * To prevent buffer overflow, we avoid generating them. + * insn_la_mcount will not be used later in ftrace_make_call. + */ + if (uasm_in_compat_space_p(MCOUNT_ADDR)) { + /* la v1, _mcount */ + v1 = 3; + buf = (u32 *)&insn_la_mcount[0]; + UASM_i_LA(&buf, v1, MCOUNT_ADDR); + } else { + pr_warn("ftrace: mcount address beyond 32 bits is not supported (%lX)\n", + MCOUNT_ADDR); + } /* jal (ftrace_caller + 8), jump over the first two instruction */ buf = (u32 *)&insn_jal_ftrace_caller; @@ -77,7 +83,6 @@ static inline void ftrace_dyn_arch_init_insns(void) static int ftrace_modify_code(unsigned long ip, unsigned int new_code) { int faulted; - mm_segment_t old_fs; /* *(unsigned int *)ip = new_code; */ safe_store_code(new_code, ip, faulted); @@ -85,10 +90,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code) if (unlikely(faulted)) return -EFAULT; - old_fs = get_fs(); - set_fs(KERNEL_DS); flush_icache_range(ip, ip + 8); - set_fs(old_fs); return 0; } @@ -98,7 +100,6 @@ 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)) @@ -110,10 +111,7 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1, return -EFAULT; ip -= 4; - old_fs = get_fs(); - set_fs(KERNEL_DS); flush_icache_range(ip, ip + 8); - set_fs(old_fs); return 0; } @@ -122,7 +120,6 @@ 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); @@ -134,10 +131,7 @@ static int ftrace_modify_code_2r(unsigned long ip, unsigned int new_code1, if (unlikely(faulted)) return -EFAULT; - old_fs = get_fs(); - set_fs(KERNEL_DS); flush_icache_range(ip, ip + 8); - set_fs(old_fs); return 0; } @@ -205,6 +199,13 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned int new; unsigned long ip = rec->ip; + /* When the code to patch does not belong to the kernel code + * space, we must use insn_la_mcount. However, if MCOUNT_ADDR + * is not in compat space, insn_la_mcount is not usable. + */ + if (!core_kernel_text(ip) && !uasm_in_compat_space_p(MCOUNT_ADDR)) + return -EFAULT; + new = core_kernel_text(ip) ? insn_jal_ftrace_caller : insn_la_mcount[0]; #ifdef CONFIG_64BIT @@ -264,7 +265,7 @@ int ftrace_disable_ftrace_graph_caller(void) #define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */ #define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */ -unsigned long ftrace_get_parent_ra_addr(unsigned long self_ra, unsigned long +static unsigned long ftrace_get_parent_ra_addr(unsigned long self_ra, unsigned long old_parent_ra, unsigned long parent_ra_addr, unsigned long fp) { unsigned long sp, ip, tmp; |
