xref: /OK3568_Linux_fs/kernel/arch/x86/include/asm/alternative.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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