diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kernel/ftrace.c | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 96aadbfedcc6..4151c91254e8 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
@@ -16,8 +16,8 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/list.h> | 17 | #include <linux/list.h> |
18 | 18 | ||
19 | #include <asm/alternative.h> | ||
20 | #include <asm/ftrace.h> | 19 | #include <asm/ftrace.h> |
20 | #include <asm/nops.h> | ||
21 | 21 | ||
22 | 22 | ||
23 | /* Long is fine, even if it is only 4 bytes ;-) */ | 23 | /* Long is fine, even if it is only 4 bytes ;-) */ |
@@ -119,13 +119,67 @@ notrace int ftrace_mcount_set(unsigned long *data) | |||
119 | 119 | ||
120 | int __init ftrace_dyn_arch_init(void *data) | 120 | int __init ftrace_dyn_arch_init(void *data) |
121 | { | 121 | { |
122 | const unsigned char *const *noptable = find_nop_table(); | 122 | extern const unsigned char ftrace_test_p6nop[]; |
123 | 123 | extern const unsigned char ftrace_test_nop5[]; | |
124 | /* This is running in kstop_machine */ | 124 | extern const unsigned char ftrace_test_jmp[]; |
125 | 125 | int faulted = 0; | |
126 | ftrace_mcount_set(data); | ||
127 | 126 | ||
128 | ftrace_nop = (unsigned long *)noptable[MCOUNT_INSN_SIZE]; | 127 | /* |
128 | * There is no good nop for all x86 archs. | ||
129 | * We will default to using the P6_NOP5, but first we | ||
130 | * will test to make sure that the nop will actually | ||
131 | * work on this CPU. If it faults, we will then | ||
132 | * go to a lesser efficient 5 byte nop. If that fails | ||
133 | * we then just use a jmp as our nop. This isn't the most | ||
134 | * efficient nop, but we can not use a multi part nop | ||
135 | * since we would then risk being preempted in the middle | ||
136 | * of that nop, and if we enabled tracing then, it might | ||
137 | * cause a system crash. | ||
138 | * | ||
139 | * TODO: check the cpuid to determine the best nop. | ||
140 | */ | ||
141 | asm volatile ( | ||
142 | "jmp ftrace_test_jmp\n" | ||
143 | /* This code needs to stay around */ | ||
144 | ".section .text, \"ax\"\n" | ||
145 | "ftrace_test_jmp:" | ||
146 | "jmp ftrace_test_p6nop\n" | ||
147 | ".byte 0x00,0x00,0x00\n" /* 2 byte jmp + 3 bytes */ | ||
148 | "ftrace_test_p6nop:" | ||
149 | P6_NOP5 | ||
150 | "jmp 1f\n" | ||
151 | "ftrace_test_nop5:" | ||
152 | ".byte 0x66,0x66,0x66,0x66,0x90\n" | ||
153 | "jmp 1f\n" | ||
154 | ".previous\n" | ||
155 | "1:" | ||
156 | ".section .fixup, \"ax\"\n" | ||
157 | "2: movl $1, %0\n" | ||
158 | " jmp ftrace_test_nop5\n" | ||
159 | "3: movl $2, %0\n" | ||
160 | " jmp 1b\n" | ||
161 | ".previous\n" | ||
162 | _ASM_EXTABLE(ftrace_test_p6nop, 2b) | ||
163 | _ASM_EXTABLE(ftrace_test_nop5, 3b) | ||
164 | : "=r"(faulted) : "0" (faulted)); | ||
165 | |||
166 | switch (faulted) { | ||
167 | case 0: | ||
168 | pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); | ||
169 | ftrace_nop = (unsigned long *)ftrace_test_p6nop; | ||
170 | break; | ||
171 | case 1: | ||
172 | pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); | ||
173 | ftrace_nop = (unsigned long *)ftrace_test_nop5; | ||
174 | break; | ||
175 | case 2: | ||
176 | pr_info("ftrace: converting mcount calls to jmp 1f\n"); | ||
177 | ftrace_nop = (unsigned long *)ftrace_test_jmp; | ||
178 | break; | ||
179 | } | ||
180 | |||
181 | /* The return code is retured via data */ | ||
182 | *(unsigned long *)data = 0; | ||
129 | 183 | ||
130 | return 0; | 184 | return 0; |
131 | } | 185 | } |