summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/ftrace.c')
-rw-r--r--arch/mips/kernel/ftrace.c43
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;