/root/src/xen/xen/include/asm/alternative.h
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef __X86_ALTERNATIVE_H__ |
2 | | #define __X86_ALTERNATIVE_H__ |
3 | | |
4 | | #include <asm/nops.h> |
5 | | |
6 | | #ifdef __ASSEMBLY__ |
7 | | .macro altinstruction_entry orig alt feature orig_len alt_len |
8 | | .long \orig - . |
9 | | .long \alt - . |
10 | | .word \feature |
11 | | .byte \orig_len |
12 | | .byte \alt_len |
13 | | .endm |
14 | | #else |
15 | | #include <xen/stringify.h> |
16 | | #include <xen/types.h> |
17 | | |
18 | | struct alt_instr { |
19 | | s32 instr_offset; /* original instruction */ |
20 | | s32 repl_offset; /* offset to replacement instruction */ |
21 | | u16 cpuid; /* cpuid bit set for replacement */ |
22 | | u8 instrlen; /* length of original instruction */ |
23 | | u8 replacementlen; /* length of new instruction, <= instrlen */ |
24 | | }; |
25 | | |
26 | | #define __ALT_PTR(a,f) ((u8 *)((void *)&(a)->f + (a)->f)) |
27 | | #define ALT_ORIG_PTR(a) __ALT_PTR(a, instr_offset) |
28 | | #define ALT_REPL_PTR(a) __ALT_PTR(a, repl_offset) |
29 | | |
30 | | extern void add_nops(void *insns, unsigned int len); |
31 | | /* Similar to alternative_instructions except it can be run with IRQs enabled. */ |
32 | | extern void apply_alternatives(const struct alt_instr *start, |
33 | | const struct alt_instr *end); |
34 | | extern void alternative_instructions(void); |
35 | | |
36 | | #define OLDINSTR(oldinstr) "661:\n\t" oldinstr "\n662:\n" |
37 | | |
38 | | #define b_replacement(number) "663"#number |
39 | | #define e_replacement(number) "664"#number |
40 | | |
41 | | #define alt_slen "662b-661b" |
42 | | #define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f" |
43 | | |
44 | | #define ALTINSTR_ENTRY(feature, number) \ |
45 | | " .long 661b - .\n" /* label */ \ |
46 | | " .long " b_replacement(number)"f - .\n" /* new instruction */ \ |
47 | | " .word " __stringify(feature) "\n" /* feature bit */ \ |
48 | | " .byte " alt_slen "\n" /* source len */ \ |
49 | | " .byte " alt_rlen(number) "\n" /* replacement len */ |
50 | | |
51 | | #define DISCARD_ENTRY(number) /* rlen <= slen */ \ |
52 | | " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n" |
53 | | |
54 | | #define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */ \ |
55 | | b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t" |
56 | | |
57 | | #define ALTERNATIVE_N(newinstr, feature, number) \ |
58 | | ".pushsection .altinstructions,\"a\"\n" \ |
59 | | ALTINSTR_ENTRY(feature, number) \ |
60 | | ".section .discard,\"a\",@progbits\n" \ |
61 | | DISCARD_ENTRY(number) \ |
62 | | ".section .altinstr_replacement, \"ax\"\n" \ |
63 | | ALTINSTR_REPLACEMENT(newinstr, feature, number) \ |
64 | | ".popsection\n" |
65 | | |
66 | | /* alternative assembly primitive: */ |
67 | | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
68 | | OLDINSTR(oldinstr) \ |
69 | | ALTERNATIVE_N(newinstr, feature, 1) |
70 | | |
71 | | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \ |
72 | | ALTERNATIVE(oldinstr, newinstr1, feature1) \ |
73 | | ALTERNATIVE_N(newinstr2, feature2, 2) |
74 | | |
75 | | #define ALTERNATIVE_3(oldinstr, newinstr1, feature1, newinstr2, feature2, \ |
76 | | newinstr3, feature3) \ |
77 | | ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \ |
78 | | ALTERNATIVE_N(newinstr3, feature3, 3) |
79 | | |
80 | | /* |
81 | | * Alternative instructions for different CPU types or capabilities. |
82 | | * |
83 | | * This allows to use optimized instructions even on generic binary |
84 | | * kernels. |
85 | | * |
86 | | * length of oldinstr must be longer or equal the length of newinstr |
87 | | * It can be padded with nops as needed. |
88 | | * |
89 | | * For non barrier like inlines please define new variants |
90 | | * without volatile and memory clobber. |
91 | | */ |
92 | | #define alternative(oldinstr, newinstr, feature) \ |
93 | 200M | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory") |
94 | | |
95 | | /* |
96 | | * Alternative inline assembly with input. |
97 | | * |
98 | | * Pecularities: |
99 | | * No memory clobber here. |
100 | | * Argument numbers start with 1. |
101 | | * Best is to use constraints that are fixed size (like (%1) ... "r") |
102 | | * If you use variable sized constraints like "m" or "g" in the |
103 | | * replacement make sure to pad to the worst case length. |
104 | | */ |
105 | | #define alternative_input(oldinstr, newinstr, feature, input...) \ |
106 | 0 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
107 | 0 | : : input) |
108 | | |
109 | | /* Like alternative_input, but with a single output argument */ |
110 | | #define alternative_io(oldinstr, newinstr, feature, output, input...) \ |
111 | 277 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
112 | 277 | : output : input) |
113 | | |
114 | | /* |
115 | | * This is similar to alternative_io. But it has two features and |
116 | | * respective instructions. |
117 | | * |
118 | | * If CPU has feature2, newinstr2 is used. |
119 | | * Otherwise, if CPU has feature1, newinstr1 is used. |
120 | | * Otherwise, oldinstr is used. |
121 | | */ |
122 | | #define alternative_io_2(oldinstr, newinstr1, feature1, newinstr2, \ |
123 | | feature2, output, input...) \ |
124 | | asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \ |
125 | | newinstr2, feature2) \ |
126 | | : output : input) |
127 | | |
128 | | /* |
129 | | * This is similar to alternative_io. But it has three features and |
130 | | * respective instructions. |
131 | | * |
132 | | * If CPU has feature3, newinstr3 is used. |
133 | | * Otherwise, if CPU has feature2, newinstr2 is used. |
134 | | * Otherwise, if CPU has feature1, newinstr1 is used. |
135 | | * Otherwise, oldinstr is used. |
136 | | */ |
137 | | #define alternative_io_3(oldinstr, newinstr1, feature1, newinstr2, \ |
138 | | feature2, newinstr3, feature3, output, \ |
139 | | input...) \ |
140 | | asm volatile(ALTERNATIVE_3(oldinstr, newinstr1, feature1, \ |
141 | | newinstr2, feature2, newinstr3, \ |
142 | | feature3) \ |
143 | | : output : input) |
144 | | |
145 | | /* Use this macro(s) if you need more than one output parameter. */ |
146 | | #define ASM_OUTPUT2(a...) a |
147 | | |
148 | | #endif /* __ASSEMBLY__ */ |
149 | | |
150 | | #endif /* __X86_ALTERNATIVE_H__ */ |