xref: /OK3568_Linux_fs/kernel/arch/arm64/include/asm/alternative-macros.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */
2*4882a593Smuzhiyun #ifndef __ASM_ALTERNATIVE_MACROS_H
3*4882a593Smuzhiyun #define __ASM_ALTERNATIVE_MACROS_H
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun #include <asm/cpucaps.h>
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #define ARM64_CB_PATCH ARM64_NCAPS
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun /* A64 instructions are always 32 bits. */
10*4882a593Smuzhiyun #define	AARCH64_INSN_SIZE		4
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #ifndef BUILD_FIPS140_KO
13*4882a593Smuzhiyun #ifndef __ASSEMBLY__
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/stringify.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define ALTINSTR_ENTRY(feature)					              \
18*4882a593Smuzhiyun 	" .word 661b - .\n"				/* label           */ \
19*4882a593Smuzhiyun 	" .word 663f - .\n"				/* new instruction */ \
20*4882a593Smuzhiyun 	" .hword " __stringify(feature) "\n"		/* feature bit     */ \
21*4882a593Smuzhiyun 	" .byte 662b-661b\n"				/* source len      */ \
22*4882a593Smuzhiyun 	" .byte 664f-663f\n"				/* replacement len */
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define ALTINSTR_ENTRY_CB(feature, cb)					      \
25*4882a593Smuzhiyun 	" .word 661b - .\n"				/* label           */ \
26*4882a593Smuzhiyun 	" .word " __stringify(cb) "- .\n"		/* callback */	      \
27*4882a593Smuzhiyun 	" .hword " __stringify(feature) "\n"		/* feature bit     */ \
28*4882a593Smuzhiyun 	" .byte 662b-661b\n"				/* source len      */ \
29*4882a593Smuzhiyun 	" .byte 664f-663f\n"				/* replacement len */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * alternative assembly primitive:
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * If any of these .org directive fail, it means that insn1 and insn2
35*4882a593Smuzhiyun  * don't have the same length. This used to be written as
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  * .if ((664b-663b) != (662b-661b))
38*4882a593Smuzhiyun  * 	.error "Alternatives instruction length mismatch"
39*4882a593Smuzhiyun  * .endif
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  * but most assemblers die if insn1 or insn2 have a .inst. This should
42*4882a593Smuzhiyun  * be fixed in a binutils release posterior to 2.25.51.0.2 (anything
43*4882a593Smuzhiyun  * containing commit 4e4d08cf7399b606 or c1baaddf8861).
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * Alternatives with callbacks do not generate replacement instructions.
46*4882a593Smuzhiyun  */
47*4882a593Smuzhiyun #define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled)	\
48*4882a593Smuzhiyun 	".if "__stringify(cfg_enabled)" == 1\n"				\
49*4882a593Smuzhiyun 	"661:\n\t"							\
50*4882a593Smuzhiyun 	oldinstr "\n"							\
51*4882a593Smuzhiyun 	"662:\n"							\
52*4882a593Smuzhiyun 	".pushsection .altinstructions,\"a\"\n"				\
53*4882a593Smuzhiyun 	ALTINSTR_ENTRY(feature)						\
54*4882a593Smuzhiyun 	".popsection\n"							\
55*4882a593Smuzhiyun 	".subsection 1\n"						\
56*4882a593Smuzhiyun 	"663:\n\t"							\
57*4882a593Smuzhiyun 	newinstr "\n"							\
58*4882a593Smuzhiyun 	"664:\n\t"							\
59*4882a593Smuzhiyun 	".org	. - (664b-663b) + (662b-661b)\n\t"			\
60*4882a593Smuzhiyun 	".org	. - (662b-661b) + (664b-663b)\n\t"			\
61*4882a593Smuzhiyun 	".previous\n"							\
62*4882a593Smuzhiyun 	".endif\n"
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define __ALTERNATIVE_CFG_CB(oldinstr, feature, cfg_enabled, cb)	\
65*4882a593Smuzhiyun 	".if "__stringify(cfg_enabled)" == 1\n"				\
66*4882a593Smuzhiyun 	"661:\n\t"							\
67*4882a593Smuzhiyun 	oldinstr "\n"							\
68*4882a593Smuzhiyun 	"662:\n"							\
69*4882a593Smuzhiyun 	".pushsection .altinstructions,\"a\"\n"				\
70*4882a593Smuzhiyun 	ALTINSTR_ENTRY_CB(feature, cb)					\
71*4882a593Smuzhiyun 	".popsection\n"							\
72*4882a593Smuzhiyun 	"663:\n\t"							\
73*4882a593Smuzhiyun 	"664:\n\t"							\
74*4882a593Smuzhiyun 	".endif\n"
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...)	\
77*4882a593Smuzhiyun 	__ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define ALTERNATIVE_CB(oldinstr, cb) \
80*4882a593Smuzhiyun 	__ALTERNATIVE_CFG_CB(oldinstr, ARM64_CB_PATCH, 1, cb)
81*4882a593Smuzhiyun #else
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #include <asm/assembler.h>
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun .macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
86*4882a593Smuzhiyun 	.word \orig_offset - .
87*4882a593Smuzhiyun 	.word \alt_offset - .
88*4882a593Smuzhiyun 	.hword \feature
89*4882a593Smuzhiyun 	.byte \orig_len
90*4882a593Smuzhiyun 	.byte \alt_len
91*4882a593Smuzhiyun .endm
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun .macro alternative_insn insn1, insn2, cap, enable = 1
94*4882a593Smuzhiyun 	.if \enable
95*4882a593Smuzhiyun 661:	\insn1
96*4882a593Smuzhiyun 662:	.pushsection .altinstructions, "a"
97*4882a593Smuzhiyun 	altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
98*4882a593Smuzhiyun 	.popsection
99*4882a593Smuzhiyun 	.subsection 1
100*4882a593Smuzhiyun 663:	\insn2
101*4882a593Smuzhiyun 664:	.org	. - (664b-663b) + (662b-661b)
102*4882a593Smuzhiyun 	.org	. - (662b-661b) + (664b-663b)
103*4882a593Smuzhiyun 	.previous
104*4882a593Smuzhiyun 	.endif
105*4882a593Smuzhiyun .endm
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun  * Alternative sequences
109*4882a593Smuzhiyun  *
110*4882a593Smuzhiyun  * The code for the case where the capability is not present will be
111*4882a593Smuzhiyun  * assembled and linked as normal. There are no restrictions on this
112*4882a593Smuzhiyun  * code.
113*4882a593Smuzhiyun  *
114*4882a593Smuzhiyun  * The code for the case where the capability is present will be
115*4882a593Smuzhiyun  * assembled into a special section to be used for dynamic patching.
116*4882a593Smuzhiyun  * Code for that case must:
117*4882a593Smuzhiyun  *
118*4882a593Smuzhiyun  * 1. Be exactly the same length (in bytes) as the default code
119*4882a593Smuzhiyun  *    sequence.
120*4882a593Smuzhiyun  *
121*4882a593Smuzhiyun  * 2. Not contain a branch target that is used outside of the
122*4882a593Smuzhiyun  *    alternative sequence it is defined in (branches into an
123*4882a593Smuzhiyun  *    alternative sequence are not fixed up).
124*4882a593Smuzhiyun  */
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun  * Begin an alternative code sequence.
128*4882a593Smuzhiyun  */
129*4882a593Smuzhiyun .macro alternative_if_not cap
130*4882a593Smuzhiyun 	.set .Lasm_alt_mode, 0
131*4882a593Smuzhiyun 	.pushsection .altinstructions, "a"
132*4882a593Smuzhiyun 	altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f
133*4882a593Smuzhiyun 	.popsection
134*4882a593Smuzhiyun 661:
135*4882a593Smuzhiyun .endm
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun .macro alternative_if cap
138*4882a593Smuzhiyun 	.set .Lasm_alt_mode, 1
139*4882a593Smuzhiyun 	.pushsection .altinstructions, "a"
140*4882a593Smuzhiyun 	altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f
141*4882a593Smuzhiyun 	.popsection
142*4882a593Smuzhiyun 	.subsection 1
143*4882a593Smuzhiyun 	.align 2	/* So GAS knows label 661 is suitably aligned */
144*4882a593Smuzhiyun 661:
145*4882a593Smuzhiyun .endm
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun .macro alternative_cb cb
148*4882a593Smuzhiyun 	.set .Lasm_alt_mode, 0
149*4882a593Smuzhiyun 	.pushsection .altinstructions, "a"
150*4882a593Smuzhiyun 	altinstruction_entry 661f, \cb, ARM64_CB_PATCH, 662f-661f, 0
151*4882a593Smuzhiyun 	.popsection
152*4882a593Smuzhiyun 661:
153*4882a593Smuzhiyun .endm
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /*
156*4882a593Smuzhiyun  * Provide the other half of the alternative code sequence.
157*4882a593Smuzhiyun  */
158*4882a593Smuzhiyun .macro alternative_else
159*4882a593Smuzhiyun 662:
160*4882a593Smuzhiyun 	.if .Lasm_alt_mode==0
161*4882a593Smuzhiyun 	.subsection 1
162*4882a593Smuzhiyun 	.else
163*4882a593Smuzhiyun 	.previous
164*4882a593Smuzhiyun 	.endif
165*4882a593Smuzhiyun 663:
166*4882a593Smuzhiyun .endm
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun /*
169*4882a593Smuzhiyun  * Complete an alternative code sequence.
170*4882a593Smuzhiyun  */
171*4882a593Smuzhiyun .macro alternative_endif
172*4882a593Smuzhiyun 664:
173*4882a593Smuzhiyun 	.org	. - (664b-663b) + (662b-661b)
174*4882a593Smuzhiyun 	.org	. - (662b-661b) + (664b-663b)
175*4882a593Smuzhiyun 	.if .Lasm_alt_mode==0
176*4882a593Smuzhiyun 	.previous
177*4882a593Smuzhiyun 	.endif
178*4882a593Smuzhiyun .endm
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun /*
181*4882a593Smuzhiyun  * Callback-based alternative epilogue
182*4882a593Smuzhiyun  */
183*4882a593Smuzhiyun .macro alternative_cb_end
184*4882a593Smuzhiyun 662:
185*4882a593Smuzhiyun .endm
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun /*
188*4882a593Smuzhiyun  * Provides a trivial alternative or default sequence consisting solely
189*4882a593Smuzhiyun  * of NOPs. The number of NOPs is chosen automatically to match the
190*4882a593Smuzhiyun  * previous case.
191*4882a593Smuzhiyun  */
192*4882a593Smuzhiyun .macro alternative_else_nop_endif
193*4882a593Smuzhiyun alternative_else
194*4882a593Smuzhiyun 	nops	(662b-661b) / AARCH64_INSN_SIZE
195*4882a593Smuzhiyun alternative_endif
196*4882a593Smuzhiyun .endm
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun #define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...)	\
199*4882a593Smuzhiyun 	alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun .macro user_alt, label, oldinstr, newinstr, cond
202*4882a593Smuzhiyun 9999:	alternative_insn "\oldinstr", "\newinstr", \cond
203*4882a593Smuzhiyun 	_asm_extable 9999b, \label
204*4882a593Smuzhiyun .endm
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun #endif  /*  __ASSEMBLY__  */
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun /*
209*4882a593Smuzhiyun  * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature));
210*4882a593Smuzhiyun  *
211*4882a593Smuzhiyun  * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature, CONFIG_FOO));
212*4882a593Smuzhiyun  * N.B. If CONFIG_FOO is specified, but not selected, the whole block
213*4882a593Smuzhiyun  *      will be omitted, including oldinstr.
214*4882a593Smuzhiyun  */
215*4882a593Smuzhiyun #define ALTERNATIVE(oldinstr, newinstr, ...)   \
216*4882a593Smuzhiyun 	_ALTERNATIVE_CFG(oldinstr, newinstr, __VA_ARGS__, 1)
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun #else
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun /*
221*4882a593Smuzhiyun  * The FIPS140 module does not support alternatives patching, as this
222*4882a593Smuzhiyun  * invalidates the HMAC digest of the .text section. However, some alternatives
223*4882a593Smuzhiyun  * are known to be irrelevant so we can tolerate them in the FIPS140 module, as
224*4882a593Smuzhiyun  * they will never be applied in the first place in the use cases that the
225*4882a593Smuzhiyun  * FIPS140 module targets (Android running on a production phone). Any other
226*4882a593Smuzhiyun  * uses of alternatives should be avoided, as it is not safe in the general
227*4882a593Smuzhiyun  * case to simply use the default sequence in one place (the fips module) and
228*4882a593Smuzhiyun  * the alternative sequence everywhere else.
229*4882a593Smuzhiyun  *
230*4882a593Smuzhiyun  * Below is an allowlist of features that we can ignore, by simply taking the
231*4882a593Smuzhiyun  * safe default instruction sequence. Note that this implies that the FIPS140
232*4882a593Smuzhiyun  * module is not compatible with VHE, or with pseudo-NMI support.
233*4882a593Smuzhiyun  */
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun #define __ALT_ARM64_HAS_LDAPR			0,
236*4882a593Smuzhiyun #define __ALT_ARM64_HAS_VIRT_HOST_EXTN		0,
237*4882a593Smuzhiyun #define __ALT_ARM64_HAS_IRQ_PRIO_MASKING	0,
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun #define ALTERNATIVE(oldinstr, newinstr, feature, ...)   \
240*4882a593Smuzhiyun 	_ALTERNATIVE(oldinstr, __ALT_ ## feature, #feature)
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun #define _ALTERNATIVE(oldinstr, feature, feature_str)   \
243*4882a593Smuzhiyun 	__take_second_arg(feature oldinstr, \
244*4882a593Smuzhiyun 		".err Feature " feature_str " not supported in fips140 module")
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun #endif /* BUILD_FIPS140_KO */
247*4882a593Smuzhiyun #endif /* __ASM_ALTERNATIVE_MACROS_H */
248