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