Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 6319/1: ftrace: add Thumb-2 support to dynamic ftrace

Handle the different nop and call instructions for Thumb-2. Also, we
need to adjust the recorded mcount_loc addresses because they have the
lsb set.

Cc: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org> [recordmcount.pl change]
Signed-off-by: Rabin Vincent <rabin@rab.in>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Rabin Vincent and committed by
Russell King
72dc43a9 3b6c223b

+36 -2
+2 -1
arch/arm/include/asm/ftrace.h
··· 18 18 19 19 static inline unsigned long ftrace_call_adjust(unsigned long addr) 20 20 { 21 - return addr; 21 + /* With Thumb-2, the recorded addresses have the lsb set */ 22 + return addr & ~1; 22 23 } 23 24 24 25 extern void ftrace_caller_old(void);
+33
arch/arm/kernel/ftrace.c
··· 18 18 #include <asm/cacheflush.h> 19 19 #include <asm/ftrace.h> 20 20 21 + #ifdef CONFIG_THUMB2_KERNEL 22 + #define NOP 0xeb04f85d /* pop.w {lr} */ 23 + #else 21 24 #define NOP 0xe8bd4000 /* pop {lr} */ 25 + #endif 22 26 23 27 #ifdef CONFIG_OLD_MCOUNT 24 28 #define OLD_MCOUNT_ADDR ((unsigned long) mcount) ··· 60 56 #endif 61 57 62 58 /* construct a branch (BL) instruction to addr */ 59 + #ifdef CONFIG_THUMB2_KERNEL 60 + static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) 61 + { 62 + unsigned long s, j1, j2, i1, i2, imm10, imm11; 63 + unsigned long first, second; 64 + long offset; 65 + 66 + offset = (long)addr - (long)(pc + 4); 67 + if (offset < -16777216 || offset > 16777214) { 68 + WARN_ON_ONCE(1); 69 + return 0; 70 + } 71 + 72 + s = (offset >> 24) & 0x1; 73 + i1 = (offset >> 23) & 0x1; 74 + i2 = (offset >> 22) & 0x1; 75 + imm10 = (offset >> 12) & 0x3ff; 76 + imm11 = (offset >> 1) & 0x7ff; 77 + 78 + j1 = (!i1) ^ s; 79 + j2 = (!i2) ^ s; 80 + 81 + first = 0xf000 | (s << 10) | imm10; 82 + second = 0xd000 | (j1 << 13) | (j2 << 11) | imm11; 83 + 84 + return (second << 16) | first; 85 + } 86 + #else 63 87 static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) 64 88 { 65 89 long offset; ··· 105 73 106 74 return 0xeb000000 | offset; 107 75 } 76 + #endif 108 77 109 78 static int ftrace_modify_code(unsigned long pc, unsigned long old, 110 79 unsigned long new)
+1 -1
scripts/recordmcount.pl
··· 270 270 } elsif ($arch eq "arm") { 271 271 $alignment = 2; 272 272 $section_type = '%progbits'; 273 - $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24)" . 273 + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24|THM_CALL)" . 274 274 "\\s+(__gnu_mcount_nc|mcount)\$"; 275 275 276 276 } elsif ($arch eq "ia64") {