diff options
Diffstat (limited to 'arch/x86/include/asm/alternative.h')
-rw-r--r-- | arch/x86/include/asm/alternative.h | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 69b74a7b877f..bc6abb7bc7ee 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h | |||
@@ -28,27 +28,26 @@ | |||
28 | */ | 28 | */ |
29 | 29 | ||
30 | #ifdef CONFIG_SMP | 30 | #ifdef CONFIG_SMP |
31 | #define LOCK_PREFIX \ | 31 | #define LOCK_PREFIX_HERE \ |
32 | ".section .smp_locks,\"a\"\n" \ | 32 | ".section .smp_locks,\"a\"\n" \ |
33 | _ASM_ALIGN "\n" \ | 33 | ".balign 4\n" \ |
34 | _ASM_PTR "661f\n" /* address */ \ | 34 | ".long 671f - .\n" /* offset */ \ |
35 | ".previous\n" \ | 35 | ".previous\n" \ |
36 | "661:\n\tlock; " | 36 | "671:" |
37 | |||
38 | #define LOCK_PREFIX LOCK_PREFIX_HERE "\n\tlock; " | ||
37 | 39 | ||
38 | #else /* ! CONFIG_SMP */ | 40 | #else /* ! CONFIG_SMP */ |
41 | #define LOCK_PREFIX_HERE "" | ||
39 | #define LOCK_PREFIX "" | 42 | #define LOCK_PREFIX "" |
40 | #endif | 43 | #endif |
41 | 44 | ||
42 | /* This must be included *after* the definition of LOCK_PREFIX */ | ||
43 | #include <asm/cpufeature.h> | ||
44 | |||
45 | struct alt_instr { | 45 | struct alt_instr { |
46 | u8 *instr; /* original instruction */ | 46 | u8 *instr; /* original instruction */ |
47 | u8 *replacement; | 47 | u8 *replacement; |
48 | u8 cpuid; /* cpuid bit set for replacement */ | 48 | u16 cpuid; /* cpuid bit set for replacement */ |
49 | u8 instrlen; /* length of original instruction */ | 49 | u8 instrlen; /* length of original instruction */ |
50 | u8 replacementlen; /* length of new instruction, <= instrlen */ | 50 | u8 replacementlen; /* length of new instruction, <= instrlen */ |
51 | u8 pad1; | ||
52 | #ifdef CONFIG_X86_64 | 51 | #ifdef CONFIG_X86_64 |
53 | u32 pad2; | 52 | u32 pad2; |
54 | #endif | 53 | #endif |
@@ -65,12 +64,17 @@ extern void alternatives_smp_module_add(struct module *mod, char *name, | |||
65 | void *text, void *text_end); | 64 | void *text, void *text_end); |
66 | extern void alternatives_smp_module_del(struct module *mod); | 65 | extern void alternatives_smp_module_del(struct module *mod); |
67 | extern void alternatives_smp_switch(int smp); | 66 | extern void alternatives_smp_switch(int smp); |
67 | extern int alternatives_text_reserved(void *start, void *end); | ||
68 | #else | 68 | #else |
69 | static inline void alternatives_smp_module_add(struct module *mod, char *name, | 69 | static inline void alternatives_smp_module_add(struct module *mod, char *name, |
70 | void *locks, void *locks_end, | 70 | void *locks, void *locks_end, |
71 | void *text, void *text_end) {} | 71 | void *text, void *text_end) {} |
72 | static inline void alternatives_smp_module_del(struct module *mod) {} | 72 | static inline void alternatives_smp_module_del(struct module *mod) {} |
73 | static inline void alternatives_smp_switch(int smp) {} | 73 | static inline void alternatives_smp_switch(int smp) {} |
74 | static inline int alternatives_text_reserved(void *start, void *end) | ||
75 | { | ||
76 | return 0; | ||
77 | } | ||
74 | #endif /* CONFIG_SMP */ | 78 | #endif /* CONFIG_SMP */ |
75 | 79 | ||
76 | /* alternative assembly primitive: */ | 80 | /* alternative assembly primitive: */ |
@@ -81,9 +85,11 @@ static inline void alternatives_smp_switch(int smp) {} | |||
81 | _ASM_ALIGN "\n" \ | 85 | _ASM_ALIGN "\n" \ |
82 | _ASM_PTR "661b\n" /* label */ \ | 86 | _ASM_PTR "661b\n" /* label */ \ |
83 | _ASM_PTR "663f\n" /* new instruction */ \ | 87 | _ASM_PTR "663f\n" /* new instruction */ \ |
84 | " .byte " __stringify(feature) "\n" /* feature bit */ \ | 88 | " .word " __stringify(feature) "\n" /* feature bit */ \ |
85 | " .byte 662b-661b\n" /* sourcelen */ \ | 89 | " .byte 662b-661b\n" /* sourcelen */ \ |
86 | " .byte 664f-663f\n" /* replacementlen */ \ | 90 | " .byte 664f-663f\n" /* replacementlen */ \ |
91 | ".previous\n" \ | ||
92 | ".section .discard,\"aw\",@progbits\n" \ | ||
87 | " .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */ \ | 93 | " .byte 0xff + (664f-663f) - (662b-661b)\n" /* rlen <= slen */ \ |
88 | ".previous\n" \ | 94 | ".previous\n" \ |
89 | ".section .altinstr_replacement, \"ax\"\n" \ | 95 | ".section .altinstr_replacement, \"ax\"\n" \ |
@@ -91,6 +97,12 @@ static inline void alternatives_smp_switch(int smp) {} | |||
91 | ".previous" | 97 | ".previous" |
92 | 98 | ||
93 | /* | 99 | /* |
100 | * This must be included *after* the definition of ALTERNATIVE due to | ||
101 | * <asm/arch_hweight.h> | ||
102 | */ | ||
103 | #include <asm/cpufeature.h> | ||
104 | |||
105 | /* | ||
94 | * Alternative instructions for different CPU types or capabilities. | 106 | * Alternative instructions for different CPU types or capabilities. |
95 | * | 107 | * |
96 | * This allows to use optimized instructions even on generic binary | 108 | * This allows to use optimized instructions even on generic binary |
@@ -125,11 +137,16 @@ static inline void alternatives_smp_switch(int smp) {} | |||
125 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ | 137 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) \ |
126 | : output : "i" (0), ## input) | 138 | : output : "i" (0), ## input) |
127 | 139 | ||
140 | /* Like alternative_io, but for replacing a direct call with another one. */ | ||
141 | #define alternative_call(oldfunc, newfunc, feature, output, input...) \ | ||
142 | asm volatile (ALTERNATIVE("call %P[old]", "call %P[new]", feature) \ | ||
143 | : output : [old] "i" (oldfunc), [new] "i" (newfunc), ## input) | ||
144 | |||
128 | /* | 145 | /* |
129 | * use this macro(s) if you need more than one output parameter | 146 | * use this macro(s) if you need more than one output parameter |
130 | * in alternative_io | 147 | * in alternative_io |
131 | */ | 148 | */ |
132 | #define ASM_OUTPUT2(a, b) a, b | 149 | #define ASM_OUTPUT2(a...) a |
133 | 150 | ||
134 | struct paravirt_patch_site; | 151 | struct paravirt_patch_site; |
135 | #ifdef CONFIG_PARAVIRT | 152 | #ifdef CONFIG_PARAVIRT |
@@ -155,10 +172,12 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, | |||
155 | * invalid instruction possible) or if the instructions are changed from a | 172 | * invalid instruction possible) or if the instructions are changed from a |
156 | * consistent state to another consistent state atomically. | 173 | * consistent state to another consistent state atomically. |
157 | * More care must be taken when modifying code in the SMP case because of | 174 | * More care must be taken when modifying code in the SMP case because of |
158 | * Intel's errata. | 175 | * Intel's errata. text_poke_smp() takes care that errata, but still |
176 | * doesn't support NMI/MCE handler code modifying. | ||
159 | * On the local CPU you need to be protected again NMI or MCE handlers seeing an | 177 | * On the local CPU you need to be protected again NMI or MCE handlers seeing an |
160 | * inconsistent instruction while you patch. | 178 | * inconsistent instruction while you patch. |
161 | */ | 179 | */ |
162 | extern void *text_poke(void *addr, const void *opcode, size_t len); | 180 | extern void *text_poke(void *addr, const void *opcode, size_t len); |
181 | extern void *text_poke_smp(void *addr, const void *opcode, size_t len); | ||
163 | 182 | ||
164 | #endif /* _ASM_X86_ALTERNATIVE_H */ | 183 | #endif /* _ASM_X86_ALTERNATIVE_H */ |