^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #ifndef _ASM_S390_ALTERNATIVE_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #define _ASM_S390_ALTERNATIVE_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #ifndef __ASSEMBLY__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/stddef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/stringify.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct alt_instr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) s32 instr_offset; /* original instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) s32 repl_offset; /* offset to replacement instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) u16 facility; /* facility bit set for replacement */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) u8 instrlen; /* length of original instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) u8 replacementlen; /* length of new instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) } __packed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) void apply_alternative_instructions(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * |661: |662: |6620 |663:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * +-----------+---------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * | oldinstr | oldinstr_padding |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * | +----------+----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * | | | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * | | >6 bytes |6/4/2 nops|
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * | |6 bytes jg----------->
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * +-----------+---------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * ^^ static padding ^^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * .altinstr_replacement section
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * +---------------------+-----------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * |6641: |6651:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * | alternative instr 1 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * +-----------+---------+- - - - - -+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * |6642: |6652: |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * | alternative instr 2 | padding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * +---------------------+- - - - - -+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * ^ runtime ^
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * .altinstructions section
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * +---------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * | alt_instr entries for each |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * | alternative instr |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * +---------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define b_altinstr(num) "664"#num
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define e_altinstr(num) "665"#num
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define e_oldinstr_pad_end "663"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define oldinstr_len "662b-661b"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define oldinstr_total_len e_oldinstr_pad_end"b-661b"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define oldinstr_pad_len(num) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) "-(((" altinstr_len(num) ")-(" oldinstr_len ")) > 0) * " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) "((" altinstr_len(num) ")-(" oldinstr_len "))"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define INSTR_LEN_SANITY_CHECK(len) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ".if " len " > 254\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) "\t.error \"cpu alternatives does not support instructions " \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) "blocks > 254 bytes\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ".endif\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ".if (" len ") %% 2\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) "\t.error \"cpu alternatives instructions length is odd\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ".endif\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define OLDINSTR_PADDING(oldinstr, num) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ".if " oldinstr_pad_len(num) " > 6\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) "\tjg " e_oldinstr_pad_end "f\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) "6620:\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) "\t.fill (" oldinstr_pad_len(num) " - (6620b-662b)) / 2, 2, 0x0700\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ".else\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) "\t.fill " oldinstr_pad_len(num) " / 6, 6, 0xc0040000\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) "\t.fill " oldinstr_pad_len(num) " %% 6 / 4, 4, 0x47000000\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) "\t.fill " oldinstr_pad_len(num) " %% 6 %% 4 / 2, 2, 0x0700\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ".endif\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define OLDINSTR(oldinstr, num) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) "661:\n\t" oldinstr "\n662:\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) OLDINSTR_PADDING(oldinstr, num) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) e_oldinstr_pad_end ":\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) INSTR_LEN_SANITY_CHECK(oldinstr_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define OLDINSTR_2(oldinstr, num1, num2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) "661:\n\t" oldinstr "\n662:\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ".if " altinstr_len(num1) " < " altinstr_len(num2) "\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) OLDINSTR_PADDING(oldinstr, num2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) ".else\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) OLDINSTR_PADDING(oldinstr, num1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) ".endif\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) e_oldinstr_pad_end ":\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) INSTR_LEN_SANITY_CHECK(oldinstr_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define ALTINSTR_ENTRY(facility, num) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) "\t.long 661b - .\n" /* old instruction */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) "\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) "\t.word " __stringify(facility) "\n" /* facility bit */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) "\t.byte " oldinstr_total_len "\n" /* source len */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) "\t.byte " altinstr_len(num) "\n" /* alt instruction len */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) INSTR_LEN_SANITY_CHECK(altinstr_len(num))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) /* alternative assembly primitive: */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define ALTERNATIVE(oldinstr, altinstr, facility) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ".pushsection .altinstr_replacement, \"ax\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) ALTINSTR_REPLACEMENT(altinstr, 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) ".popsection\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) OLDINSTR(oldinstr, 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ".pushsection .altinstructions,\"a\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) ALTINSTR_ENTRY(facility, 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) ".popsection\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) ".pushsection .altinstr_replacement, \"ax\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) ALTINSTR_REPLACEMENT(altinstr1, 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ALTINSTR_REPLACEMENT(altinstr2, 2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ".popsection\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) OLDINSTR_2(oldinstr, 1, 2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) ".pushsection .altinstructions,\"a\"\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ALTINSTR_ENTRY(facility1, 1) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) ALTINSTR_ENTRY(facility2, 2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ".popsection\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * Alternative instructions for different CPU types or capabilities.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * This allows to use optimized instructions even on generic binary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * kernels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * oldinstr is padded with jump and nops at compile time if altinstr is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * longer. altinstr is padded with jump and nops at run-time during patching.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * For non barrier like inlines please define new variants
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * without volatile and memory clobber.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define alternative(oldinstr, altinstr, facility) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) altinstr2, facility2) ::: "memory")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #endif /* __ASSEMBLY__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #endif /* _ASM_S390_ALTERNATIVE_H */