aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/ftrace.c')
-rw-r--r--arch/x86/kernel/ftrace.c40
1 files changed, 24 insertions, 16 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 5dd58136ef02..2e060c58b860 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -16,11 +16,12 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/list.h> 17#include <linux/list.h>
18 18
19#define CALL_BACK 5 19#include <asm/alternative.h>
20 20
21#define JMPFWD 0x03eb 21#define CALL_BACK 5
22 22
23static unsigned short ftrace_jmp = JMPFWD; 23/* Long is fine, even if it is only 4 bytes ;-) */
24static long *ftrace_nop;
24 25
25struct ftrace_record { 26struct ftrace_record {
26 struct dyn_ftrace rec; 27 struct dyn_ftrace rec;
@@ -55,13 +56,13 @@ static struct ftrace_page *ftrace_pages;
55notrace struct dyn_ftrace *ftrace_alloc_shutdown_node(unsigned long ip) 56notrace struct dyn_ftrace *ftrace_alloc_shutdown_node(unsigned long ip)
56{ 57{
57 struct ftrace_record *rec; 58 struct ftrace_record *rec;
58 unsigned short save; 59 unsigned long save;
59 60
60 ip -= CALL_BACK; 61 ip -= CALL_BACK;
61 save = *(short *)ip; 62 save = *(long *)ip;
62 63
63 /* If this was already converted, skip it */ 64 /* If this was already converted, skip it */
64 if (save == JMPFWD) 65 if (save == *ftrace_nop)
65 return NULL; 66 return NULL;
66 67
67 if (ftrace_pages->index == ENTRIES_PER_PAGE) { 68 if (ftrace_pages->index == ENTRIES_PER_PAGE) {
@@ -79,9 +80,10 @@ static int notrace
79ftrace_modify_code(unsigned long ip, unsigned char *old_code, 80ftrace_modify_code(unsigned long ip, unsigned char *old_code,
80 unsigned char *new_code) 81 unsigned char *new_code)
81{ 82{
82 unsigned short old = *(unsigned short *)old_code; 83 unsigned replaced;
83 unsigned short new = *(unsigned short *)new_code; 84 unsigned old = *(unsigned *)old_code; /* 4 bytes */
84 unsigned short replaced; 85 unsigned new = *(unsigned *)new_code; /* 4 bytes */
86 unsigned char newch = new_code[4];
85 int faulted = 0; 87 int faulted = 0;
86 88
87 /* 89 /*
@@ -94,7 +96,9 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
94 */ 96 */
95 asm volatile ( 97 asm volatile (
96 "1: lock\n" 98 "1: lock\n"
97 " cmpxchg %w3, (%2)\n" 99 " cmpxchg %3, (%2)\n"
100 " jnz 2f\n"
101 " movb %b4, 4(%2)\n"
98 "2:\n" 102 "2:\n"
99 ".section .fixup, \"ax\"\n" 103 ".section .fixup, \"ax\"\n"
100 " movl $1, %0\n" 104 " movl $1, %0\n"
@@ -102,11 +106,12 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
102 ".previous\n" 106 ".previous\n"
103 _ASM_EXTABLE(1b, 3b) 107 _ASM_EXTABLE(1b, 3b)
104 : "=r"(faulted), "=a"(replaced) 108 : "=r"(faulted), "=a"(replaced)
105 : "r"(ip), "r"(new), "0"(faulted), "a"(old) 109 : "r"(ip), "r"(new), "r"(newch),
110 "0"(faulted), "a"(old)
106 : "memory"); 111 : "memory");
107 sync_core(); 112 sync_core();
108 113
109 if (replaced != old) 114 if (replaced != old && replaced != new)
110 faulted = 2; 115 faulted = 2;
111 116
112 return faulted; 117 return faulted;
@@ -132,7 +137,7 @@ notrace void ftrace_code_disable(struct dyn_ftrace *rec)
132 /* move the IP back to the start of the call */ 137 /* move the IP back to the start of the call */
133 ip -= CALL_BACK; 138 ip -= CALL_BACK;
134 139
135 r->failed = ftrace_modify_code(ip, save.code, (char *)&ftrace_jmp); 140 r->failed = ftrace_modify_code(ip, save.code, (char *)ftrace_nop);
136} 141}
137 142
138static void notrace ftrace_replace_code(int saved) 143static void notrace ftrace_replace_code(int saved)
@@ -144,9 +149,9 @@ static void notrace ftrace_replace_code(int saved)
144 int i; 149 int i;
145 150
146 if (saved) 151 if (saved)
147 old = (char *)&ftrace_jmp; 152 old = (char *)ftrace_nop;
148 else 153 else
149 new = (char *)&ftrace_jmp; 154 new = (char *)ftrace_nop;
150 155
151 for (pg = ftrace_pages_start; pg; pg = pg->next) { 156 for (pg = ftrace_pages_start; pg; pg = pg->next) {
152 for (i = 0; i < pg->index; i++) { 157 for (i = 0; i < pg->index; i++) {
@@ -194,12 +199,15 @@ notrace void ftrace_shutdown_replenish(void)
194 ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL); 199 ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
195} 200}
196 201
197notrace int ftrace_shutdown_arch_init(void) 202notrace int __init ftrace_shutdown_arch_init(void)
198{ 203{
204 const unsigned char *const *noptable = find_nop_table();
199 struct ftrace_page *pg; 205 struct ftrace_page *pg;
200 int cnt; 206 int cnt;
201 int i; 207 int i;
202 208
209 ftrace_nop = (unsigned long *)noptable[CALL_BACK];
210
203 /* allocate a few pages */ 211 /* allocate a few pages */
204 ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL); 212 ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL);
205 if (!ftrace_pages_start) 213 if (!ftrace_pages_start)