1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef _ASM_X86_ALTERNATIVE_H
3*4882a593Smuzhiyun #define _ASM_X86_ALTERNATIVE_H
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun #include <linux/types.h>
6*4882a593Smuzhiyun #include <linux/stringify.h>
7*4882a593Smuzhiyun #include <asm/asm.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define ALTINSTR_FLAG_INV (1 << 15)
10*4882a593Smuzhiyun #define ALT_NOT(feat) ((feat) | ALTINSTR_FLAG_INV)
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #ifndef __ASSEMBLY__
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/stddef.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun /*
17*4882a593Smuzhiyun * Alternative inline assembly for SMP.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * The LOCK_PREFIX macro defined here replaces the LOCK and
20*4882a593Smuzhiyun * LOCK_PREFIX macros used everywhere in the source tree.
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * SMP alternatives use the same data structures as the other
23*4882a593Smuzhiyun * alternatives and the X86_FEATURE_UP flag to indicate the case of a
24*4882a593Smuzhiyun * UP system running a SMP kernel. The existing apply_alternatives()
25*4882a593Smuzhiyun * works fine for patching a SMP kernel for UP.
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * The SMP alternative tables can be kept after boot and contain both
28*4882a593Smuzhiyun * UP and SMP versions of the instructions to allow switching back to
29*4882a593Smuzhiyun * SMP at runtime, when hotplugging in a new CPU, which is especially
30*4882a593Smuzhiyun * useful in virtualized environments.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * The very common lock prefix is handled as special case in a
33*4882a593Smuzhiyun * separate table which is a pure address list without replacement ptr
34*4882a593Smuzhiyun * and size information. That keeps the table sizes small.
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun #ifdef CONFIG_SMP
38*4882a593Smuzhiyun #define LOCK_PREFIX_HERE \
39*4882a593Smuzhiyun ".pushsection .smp_locks,\"a\"\n" \
40*4882a593Smuzhiyun ".balign 4\n" \
41*4882a593Smuzhiyun ".long 671f - .\n" /* offset */ \
42*4882a593Smuzhiyun ".popsection\n" \
43*4882a593Smuzhiyun "671:"
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #else /* ! CONFIG_SMP */
48*4882a593Smuzhiyun #define LOCK_PREFIX_HERE ""
49*4882a593Smuzhiyun #define LOCK_PREFIX ""
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * objtool annotation to ignore the alternatives and only consider the original
54*4882a593Smuzhiyun * instruction(s).
55*4882a593Smuzhiyun */
56*4882a593Smuzhiyun #define ANNOTATE_IGNORE_ALTERNATIVE \
57*4882a593Smuzhiyun "999:\n\t" \
58*4882a593Smuzhiyun ".pushsection .discard.ignore_alts\n\t" \
59*4882a593Smuzhiyun ".long 999b - .\n\t" \
60*4882a593Smuzhiyun ".popsection\n\t"
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun struct alt_instr {
63*4882a593Smuzhiyun s32 instr_offset; /* original instruction */
64*4882a593Smuzhiyun s32 repl_offset; /* offset to replacement instruction */
65*4882a593Smuzhiyun u16 cpuid; /* cpuid bit set for replacement */
66*4882a593Smuzhiyun u8 instrlen; /* length of original instruction */
67*4882a593Smuzhiyun u8 replacementlen; /* length of new instruction */
68*4882a593Smuzhiyun } __packed;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * Debug flag that can be tested to see whether alternative
72*4882a593Smuzhiyun * instructions were patched in already:
73*4882a593Smuzhiyun */
74*4882a593Smuzhiyun extern int alternatives_patched;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun extern void alternative_instructions(void);
77*4882a593Smuzhiyun extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
78*4882a593Smuzhiyun extern void apply_retpolines(s32 *start, s32 *end);
79*4882a593Smuzhiyun extern void apply_returns(s32 *start, s32 *end);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun struct module;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun #ifdef CONFIG_SMP
84*4882a593Smuzhiyun extern void alternatives_smp_module_add(struct module *mod, char *name,
85*4882a593Smuzhiyun void *locks, void *locks_end,
86*4882a593Smuzhiyun void *text, void *text_end);
87*4882a593Smuzhiyun extern void alternatives_smp_module_del(struct module *mod);
88*4882a593Smuzhiyun extern void alternatives_enable_smp(void);
89*4882a593Smuzhiyun extern int alternatives_text_reserved(void *start, void *end);
90*4882a593Smuzhiyun extern bool skip_smp_alternatives;
91*4882a593Smuzhiyun #else
alternatives_smp_module_add(struct module * mod,char * name,void * locks,void * locks_end,void * text,void * text_end)92*4882a593Smuzhiyun static inline void alternatives_smp_module_add(struct module *mod, char *name,
93*4882a593Smuzhiyun void *locks, void *locks_end,
94*4882a593Smuzhiyun void *text, void *text_end) {}
alternatives_smp_module_del(struct module * mod)95*4882a593Smuzhiyun static inline void alternatives_smp_module_del(struct module *mod) {}
alternatives_enable_smp(void)96*4882a593Smuzhiyun static inline void alternatives_enable_smp(void) {}
alternatives_text_reserved(void * start,void * end)97*4882a593Smuzhiyun static inline int alternatives_text_reserved(void *start, void *end)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun return 0;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun #endif /* CONFIG_SMP */
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun #define b_replacement(num) "664"#num
104*4882a593Smuzhiyun #define e_replacement(num) "665"#num
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun #define alt_end_marker "663"
107*4882a593Smuzhiyun #define alt_slen "662b-661b"
108*4882a593Smuzhiyun #define alt_total_slen alt_end_marker"b-661b"
109*4882a593Smuzhiyun #define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f"
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun #define OLDINSTR(oldinstr, num) \
112*4882a593Smuzhiyun "# ALT: oldnstr\n" \
113*4882a593Smuzhiyun "661:\n\t" oldinstr "\n662:\n" \
114*4882a593Smuzhiyun "# ALT: padding\n" \
115*4882a593Smuzhiyun ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \
116*4882a593Smuzhiyun "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n" \
117*4882a593Smuzhiyun alt_end_marker ":\n"
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * gas compatible max based on the idea from:
121*4882a593Smuzhiyun * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
122*4882a593Smuzhiyun *
123*4882a593Smuzhiyun * The additional "-" is needed because gas uses a "true" value of -1.
124*4882a593Smuzhiyun */
125*4882a593Smuzhiyun #define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") < (" b ")))))"
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun /*
128*4882a593Smuzhiyun * Pad the second replacement alternative with additional NOPs if it is
129*4882a593Smuzhiyun * additionally longer than the first replacement alternative.
130*4882a593Smuzhiyun */
131*4882a593Smuzhiyun #define OLDINSTR_2(oldinstr, num1, num2) \
132*4882a593Smuzhiyun "# ALT: oldinstr2\n" \
133*4882a593Smuzhiyun "661:\n\t" oldinstr "\n662:\n" \
134*4882a593Smuzhiyun "# ALT: padding2\n" \
135*4882a593Smuzhiyun ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \
136*4882a593Smuzhiyun "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n" \
137*4882a593Smuzhiyun alt_end_marker ":\n"
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define OLDINSTR_3(oldinsn, n1, n2, n3) \
140*4882a593Smuzhiyun "# ALT: oldinstr3\n" \
141*4882a593Smuzhiyun "661:\n\t" oldinsn "\n662:\n" \
142*4882a593Smuzhiyun "# ALT: padding3\n" \
143*4882a593Smuzhiyun ".skip -((" alt_max_short(alt_max_short(alt_rlen(n1), alt_rlen(n2)), alt_rlen(n3)) \
144*4882a593Smuzhiyun " - (" alt_slen ")) > 0) * " \
145*4882a593Smuzhiyun "(" alt_max_short(alt_max_short(alt_rlen(n1), alt_rlen(n2)), alt_rlen(n3)) \
146*4882a593Smuzhiyun " - (" alt_slen ")), 0x90\n" \
147*4882a593Smuzhiyun alt_end_marker ":\n"
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun #define ALTINSTR_ENTRY(feature, num) \
150*4882a593Smuzhiyun " .long 661b - .\n" /* label */ \
151*4882a593Smuzhiyun " .long " b_replacement(num)"f - .\n" /* new instruction */ \
152*4882a593Smuzhiyun " .word " __stringify(feature) "\n" /* feature bit */ \
153*4882a593Smuzhiyun " .byte " alt_total_slen "\n" /* source len */ \
154*4882a593Smuzhiyun " .byte " alt_rlen(num) "\n" /* replacement len */
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun #define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \
157*4882a593Smuzhiyun "# ALT: replacement " #num "\n" \
158*4882a593Smuzhiyun b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n"
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /* alternative assembly primitive: */
161*4882a593Smuzhiyun #define ALTERNATIVE(oldinstr, newinstr, feature) \
162*4882a593Smuzhiyun OLDINSTR(oldinstr, 1) \
163*4882a593Smuzhiyun ".pushsection .altinstructions,\"a\"\n" \
164*4882a593Smuzhiyun ALTINSTR_ENTRY(feature, 1) \
165*4882a593Smuzhiyun ".popsection\n" \
166*4882a593Smuzhiyun ".pushsection .altinstr_replacement, \"ax\"\n" \
167*4882a593Smuzhiyun ALTINSTR_REPLACEMENT(newinstr, feature, 1) \
168*4882a593Smuzhiyun ".popsection\n"
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
171*4882a593Smuzhiyun OLDINSTR_2(oldinstr, 1, 2) \
172*4882a593Smuzhiyun ".pushsection .altinstructions,\"a\"\n" \
173*4882a593Smuzhiyun ALTINSTR_ENTRY(feature1, 1) \
174*4882a593Smuzhiyun ALTINSTR_ENTRY(feature2, 2) \
175*4882a593Smuzhiyun ".popsection\n" \
176*4882a593Smuzhiyun ".pushsection .altinstr_replacement, \"ax\"\n" \
177*4882a593Smuzhiyun ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \
178*4882a593Smuzhiyun ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \
179*4882a593Smuzhiyun ".popsection\n"
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
182*4882a593Smuzhiyun #define ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) \
183*4882a593Smuzhiyun ALTERNATIVE_2(oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
184*4882a593Smuzhiyun newinstr_yes, feature)
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun #define ALTERNATIVE_3(oldinsn, newinsn1, feat1, newinsn2, feat2, newinsn3, feat3) \
187*4882a593Smuzhiyun OLDINSTR_3(oldinsn, 1, 2, 3) \
188*4882a593Smuzhiyun ".pushsection .altinstructions,\"a\"\n" \
189*4882a593Smuzhiyun ALTINSTR_ENTRY(feat1, 1) \
190*4882a593Smuzhiyun ALTINSTR_ENTRY(feat2, 2) \
191*4882a593Smuzhiyun ALTINSTR_ENTRY(feat3, 3) \
192*4882a593Smuzhiyun ".popsection\n" \
193*4882a593Smuzhiyun ".pushsection .altinstr_replacement, \"ax\"\n" \
194*4882a593Smuzhiyun ALTINSTR_REPLACEMENT(newinsn1, feat1, 1) \
195*4882a593Smuzhiyun ALTINSTR_REPLACEMENT(newinsn2, feat2, 2) \
196*4882a593Smuzhiyun ALTINSTR_REPLACEMENT(newinsn3, feat3, 3) \
197*4882a593Smuzhiyun ".popsection\n"
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun /*
200*4882a593Smuzhiyun * Alternative instructions for different CPU types or capabilities.
201*4882a593Smuzhiyun *
202*4882a593Smuzhiyun * This allows to use optimized instructions even on generic binary
203*4882a593Smuzhiyun * kernels.
204*4882a593Smuzhiyun *
205*4882a593Smuzhiyun * length of oldinstr must be longer or equal the length of newinstr
206*4882a593Smuzhiyun * It can be padded with nops as needed.
207*4882a593Smuzhiyun *
208*4882a593Smuzhiyun * For non barrier like inlines please define new variants
209*4882a593Smuzhiyun * without volatile and memory clobber.
210*4882a593Smuzhiyun */
211*4882a593Smuzhiyun #define alternative(oldinstr, newinstr, feature) \
212*4882a593Smuzhiyun asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun #define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
215*4882a593Smuzhiyun asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory")
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun #define alternative_ternary(oldinstr, feature, newinstr_yes, newinstr_no) \
218*4882a593Smuzhiyun asm_inline volatile(ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) ::: "memory")
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /*
221*4882a593Smuzhiyun * Alternative inline assembly with input.
222*4882a593Smuzhiyun *
223*4882a593Smuzhiyun * Peculiarities:
224*4882a593Smuzhiyun * No memory clobber here.
225*4882a593Smuzhiyun * Argument numbers start with 1.
226*4882a593Smuzhiyun * Leaving an unused argument 0 to keep API compatibility.
227*4882a593Smuzhiyun */
228*4882a593Smuzhiyun #define alternative_input(oldinstr, newinstr, feature, input...) \
229*4882a593Smuzhiyun asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
230*4882a593Smuzhiyun : : "i" (0), ## input)
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /*
233*4882a593Smuzhiyun * This is similar to alternative_input. But it has two features and
234*4882a593Smuzhiyun * respective instructions.
235*4882a593Smuzhiyun *
236*4882a593Smuzhiyun * If CPU has feature2, newinstr2 is used.
237*4882a593Smuzhiyun * Otherwise, if CPU has feature1, newinstr1 is used.
238*4882a593Smuzhiyun * Otherwise, oldinstr is used.
239*4882a593Smuzhiyun */
240*4882a593Smuzhiyun #define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \
241*4882a593Smuzhiyun feature2, input...) \
242*4882a593Smuzhiyun asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \
243*4882a593Smuzhiyun newinstr2, feature2) \
244*4882a593Smuzhiyun : : "i" (0), ## input)
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* Like alternative_input, but with a single output argument */
247*4882a593Smuzhiyun #define alternative_io(oldinstr, newinstr, feature, output, input...) \
248*4882a593Smuzhiyun asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
249*4882a593Smuzhiyun : output : "i" (0), ## input)
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /* Like alternative_io, but for replacing a direct call with another one. */
252*4882a593Smuzhiyun #define alternative_call(oldfunc, newfunc, feature, output, input...) \
253*4882a593Smuzhiyun asm_inline volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \
254*4882a593Smuzhiyun : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input)
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun /*
257*4882a593Smuzhiyun * Like alternative_call, but there are two features and respective functions.
258*4882a593Smuzhiyun * If CPU has feature2, function2 is used.
259*4882a593Smuzhiyun * Otherwise, if CPU has feature1, function1 is used.
260*4882a593Smuzhiyun * Otherwise, old function is used.
261*4882a593Smuzhiyun */
262*4882a593Smuzhiyun #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
263*4882a593Smuzhiyun output, input...) \
264*4882a593Smuzhiyun asm_inline volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
265*4882a593Smuzhiyun "call %P[new2]", feature2) \
266*4882a593Smuzhiyun : output, ASM_CALL_CONSTRAINT \
267*4882a593Smuzhiyun : [old] "i" (oldfunc), [new1] "i" (newfunc1), \
268*4882a593Smuzhiyun [new2] "i" (newfunc2), ## input)
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /*
271*4882a593Smuzhiyun * use this macro(s) if you need more than one output parameter
272*4882a593Smuzhiyun * in alternative_io
273*4882a593Smuzhiyun */
274*4882a593Smuzhiyun #define ASM_OUTPUT2(a...) a
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /*
277*4882a593Smuzhiyun * use this macro if you need clobbers but no inputs in
278*4882a593Smuzhiyun * alternative_{input,io,call}()
279*4882a593Smuzhiyun */
280*4882a593Smuzhiyun #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun #else /* __ASSEMBLY__ */
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun #ifdef CONFIG_SMP
285*4882a593Smuzhiyun .macro LOCK_PREFIX
286*4882a593Smuzhiyun 672: lock
287*4882a593Smuzhiyun .pushsection .smp_locks,"a"
288*4882a593Smuzhiyun .balign 4
289*4882a593Smuzhiyun .long 672b - .
290*4882a593Smuzhiyun .popsection
291*4882a593Smuzhiyun .endm
292*4882a593Smuzhiyun #else
293*4882a593Smuzhiyun .macro LOCK_PREFIX
294*4882a593Smuzhiyun .endm
295*4882a593Smuzhiyun #endif
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun /*
298*4882a593Smuzhiyun * objtool annotation to ignore the alternatives and only consider the original
299*4882a593Smuzhiyun * instruction(s).
300*4882a593Smuzhiyun */
301*4882a593Smuzhiyun .macro ANNOTATE_IGNORE_ALTERNATIVE
302*4882a593Smuzhiyun .Lannotate_\@:
303*4882a593Smuzhiyun .pushsection .discard.ignore_alts
304*4882a593Smuzhiyun .long .Lannotate_\@ - .
305*4882a593Smuzhiyun .popsection
306*4882a593Smuzhiyun .endm
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun /*
309*4882a593Smuzhiyun * Issue one struct alt_instr descriptor entry (need to put it into
310*4882a593Smuzhiyun * the section .altinstructions, see below). This entry contains
311*4882a593Smuzhiyun * enough information for the alternatives patching code to patch an
312*4882a593Smuzhiyun * instruction. See apply_alternatives().
313*4882a593Smuzhiyun */
314*4882a593Smuzhiyun .macro altinstruction_entry orig alt feature orig_len alt_len
315*4882a593Smuzhiyun .long \orig - .
316*4882a593Smuzhiyun .long \alt - .
317*4882a593Smuzhiyun .word \feature
318*4882a593Smuzhiyun .byte \orig_len
319*4882a593Smuzhiyun .byte \alt_len
320*4882a593Smuzhiyun .endm
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun /*
323*4882a593Smuzhiyun * Define an alternative between two instructions. If @feature is
324*4882a593Smuzhiyun * present, early code in apply_alternatives() replaces @oldinstr with
325*4882a593Smuzhiyun * @newinstr. ".skip" directive takes care of proper instruction padding
326*4882a593Smuzhiyun * in case @newinstr is longer than @oldinstr.
327*4882a593Smuzhiyun */
328*4882a593Smuzhiyun .macro ALTERNATIVE oldinstr, newinstr, feature
329*4882a593Smuzhiyun 140:
330*4882a593Smuzhiyun \oldinstr
331*4882a593Smuzhiyun 141:
332*4882a593Smuzhiyun .skip -(((144f-143f)-(141b-140b)) > 0) * ((144f-143f)-(141b-140b)),0x90
333*4882a593Smuzhiyun 142:
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun .pushsection .altinstructions,"a"
336*4882a593Smuzhiyun altinstruction_entry 140b,143f,\feature,142b-140b,144f-143f
337*4882a593Smuzhiyun .popsection
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun .pushsection .altinstr_replacement,"ax"
340*4882a593Smuzhiyun 143:
341*4882a593Smuzhiyun \newinstr
342*4882a593Smuzhiyun 144:
343*4882a593Smuzhiyun .popsection
344*4882a593Smuzhiyun .endm
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun #define old_len 141b-140b
347*4882a593Smuzhiyun #define new_len1 144f-143f
348*4882a593Smuzhiyun #define new_len2 145f-144f
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun /*
351*4882a593Smuzhiyun * gas compatible max based on the idea from:
352*4882a593Smuzhiyun * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
353*4882a593Smuzhiyun *
354*4882a593Smuzhiyun * The additional "-" is needed because gas uses a "true" value of -1.
355*4882a593Smuzhiyun */
356*4882a593Smuzhiyun #define alt_max_short(a, b) ((a) ^ (((a) ^ (b)) & -(-((a) < (b)))))
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun /*
360*4882a593Smuzhiyun * Same as ALTERNATIVE macro above but for two alternatives. If CPU
361*4882a593Smuzhiyun * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has
362*4882a593Smuzhiyun * @feature2, it replaces @oldinstr with @feature2.
363*4882a593Smuzhiyun */
364*4882a593Smuzhiyun .macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
365*4882a593Smuzhiyun 140:
366*4882a593Smuzhiyun \oldinstr
367*4882a593Smuzhiyun 141:
368*4882a593Smuzhiyun .skip -((alt_max_short(new_len1, new_len2) - (old_len)) > 0) * \
369*4882a593Smuzhiyun (alt_max_short(new_len1, new_len2) - (old_len)),0x90
370*4882a593Smuzhiyun 142:
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun .pushsection .altinstructions,"a"
373*4882a593Smuzhiyun altinstruction_entry 140b,143f,\feature1,142b-140b,144f-143f
374*4882a593Smuzhiyun altinstruction_entry 140b,144f,\feature2,142b-140b,145f-144f
375*4882a593Smuzhiyun .popsection
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun .pushsection .altinstr_replacement,"ax"
378*4882a593Smuzhiyun 143:
379*4882a593Smuzhiyun \newinstr1
380*4882a593Smuzhiyun 144:
381*4882a593Smuzhiyun \newinstr2
382*4882a593Smuzhiyun 145:
383*4882a593Smuzhiyun .popsection
384*4882a593Smuzhiyun .endm
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
387*4882a593Smuzhiyun #define ALTERNATIVE_TERNARY(oldinstr, feature, newinstr_yes, newinstr_no) \
388*4882a593Smuzhiyun ALTERNATIVE_2 oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
389*4882a593Smuzhiyun newinstr_yes, feature
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun #endif /* __ASSEMBLY__ */
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun #endif /* _ASM_X86_ALTERNATIVE_H */
394