Rev 5270 | Rev 6934 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5270 | Rev 6082 | ||
---|---|---|---|
1 | #ifndef _ASM_X86_ALTERNATIVE_H |
1 | #ifndef _ASM_X86_ALTERNATIVE_H |
2 | #define _ASM_X86_ALTERNATIVE_H |
2 | #define _ASM_X86_ALTERNATIVE_H |
3 | 3 | ||
4 | #include |
4 | #include |
5 | #include |
5 | #include |
6 | #include |
6 | #include |
7 | #include |
7 | #include |
- | 8 | #include |
|
8 | 9 | ||
9 | /* |
10 | /* |
10 | * Alternative inline assembly for SMP. |
11 | * Alternative inline assembly for SMP. |
11 | * |
12 | * |
12 | * The LOCK_PREFIX macro defined here replaces the LOCK and |
13 | * The LOCK_PREFIX macro defined here replaces the LOCK and |
13 | * LOCK_PREFIX macros used everywhere in the source tree. |
14 | * LOCK_PREFIX macros used everywhere in the source tree. |
14 | * |
15 | * |
15 | * SMP alternatives use the same data structures as the other |
16 | * SMP alternatives use the same data structures as the other |
16 | * alternatives and the X86_FEATURE_UP flag to indicate the case of a |
17 | * alternatives and the X86_FEATURE_UP flag to indicate the case of a |
17 | * UP system running a SMP kernel. The existing apply_alternatives() |
18 | * UP system running a SMP kernel. The existing apply_alternatives() |
18 | * works fine for patching a SMP kernel for UP. |
19 | * works fine for patching a SMP kernel for UP. |
19 | * |
20 | * |
20 | * The SMP alternative tables can be kept after boot and contain both |
21 | * The SMP alternative tables can be kept after boot and contain both |
21 | * UP and SMP versions of the instructions to allow switching back to |
22 | * UP and SMP versions of the instructions to allow switching back to |
22 | * SMP at runtime, when hotplugging in a new CPU, which is especially |
23 | * SMP at runtime, when hotplugging in a new CPU, which is especially |
23 | * useful in virtualized environments. |
24 | * useful in virtualized environments. |
24 | * |
25 | * |
25 | * The very common lock prefix is handled as special case in a |
26 | * The very common lock prefix is handled as special case in a |
26 | * separate table which is a pure address list without replacement ptr |
27 | * separate table which is a pure address list without replacement ptr |
27 | * and size information. That keeps the table sizes small. |
28 | * and size information. That keeps the table sizes small. |
28 | */ |
29 | */ |
29 | 30 | ||
30 | #ifdef CONFIG_SMP |
31 | #ifdef CONFIG_SMP |
31 | #define LOCK_PREFIX_HERE \ |
32 | #define LOCK_PREFIX_HERE \ |
32 | ".pushsection .smp_locks,\"a\"\n" \ |
33 | ".pushsection .smp_locks,\"a\"\n" \ |
33 | ".balign 4\n" \ |
34 | ".balign 4\n" \ |
34 | ".long 671f - .\n" /* offset */ \ |
35 | ".long 671f - .\n" /* offset */ \ |
35 | ".popsection\n" \ |
36 | ".popsection\n" \ |
36 | "671:" |
37 | "671:" |
37 | 38 | ||
38 | #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; " |
39 | #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; " |
39 | 40 | ||
40 | #else /* ! CONFIG_SMP */ |
41 | #else /* ! CONFIG_SMP */ |
41 | #define LOCK_PREFIX_HERE "" |
42 | #define LOCK_PREFIX_HERE "" |
42 | #define LOCK_PREFIX "" |
43 | #define LOCK_PREFIX "" |
43 | #endif |
44 | #endif |
44 | 45 | ||
45 | struct alt_instr { |
46 | struct alt_instr { |
46 | s32 instr_offset; /* original instruction */ |
47 | s32 instr_offset; /* original instruction */ |
47 | s32 repl_offset; /* offset to replacement instruction */ |
48 | s32 repl_offset; /* offset to replacement instruction */ |
48 | u16 cpuid; /* cpuid bit set for replacement */ |
49 | u16 cpuid; /* cpuid bit set for replacement */ |
49 | u8 instrlen; /* length of original instruction */ |
50 | u8 instrlen; /* length of original instruction */ |
50 | u8 replacementlen; /* length of new instruction, <= instrlen */ |
51 | u8 replacementlen; /* length of new instruction */ |
- | 52 | u8 padlen; /* length of build-time padding */ |
|
- | 53 | } __packed; |
|
- | 54 | ||
51 | }; |
55 | /* |
- | 56 | * Debug flag that can be tested to see whether alternative |
|
- | 57 | * instructions were patched in already: |
|
- | 58 | */ |
|
- | 59 | extern int alternatives_patched; |
|
52 | 60 | ||
53 | extern void alternative_instructions(void); |
61 | extern void alternative_instructions(void); |
54 | extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); |
62 | extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); |
55 | 63 | ||
56 | struct module; |
64 | struct module; |
57 | 65 | ||
58 | #ifdef CONFIG_SMP |
66 | #ifdef CONFIG_SMP |
59 | extern void alternatives_smp_module_add(struct module *mod, char *name, |
67 | extern void alternatives_smp_module_add(struct module *mod, char *name, |
60 | void *locks, void *locks_end, |
68 | void *locks, void *locks_end, |
61 | void *text, void *text_end); |
69 | void *text, void *text_end); |
62 | extern void alternatives_smp_module_del(struct module *mod); |
70 | extern void alternatives_smp_module_del(struct module *mod); |
63 | extern void alternatives_enable_smp(void); |
71 | extern void alternatives_enable_smp(void); |
64 | extern int alternatives_text_reserved(void *start, void *end); |
72 | extern int alternatives_text_reserved(void *start, void *end); |
65 | extern bool skip_smp_alternatives; |
73 | extern bool skip_smp_alternatives; |
66 | #else |
74 | #else |
67 | static inline void alternatives_smp_module_add(struct module *mod, char *name, |
75 | static inline void alternatives_smp_module_add(struct module *mod, char *name, |
68 | void *locks, void *locks_end, |
76 | void *locks, void *locks_end, |
69 | void *text, void *text_end) {} |
77 | void *text, void *text_end) {} |
70 | static inline void alternatives_smp_module_del(struct module *mod) {} |
78 | static inline void alternatives_smp_module_del(struct module *mod) {} |
71 | static inline void alternatives_enable_smp(void) {} |
79 | static inline void alternatives_enable_smp(void) {} |
72 | static inline int alternatives_text_reserved(void *start, void *end) |
80 | static inline int alternatives_text_reserved(void *start, void *end) |
73 | { |
81 | { |
74 | return 0; |
82 | return 0; |
75 | } |
83 | } |
76 | #endif /* CONFIG_SMP */ |
84 | #endif /* CONFIG_SMP */ |
77 | - | ||
78 | #define OLDINSTR(oldinstr) "661:\n\t" oldinstr "\n662:\n" |
- | |
79 | 85 | ||
80 | #define b_replacement(number) "663"#number |
86 | #define b_replacement(num) "664"#num |
- | 87 | #define e_replacement(num) "665"#num |
|
81 | #define e_replacement(number) "664"#number |
88 | |
- | 89 | #define alt_end_marker "663" |
|
- | 90 | #define alt_slen "662b-661b" |
|
82 | 91 | #define alt_pad_len alt_end_marker"b-662b" |
|
- | 92 | #define alt_total_slen alt_end_marker"b-661b" |
|
- | 93 | #define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f" |
|
- | 94 | ||
- | 95 | #define __OLDINSTR(oldinstr, num) \ |
|
- | 96 | "661:\n\t" oldinstr "\n662:\n" \ |
|
- | 97 | ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \ |
|
- | 98 | "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n" |
|
- | 99 | ||
- | 100 | #define OLDINSTR(oldinstr, num) \ |
|
- | 101 | __OLDINSTR(oldinstr, num) \ |
|
- | 102 | alt_end_marker ":\n" |
|
- | 103 | ||
- | 104 | /* |
|
- | 105 | * max without conditionals. Idea adapted from: |
|
- | 106 | * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax |
|
- | 107 | * |
|
- | 108 | * The additional "-" is needed because gas works with s32s. |
|
- | 109 | */ |
|
- | 110 | #define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))" |
|
- | 111 | ||
- | 112 | /* |
|
- | 113 | * Pad the second replacement alternative with additional NOPs if it is |
|
- | 114 | * additionally longer than the first replacement alternative. |
|
- | 115 | */ |
|
- | 116 | #define OLDINSTR_2(oldinstr, num1, num2) \ |
|
- | 117 | "661:\n\t" oldinstr "\n662:\n" \ |
|
- | 118 | ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \ |
|
83 | #define alt_slen "662b-661b" |
119 | "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n" \ |
84 | #define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f" |
120 | alt_end_marker ":\n" |
85 | 121 | ||
86 | #define ALTINSTR_ENTRY(feature, number) \ |
122 | #define ALTINSTR_ENTRY(feature, num) \ |
87 | " .long 661b - .\n" /* label */ \ |
123 | " .long 661b - .\n" /* label */ \ |
88 | " .long " b_replacement(number)"f - .\n" /* new instruction */ \ |
124 | " .long " b_replacement(num)"f - .\n" /* new instruction */ \ |
89 | " .word " __stringify(feature) "\n" /* feature bit */ \ |
- | |
90 | " .byte " alt_slen "\n" /* source len */ \ |
- | |
91 | " .byte " alt_rlen(number) "\n" /* replacement len */ |
125 | " .word " __stringify(feature) "\n" /* feature bit */ \ |
92 | 126 | " .byte " alt_total_slen "\n" /* source len */ \ |
|
93 | #define DISCARD_ENTRY(number) /* rlen <= slen */ \ |
127 | " .byte " alt_rlen(num) "\n" /* replacement len */ \ |
94 | " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n" |
128 | " .byte " alt_pad_len "\n" /* pad len */ |
95 | 129 | ||
96 | #define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */ \ |
130 | #define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \ |
97 | b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t" |
131 | b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t" |
98 | 132 | ||
99 | /* alternative assembly primitive: */ |
133 | /* alternative assembly primitive: */ |
100 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
134 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
101 | OLDINSTR(oldinstr) \ |
135 | OLDINSTR(oldinstr, 1) \ |
102 | ".pushsection .altinstructions,\"a\"\n" \ |
136 | ".pushsection .altinstructions,\"a\"\n" \ |
103 | ALTINSTR_ENTRY(feature, 1) \ |
137 | ALTINSTR_ENTRY(feature, 1) \ |
104 | ".popsection\n" \ |
138 | ".popsection\n" \ |
105 | ".pushsection .discard,\"aw\",@progbits\n" \ |
- | |
106 | DISCARD_ENTRY(1) \ |
- | |
107 | ".popsection\n" \ |
- | |
108 | ".pushsection .altinstr_replacement, \"ax\"\n" \ |
139 | ".pushsection .altinstr_replacement, \"ax\"\n" \ |
109 | ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ |
140 | ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ |
110 | ".popsection" |
141 | ".popsection" |
111 | 142 | ||
112 | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ |
143 | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ |
113 | OLDINSTR(oldinstr) \ |
144 | OLDINSTR_2(oldinstr, 1, 2) \ |
114 | ".pushsection .altinstructions,\"a\"\n" \ |
145 | ".pushsection .altinstructions,\"a\"\n" \ |
115 | ALTINSTR_ENTRY(feature1, 1) \ |
146 | ALTINSTR_ENTRY(feature1, 1) \ |
116 | ALTINSTR_ENTRY(feature2, 2) \ |
147 | ALTINSTR_ENTRY(feature2, 2) \ |
117 | ".popsection\n" \ |
148 | ".popsection\n" \ |
118 | ".pushsection .discard,\"aw\",@progbits\n" \ |
- | |
119 | DISCARD_ENTRY(1) \ |
- | |
120 | DISCARD_ENTRY(2) \ |
- | |
121 | ".popsection\n" \ |
- | |
122 | ".pushsection .altinstr_replacement, \"ax\"\n" \ |
149 | ".pushsection .altinstr_replacement, \"ax\"\n" \ |
123 | ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ |
150 | ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \ |
124 | ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ |
151 | ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \ |
125 | ".popsection" |
152 | ".popsection" |
126 | 153 | ||
127 | /* |
154 | /* |
128 | * This must be included *after* the definition of ALTERNATIVE due to |
155 | * This must be included *after* the definition of ALTERNATIVE due to |
129 | * |
156 | * |
130 | */ |
157 | */ |
131 | #include |
158 | #include |
132 | 159 | ||
133 | /* |
160 | /* |
134 | * Alternative instructions for different CPU types or capabilities. |
161 | * Alternative instructions for different CPU types or capabilities. |
135 | * |
162 | * |
136 | * This allows to use optimized instructions even on generic binary |
163 | * This allows to use optimized instructions even on generic binary |
137 | * kernels. |
164 | * kernels. |
138 | * |
165 | * |
139 | * length of oldinstr must be longer or equal the length of newinstr |
166 | * length of oldinstr must be longer or equal the length of newinstr |
140 | * It can be padded with nops as needed. |
167 | * It can be padded with nops as needed. |
141 | * |
168 | * |
142 | * For non barrier like inlines please define new variants |
169 | * For non barrier like inlines please define new variants |
143 | * without volatile and memory clobber. |
170 | * without volatile and memory clobber. |
144 | */ |
171 | */ |
145 | #define alternative(oldinstr, newinstr, feature) \ |
172 | #define alternative(oldinstr, newinstr, feature) \ |
146 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory") |
173 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory") |
- | 174 | ||
- | 175 | #define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \ |
|
- | 176 | asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory") |
|
147 | 177 | ||
148 | /* |
178 | /* |
149 | * Alternative inline assembly with input. |
179 | * Alternative inline assembly with input. |
150 | * |
180 | * |
151 | * Pecularities: |
181 | * Pecularities: |
152 | * No memory clobber here. |
182 | * No memory clobber here. |
153 | * Argument numbers start with 1. |
183 | * Argument numbers start with 1. |
154 | * Best is to use constraints that are fixed size (like (%1) ... "r") |
184 | * Best is to use constraints that are fixed size (like (%1) ... "r") |
155 | * If you use variable sized constraints like "m" or "g" in the |
185 | * If you use variable sized constraints like "m" or "g" in the |
156 | * replacement make sure to pad to the worst case length. |
186 | * replacement make sure to pad to the worst case length. |
157 | * Leaving an unused argument 0 to keep API compatibility. |
187 | * Leaving an unused argument 0 to keep API compatibility. |
158 | */ |
188 | */ |
159 | #define alternative_input(oldinstr, newinstr, feature, input...) \ |
189 | #define alternative_input(oldinstr, newinstr, feature, input...) \ |
160 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
190 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
161 | : : "i" (0), ## input) |
191 | : : "i" (0), ## input) |
162 | 192 | ||
163 | /* |
193 | /* |
164 | * This is similar to alternative_input. But it has two features and |
194 | * This is similar to alternative_input. But it has two features and |
165 | * respective instructions. |
195 | * respective instructions. |
166 | * |
196 | * |
167 | * If CPU has feature2, newinstr2 is used. |
197 | * If CPU has feature2, newinstr2 is used. |
168 | * Otherwise, if CPU has feature1, newinstr1 is used. |
198 | * Otherwise, if CPU has feature1, newinstr1 is used. |
169 | * Otherwise, oldinstr is used. |
199 | * Otherwise, oldinstr is used. |
170 | */ |
200 | */ |
171 | #define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \ |
201 | #define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \ |
172 | feature2, input...) \ |
202 | feature2, input...) \ |
173 | asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \ |
203 | asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \ |
174 | newinstr2, feature2) \ |
204 | newinstr2, feature2) \ |
175 | : : "i" (0), ## input) |
205 | : : "i" (0), ## input) |
176 | 206 | ||
177 | /* Like alternative_input, but with a single output argument */ |
207 | /* Like alternative_input, but with a single output argument */ |
178 | #define alternative_io(oldinstr, newinstr, feature, output, input...) \ |
208 | #define alternative_io(oldinstr, newinstr, feature, output, input...) \ |
179 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
209 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
180 | : output : "i" (0), ## input) |
210 | : output : "i" (0), ## input) |
181 | 211 | ||
182 | /* Like alternative_io, but for replacing a direct call with another one. */ |
212 | /* Like alternative_io, but for replacing a direct call with another one. */ |
183 | #define alternative_call(oldfunc, newfunc, feature, output, input...) \ |
213 | #define alternative_call(oldfunc, newfunc, feature, output, input...) \ |
184 | asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \ |
214 | asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \ |
185 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) |
215 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) |
186 | 216 | ||
187 | /* |
217 | /* |
188 | * Like alternative_call, but there are two features and respective functions. |
218 | * Like alternative_call, but there are two features and respective functions. |
189 | * If CPU has feature2, function2 is used. |
219 | * If CPU has feature2, function2 is used. |
190 | * Otherwise, if CPU has feature1, function1 is used. |
220 | * Otherwise, if CPU has feature1, function1 is used. |
191 | * Otherwise, old function is used. |
221 | * Otherwise, old function is used. |
192 | */ |
222 | */ |
193 | #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \ |
223 | #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \ |
194 | output, input...) \ |
224 | output, input...) \ |
195 | asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\ |
225 | asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\ |
196 | "call %P[new2]", feature2) \ |
226 | "call %P[new2]", feature2) \ |
197 | : output : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ |
227 | : output : [old] "i" (oldfunc), [new1] "i" (newfunc1), \ |
198 | [new2] "i" (newfunc2), ## input) |
228 | [new2] "i" (newfunc2), ## input) |
199 | 229 | ||
200 | /* |
230 | /* |
201 | * use this macro(s) if you need more than one output parameter |
231 | * use this macro(s) if you need more than one output parameter |
202 | * in alternative_io |
232 | * in alternative_io |
203 | */ |
233 | */ |
204 | #define ASM_OUTPUT2(a...) a |
234 | #define ASM_OUTPUT2(a...) a |
205 | 235 | ||
206 | /* |
236 | /* |
207 | * use this macro if you need clobbers but no inputs in |
237 | * use this macro if you need clobbers but no inputs in |
208 | * alternative_{input,io,call}() |
238 | * alternative_{input,io,call}() |
209 | */ |
239 | */ |
210 | #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr |
240 | #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr |
211 | 241 | ||
212 | struct paravirt_patch_site; |
242 | struct paravirt_patch_site; |
213 | #ifdef CONFIG_PARAVIRT |
243 | #ifdef CONFIG_PARAVIRT |
214 | void apply_paravirt(struct paravirt_patch_site *start, |
244 | void apply_paravirt(struct paravirt_patch_site *start, |
215 | struct paravirt_patch_site *end); |
245 | struct paravirt_patch_site *end); |
216 | #else |
246 | #else |
217 | static inline void apply_paravirt(struct paravirt_patch_site *start, |
247 | static inline void apply_paravirt(struct paravirt_patch_site *start, |
218 | struct paravirt_patch_site *end) |
248 | struct paravirt_patch_site *end) |
219 | {} |
249 | {} |
220 | #define __parainstructions NULL |
250 | #define __parainstructions NULL |
221 | #define __parainstructions_end NULL |
251 | #define __parainstructions_end NULL |
222 | #endif |
252 | #endif |
223 | 253 | ||
224 | extern void *text_poke_early(void *addr, const void *opcode, size_t len); |
254 | extern void *text_poke_early(void *addr, const void *opcode, size_t len); |
225 | 255 | ||
226 | /* |
256 | /* |
227 | * Clear and restore the kernel write-protection flag on the local CPU. |
257 | * Clear and restore the kernel write-protection flag on the local CPU. |
228 | * Allows the kernel to edit read-only pages. |
258 | * Allows the kernel to edit read-only pages. |
229 | * Side-effect: any interrupt handler running between save and restore will have |
259 | * Side-effect: any interrupt handler running between save and restore will have |
230 | * the ability to write to read-only pages. |
260 | * the ability to write to read-only pages. |
231 | * |
261 | * |
232 | * Warning: |
262 | * Warning: |
233 | * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and |
263 | * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and |
234 | * no thread can be preempted in the instructions being modified (no iret to an |
264 | * no thread can be preempted in the instructions being modified (no iret to an |
235 | * invalid instruction possible) or if the instructions are changed from a |
265 | * invalid instruction possible) or if the instructions are changed from a |
236 | * consistent state to another consistent state atomically. |
266 | * consistent state to another consistent state atomically. |
237 | * On the local CPU you need to be protected again NMI or MCE handlers seeing an |
267 | * On the local CPU you need to be protected again NMI or MCE handlers seeing an |
238 | * inconsistent instruction while you patch. |
268 | * inconsistent instruction while you patch. |
239 | */ |
269 | */ |
240 | extern void *text_poke(void *addr, const void *opcode, size_t len); |
270 | extern void *text_poke(void *addr, const void *opcode, size_t len); |
241 | extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler); |
271 | extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler); |
242 | 272 | ||
243 | #endif /* _ASM_X86_ALTERNATIVE_H */=>=> |
273 | #endif /* _ASM_X86_ALTERNATIVE_H */ |