diff options
Diffstat (limited to 'arch/x86/kernel/alternative.c')
| -rw-r--r-- | arch/x86/kernel/alternative.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 1a160d5d44d0..70237732a6c7 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
| @@ -194,7 +194,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len) | |||
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; | 196 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; |
| 197 | extern u8 *__smp_locks[], *__smp_locks_end[]; | 197 | extern s32 __smp_locks[], __smp_locks_end[]; |
| 198 | static void *text_poke_early(void *addr, const void *opcode, size_t len); | 198 | static void *text_poke_early(void *addr, const void *opcode, size_t len); |
| 199 | 199 | ||
| 200 | /* Replace instructions with better alternatives for this CPU type. | 200 | /* Replace instructions with better alternatives for this CPU type. |
| @@ -235,37 +235,41 @@ void __init_or_module apply_alternatives(struct alt_instr *start, | |||
| 235 | 235 | ||
| 236 | #ifdef CONFIG_SMP | 236 | #ifdef CONFIG_SMP |
| 237 | 237 | ||
| 238 | static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end) | 238 | static void alternatives_smp_lock(const s32 *start, const s32 *end, |
| 239 | u8 *text, u8 *text_end) | ||
| 239 | { | 240 | { |
| 240 | u8 **ptr; | 241 | const s32 *poff; |
| 241 | 242 | ||
| 242 | mutex_lock(&text_mutex); | 243 | mutex_lock(&text_mutex); |
| 243 | for (ptr = start; ptr < end; ptr++) { | 244 | for (poff = start; poff < end; poff++) { |
| 244 | if (*ptr < text) | 245 | u8 *ptr = (u8 *)poff + *poff; |
| 245 | continue; | 246 | |
| 246 | if (*ptr > text_end) | 247 | if (!*poff || ptr < text || ptr >= text_end) |
| 247 | continue; | 248 | continue; |
| 248 | /* turn DS segment override prefix into lock prefix */ | 249 | /* turn DS segment override prefix into lock prefix */ |
| 249 | text_poke(*ptr, ((unsigned char []){0xf0}), 1); | 250 | if (*ptr == 0x3e) |
| 251 | text_poke(ptr, ((unsigned char []){0xf0}), 1); | ||
| 250 | }; | 252 | }; |
| 251 | mutex_unlock(&text_mutex); | 253 | mutex_unlock(&text_mutex); |
| 252 | } | 254 | } |
| 253 | 255 | ||
| 254 | static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end) | 256 | static void alternatives_smp_unlock(const s32 *start, const s32 *end, |
| 257 | u8 *text, u8 *text_end) | ||
| 255 | { | 258 | { |
| 256 | u8 **ptr; | 259 | const s32 *poff; |
| 257 | 260 | ||
| 258 | if (noreplace_smp) | 261 | if (noreplace_smp) |
| 259 | return; | 262 | return; |
| 260 | 263 | ||
| 261 | mutex_lock(&text_mutex); | 264 | mutex_lock(&text_mutex); |
| 262 | for (ptr = start; ptr < end; ptr++) { | 265 | for (poff = start; poff < end; poff++) { |
| 263 | if (*ptr < text) | 266 | u8 *ptr = (u8 *)poff + *poff; |
| 264 | continue; | 267 | |
| 265 | if (*ptr > text_end) | 268 | if (!*poff || ptr < text || ptr >= text_end) |
| 266 | continue; | 269 | continue; |
| 267 | /* turn lock prefix into DS segment override prefix */ | 270 | /* turn lock prefix into DS segment override prefix */ |
| 268 | text_poke(*ptr, ((unsigned char []){0x3E}), 1); | 271 | if (*ptr == 0xf0) |
| 272 | text_poke(ptr, ((unsigned char []){0x3E}), 1); | ||
| 269 | }; | 273 | }; |
| 270 | mutex_unlock(&text_mutex); | 274 | mutex_unlock(&text_mutex); |
| 271 | } | 275 | } |
| @@ -276,8 +280,8 @@ struct smp_alt_module { | |||
| 276 | char *name; | 280 | char *name; |
| 277 | 281 | ||
| 278 | /* ptrs to lock prefixes */ | 282 | /* ptrs to lock prefixes */ |
| 279 | u8 **locks; | 283 | const s32 *locks; |
| 280 | u8 **locks_end; | 284 | const s32 *locks_end; |
| 281 | 285 | ||
| 282 | /* .text segment, needed to avoid patching init code ;) */ | 286 | /* .text segment, needed to avoid patching init code ;) */ |
| 283 | u8 *text; | 287 | u8 *text; |
| @@ -398,16 +402,19 @@ void alternatives_smp_switch(int smp) | |||
| 398 | int alternatives_text_reserved(void *start, void *end) | 402 | int alternatives_text_reserved(void *start, void *end) |
| 399 | { | 403 | { |
| 400 | struct smp_alt_module *mod; | 404 | struct smp_alt_module *mod; |
| 401 | u8 **ptr; | 405 | const s32 *poff; |
| 402 | u8 *text_start = start; | 406 | u8 *text_start = start; |
| 403 | u8 *text_end = end; | 407 | u8 *text_end = end; |
| 404 | 408 | ||
| 405 | list_for_each_entry(mod, &smp_alt_modules, next) { | 409 | list_for_each_entry(mod, &smp_alt_modules, next) { |
| 406 | if (mod->text > text_end || mod->text_end < text_start) | 410 | if (mod->text > text_end || mod->text_end < text_start) |
| 407 | continue; | 411 | continue; |
| 408 | for (ptr = mod->locks; ptr < mod->locks_end; ptr++) | 412 | for (poff = mod->locks; poff < mod->locks_end; poff++) { |
| 409 | if (text_start <= *ptr && text_end >= *ptr) | 413 | const u8 *ptr = (const u8 *)poff + *poff; |
| 414 | |||
| 415 | if (text_start <= ptr && text_end > ptr) | ||
| 410 | return 1; | 416 | return 1; |
| 417 | } | ||
| 411 | } | 418 | } |
| 412 | 419 | ||
| 413 | return 0; | 420 | return 0; |
