alternative.h 5.0 KB

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