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