Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _ASM_S390_ALTERNATIVE_H
0003 #define _ASM_S390_ALTERNATIVE_H
0004 
0005 #ifndef __ASSEMBLY__
0006 
0007 #include <linux/types.h>
0008 #include <linux/stddef.h>
0009 #include <linux/stringify.h>
0010 
0011 struct alt_instr {
0012     s32 instr_offset;   /* original instruction */
0013     s32 repl_offset;    /* offset to replacement instruction */
0014     u16 facility;       /* facility bit set for replacement */
0015     u8  instrlen;       /* length of original instruction */
0016 } __packed;
0017 
0018 void apply_alternative_instructions(void);
0019 void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
0020 
0021 /*
0022  * +---------------------------------+
0023  * |661:                 |662:
0024  * | oldinstr                |
0025  * +---------------------------------+
0026  *
0027  * .altinstr_replacement section
0028  * +---------------------------------+
0029  * |6641:                |6651:
0030  * | alternative instr 1         |
0031  * +---------------------------------+
0032  * |6642:                |6652:
0033  * | alternative instr 2         |
0034  * +---------------------------------+
0035  *
0036  * .altinstructions section
0037  * +---------------------------------+
0038  * | alt_instr entries for each      |
0039  * | alternative instr           |
0040  * +---------------------------------+
0041  */
0042 
0043 #define b_altinstr(num)     "664"#num
0044 #define e_altinstr(num)     "665"#num
0045 #define oldinstr_len        "662b-661b"
0046 #define altinstr_len(num)   e_altinstr(num)"b-"b_altinstr(num)"b"
0047 
0048 #define OLDINSTR(oldinstr) \
0049     "661:\n\t" oldinstr "\n662:\n"
0050 
0051 #define ALTINSTR_ENTRY(facility, num)                   \
0052     "\t.long 661b - .\n"            /* old instruction */   \
0053     "\t.long " b_altinstr(num)"b - .\n" /* alt instruction */   \
0054     "\t.word " __stringify(facility) "\n"   /* facility bit    */   \
0055     "\t.byte " oldinstr_len "\n"        /* instruction len */   \
0056     "\t.org . - (" oldinstr_len ") + (" altinstr_len(num) ")\n" \
0057     "\t.org . - (" altinstr_len(num) ") + (" oldinstr_len ")\n"
0058 
0059 #define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */   \
0060     b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"
0061 
0062 /* alternative assembly primitive: */
0063 #define ALTERNATIVE(oldinstr, altinstr, facility) \
0064     ".pushsection .altinstr_replacement, \"ax\"\n"          \
0065     ALTINSTR_REPLACEMENT(altinstr, 1)               \
0066     ".popsection\n"                         \
0067     OLDINSTR(oldinstr)                      \
0068     ".pushsection .altinstructions,\"a\"\n"             \
0069     ALTINSTR_ENTRY(facility, 1)                 \
0070     ".popsection\n"
0071 
0072 #define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
0073     ".pushsection .altinstr_replacement, \"ax\"\n"          \
0074     ALTINSTR_REPLACEMENT(altinstr1, 1)              \
0075     ALTINSTR_REPLACEMENT(altinstr2, 2)              \
0076     ".popsection\n"                         \
0077     OLDINSTR(oldinstr)                      \
0078     ".pushsection .altinstructions,\"a\"\n"             \
0079     ALTINSTR_ENTRY(facility1, 1)                    \
0080     ALTINSTR_ENTRY(facility2, 2)                    \
0081     ".popsection\n"
0082 
0083 /*
0084  * Alternative instructions for different CPU types or capabilities.
0085  *
0086  * This allows to use optimized instructions even on generic binary
0087  * kernels.
0088  *
0089  * oldinstr is padded with jump and nops at compile time if altinstr is
0090  * longer. altinstr is padded with jump and nops at run-time during patching.
0091  *
0092  * For non barrier like inlines please define new variants
0093  * without volatile and memory clobber.
0094  */
0095 #define alternative(oldinstr, altinstr, facility)           \
0096     asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
0097 
0098 #define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
0099     asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1,   \
0100                    altinstr2, facility2) ::: "memory")
0101 
0102 /* Alternative inline assembly with input. */
0103 #define alternative_input(oldinstr, newinstr, feature, input...)    \
0104     asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature)   \
0105         : : input)
0106 
0107 /* Like alternative_input, but with a single output argument */
0108 #define alternative_io(oldinstr, altinstr, facility, output, input...)  \
0109     asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, facility)   \
0110         : output : input)
0111 
0112 /* Use this macro if more than one output parameter is needed. */
0113 #define ASM_OUTPUT2(a...) a
0114 
0115 /* Use this macro if clobbers are needed without inputs. */
0116 #define ASM_NO_INPUT_CLOBBER(clobber...) : clobber
0117 
0118 #endif /* __ASSEMBLY__ */
0119 
0120 #endif /* _ASM_S390_ALTERNATIVE_H */