1 #ifndef _ASM_X86_ALTERNATIVE_ASM_H_ 2 #define _ASM_X86_ALTERNATIVE_ASM_H_ 3 4 #include <asm/nops.h> 5 6 #ifdef __ASSEMBLY__ 7 8 /* 9 * Issue one struct alt_instr descriptor entry (need to put it into 10 * the section .altinstructions, see below). This entry contains 11 * enough information for the alternatives patching code to patch an 12 * instruction. See apply_alternatives(). 13 */ 14 .macro altinstruction_entry orig, repl, feature, orig_len, repl_len, pad_len 15 .if ((\feature) & ~ALT_FLAG_NOT) >= NCAPINTS * 32 16 .error "alternative feature outside of featureset range" 17 .endif 18 .long \orig - . 19 .long \repl - . 20 .word \feature 21 .byte \orig_len 22 .byte \repl_len 23 .byte \pad_len 24 .byte 0 /* priv */ 25 .endm 26 27 .macro mknops nr_bytes 28 #ifdef HAVE_AS_NOPS_DIRECTIVE 29 .nops \nr_bytes, ASM_NOP_MAX 30 #else 31 .skip \nr_bytes, 0x90 32 #endif 33 .endm 34 35 /* 36 * GAS's idea of true is sometimes 1 and sometimes -1, while Clang's idea 37 * was consistently 1 up to 6.x (it matches GAS's now). Transform it to 38 * uniformly 1. 39 */ 40 #define as_true(x) ((x) & 1) 41 42 #define decl_orig(insn, padding) \ 43 .L\@_orig_s: insn; .L\@_orig_e: \ 44 .L\@_diff = padding; \ 45 mknops (as_true(.L\@_diff > 0) * .L\@_diff); \ 46 .L\@_orig_p: 47 48 #define orig_len (.L\@_orig_e - .L\@_orig_s) 49 #define pad_len (.L\@_orig_p - .L\@_orig_e) 50 #define total_len (.L\@_orig_p - .L\@_orig_s) 51 52 #define decl_repl(insn, nr) .L\@_repl_s\()nr: insn; .L\@_repl_e\()nr: 53 #define repl_len(nr) (.L\@_repl_e\()nr - .L\@_repl_s\()nr) 54 #define clone_repl(new, old) .equiv .L\@_repl_s\()new, .L\@_repl_s\()old; \ 55 .equiv .L\@_repl_e\()new, .L\@_repl_e\()old 56 57 #define as_max(a, b) ((a) ^ (((a) ^ (b)) & -as_true((a) < (b)))) 58 59 .macro ALTERNATIVE oldinstr, newinstr, feature 60 decl_orig(\oldinstr, repl_len(1) - orig_len) 61 62 .pushsection .altinstructions, "a", @progbits 63 altinstruction_entry .L\@_orig_s, .L\@_repl_s1, \feature, \ 64 orig_len, repl_len(1), pad_len 65 66 .section .discard, "a", @progbits 67 /* 68 * Assembler-time checks: 69 * - total_len <= 255 70 * - \newinstr <= total_len 71 */ 72 .byte total_len 73 .byte 0xff + repl_len(1) - total_len 74 75 .section .altinstr_replacement, "ax", @progbits 76 77 decl_repl(\newinstr, 1) 78 79 .popsection 80 .endm 81 82 .macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 83 decl_orig(\oldinstr, as_max(repl_len(1), repl_len(2)) - orig_len) 84 85 .pushsection .altinstructions, "a", @progbits 86 87 altinstruction_entry .L\@_orig_s, .L\@_repl_s1, \feature1, \ 88 orig_len, repl_len(1), pad_len 89 altinstruction_entry .L\@_orig_s, .L\@_repl_s2, \feature2, \ 90 orig_len, repl_len(2), pad_len 91 92 .section .discard, "a", @progbits 93 /* 94 * Assembler-time checks: 95 * - total_len <= 255 96 * - \newinstr* <= total_len 97 */ 98 .byte total_len 99 .byte 0xff + repl_len(1) - total_len 100 .byte 0xff + repl_len(2) - total_len 101 102 .section .altinstr_replacement, "ax", @progbits 103 104 decl_repl(\newinstr1, 1) 105 .ifnes "\newinstr2", "\newinstr1" 106 decl_repl(\newinstr2, 2) 107 .else 108 clone_repl(2, 1) 109 .endif 110 111 .popsection 112 .endm 113 114 #undef as_max 115 #undef repl_len 116 #undef decl_repl 117 #undef total_len 118 #undef pad_len 119 #undef orig_len 120 #undef decl_orig 121 #undef as_true 122 123 #endif /* __ASSEMBLY__ */ 124 #endif /* _ASM_X86_ALTERNATIVE_ASM_H_ */ 125 126 /* 127 * Local variables: 128 * mode: C 129 * c-file-style: "BSD" 130 * c-basic-offset: 4 131 * tab-width: 4 132 * indent-tabs-mode: nil 133 * End: 134 */ 135