x86/mm/pat: Don't report PAT on CPUs that don't support it
[linux/fpc-iii.git] / arch / x86 / include / asm / alternative.h
blob1b020381ab38965ae2a80d2d86df32c66c92e2e8
1 #ifndef _ASM_X86_ALTERNATIVE_H
2 #define _ASM_X86_ALTERNATIVE_H
4 #ifndef __ASSEMBLY__
6 #include <linux/types.h>
7 #include <linux/stddef.h>
8 #include <linux/stringify.h>
9 #include <asm/asm.h>
12 * Alternative inline assembly for SMP.
14 * The LOCK_PREFIX macro defined here replaces the LOCK and
15 * LOCK_PREFIX macros used everywhere in the source tree.
17 * SMP alternatives use the same data structures as the other
18 * alternatives and the X86_FEATURE_UP flag to indicate the case of a
19 * UP system running a SMP kernel. The existing apply_alternatives()
20 * works fine for patching a SMP kernel for UP.
22 * The SMP alternative tables can be kept after boot and contain both
23 * UP and SMP versions of the instructions to allow switching back to
24 * SMP at runtime, when hotplugging in a new CPU, which is especially
25 * useful in virtualized environments.
27 * The very common lock prefix is handled as special case in a
28 * separate table which is a pure address list without replacement ptr
29 * and size information. That keeps the table sizes small.
32 #ifdef CONFIG_SMP
33 #define LOCK_PREFIX_HERE \
34 ".pushsection .smp_locks,\"a\"\n" \
35 ".balign 4\n" \
36 ".long 671f - .\n" /* offset */ \
37 ".popsection\n" \
38 "671:"
40 #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; "
42 #else /* ! CONFIG_SMP */
43 #define LOCK_PREFIX_HERE ""
44 #define LOCK_PREFIX ""
45 #endif
47 struct alt_instr {
48 s32 instr_offset; /* original instruction */
49 s32 repl_offset; /* offset to replacement instruction */
50 u16 cpuid; /* cpuid bit set for replacement */
51 u8 instrlen; /* length of original instruction */
52 u8 replacementlen; /* length of new instruction */
53 u8 padlen; /* length of build-time padding */
54 } __packed;
57 * Debug flag that can be tested to see whether alternative
58 * instructions were patched in already:
60 extern int alternatives_patched;
62 extern void alternative_instructions(void);
63 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
65 struct module;
67 #ifdef CONFIG_SMP
68 extern void alternatives_smp_module_add(struct module *mod, char *name,
69 void *locks, void *locks_end,
70 void *text, void *text_end);
71 extern void alternatives_smp_module_del(struct module *mod);
72 extern void alternatives_enable_smp(void);
73 extern int alternatives_text_reserved(void *start, void *end);
74 extern bool skip_smp_alternatives;
75 #else
76 static inline void alternatives_smp_module_add(struct module *mod, char *name,
77 void *locks, void *locks_end,
78 void *text, void *text_end) {}
79 static inline void alternatives_smp_module_del(struct module *mod) {}
80 static inline void alternatives_enable_smp(void) {}
81 static inline int alternatives_text_reserved(void *start, void *end)
83 return 0;
85 #endif /* CONFIG_SMP */
87 #define b_replacement(num) "664"#num
88 #define e_replacement(num) "665"#num
90 #define alt_end_marker "663"
91 #define alt_slen "662b-661b"
92 #define alt_pad_len alt_end_marker"b-662b"
93 #define alt_total_slen alt_end_marker"b-661b"
94 #define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f"
96 #define __OLDINSTR(oldinstr, num) \
97 "661:\n\t" oldinstr "\n662:\n" \
98 ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \
99 "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n"
101 #define OLDINSTR(oldinstr, num) \
102 __OLDINSTR(oldinstr, num) \
103 alt_end_marker ":\n"
106 * max without conditionals. Idea adapted from:
107 * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
109 * The additional "-" is needed because gas works with s32s.
111 #define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))"
114 * Pad the second replacement alternative with additional NOPs if it is
115 * additionally longer than the first replacement alternative.
117 #define OLDINSTR_2(oldinstr, num1, num2) \
118 "661:\n\t" oldinstr "\n662:\n" \
119 ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \
120 "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n" \
121 alt_end_marker ":\n"
123 #define ALTINSTR_ENTRY(feature, num) \
124 " .long 661b - .\n" /* label */ \
125 " .long " b_replacement(num)"f - .\n" /* new instruction */ \
126 " .word " __stringify(feature) "\n" /* feature bit */ \
127 " .byte " alt_total_slen "\n" /* source len */ \
128 " .byte " alt_rlen(num) "\n" /* replacement len */ \
129 " .byte " alt_pad_len "\n" /* pad len */
131 #define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \
132 b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t"
134 /* alternative assembly primitive: */
135 #define ALTERNATIVE(oldinstr, newinstr, feature) \
136 OLDINSTR(oldinstr, 1) \
137 ".pushsection .altinstructions,\"a\"\n" \
138 ALTINSTR_ENTRY(feature, 1) \
139 ".popsection\n" \
140 ".pushsection .altinstr_replacement, \"ax\"\n" \
141 ALTINSTR_REPLACEMENT(newinstr, feature, 1) \
142 ".popsection"
144 #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\
145 OLDINSTR_2(oldinstr, 1, 2) \
146 ".pushsection .altinstructions,\"a\"\n" \
147 ALTINSTR_ENTRY(feature1, 1) \
148 ALTINSTR_ENTRY(feature2, 2) \
149 ".popsection\n" \
150 ".pushsection .altinstr_replacement, \"ax\"\n" \
151 ALTINSTR_REPLACEMENT(newinstr1, feature1, 1) \
152 ALTINSTR_REPLACEMENT(newinstr2, feature2, 2) \
153 ".popsection"
156 * Alternative instructions for different CPU types or capabilities.
158 * This allows to use optimized instructions even on generic binary
159 * kernels.
161 * length of oldinstr must be longer or equal the length of newinstr
162 * It can be padded with nops as needed.
164 * For non barrier like inlines please define new variants
165 * without volatile and memory clobber.
167 #define alternative(oldinstr, newinstr, feature) \
168 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
170 #define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
171 asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory")
174 * Alternative inline assembly with input.
176 * Pecularities:
177 * No memory clobber here.
178 * Argument numbers start with 1.
179 * Best is to use constraints that are fixed size (like (%1) ... "r")
180 * If you use variable sized constraints like "m" or "g" in the
181 * replacement make sure to pad to the worst case length.
182 * Leaving an unused argument 0 to keep API compatibility.
184 #define alternative_input(oldinstr, newinstr, feature, input...) \
185 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
186 : : "i" (0), ## input)
189 * This is similar to alternative_input. But it has two features and
190 * respective instructions.
192 * If CPU has feature2, newinstr2 is used.
193 * Otherwise, if CPU has feature1, newinstr1 is used.
194 * Otherwise, oldinstr is used.
196 #define alternative_input_2(oldinstr, newinstr1, feature1, newinstr2, \
197 feature2, input...) \
198 asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \
199 newinstr2, feature2) \
200 : : "i" (0), ## input)
202 /* Like alternative_input, but with a single output argument */
203 #define alternative_io(oldinstr, newinstr, feature, output, input...) \
204 asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
205 : output : "i" (0), ## input)
207 /* Like alternative_io, but for replacing a direct call with another one. */
208 #define alternative_call(oldfunc, newfunc, feature, output, input...) \
209 asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \
210 : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input)
213 * Like alternative_call, but there are two features and respective functions.
214 * If CPU has feature2, function2 is used.
215 * Otherwise, if CPU has feature1, function1 is used.
216 * Otherwise, old function is used.
218 #define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
219 output, input...) \
221 register void *__sp asm(_ASM_SP); \
222 asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
223 "call %P[new2]", feature2) \
224 : output, "+r" (__sp) \
225 : [old] "i" (oldfunc), [new1] "i" (newfunc1), \
226 [new2] "i" (newfunc2), ## input); \
230 * use this macro(s) if you need more than one output parameter
231 * in alternative_io
233 #define ASM_OUTPUT2(a...) a
236 * use this macro if you need clobbers but no inputs in
237 * alternative_{input,io,call}()
239 #define ASM_NO_INPUT_CLOBBER(clbr...) "i" (0) : clbr
241 #endif /* __ASSEMBLY__ */
243 #endif /* _ASM_X86_ALTERNATIVE_H */