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