From 3a2af2dc1bcbfe86b1f39e9e5f9c2c5447943f16 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Fri, 14 May 2010 19:08:30 +0800 Subject: MIPS: Tracing: Fix 32-bit support with -mmcount-ra-address For 32-bit kernel the -mmcount-ra-address option of gcc 4.5 emits one extra instruction before calling to _mcount so we need to use a different "b 1f" for it. Signed-off-by: Wu Zhangjin Cc: linux-mips Cc: David Daney Patchwork: http://patchwork.linux-mips.org/patch/1228/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ftrace.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'arch/mips/kernel/ftrace.c') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index e9e64e0ff7aa..37aa7677e76d 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -62,14 +62,26 @@ int ftrace_make_nop(struct module *mod, return -EFAULT; } +#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) + /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) + * addiu v1, v1, low_16bit_of_mcount + * move at, ra + * move $12, ra_address + * jalr v1 + * sub sp, sp, 8 + * 1: offset = 5 instructions + */ + new = 0x10000005; +#else /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) * addiu v1, v1, low_16bit_of_mcount * move at, ra * jalr v1 - * nop - * 1f: (ip + 12) + * nop | move $12, ra_address | sub sp, sp, 8 + * 1: offset = 4 instructions */ new = 0x10000004; +#endif } else { /* record/calculate it for ftrace_make_call */ if (jal_mcount == 0) { -- cgit v1.2.3 From 4d6829f92a02d96e1bec2ffe6ee674ef3b49722b Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Fri, 14 May 2010 19:08:31 +0800 Subject: MIPS: Tracing: Cleanup of instructions used This patch adds some cleanups of the instructions: o use macros instead of magic numbers o use macros instead of variables to reduce some overhead o add new macro for the jal instruction Signed-off-by: Wu Zhangjin Cc: linux-mips Cc: David Daney Patchwork: http://patchwork.linux-mips.org/patch/1229/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ftrace.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'arch/mips/kernel/ftrace.c') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 37aa7677e76d..b1b8fec2432f 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -23,7 +23,10 @@ #define jump_insn_encode(op_code, addr) \ ((unsigned int)((op_code) | (((addr) >> 2) & ADDR_MASK))) -static unsigned int ftrace_nop = 0x00000000; +#define INSN_B_1F_4 0x10000004 /* b 1f; offset = 4 */ +#define INSN_B_1F_5 0x10000005 /* b 1f; offset = 5 */ +#define INSN_NOP 0x00000000 /* nop */ +#define INSN_JAL(addr) jump_insn_encode(JAL, addr) static int ftrace_modify_code(unsigned long ip, unsigned int new_code) { @@ -71,7 +74,7 @@ int ftrace_make_nop(struct module *mod, * sub sp, sp, 8 * 1: offset = 5 instructions */ - new = 0x10000005; + new = INSN_B_1F_5; #else /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) * addiu v1, v1, low_16bit_of_mcount @@ -80,7 +83,7 @@ int ftrace_make_nop(struct module *mod, * nop | move $12, ra_address | sub sp, sp, 8 * 1: offset = 4 instructions */ - new = 0x10000004; + new = INSN_B_1F_4; #endif } else { /* record/calculate it for ftrace_make_call */ @@ -88,13 +91,13 @@ int ftrace_make_nop(struct module *mod, /* We can record it directly like this: * jal_mcount = *(unsigned int *)ip; * Herein, jump over the first two nop instructions */ - jal_mcount = jump_insn_encode(JAL, (MCOUNT_ADDR + 8)); + jal_mcount = INSN_JAL(MCOUNT_ADDR + 8); } /* move at, ra * jalr v1 --> nop */ - new = ftrace_nop; + new = INSN_NOP; } return ftrace_modify_code(ip, new); } @@ -109,7 +112,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) /* We just need to remove the "b ftrace_stub" at the fist time! */ if (modified == 0) { modified = 1; - ftrace_modify_code(addr, ftrace_nop); + ftrace_modify_code(addr, INSN_NOP); } /* ip, module: 0xc0000000, kernel: 0x80000000 */ new = (ip & 0x40000000) ? lui_v1 : jal_mcount; @@ -123,7 +126,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) { unsigned int new; - new = jump_insn_encode(JAL, (unsigned long)func); + new = INSN_JAL((unsigned long)func); return ftrace_modify_code(FTRACE_CALL_IP, new); } @@ -155,7 +158,7 @@ int ftrace_enable_ftrace_graph_caller(void) int ftrace_disable_ftrace_graph_caller(void) { - return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, ftrace_nop); + return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, INSN_NOP); } #endif /* !CONFIG_DYNAMIC_FTRACE */ -- cgit v1.2.3 From e424054000878d7eb11e44289242886d6e219d22 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Fri, 14 May 2010 19:08:32 +0800 Subject: MIPS: Tracing: Reduce the overhead of dynamic Function Tracer With the help of uasm this patch encodes the instructions of the dynamic function tracer in ftrace_dyn_arch_init() when initializing it. As a result we can remove the dynamic encoding of instructions in ftrace_make_nop()/call(), ftrace_enable_ftrace_graph_caller() and remove the macro jump_insn_encode() and at last this reduce the overhead of dynamic Function Tracer. This also is cleaner. Signed-off-by: Wu Zhangjin Cc: linux-mips Cc: David Daney Patchwork: http://patchwork.linux-mips.org/patch/1230/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ftrace.c | 93 +++++++++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 44 deletions(-) (limited to 'arch/mips/kernel/ftrace.c') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index b1b8fec2432f..c4042cad836e 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -2,7 +2,7 @@ * Code for replacing ftrace calls with jumps. * * Copyright (C) 2007-2008 Steven Rostedt - * Copyright (C) 2009 DSLab, Lanzhou University, China + * Copyright (C) 2009, 2010 DSLab, Lanzhou University, China * Author: Wu Zhangjin * * Thanks goes to Steven Rostedt for writing the original x86 version. @@ -12,21 +12,46 @@ #include #include -#include #include #include +#include +#include #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_insn_encode(op_code, addr) \ - ((unsigned int)((op_code) | (((addr) >> 2) & ADDR_MASK))) #define INSN_B_1F_4 0x10000004 /* b 1f; offset = 4 */ #define INSN_B_1F_5 0x10000005 /* b 1f; offset = 5 */ #define INSN_NOP 0x00000000 /* nop */ -#define INSN_JAL(addr) jump_insn_encode(JAL, addr) +#define INSN_JAL(addr) \ + ((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_j_ftrace_graph_caller __maybe_unused __read_mostly; + +static inline void ftrace_dyn_arch_init_insns(void) +{ + u32 *buf; + unsigned int v1; + + /* lui v1, hi16_mcount */ + v1 = 3; + buf = (u32 *)&insn_lui_v1_hi16_mcount; + UASM_i_LA_mostly(&buf, v1, MCOUNT_ADDR); + + /* jal (ftrace_caller + 8), jump over the first two instruction */ + buf = (u32 *)&insn_jal_ftrace_caller; + uasm_i_jal(&buf, (FTRACE_ADDR + 8)); + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + /* j ftrace_graph_caller */ + buf = (u32 *)&insn_j_ftrace_graph_caller; + uasm_i_j(&buf, (unsigned long)ftrace_graph_caller); +#endif +} static int ftrace_modify_code(unsigned long ip, unsigned int new_code) { @@ -43,30 +68,20 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code) return 0; } -static int lui_v1; -static int jal_mcount; - int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr) { unsigned int new; - int faulted; unsigned long ip = rec->ip; - /* We have compiled module with -mlong-calls, but compiled the kernel - * without it, we need to cope with them respectively. */ + /* + * We have compiled module with -mlong-calls, but compiled the kernel + * without it, we need to cope with them respectively. + */ if (ip & 0x40000000) { - /* record it for ftrace_make_call */ - if (lui_v1 == 0) { - /* lui_v1 = *(unsigned int *)ip; */ - safe_load_code(lui_v1, ip, faulted); - - if (unlikely(faulted)) - return -EFAULT; - } - #if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) - /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) + /* + * lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) * addiu v1, v1, low_16bit_of_mcount * move at, ra * move $12, ra_address @@ -76,7 +91,8 @@ int ftrace_make_nop(struct module *mod, */ new = INSN_B_1F_5; #else - /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) + /* + * lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) * addiu v1, v1, low_16bit_of_mcount * move at, ra * jalr v1 @@ -86,36 +102,22 @@ int ftrace_make_nop(struct module *mod, new = INSN_B_1F_4; #endif } else { - /* record/calculate it for ftrace_make_call */ - if (jal_mcount == 0) { - /* We can record it directly like this: - * jal_mcount = *(unsigned int *)ip; - * Herein, jump over the first two nop instructions */ - jal_mcount = INSN_JAL(MCOUNT_ADDR + 8); - } - - /* move at, ra - * jalr v1 --> nop + /* + * move at, ra + * jal _mcount --> nop */ new = INSN_NOP; } return ftrace_modify_code(ip, new); } -static int modified; /* initialized as 0 by default */ - int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) { unsigned int new; unsigned long ip = rec->ip; - /* We just need to remove the "b ftrace_stub" at the fist time! */ - if (modified == 0) { - modified = 1; - ftrace_modify_code(addr, INSN_NOP); - } /* ip, module: 0xc0000000, kernel: 0x80000000 */ - new = (ip & 0x40000000) ? lui_v1 : jal_mcount; + new = (ip & 0x40000000) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller; return ftrace_modify_code(ip, new); } @@ -133,6 +135,12 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int __init ftrace_dyn_arch_init(void *data) { + /* Encode the instructions when booting */ + ftrace_dyn_arch_init_insns(); + + /* Remove "b ftrace_stub" to ensure ftrace_caller() is executed */ + ftrace_modify_code(MCOUNT_ADDR, INSN_NOP); + /* The return code is retured via data */ *(unsigned long *)data = 0; @@ -145,15 +153,12 @@ int __init ftrace_dyn_arch_init(void *data) #ifdef CONFIG_DYNAMIC_FTRACE extern void ftrace_graph_call(void); -#define JMP 0x08000000 /* jump to target directly */ -#define CALL_FTRACE_GRAPH_CALLER \ - jump_insn_encode(JMP, (unsigned long)(&ftrace_graph_caller)) #define FTRACE_GRAPH_CALL_IP ((unsigned long)(&ftrace_graph_call)) int ftrace_enable_ftrace_graph_caller(void) { return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, - CALL_FTRACE_GRAPH_CALLER); + insn_j_ftrace_graph_caller); } int ftrace_disable_ftrace_graph_caller(void) -- cgit v1.2.3 From 68ccf7521dc89bfcf01432fd1bf8cb4d7d534e4c Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Fri, 14 May 2010 19:08:33 +0800 Subject: MIPS: Tracing: Cleanup of function graph tracer Cleans up comments and ftrace_get_parent_addr() of function graph tracer. Signed-off-by: Wu Zhangjin Cc: linux-mips Cc: David Daney Patchwork: http://patchwork.linux-mips.org/patch/1231/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ftrace.c | 48 +++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'arch/mips/kernel/ftrace.c') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index c4042cad836e..628e90b992d1 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -146,7 +146,7 @@ int __init ftrace_dyn_arch_init(void *data) return 0; } -#endif /* CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_DYNAMIC_FTRACE */ #ifdef CONFIG_FUNCTION_GRAPH_TRACER @@ -166,9 +166,10 @@ int ftrace_disable_ftrace_graph_caller(void) return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, INSN_NOP); } -#endif /* !CONFIG_DYNAMIC_FTRACE */ +#endif /* CONFIG_DYNAMIC_FTRACE */ #ifndef KBUILD_MCOUNT_RA_ADDRESS + #define S_RA_SP (0xafbf << 16) /* s{d,w} ra, offset(sp) */ #define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */ #define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */ @@ -182,17 +183,17 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, unsigned int code; int faulted; - /* in module or kernel? */ - if (self_addr & 0x40000000) { - /* module: move to the instruction "lui v1, HI_16BIT_OF_MCOUNT" */ - ip = self_addr - 20; - } else { - /* kernel: move to the instruction "move ra, at" */ - ip = self_addr - 12; - } + /* + * For module, move the ip from calling site of mcount to the + * instruction "lui v1, hi_16bit_of_mcount"(offset is 20), but for + * kernel, move to the instruction "move ra, at"(offset is 12) + */ + ip = self_addr - ((self_addr & 0x40000000) ? 20 : 12); - /* search the text until finding the non-store instruction or "s{d,w} - * ra, offset(sp)" instruction */ + /* + * search the text until finding the non-store instruction or "s{d,w} + * ra, offset(sp)" instruction + */ do { ip -= 4; @@ -201,10 +202,11 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, if (unlikely(faulted)) return 0; - - /* If we hit the non-store instruction before finding where the + /* + * If we hit the non-store instruction before finding where the * ra is stored, then this is a leaf function and it does not - * store the ra on the stack. */ + * store the ra on the stack + */ if ((code & S_R_SP) != S_R_SP) return parent_addr; @@ -222,7 +224,7 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, return 0; } -#endif +#endif /* !KBUILD_MCOUNT_RA_ADDRESS */ /* * Hook the return address and push it in the stack of return addrs @@ -240,7 +242,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, if (unlikely(atomic_read(¤t->tracing_graph_pause))) return; - /* "parent" is the stack address saved the return address of the caller + /* + * "parent" is the stack address saved the return address of the caller * of _mcount. * * if the gcc < 4.5, a leaf function does not save the return address @@ -262,10 +265,11 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, goto out; #ifndef KBUILD_MCOUNT_RA_ADDRESS parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old, - (unsigned long)parent, - fp); - /* If fails when getting the stack address of the non-leaf function's - * ra, stop function graph tracer and return */ + (unsigned long)parent, fp); + /* + * If fails when getting the stack address of the non-leaf function's + * ra, stop function graph tracer and return + */ if (parent == 0) goto out; #endif @@ -292,4 +296,4 @@ out: ftrace_graph_stop(); WARN_ON(1); } -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -- cgit v1.2.3 From c9f84873c1231621508cd438bb2991ddba770a69 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Fri, 14 May 2010 19:08:34 +0800 Subject: MIPS: Tracing: Cleanup of address space checking This patch adds an inline function in_module() to check which space the instruction pointer in, kernel space or module space. Note: This will not work when the kernel space and module space are the same. If they are the same, we need to modify scripts/recordmcount.pl, ftrace_make_nop/call() and the other related parts to ensure the enabling/disabling of the calling site to _mcount is right for both kernel and module. [Ralf: It also is still incorrect for some 64-bit kernels.] Signed-off-by: Wu Zhangjin Cc: linux-mips Cc: David Daney Patchwork: http://patchwork.linux-mips.org/patch/1232/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/ftrace.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'arch/mips/kernel/ftrace.c') diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 628e90b992d1..5a84a1f11231 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c @@ -17,6 +17,22 @@ #include #include +/* + * If the Instruction Pointer is in module space (0xc0000000), return true; + * otherwise, it is in kernel space (0x80000000), return false. + * + * FIXME: This will not work when the kernel space and module space are the + * same. If they are the same, we need to modify scripts/recordmcount.pl, + * ftrace_make_nop/call() and the other related parts to ensure the + * enabling/disabling of the calling site to _mcount is right for both kernel + * and module. + */ + +static inline int in_module(unsigned long ip) +{ + return ip & 0x40000000; +} + #ifdef CONFIG_DYNAMIC_FTRACE #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ @@ -78,7 +94,7 @@ int ftrace_make_nop(struct module *mod, * We have compiled module with -mlong-calls, but compiled the kernel * without it, we need to cope with them respectively. */ - if (ip & 0x40000000) { + if (in_module(ip)) { #if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) /* * lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) @@ -117,7 +133,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) unsigned long ip = rec->ip; /* ip, module: 0xc0000000, kernel: 0x80000000 */ - new = (ip & 0x40000000) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller; + new = in_module(ip) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller; return ftrace_modify_code(ip, new); } @@ -188,7 +204,7 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, * instruction "lui v1, hi_16bit_of_mcount"(offset is 20), but for * kernel, move to the instruction "move ra, at"(offset is 12) */ - ip = self_addr - ((self_addr & 0x40000000) ? 20 : 12); + ip = self_addr - (in_module(self_addr) ? 20 : 12); /* * search the text until finding the non-store instruction or "s{d,w} -- cgit v1.2.3