1 #define pr_fmt(fmt) "SMP alternatives: " fmt
3 #include <linux/module.h>
4 #include <linux/sched.h>
6 #include <linux/list.h>
13 #include <linux/slab.h>
15 #include <asm/sections.h>
16 #include <asm/pgtable.h>
19 #include <asm/cacheflush.h>
20 #include <asm/tlbflush.h>
22 #include <asm/fixmap.h>
24 #define MAX_PATCH_LEN (255-1)
30 debug_alternative = 1;
33 __setup(
"debug-alternative", debug_alt);
35 static int noreplace_smp;
37 static int __init setup_noreplace_smp(
char *
str)
42 __setup(
"noreplace-smp", setup_noreplace_smp);
44 #ifdef CONFIG_PARAVIRT
47 static int __init setup_noreplace_paravirt(
char *
str)
49 noreplace_paravirt = 1;
52 __setup(
"noreplace-paravirt", setup_noreplace_paravirt);
55 #define DPRINTK(fmt, ...) \
57 if (debug_alternative) \
58 printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
70 #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64)
71 static const unsigned char intelnops[] =
83 static const unsigned char *
const intel_nops[
ASM_NOP_MAX+2] =
89 intelnops + 1 + 2 + 3,
90 intelnops + 1 + 2 + 3 + 4,
91 intelnops + 1 + 2 + 3 + 4 + 5,
92 intelnops + 1 + 2 + 3 + 4 + 5 + 6,
93 intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
94 intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
99 static const unsigned char k8nops[] =
111 static const unsigned char *
const k8_nops[
ASM_NOP_MAX+2] =
118 k8nops + 1 + 2 + 3 + 4,
119 k8nops + 1 + 2 + 3 + 4 + 5,
120 k8nops + 1 + 2 + 3 + 4 + 5 + 6,
121 k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
122 k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
126 #if defined(K7_NOP1) && !defined(CONFIG_X86_64)
127 static const unsigned char k7nops[] =
139 static const unsigned char *
const k7_nops[
ASM_NOP_MAX+2] =
146 k7nops + 1 + 2 + 3 + 4,
147 k7nops + 1 + 2 + 3 + 4 + 5,
148 k7nops + 1 + 2 + 3 + 4 + 5 + 6,
149 k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
150 k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
155 static const unsigned char p6nops[] =
167 static const unsigned char *
const p6_nops[
ASM_NOP_MAX+2] =
174 p6nops + 1 + 2 + 3 + 4,
175 p6nops + 1 + 2 + 3 + 4 + 5,
176 p6nops + 1 + 2 + 3 + 4 + 5 + 6,
177 p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
178 p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
184 const unsigned char *
const *
ideal_nops = p6_nops;
233 unsigned int noplen = len;
259 DPRINTK(
"%s: alt table %p -> %p\n", __func__, start, end);
269 for (a = start; a <
end; a++) {
275 if (!boot_cpu_has(a->
cpuid))
282 *(
s32 *)(insnbuf + 1) += replacement -
instr;
293 static void alternatives_smp_lock(
const s32 *
start,
const s32 *
end,
299 for (poff = start; poff <
end; poff++) {
302 if (!*poff || ptr < text || ptr >= text_end)
306 text_poke(ptr, ((
unsigned char []){0xf0}), 1);
311 static void alternatives_smp_unlock(
const s32 *start,
const s32 *end,
312 u8 *text,
u8 *text_end)
317 for (poff = start; poff <
end; poff++) {
318 u8 *ptr = (
u8 *)poff + *poff;
320 if (!*poff || ptr < text || ptr >= text_end)
324 text_poke(ptr, ((
unsigned char []){0x3E}), 1);
329 struct smp_alt_module {
336 const s32 *locks_end;
346 static bool uniproc_patched =
false;
350 void *locks,
void *locks_end,
351 void *text,
void *text_end)
353 struct smp_alt_module *
smp;
356 if (!uniproc_patched)
371 smp->locks_end = locks_end;
373 smp->text_end = text_end;
374 DPRINTK(
"%s: locks %p -> %p, text %p -> %p, name %s\n",
375 __func__, smp->locks, smp->locks_end,
376 smp->text, smp->text_end, smp->name);
380 alternatives_smp_unlock(locks, locks_end, text, text_end);
387 struct smp_alt_module *
item;
391 if (mod != item->mod)
400 void alternatives_enable_smp(
void)
402 struct smp_alt_module *
mod;
404 #ifdef CONFIG_LOCKDEP
412 pr_info(
"lockdep: fixing up alternatives\n");
420 if (uniproc_patched) {
421 pr_info(
"switching to SMP code\n");
426 alternatives_smp_lock(mod->locks, mod->locks_end,
427 mod->text, mod->text_end);
428 uniproc_patched =
false;
434 int alternatives_text_reserved(
void *start,
void *end)
436 struct smp_alt_module *
mod;
442 if (mod->text > text_end || mod->text_end < text_start)
444 for (poff = mod->locks; poff < mod->locks_end; poff++) {
445 const u8 *ptr = (
const u8 *)poff + *poff;
447 if (text_start <= ptr && text_end > ptr)
456 #ifdef CONFIG_PARAVIRT
463 if (noreplace_paravirt)
466 for (p = start; p <
end; p++) {
478 add_nops(insnbuf + used, p->
len - used);
483 __stop_parainstructions[];
509 uniproc_patched =
true;
510 alternatives_smp_module_add(
NULL,
"core kernel",
511 __smp_locks, __smp_locks_end,
517 (
unsigned long)__smp_locks,
518 (
unsigned long)__smp_locks_end);
543 memcpy(addr, opcode, len);
576 WARN_ON(!PageReserved(pages[0]));
593 for (i = 0; i < len; i++)
594 BUG_ON(((
char *)addr)[i] != ((
char *)opcode)[i]);
604 static int wrote_text;
618 for (i = 0; i < tpp->
nparams; i++) {
630 for (i = 0; i < tpp->
nparams; i++) {
633 (
unsigned long)p->
addr + p->
len);