alternative.h 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. #ifndef __ASM_ALTERNATIVE_H
  2. #define __ASM_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 orig_offset; /* offset to original instruction */
  9. s32 alt_offset; /* offset to replacement instruction */
  10. u16 cpufeature; /* cpufeature bit set for replacement */
  11. u8 orig_len; /* size of original instruction(s) */
  12. u8 alt_len; /* size of new instruction(s), <= orig_len */
  13. };
  14. void apply_alternatives_all(void);
  15. void apply_alternatives(void *start, size_t length);
  16. void free_alternatives_memory(void);
  17. #define ALTINSTR_ENTRY(feature) \
  18. " .word 661b - .\n" /* label */ \
  19. " .word 663f - .\n" /* new instruction */ \
  20. " .hword " __stringify(feature) "\n" /* feature bit */ \
  21. " .byte 662b-661b\n" /* source len */ \
  22. " .byte 664f-663f\n" /* replacement len */
  23. /*
  24. * alternative assembly primitive:
  25. *
  26. * If any of these .org directive fail, it means that insn1 and insn2
  27. * don't have the same length. This used to be written as
  28. *
  29. * .if ((664b-663b) != (662b-661b))
  30. * .error "Alternatives instruction length mismatch"
  31. * .endif
  32. *
  33. * but most assemblers die if insn1 or insn2 have a .inst. This should
  34. * be fixed in a binutils release posterior to 2.25.51.0.2 (anything
  35. * containing commit 4e4d08cf7399b606 or c1baaddf8861).
  36. */
  37. #define ALTERNATIVE(oldinstr, newinstr, feature) \
  38. "661:\n\t" \
  39. oldinstr "\n" \
  40. "662:\n" \
  41. ".pushsection .altinstructions,\"a\"\n" \
  42. ALTINSTR_ENTRY(feature) \
  43. ".popsection\n" \
  44. ".pushsection .altinstr_replacement, \"a\"\n" \
  45. "663:\n\t" \
  46. newinstr "\n" \
  47. "664:\n\t" \
  48. ".popsection\n\t" \
  49. ".org . - (664b-663b) + (662b-661b)\n\t" \
  50. ".org . - (662b-661b) + (664b-663b)\n"
  51. #else
  52. .macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
  53. .word \orig_offset - .
  54. .word \alt_offset - .
  55. .hword \feature
  56. .byte \orig_len
  57. .byte \alt_len
  58. .endm
  59. .macro alternative_insn insn1 insn2 cap
  60. 661: \insn1
  61. 662: .pushsection .altinstructions, "a"
  62. altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
  63. .popsection
  64. .pushsection .altinstr_replacement, "ax"
  65. 663: \insn2
  66. 664: .popsection
  67. .org . - (664b-663b) + (662b-661b)
  68. .org . - (662b-661b) + (664b-663b)
  69. .endm
  70. #endif /* __ASSEMBLY__ */
  71. #endif /* __ASM_ALTERNATIVE_H */