55#include <asm/cpucaps.h>
66#include <asm/insn.h>
77
8+ #define ARM64_CB_PATCH ARM64_NCAPS
9+
810#ifndef __ASSEMBLY__
911
1012#include <linux/init.h>
1113#include <linux/types.h>
1214#include <linux/stddef.h>
1315#include <linux/stringify.h>
1416
17+ extern int alternatives_applied ;
18+
1519struct alt_instr {
1620 s32 orig_offset ; /* offset to original instruction */
1721 s32 alt_offset ; /* offset to replacement instruction */
@@ -20,12 +24,19 @@ struct alt_instr {
2024 u8 alt_len ; /* size of new instruction(s), <= orig_len */
2125};
2226
27+ typedef void (* alternative_cb_t )(struct alt_instr * alt ,
28+ __le32 * origptr , __le32 * updptr , int nr_inst );
29+
2330void __init apply_alternatives_all (void );
2431void apply_alternatives (void * start , size_t length );
2532
26- #define ALTINSTR_ENTRY (feature ) \
33+ #define ALTINSTR_ENTRY (feature , cb ) \
2734 " .word 661b - .\n" /* label */ \
35+ " .if " __stringify (cb ) " == 0\n" \
2836 " .word 663f - .\n" /* new instruction */ \
37+ " .else\n" \
38+ " .word " __stringify (cb ) "- .\n" /* callback */ \
39+ " .endif\n" \
2940 " .hword " __stringify (feature ) "\n" /* feature bit */ \
3041 " .byte 662b-661b\n" /* source len */ \
3142 " .byte 664f-663f\n" /* replacement len */
@@ -43,27 +54,36 @@ void apply_alternatives(void *start, size_t length);
4354 * but most assemblers die if insn1 or insn2 have a .inst. This should
4455 * be fixed in a binutils release posterior to 2.25.51.0.2 (anything
4556 * containing commit 4e4d08cf7399b606 or c1baaddf8861).
57+ *
58+ * Alternatives with callbacks do not generate replacement instructions.
4659 */
47- #define __ALTERNATIVE_CFG (oldinstr , newinstr , feature , cfg_enabled ) \
60+ #define __ALTERNATIVE_CFG (oldinstr , newinstr , feature , cfg_enabled , cb ) \
4861 ".if "__stringify(cfg_enabled)" == 1\n" \
4962 "661:\n\t" \
5063 oldinstr "\n" \
5164 "662:\n" \
5265 ".pushsection .altinstructions,\"a\"\n" \
53- ALTINSTR_ENTRY(feature) \
66+ ALTINSTR_ENTRY(feature,cb) \
5467 ".popsection\n" \
68+ " .if " __stringify(cb) " == 0\n" \
5569 ".pushsection .altinstr_replacement, \"a\"\n" \
5670 "663:\n\t" \
5771 newinstr "\n" \
5872 "664:\n\t" \
5973 ".popsection\n\t" \
6074 ".org . - (664b-663b) + (662b-661b)\n\t" \
6175 ".org . - (662b-661b) + (664b-663b)\n" \
76+ ".else\n\t" \
77+ "663:\n\t" \
78+ "664:\n\t" \
79+ ".endif\n" \
6280 ".endif\n"
6381
6482#define _ALTERNATIVE_CFG (oldinstr , newinstr , feature , cfg , ...) \
65- __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
83+ __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg), 0 )
6684
85+ #define ALTERNATIVE_CB (oldinstr , cb ) \
86+ __ALTERNATIVE_CFG(oldinstr, "NOT_AN_INSTRUCTION", ARM64_CB_PATCH, 1, cb)
6787#else
6888
6989#include <asm/assembler.h>
@@ -130,6 +150,14 @@ void apply_alternatives(void *start, size_t length);
130150661 :
131151.endm
132152
153+ .macro alternative_cb cb
154+ .set .Lasm_alt_mode , 0
155+ .pushsection .altinstructions , "a"
156+ altinstruction_entry 661f , \cb , ARM64_CB_PATCH , 662f - 661f , 0
157+ .popsection
158+ 661 :
159+ .endm
160+
133161/*
134162 * Provide the other half of the alternative code sequence.
135163 */
@@ -155,6 +183,13 @@ void apply_alternatives(void *start, size_t length);
155183 .org . - (662b - 661b ) + (664b - 663b )
156184.endm
157185
186+ /*
187+ * Callback-based alternative epilogue
188+ */
189+ .macro alternative_cb_end
190+ 662 :
191+ .endm
192+
158193/*
159194 * Provides a trivial alternative or default sequence consisting solely
160195 * of NOPs. The number of NOPs is chosen automatically to match the
0 commit comments