alternative.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_S390_ALTERNATIVE_H
  3. #define _ASM_S390_ALTERNATIVE_H
  4. #ifndef __ASSEMBLY__
  5. #include <linux/types.h>
  6. #include <linux/stddef.h>
  7. #include <linux/stringify.h>
  8. struct alt_instr {
  9. s32 instr_offset; /* original instruction */
  10. s32 repl_offset; /* offset to replacement instruction */
  11. u16 facility; /* facility bit set for replacement */
  12. u8 instrlen; /* length of original instruction */
  13. } __packed;
  14. void apply_alternative_instructions(void);
  15. void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
  16. /*
  17. * +---------------------------------+
  18. * |661: |662:
  19. * | oldinstr |
  20. * +---------------------------------+
  21. *
  22. * .altinstr_replacement section
  23. * +---------------------------------+
  24. * |6641: |6651:
  25. * | alternative instr 1 |
  26. * +---------------------------------+
  27. * |6642: |6652:
  28. * | alternative instr 2 |
  29. * +---------------------------------+
  30. *
  31. * .altinstructions section
  32. * +---------------------------------+
  33. * | alt_instr entries for each |
  34. * | alternative instr |
  35. * +---------------------------------+
  36. */
  37. #define b_altinstr(num) "664"#num
  38. #define e_altinstr(num) "665"#num
  39. #define oldinstr_len "662b-661b"
  40. #define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b"
  41. #define OLDINSTR(oldinstr) \
  42. "661:\n\t" oldinstr "\n662:\n"
  43. #define ALTINSTR_ENTRY(facility, num) \
  44. "\t.long 661b - .\n" /* old instruction */ \
  45. "\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \
  46. "\t.word " __stringify(facility) "\n" /* facility bit */ \
  47. "\t.byte " oldinstr_len "\n" /* instruction len */ \
  48. "\t.org . - (" oldinstr_len ") + (" altinstr_len(num) ")\n" \
  49. "\t.org . - (" altinstr_len(num) ") + (" oldinstr_len ")\n"
  50. #define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \
  51. b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"
  52. /* alternative assembly primitive: */
  53. #define ALTERNATIVE(oldinstr, altinstr, facility) \
  54. ".pushsection .altinstr_replacement, \"ax\"\n" \
  55. ALTINSTR_REPLACEMENT(altinstr, 1) \
  56. ".popsection\n" \
  57. OLDINSTR(oldinstr) \
  58. ".pushsection .altinstructions,\"a\"\n" \
  59. ALTINSTR_ENTRY(facility, 1) \
  60. ".popsection\n"
  61. #define ALTERNATIVE_2(oldinstr, altinstr1, facility1, altinstr2, facility2)\
  62. ".pushsection .altinstr_replacement, \"ax\"\n" \
  63. ALTINSTR_REPLACEMENT(altinstr1, 1) \
  64. ALTINSTR_REPLACEMENT(altinstr2, 2) \
  65. ".popsection\n" \
  66. OLDINSTR(oldinstr) \
  67. ".pushsection .altinstructions,\"a\"\n" \
  68. ALTINSTR_ENTRY(facility1, 1) \
  69. ALTINSTR_ENTRY(facility2, 2) \
  70. ".popsection\n"
  71. /*
  72. * Alternative instructions for different CPU types or capabilities.
  73. *
  74. * This allows to use optimized instructions even on generic binary
  75. * kernels.
  76. *
  77. * oldinstr is padded with jump and nops at compile time if altinstr is
  78. * longer. altinstr is padded with jump and nops at run-time during patching.
  79. *
  80. * For non barrier like inlines please define new variants
  81. * without volatile and memory clobber.
  82. */
  83. #define alternative(oldinstr, altinstr, facility) \
  84. asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, facility) : : : "memory")
  85. #define alternative_2(oldinstr, altinstr1, facility1, altinstr2, facility2) \
  86. asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, facility1, \
  87. altinstr2, facility2) ::: "memory")
  88. /* Alternative inline assembly with input. */
  89. #define alternative_input(oldinstr, newinstr, feature, input...) \
  90. asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
  91. : : input)
  92. /* Like alternative_input, but with a single output argument */
  93. #define alternative_io(oldinstr, altinstr, facility, output, input...) \
  94. asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, facility) \
  95. : output : input)
  96. /* Use this macro if more than one output parameter is needed. */
  97. #define ASM_OUTPUT2(a...) a
  98. /* Use this macro if clobbers are needed without inputs. */
  99. #define ASM_NO_INPUT_CLOBBER(clobber...) : clobber
  100. #endif /* __ASSEMBLY__ */
  101. #endif /* _ASM_S390_ALTERNATIVE_H */