6
6
#include <linux/stringify.h>
7
7
#include <asm/asm.h>
8
8
9
- #define ALTINSTR_FLAG_INV (1 << 15)
10
- #define ALT_NOT (feat ) ((feat) | ALTINSTR_FLAG_INV)
9
+ #define ALT_FLAGS_SHIFT 16
10
+
11
+ #define ALT_FLAG_NOT BIT(0)
12
+ #define ALT_NOT (feature ) ((ALT_FLAG_NOT << ALT_FLAGS_SHIFT) | (feature))
11
13
12
14
#ifndef __ASSEMBLY__
13
15
59
61
".long 999b - .\n\t" \
60
62
".popsection\n\t"
61
63
64
+ /*
65
+ * The patching flags are part of the upper bits of the @ft_flags parameter when
66
+ * specifying them. The split is currently like this:
67
+ *
68
+ * [31... flags ...16][15... CPUID feature bit ...0]
69
+ *
70
+ * but since this is all hidden in the macros argument being split, those fields can be
71
+ * extended in the future to fit in a u64 or however the need arises.
72
+ */
62
73
struct alt_instr {
63
74
s32 instr_offset ; /* original instruction */
64
75
s32 repl_offset ; /* offset to replacement instruction */
65
- u16 cpuid ; /* cpuid bit set for replacement */
76
+
77
+ union {
78
+ struct {
79
+ u32 cpuid : 16 ; /* CPUID bit set for replacement */
80
+ u32 flags : 16 ; /* patching control flags */
81
+ };
82
+ u32 ft_flags ;
83
+ };
84
+
66
85
u8 instrlen ; /* length of original instruction */
67
86
u8 replacementlen ; /* length of new instruction */
68
87
} __packed ;
@@ -182,10 +201,10 @@ static inline int alternatives_text_reserved(void *start, void *end)
182
201
" - (" alt_slen ")), 0x90\n" \
183
202
alt_end_marker ":\n"
184
203
185
- #define ALTINSTR_ENTRY (feature , num ) \
204
+ #define ALTINSTR_ENTRY (ft_flags , num ) \
186
205
" .long 661b - .\n" /* label */ \
187
206
" .long " b_replacement (num )"f - .\n" /* new instruction */ \
188
- " .word " __stringify (feature ) "\n" /* feature bit */ \
207
+ " .4byte " __stringify (ft_flags ) "\n" /* feature + flags */ \
189
208
" .byte " alt_total_slen "\n" /* source len */ \
190
209
" .byte " alt_rlen (num ) "\n" /* replacement len */
191
210
@@ -194,42 +213,43 @@ static inline int alternatives_text_reserved(void *start, void *end)
194
213
b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n"
195
214
196
215
/* alternative assembly primitive: */
197
- #define ALTERNATIVE (oldinstr , newinstr , feature ) \
216
+ #define ALTERNATIVE (oldinstr , newinstr , ft_flags ) \
198
217
OLDINSTR(oldinstr, 1) \
199
218
".pushsection .altinstructions,\"a\"\n" \
200
- ALTINSTR_ENTRY(feature , 1) \
219
+ ALTINSTR_ENTRY(ft_flags , 1) \
201
220
".popsection\n" \
202
221
".pushsection .altinstr_replacement, \"ax\"\n" \
203
222
ALTINSTR_REPLACEMENT(newinstr, 1) \
204
223
".popsection\n"
205
224
206
- #define ALTERNATIVE_2 (oldinstr , newinstr1 , feature1 , newinstr2 , feature2 ) \
225
+ #define ALTERNATIVE_2 (oldinstr , newinstr1 , ft_flags1 , newinstr2 , ft_flags2 ) \
207
226
OLDINSTR_2(oldinstr, 1, 2) \
208
227
".pushsection .altinstructions,\"a\"\n" \
209
- ALTINSTR_ENTRY(feature1 , 1) \
210
- ALTINSTR_ENTRY(feature2 , 2) \
228
+ ALTINSTR_ENTRY(ft_flags1 , 1) \
229
+ ALTINSTR_ENTRY(ft_flags2 , 2) \
211
230
".popsection\n" \
212
231
".pushsection .altinstr_replacement, \"ax\"\n" \
213
232
ALTINSTR_REPLACEMENT(newinstr1, 1) \
214
233
ALTINSTR_REPLACEMENT(newinstr2, 2) \
215
234
".popsection\n"
216
235
217
236
/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
218
- #define ALTERNATIVE_TERNARY (oldinstr , feature , newinstr_yes , newinstr_no ) \
237
+ #define ALTERNATIVE_TERNARY (oldinstr , ft_flags , newinstr_yes , newinstr_no ) \
219
238
ALTERNATIVE_2(oldinstr, newinstr_no, X86_FEATURE_ALWAYS, \
220
- newinstr_yes, feature)
221
-
222
- #define ALTERNATIVE_3 (oldinsn , newinsn1 , feat1 , newinsn2 , feat2 , newinsn3 , feat3 ) \
223
- OLDINSTR_3(oldinsn, 1, 2, 3) \
224
- ".pushsection .altinstructions,\"a\"\n" \
225
- ALTINSTR_ENTRY(feat1, 1) \
226
- ALTINSTR_ENTRY(feat2, 2) \
227
- ALTINSTR_ENTRY(feat3, 3) \
228
- ".popsection\n" \
229
- ".pushsection .altinstr_replacement, \"ax\"\n" \
230
- ALTINSTR_REPLACEMENT(newinsn1, 1) \
231
- ALTINSTR_REPLACEMENT(newinsn2, 2) \
232
- ALTINSTR_REPLACEMENT(newinsn3, 3) \
239
+ newinstr_yes, ft_flags)
240
+
241
+ #define ALTERNATIVE_3 (oldinsn , newinsn1 , ft_flags1 , newinsn2 , ft_flags2 , \
242
+ newinsn3 , ft_flags3 ) \
243
+ OLDINSTR_3(oldinsn, 1, 2, 3) \
244
+ ".pushsection .altinstructions,\"a\"\n" \
245
+ ALTINSTR_ENTRY(ft_flags1, 1) \
246
+ ALTINSTR_ENTRY(ft_flags2, 2) \
247
+ ALTINSTR_ENTRY(ft_flags3, 3) \
248
+ ".popsection\n" \
249
+ ".pushsection .altinstr_replacement, \"ax\"\n" \
250
+ ALTINSTR_REPLACEMENT(newinsn1, 1) \
251
+ ALTINSTR_REPLACEMENT(newinsn2, 2) \
252
+ ALTINSTR_REPLACEMENT(newinsn3, 3) \
233
253
".popsection\n"
234
254
235
255
/*
@@ -244,14 +264,14 @@ static inline int alternatives_text_reserved(void *start, void *end)
244
264
* For non barrier like inlines please define new variants
245
265
* without volatile and memory clobber.
246
266
*/
247
- #define alternative (oldinstr , newinstr , feature ) \
248
- asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature ) : : : "memory")
267
+ #define alternative (oldinstr , newinstr , ft_flags ) \
268
+ asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, ft_flags ) : : : "memory")
249
269
250
- #define alternative_2 (oldinstr , newinstr1 , feature1 , newinstr2 , feature2 ) \
251
- asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1 , newinstr2, feature2 ) ::: "memory")
270
+ #define alternative_2 (oldinstr , newinstr1 , ft_flags1 , newinstr2 , ft_flags2 ) \
271
+ asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1 , newinstr2, ft_flags2 ) ::: "memory")
252
272
253
- #define alternative_ternary (oldinstr , feature , newinstr_yes , newinstr_no ) \
254
- asm_inline volatile(ALTERNATIVE_TERNARY(oldinstr, feature , newinstr_yes, newinstr_no) ::: "memory")
273
+ #define alternative_ternary (oldinstr , ft_flags , newinstr_yes , newinstr_no ) \
274
+ asm_inline volatile(ALTERNATIVE_TERNARY(oldinstr, ft_flags , newinstr_yes, newinstr_no) ::: "memory")
255
275
256
276
/*
257
277
* Alternative inline assembly with input.
@@ -261,8 +281,8 @@ static inline int alternatives_text_reserved(void *start, void *end)
261
281
* Argument numbers start with 1.
262
282
* Leaving an unused argument 0 to keep API compatibility.
263
283
*/
264
- #define alternative_input (oldinstr , newinstr , feature , input ...) \
265
- asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature ) \
284
+ #define alternative_input (oldinstr , newinstr , ft_flags , input ...) \
285
+ asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, ft_flags ) \
266
286
: : "i" (0), ## input)
267
287
268
288
/*
@@ -273,20 +293,20 @@ static inline int alternatives_text_reserved(void *start, void *end)
273
293
* Otherwise, if CPU has feature1, newinstr1 is used.
274
294
* Otherwise, oldinstr is used.
275
295
*/
276
- #define alternative_input_2 (oldinstr , newinstr1 , feature1 , newinstr2 , \
277
- feature2 , input ...) \
278
- asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1 , \
279
- newinstr2, feature2 ) \
296
+ #define alternative_input_2 (oldinstr , newinstr1 , ft_flags1 , newinstr2 , \
297
+ ft_flags2 , input ...) \
298
+ asm_inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1 , \
299
+ newinstr2, ft_flags2 ) \
280
300
: : "i" (0), ## input)
281
301
282
302
/* Like alternative_input, but with a single output argument */
283
- #define alternative_io (oldinstr , newinstr , feature , output , input ...) \
284
- asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature ) \
303
+ #define alternative_io (oldinstr , newinstr , ft_flags , output , input ...) \
304
+ asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, ft_flags ) \
285
305
: output : "i" (0), ## input)
286
306
287
307
/* Like alternative_io, but for replacing a direct call with another one. */
288
- #define alternative_call (oldfunc , newfunc , feature , output , input ...) \
289
- asm_inline volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature ) \
308
+ #define alternative_call (oldfunc , newfunc , ft_flags , output , input ...) \
309
+ asm_inline volatile (ALTERNATIVE("call %P[old]", "call %P[new]", ft_flags ) \
290
310
: output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input)
291
311
292
312
/*
@@ -295,10 +315,10 @@ static inline int alternatives_text_reserved(void *start, void *end)
295
315
* Otherwise, if CPU has feature1, function1 is used.
296
316
* Otherwise, old function is used.
297
317
*/
298
- #define alternative_call_2 (oldfunc , newfunc1 , feature1 , newfunc2 , feature2 , \
318
+ #define alternative_call_2 (oldfunc , newfunc1 , ft_flags1 , newfunc2 , ft_flags2 , \
299
319
output , input ...) \
300
- asm_inline volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1 ,\
301
- "call %P[new2]", feature2 ) \
320
+ asm_inline volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", ft_flags1 ,\
321
+ "call %P[new2]", ft_flags2 ) \
302
322
: output, ASM_CALL_CONSTRAINT \
303
323
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
304
324
[new2] "i" (newfunc2), ## input)
@@ -347,10 +367,10 @@ static inline int alternatives_text_reserved(void *start, void *end)
347
367
* enough information for the alternatives patching code to patch an
348
368
* instruction. See apply_alternatives().
349
369
*/
350
- .macro altinstruction_entry orig alt feature orig_len alt_len
370
+ .macro altinstr_entry orig alt ft_flags orig_len alt_len
351
371
.long \orig - .
352
372
.long \alt - .
353
- .word \ feature
373
+ .4b yte \ ft_flags
354
374
.byte \orig_len
355
375
.byte \alt_len
356
376
.endm
@@ -361,15 +381,15 @@ static inline int alternatives_text_reserved(void *start, void *end)
361
381
* @newinstr. ".skip" directive takes care of proper instruction padding
362
382
* in case @newinstr is longer than @oldinstr.
363
383
*/
364
- .macro ALTERNATIVE oldinstr , newinstr , feature
384
+ .macro ALTERNATIVE oldinstr , newinstr , ft_flags
365
385
140 :
366
386
\oldinstr
367
387
141 :
368
388
.skip - (((144f - 143f )- (141b - 140b )) > 0 ) * ((144f - 143f )- (141b - 140b )),0x90
369
389
142 :
370
390
371
391
.pushsection .altinstructions ,"a"
372
- altinstruction_entry 140b ,143f ,\feature ,142b - 140b ,144f - 143f
392
+ altinstr_entry 140b ,143f ,\ft_flags ,142b - 140b ,144f - 143f
373
393
.popsection
374
394
375
395
.pushsection .altinstr_replacement ,"ax"
@@ -399,7 +419,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
399
419
* has @feature1, it replaces @oldinstr with @newinstr1. If CPU has
400
420
* @feature2, it replaces @oldinstr with @feature2.
401
421
*/
402
- .macro ALTERNATIVE_2 oldinstr , newinstr1 , feature1 , newinstr2 , feature2
422
+ .macro ALTERNATIVE_2 oldinstr , newinstr1 , ft_flags1 , newinstr2 , ft_flags2
403
423
140 :
404
424
\oldinstr
405
425
141 :
@@ -408,8 +428,8 @@ static inline int alternatives_text_reserved(void *start, void *end)
408
428
142 :
409
429
410
430
.pushsection .altinstructions ,"a "
411
- altinstruction_entry 140b ,143f ,\feature1 ,142b -140b ,144f -143f
412
- altinstruction_entry 140b ,144f ,\feature2 ,142b -140b ,145f -144f
431
+ altinstr_entry 140b ,143f ,\ft_flags1 ,142b -140b ,144f -143f
432
+ altinstr_entry 140b ,144f ,\ft_flags2 ,142b -140b ,145f -144f
413
433
.popsection
414
434
415
435
.pushsection .altinstr_replacement ,"ax "
@@ -421,7 +441,7 @@ static inline int alternatives_text_reserved(void *start, void *end)
421
441
.popsection
422
442
.endm
423
443
424
- .macro ALTERNATIVE_3 oldinstr , newinstr1 , feature1 , newinstr2 , feature2 , newinstr3 , feature3
444
+ .macro ALTERNATIVE_3 oldinstr , newinstr1 , ft_flags1 , newinstr2 , ft_flags2 , newinstr3 , ft_flags3
425
445
140 :
426
446
\oldinstr
427
447
141 :
@@ -430,9 +450,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
430
450
142 :
431
451
432
452
.pushsection .altinstructions ,"a "
433
- altinstruction_entry 140b ,143f ,\feature1 ,142b -140b ,144f -143f
434
- altinstruction_entry 140b ,144f ,\feature2 ,142b -140b ,145f -144f
435
- altinstruction_entry 140b ,145f ,\feature3 ,142b -140b ,146f -145f
453
+ altinstr_entry 140b ,143f ,\ft_flags1 ,142b -140b ,144f -143f
454
+ altinstr_entry 140b ,144f ,\ft_flags2 ,142b -140b ,145f -144f
455
+ altinstr_entry 140b ,145f ,\ft_flags3 ,142b -140b ,146f -145f
436
456
.popsection
437
457
438
458
.pushsection .altinstr_replacement ,"ax "
@@ -447,9 +467,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
447
467
.endm
448
468
449
469
/* If @feature is set, patch in @newinstr_yes, otherwise @newinstr_no. */
450
- #define ALTERNATIVE_TERNARY (oldinstr , feature , newinstr_yes , newinstr_no ) \
470
+ #define ALTERNATIVE_TERNARY (oldinstr , ft_flags , newinstr_yes , newinstr_no ) \
451
471
ALTERNATIVE_2 oldinstr , newinstr_no , X86_FEATURE_ALWAYS , \
452
- newinstr_yes , feature
472
+ newinstr_yes , ft_flags
453
473
454
474
#endif /* __ASSEMBLY__ */
455
475
0 commit comments