diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/x86/kernel/alternative.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/x86/kernel/alternative.c')
-rw-r--r-- | arch/x86/kernel/alternative.c | 242 |
1 files changed, 172 insertions, 70 deletions
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index f65ab8b014c4..a81f2d52f869 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c | |||
@@ -67,17 +67,30 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt); | |||
67 | #define DPRINTK(fmt, args...) if (debug_alternative) \ | 67 | #define DPRINTK(fmt, args...) if (debug_alternative) \ |
68 | printk(KERN_DEBUG fmt, args) | 68 | printk(KERN_DEBUG fmt, args) |
69 | 69 | ||
70 | /* | ||
71 | * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes | ||
72 | * that correspond to that nop. Getting from one nop to the next, we | ||
73 | * add to the array the offset that is equal to the sum of all sizes of | ||
74 | * nops preceding the one we are after. | ||
75 | * | ||
76 | * Note: The GENERIC_NOP5_ATOMIC is at the end, as it breaks the | ||
77 | * nice symmetry of sizes of the previous nops. | ||
78 | */ | ||
70 | #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64) | 79 | #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64) |
71 | /* Use inline assembly to define this because the nops are defined | 80 | static const unsigned char intelnops[] = |
72 | as inline assembly strings in the include files and we cannot | 81 | { |
73 | get them easily into strings. */ | 82 | GENERIC_NOP1, |
74 | asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: " | 83 | GENERIC_NOP2, |
75 | GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 | 84 | GENERIC_NOP3, |
76 | GENERIC_NOP7 GENERIC_NOP8 | 85 | GENERIC_NOP4, |
77 | "\t.previous"); | 86 | GENERIC_NOP5, |
78 | extern const unsigned char intelnops[]; | 87 | GENERIC_NOP6, |
79 | static const unsigned char *const __initconst_or_module | 88 | GENERIC_NOP7, |
80 | intel_nops[ASM_NOP_MAX+1] = { | 89 | GENERIC_NOP8, |
90 | GENERIC_NOP5_ATOMIC | ||
91 | }; | ||
92 | static const unsigned char * const intel_nops[ASM_NOP_MAX+2] = | ||
93 | { | ||
81 | NULL, | 94 | NULL, |
82 | intelnops, | 95 | intelnops, |
83 | intelnops + 1, | 96 | intelnops + 1, |
@@ -87,17 +100,25 @@ intel_nops[ASM_NOP_MAX+1] = { | |||
87 | intelnops + 1 + 2 + 3 + 4 + 5, | 100 | intelnops + 1 + 2 + 3 + 4 + 5, |
88 | intelnops + 1 + 2 + 3 + 4 + 5 + 6, | 101 | intelnops + 1 + 2 + 3 + 4 + 5 + 6, |
89 | intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 102 | intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
103 | intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, | ||
90 | }; | 104 | }; |
91 | #endif | 105 | #endif |
92 | 106 | ||
93 | #ifdef K8_NOP1 | 107 | #ifdef K8_NOP1 |
94 | asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: " | 108 | static const unsigned char k8nops[] = |
95 | K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 | 109 | { |
96 | K8_NOP7 K8_NOP8 | 110 | K8_NOP1, |
97 | "\t.previous"); | 111 | K8_NOP2, |
98 | extern const unsigned char k8nops[]; | 112 | K8_NOP3, |
99 | static const unsigned char *const __initconst_or_module | 113 | K8_NOP4, |
100 | k8_nops[ASM_NOP_MAX+1] = { | 114 | K8_NOP5, |
115 | K8_NOP6, | ||
116 | K8_NOP7, | ||
117 | K8_NOP8, | ||
118 | K8_NOP5_ATOMIC | ||
119 | }; | ||
120 | static const unsigned char * const k8_nops[ASM_NOP_MAX+2] = | ||
121 | { | ||
101 | NULL, | 122 | NULL, |
102 | k8nops, | 123 | k8nops, |
103 | k8nops + 1, | 124 | k8nops + 1, |
@@ -107,17 +128,25 @@ k8_nops[ASM_NOP_MAX+1] = { | |||
107 | k8nops + 1 + 2 + 3 + 4 + 5, | 128 | k8nops + 1 + 2 + 3 + 4 + 5, |
108 | k8nops + 1 + 2 + 3 + 4 + 5 + 6, | 129 | k8nops + 1 + 2 + 3 + 4 + 5 + 6, |
109 | k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 130 | k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
131 | k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, | ||
110 | }; | 132 | }; |
111 | #endif | 133 | #endif |
112 | 134 | ||
113 | #if defined(K7_NOP1) && !defined(CONFIG_X86_64) | 135 | #if defined(K7_NOP1) && !defined(CONFIG_X86_64) |
114 | asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: " | 136 | static const unsigned char k7nops[] = |
115 | K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 | 137 | { |
116 | K7_NOP7 K7_NOP8 | 138 | K7_NOP1, |
117 | "\t.previous"); | 139 | K7_NOP2, |
118 | extern const unsigned char k7nops[]; | 140 | K7_NOP3, |
119 | static const unsigned char *const __initconst_or_module | 141 | K7_NOP4, |
120 | k7_nops[ASM_NOP_MAX+1] = { | 142 | K7_NOP5, |
143 | K7_NOP6, | ||
144 | K7_NOP7, | ||
145 | K7_NOP8, | ||
146 | K7_NOP5_ATOMIC | ||
147 | }; | ||
148 | static const unsigned char * const k7_nops[ASM_NOP_MAX+2] = | ||
149 | { | ||
121 | NULL, | 150 | NULL, |
122 | k7nops, | 151 | k7nops, |
123 | k7nops + 1, | 152 | k7nops + 1, |
@@ -127,17 +156,25 @@ k7_nops[ASM_NOP_MAX+1] = { | |||
127 | k7nops + 1 + 2 + 3 + 4 + 5, | 156 | k7nops + 1 + 2 + 3 + 4 + 5, |
128 | k7nops + 1 + 2 + 3 + 4 + 5 + 6, | 157 | k7nops + 1 + 2 + 3 + 4 + 5 + 6, |
129 | k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 158 | k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
159 | k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, | ||
130 | }; | 160 | }; |
131 | #endif | 161 | #endif |
132 | 162 | ||
133 | #ifdef P6_NOP1 | 163 | #ifdef P6_NOP1 |
134 | asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: " | 164 | static const unsigned char __initconst_or_module p6nops[] = |
135 | P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6 | 165 | { |
136 | P6_NOP7 P6_NOP8 | 166 | P6_NOP1, |
137 | "\t.previous"); | 167 | P6_NOP2, |
138 | extern const unsigned char p6nops[]; | 168 | P6_NOP3, |
139 | static const unsigned char *const __initconst_or_module | 169 | P6_NOP4, |
140 | p6_nops[ASM_NOP_MAX+1] = { | 170 | P6_NOP5, |
171 | P6_NOP6, | ||
172 | P6_NOP7, | ||
173 | P6_NOP8, | ||
174 | P6_NOP5_ATOMIC | ||
175 | }; | ||
176 | static const unsigned char * const p6_nops[ASM_NOP_MAX+2] = | ||
177 | { | ||
141 | NULL, | 178 | NULL, |
142 | p6nops, | 179 | p6nops, |
143 | p6nops + 1, | 180 | p6nops + 1, |
@@ -147,47 +184,65 @@ p6_nops[ASM_NOP_MAX+1] = { | |||
147 | p6nops + 1 + 2 + 3 + 4 + 5, | 184 | p6nops + 1 + 2 + 3 + 4 + 5, |
148 | p6nops + 1 + 2 + 3 + 4 + 5 + 6, | 185 | p6nops + 1 + 2 + 3 + 4 + 5 + 6, |
149 | p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, | 186 | p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7, |
187 | p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8, | ||
150 | }; | 188 | }; |
151 | #endif | 189 | #endif |
152 | 190 | ||
191 | /* Initialize these to a safe default */ | ||
153 | #ifdef CONFIG_X86_64 | 192 | #ifdef CONFIG_X86_64 |
193 | const unsigned char * const *ideal_nops = p6_nops; | ||
194 | #else | ||
195 | const unsigned char * const *ideal_nops = intel_nops; | ||
196 | #endif | ||
154 | 197 | ||
155 | extern char __vsyscall_0; | 198 | void __init arch_init_ideal_nops(void) |
156 | static const unsigned char *const *__init_or_module find_nop_table(void) | ||
157 | { | 199 | { |
158 | if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && | 200 | switch (boot_cpu_data.x86_vendor) { |
159 | boot_cpu_has(X86_FEATURE_NOPL)) | 201 | case X86_VENDOR_INTEL: |
160 | return p6_nops; | 202 | /* |
161 | else | 203 | * Due to a decoder implementation quirk, some |
162 | return k8_nops; | 204 | * specific Intel CPUs actually perform better with |
163 | } | 205 | * the "k8_nops" than with the SDM-recommended NOPs. |
164 | 206 | */ | |
165 | #else /* CONFIG_X86_64 */ | 207 | if (boot_cpu_data.x86 == 6 && |
208 | boot_cpu_data.x86_model >= 0x0f && | ||
209 | boot_cpu_data.x86_model != 0x1c && | ||
210 | boot_cpu_data.x86_model != 0x26 && | ||
211 | boot_cpu_data.x86_model != 0x27 && | ||
212 | boot_cpu_data.x86_model < 0x30) { | ||
213 | ideal_nops = k8_nops; | ||
214 | } else if (boot_cpu_has(X86_FEATURE_NOPL)) { | ||
215 | ideal_nops = p6_nops; | ||
216 | } else { | ||
217 | #ifdef CONFIG_X86_64 | ||
218 | ideal_nops = k8_nops; | ||
219 | #else | ||
220 | ideal_nops = intel_nops; | ||
221 | #endif | ||
222 | } | ||
166 | 223 | ||
167 | static const unsigned char *const *__init_or_module find_nop_table(void) | 224 | default: |
168 | { | 225 | #ifdef CONFIG_X86_64 |
169 | if (boot_cpu_has(X86_FEATURE_K8)) | 226 | ideal_nops = k8_nops; |
170 | return k8_nops; | 227 | #else |
171 | else if (boot_cpu_has(X86_FEATURE_K7)) | 228 | if (boot_cpu_has(X86_FEATURE_K8)) |
172 | return k7_nops; | 229 | ideal_nops = k8_nops; |
173 | else if (boot_cpu_has(X86_FEATURE_NOPL)) | 230 | else if (boot_cpu_has(X86_FEATURE_K7)) |
174 | return p6_nops; | 231 | ideal_nops = k7_nops; |
175 | else | 232 | else |
176 | return intel_nops; | 233 | ideal_nops = intel_nops; |
234 | #endif | ||
235 | } | ||
177 | } | 236 | } |
178 | 237 | ||
179 | #endif /* CONFIG_X86_64 */ | ||
180 | |||
181 | /* Use this to add nops to a buffer, then text_poke the whole buffer. */ | 238 | /* Use this to add nops to a buffer, then text_poke the whole buffer. */ |
182 | static void __init_or_module add_nops(void *insns, unsigned int len) | 239 | static void __init_or_module add_nops(void *insns, unsigned int len) |
183 | { | 240 | { |
184 | const unsigned char *const *noptable = find_nop_table(); | ||
185 | |||
186 | while (len > 0) { | 241 | while (len > 0) { |
187 | unsigned int noplen = len; | 242 | unsigned int noplen = len; |
188 | if (noplen > ASM_NOP_MAX) | 243 | if (noplen > ASM_NOP_MAX) |
189 | noplen = ASM_NOP_MAX; | 244 | noplen = ASM_NOP_MAX; |
190 | memcpy(insns, noptable[noplen], noplen); | 245 | memcpy(insns, ideal_nops[noplen], noplen); |
191 | insns += noplen; | 246 | insns += noplen; |
192 | len -= noplen; | 247 | len -= noplen; |
193 | } | 248 | } |
@@ -195,11 +250,12 @@ static void __init_or_module add_nops(void *insns, unsigned int len) | |||
195 | 250 | ||
196 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; | 251 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; |
197 | extern s32 __smp_locks[], __smp_locks_end[]; | 252 | extern s32 __smp_locks[], __smp_locks_end[]; |
198 | static void *text_poke_early(void *addr, const void *opcode, size_t len); | 253 | extern char __vsyscall_0; |
254 | void *text_poke_early(void *addr, const void *opcode, size_t len); | ||
199 | 255 | ||
200 | /* Replace instructions with better alternatives for this CPU type. | 256 | /* Replace instructions with better alternatives for this CPU type. |
201 | This runs before SMP is initialized to avoid SMP problems with | 257 | This runs before SMP is initialized to avoid SMP problems with |
202 | self modifying code. This implies that assymetric systems where | 258 | self modifying code. This implies that asymmetric systems where |
203 | APs have less capabilities than the boot processor are not handled. | 259 | APs have less capabilities than the boot processor are not handled. |
204 | Tough. Make sure you disable such features by hand. */ | 260 | Tough. Make sure you disable such features by hand. */ |
205 | 261 | ||
@@ -210,6 +266,15 @@ void __init_or_module apply_alternatives(struct alt_instr *start, | |||
210 | u8 insnbuf[MAX_PATCH_LEN]; | 266 | u8 insnbuf[MAX_PATCH_LEN]; |
211 | 267 | ||
212 | DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); | 268 | DPRINTK("%s: alt table %p -> %p\n", __func__, start, end); |
269 | /* | ||
270 | * The scan order should be from start to end. A later scanned | ||
271 | * alternative code can overwrite a previous scanned alternative code. | ||
272 | * Some kernel functions (e.g. memcpy, memset, etc) use this order to | ||
273 | * patch code. | ||
274 | * | ||
275 | * So be careful if you want to change the scan order to any other | ||
276 | * order. | ||
277 | */ | ||
213 | for (a = start; a < end; a++) { | 278 | for (a = start; a < end; a++) { |
214 | u8 *instr = a->instr; | 279 | u8 *instr = a->instr; |
215 | BUG_ON(a->replacementlen > a->instrlen); | 280 | BUG_ON(a->replacementlen > a->instrlen); |
@@ -353,6 +418,7 @@ void __init_or_module alternatives_smp_module_del(struct module *mod) | |||
353 | mutex_unlock(&smp_alt); | 418 | mutex_unlock(&smp_alt); |
354 | } | 419 | } |
355 | 420 | ||
421 | bool skip_smp_alternatives; | ||
356 | void alternatives_smp_switch(int smp) | 422 | void alternatives_smp_switch(int smp) |
357 | { | 423 | { |
358 | struct smp_alt_module *mod; | 424 | struct smp_alt_module *mod; |
@@ -368,7 +434,7 @@ void alternatives_smp_switch(int smp) | |||
368 | printk("lockdep: fixing up alternatives.\n"); | 434 | printk("lockdep: fixing up alternatives.\n"); |
369 | #endif | 435 | #endif |
370 | 436 | ||
371 | if (noreplace_smp || smp_alt_once) | 437 | if (noreplace_smp || smp_alt_once || skip_smp_alternatives) |
372 | return; | 438 | return; |
373 | BUG_ON(!smp && (num_online_cpus() > 1)); | 439 | BUG_ON(!smp && (num_online_cpus() > 1)); |
374 | 440 | ||
@@ -522,7 +588,7 @@ void __init alternative_instructions(void) | |||
522 | * instructions. And on the local CPU you need to be protected again NMI or MCE | 588 | * instructions. And on the local CPU you need to be protected again NMI or MCE |
523 | * handlers seeing an inconsistent instruction while you patch. | 589 | * handlers seeing an inconsistent instruction while you patch. |
524 | */ | 590 | */ |
525 | static void *__init_or_module text_poke_early(void *addr, const void *opcode, | 591 | void *__init_or_module text_poke_early(void *addr, const void *opcode, |
526 | size_t len) | 592 | size_t len) |
527 | { | 593 | { |
528 | unsigned long flags; | 594 | unsigned long flags; |
@@ -591,17 +657,21 @@ static atomic_t stop_machine_first; | |||
591 | static int wrote_text; | 657 | static int wrote_text; |
592 | 658 | ||
593 | struct text_poke_params { | 659 | struct text_poke_params { |
594 | void *addr; | 660 | struct text_poke_param *params; |
595 | const void *opcode; | 661 | int nparams; |
596 | size_t len; | ||
597 | }; | 662 | }; |
598 | 663 | ||
599 | static int __kprobes stop_machine_text_poke(void *data) | 664 | static int __kprobes stop_machine_text_poke(void *data) |
600 | { | 665 | { |
601 | struct text_poke_params *tpp = data; | 666 | struct text_poke_params *tpp = data; |
667 | struct text_poke_param *p; | ||
668 | int i; | ||
602 | 669 | ||
603 | if (atomic_dec_and_test(&stop_machine_first)) { | 670 | if (atomic_dec_and_test(&stop_machine_first)) { |
604 | text_poke(tpp->addr, tpp->opcode, tpp->len); | 671 | for (i = 0; i < tpp->nparams; i++) { |
672 | p = &tpp->params[i]; | ||
673 | text_poke(p->addr, p->opcode, p->len); | ||
674 | } | ||
605 | smp_wmb(); /* Make sure other cpus see that this has run */ | 675 | smp_wmb(); /* Make sure other cpus see that this has run */ |
606 | wrote_text = 1; | 676 | wrote_text = 1; |
607 | } else { | 677 | } else { |
@@ -610,8 +680,17 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
610 | smp_mb(); /* Load wrote_text before following execution */ | 680 | smp_mb(); /* Load wrote_text before following execution */ |
611 | } | 681 | } |
612 | 682 | ||
613 | flush_icache_range((unsigned long)tpp->addr, | 683 | for (i = 0; i < tpp->nparams; i++) { |
614 | (unsigned long)tpp->addr + tpp->len); | 684 | p = &tpp->params[i]; |
685 | flush_icache_range((unsigned long)p->addr, | ||
686 | (unsigned long)p->addr + p->len); | ||
687 | } | ||
688 | /* | ||
689 | * Intel Archiecture Software Developer's Manual section 7.1.3 specifies | ||
690 | * that a core serializing instruction such as "cpuid" should be | ||
691 | * executed on _each_ core before the new instruction is made visible. | ||
692 | */ | ||
693 | sync_core(); | ||
615 | return 0; | 694 | return 0; |
616 | } | 695 | } |
617 | 696 | ||
@@ -631,13 +710,36 @@ static int __kprobes stop_machine_text_poke(void *data) | |||
631 | void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) | 710 | void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len) |
632 | { | 711 | { |
633 | struct text_poke_params tpp; | 712 | struct text_poke_params tpp; |
713 | struct text_poke_param p; | ||
634 | 714 | ||
635 | tpp.addr = addr; | 715 | p.addr = addr; |
636 | tpp.opcode = opcode; | 716 | p.opcode = opcode; |
637 | tpp.len = len; | 717 | p.len = len; |
718 | tpp.params = &p; | ||
719 | tpp.nparams = 1; | ||
638 | atomic_set(&stop_machine_first, 1); | 720 | atomic_set(&stop_machine_first, 1); |
639 | wrote_text = 0; | 721 | wrote_text = 0; |
640 | stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); | 722 | /* Use __stop_machine() because the caller already got online_cpus. */ |
723 | __stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask); | ||
641 | return addr; | 724 | return addr; |
642 | } | 725 | } |
643 | 726 | ||
727 | /** | ||
728 | * text_poke_smp_batch - Update instructions on a live kernel on SMP | ||
729 | * @params: an array of text_poke parameters | ||
730 | * @n: the number of elements in params. | ||
731 | * | ||
732 | * Modify multi-byte instruction by using stop_machine() on SMP. Since the | ||
733 | * stop_machine() is heavy task, it is better to aggregate text_poke requests | ||
734 | * and do it once if possible. | ||
735 | * | ||
736 | * Note: Must be called under get_online_cpus() and text_mutex. | ||
737 | */ | ||
738 | void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n) | ||
739 | { | ||
740 | struct text_poke_params tpp = {.params = params, .nparams = n}; | ||
741 | |||
742 | atomic_set(&stop_machine_first, 1); | ||
743 | wrote_text = 0; | ||
744 | __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL); | ||
745 | } | ||