Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef __ASM_ALTERNATIVE_MACROS_H
0003 #define __ASM_ALTERNATIVE_MACROS_H
0004 
0005 #include <asm/cpucaps.h>
0006 #include <asm/insn-def.h>
0007 
0008 #define ARM64_CB_PATCH ARM64_NCAPS
0009 
0010 #ifndef __ASSEMBLY__
0011 
0012 #include <linux/stringify.h>
0013 
0014 #define ALTINSTR_ENTRY(feature)                               \
0015     " .word 661b - .\n"             /* label           */ \
0016     " .word 663f - .\n"             /* new instruction */ \
0017     " .hword " __stringify(feature) "\n"        /* feature bit     */ \
0018     " .byte 662b-661b\n"                /* source len      */ \
0019     " .byte 664f-663f\n"                /* replacement len */
0020 
0021 #define ALTINSTR_ENTRY_CB(feature, cb)                        \
0022     " .word 661b - .\n"             /* label           */ \
0023     " .word " __stringify(cb) "- .\n"       /* callback */        \
0024     " .hword " __stringify(feature) "\n"        /* feature bit     */ \
0025     " .byte 662b-661b\n"                /* source len      */ \
0026     " .byte 664f-663f\n"                /* replacement len */
0027 
0028 /*
0029  * alternative assembly primitive:
0030  *
0031  * If any of these .org directive fail, it means that insn1 and insn2
0032  * don't have the same length. This used to be written as
0033  *
0034  * .if ((664b-663b) != (662b-661b))
0035  *  .error "Alternatives instruction length mismatch"
0036  * .endif
0037  *
0038  * but most assemblers die if insn1 or insn2 have a .inst. This should
0039  * be fixed in a binutils release posterior to 2.25.51.0.2 (anything
0040  * containing commit 4e4d08cf7399b606 or c1baaddf8861).
0041  *
0042  * Alternatives with callbacks do not generate replacement instructions.
0043  */
0044 #define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \
0045     ".if "__stringify(cfg_enabled)" == 1\n"             \
0046     "661:\n\t"                          \
0047     oldinstr "\n"                           \
0048     "662:\n"                            \
0049     ".pushsection .altinstructions,\"a\"\n"             \
0050     ALTINSTR_ENTRY(feature)                     \
0051     ".popsection\n"                         \
0052     ".subsection 1\n"                       \
0053     "663:\n\t"                          \
0054     newinstr "\n"                           \
0055     "664:\n\t"                          \
0056     ".org   . - (664b-663b) + (662b-661b)\n\t"          \
0057     ".org   . - (662b-661b) + (664b-663b)\n\t"          \
0058     ".previous\n"                           \
0059     ".endif\n"
0060 
0061 #define __ALTERNATIVE_CFG_CB(oldinstr, feature, cfg_enabled, cb)    \
0062     ".if "__stringify(cfg_enabled)" == 1\n"             \
0063     "661:\n\t"                          \
0064     oldinstr "\n"                           \
0065     "662:\n"                            \
0066     ".pushsection .altinstructions,\"a\"\n"             \
0067     ALTINSTR_ENTRY_CB(feature, cb)                  \
0068     ".popsection\n"                         \
0069     "663:\n\t"                          \
0070     "664:\n\t"                          \
0071     ".endif\n"
0072 
0073 #define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \
0074     __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg))
0075 
0076 #define ALTERNATIVE_CB(oldinstr, cb) \
0077     __ALTERNATIVE_CFG_CB(oldinstr, ARM64_CB_PATCH, 1, cb)
0078 #else
0079 
0080 #include <asm/assembler.h>
0081 
0082 .macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
0083     .word \orig_offset - .
0084     .word \alt_offset - .
0085     .hword \feature
0086     .byte \orig_len
0087     .byte \alt_len
0088 .endm
0089 
0090 .macro alternative_insn insn1, insn2, cap, enable = 1
0091     .if \enable
0092 661:    \insn1
0093 662:    .pushsection .altinstructions, "a"
0094     altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
0095     .popsection
0096     .subsection 1
0097 663:    \insn2
0098 664:    .org    . - (664b-663b) + (662b-661b)
0099     .org    . - (662b-661b) + (664b-663b)
0100     .previous
0101     .endif
0102 .endm
0103 
0104 /*
0105  * Alternative sequences
0106  *
0107  * The code for the case where the capability is not present will be
0108  * assembled and linked as normal. There are no restrictions on this
0109  * code.
0110  *
0111  * The code for the case where the capability is present will be
0112  * assembled into a special section to be used for dynamic patching.
0113  * Code for that case must:
0114  *
0115  * 1. Be exactly the same length (in bytes) as the default code
0116  *    sequence.
0117  *
0118  * 2. Not contain a branch target that is used outside of the
0119  *    alternative sequence it is defined in (branches into an
0120  *    alternative sequence are not fixed up).
0121  */
0122 
0123 /*
0124  * Begin an alternative code sequence.
0125  */
0126 .macro alternative_if_not cap
0127     .set .Lasm_alt_mode, 0
0128     .pushsection .altinstructions, "a"
0129     altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f
0130     .popsection
0131 661:
0132 .endm
0133 
0134 .macro alternative_if cap
0135     .set .Lasm_alt_mode, 1
0136     .pushsection .altinstructions, "a"
0137     altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f
0138     .popsection
0139     .subsection 1
0140     .align 2    /* So GAS knows label 661 is suitably aligned */
0141 661:
0142 .endm
0143 
0144 .macro alternative_cb cb
0145     .set .Lasm_alt_mode, 0
0146     .pushsection .altinstructions, "a"
0147     altinstruction_entry 661f, \cb, ARM64_CB_PATCH, 662f-661f, 0
0148     .popsection
0149 661:
0150 .endm
0151 
0152 /*
0153  * Provide the other half of the alternative code sequence.
0154  */
0155 .macro alternative_else
0156 662:
0157     .if .Lasm_alt_mode==0
0158     .subsection 1
0159     .else
0160     .previous
0161     .endif
0162 663:
0163 .endm
0164 
0165 /*
0166  * Complete an alternative code sequence.
0167  */
0168 .macro alternative_endif
0169 664:
0170     .org    . - (664b-663b) + (662b-661b)
0171     .org    . - (662b-661b) + (664b-663b)
0172     .if .Lasm_alt_mode==0
0173     .previous
0174     .endif
0175 .endm
0176 
0177 /*
0178  * Callback-based alternative epilogue
0179  */
0180 .macro alternative_cb_end
0181 662:
0182 .endm
0183 
0184 /*
0185  * Provides a trivial alternative or default sequence consisting solely
0186  * of NOPs. The number of NOPs is chosen automatically to match the
0187  * previous case.
0188  */
0189 .macro alternative_else_nop_endif
0190 alternative_else
0191     nops    (662b-661b) / AARCH64_INSN_SIZE
0192 alternative_endif
0193 .endm
0194 
0195 #define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...)   \
0196     alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
0197 
0198 #endif  /*  __ASSEMBLY__  */
0199 
0200 /*
0201  * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature));
0202  *
0203  * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature, CONFIG_FOO));
0204  * N.B. If CONFIG_FOO is specified, but not selected, the whole block
0205  *      will be omitted, including oldinstr.
0206  */
0207 #define ALTERNATIVE(oldinstr, newinstr, ...)   \
0208     _ALTERNATIVE_CFG(oldinstr, newinstr, __VA_ARGS__, 1)
0209 
0210 #endif /* __ASM_ALTERNATIVE_MACROS_H */