GNU Linux-libre 4.19.264-gnu1
[releases.git] / arch / powerpc / lib / feature-fixups.c
1 /*
2  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
3  *
4  *  Modifications for ppc64:
5  *      Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
6  *
7  *  Copyright 2008 Michael Ellerman, IBM Corporation.
8  *
9  *  This program is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU General Public License
11  *  as published by the Free Software Foundation; either version
12  *  2 of the License, or (at your option) any later version.
13  */
14
15 #include <linux/types.h>
16 #include <linux/jump_label.h>
17 #include <linux/kernel.h>
18 #include <linux/string.h>
19 #include <linux/init.h>
20 #include <linux/sched/mm.h>
21 #include <linux/stop_machine.h>
22 #include <asm/cputable.h>
23 #include <asm/code-patching.h>
24 #include <asm/page.h>
25 #include <asm/sections.h>
26 #include <asm/setup.h>
27 #include <asm/security_features.h>
28 #include <asm/firmware.h>
29
30 struct fixup_entry {
31         unsigned long   mask;
32         unsigned long   value;
33         long            start_off;
34         long            end_off;
35         long            alt_start_off;
36         long            alt_end_off;
37 };
38
39 static unsigned int *calc_addr(struct fixup_entry *fcur, long offset)
40 {
41         /*
42          * We store the offset to the code as a negative offset from
43          * the start of the alt_entry, to support the VDSO. This
44          * routine converts that back into an actual address.
45          */
46         return (unsigned int *)((unsigned long)fcur + offset);
47 }
48
49 static int patch_alt_instruction(unsigned int *src, unsigned int *dest,
50                                  unsigned int *alt_start, unsigned int *alt_end)
51 {
52         unsigned int instr;
53
54         instr = *src;
55
56         if (instr_is_relative_branch(*src)) {
57                 unsigned int *target = (unsigned int *)branch_target(src);
58
59                 /* Branch within the section doesn't need translating */
60                 if (target < alt_start || target > alt_end) {
61                         instr = translate_branch(dest, src);
62                         if (!instr)
63                                 return 1;
64                 }
65         }
66
67         raw_patch_instruction(dest, instr);
68
69         return 0;
70 }
71
72 static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
73 {
74         unsigned int *start, *end, *alt_start, *alt_end, *src, *dest;
75
76         start = calc_addr(fcur, fcur->start_off);
77         end = calc_addr(fcur, fcur->end_off);
78         alt_start = calc_addr(fcur, fcur->alt_start_off);
79         alt_end = calc_addr(fcur, fcur->alt_end_off);
80
81         if ((alt_end - alt_start) > (end - start))
82                 return 1;
83
84         if ((value & fcur->mask) == fcur->value)
85                 return 0;
86
87         src = alt_start;
88         dest = start;
89
90         for (; src < alt_end; src++, dest++) {
91                 if (patch_alt_instruction(src, dest, alt_start, alt_end))
92                         return 1;
93         }
94
95         for (; dest < end; dest++)
96                 raw_patch_instruction(dest, PPC_INST_NOP);
97
98         return 0;
99 }
100
101 void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
102 {
103         struct fixup_entry *fcur, *fend;
104
105         fcur = fixup_start;
106         fend = fixup_end;
107
108         for (; fcur < fend; fcur++) {
109                 if (patch_feature_section(value, fcur)) {
110                         WARN_ON(1);
111                         printk("Unable to patch feature section at %p - %p" \
112                                 " with %p - %p\n",
113                                 calc_addr(fcur, fcur->start_off),
114                                 calc_addr(fcur, fcur->end_off),
115                                 calc_addr(fcur, fcur->alt_start_off),
116                                 calc_addr(fcur, fcur->alt_end_off));
117                 }
118         }
119 }
120
121 #ifdef CONFIG_PPC_BOOK3S_64
122 void do_stf_entry_barrier_fixups(enum stf_barrier_type types)
123 {
124         unsigned int instrs[3], *dest;
125         long *start, *end;
126         int i;
127
128         start = PTRRELOC(&__start___stf_entry_barrier_fixup),
129         end = PTRRELOC(&__stop___stf_entry_barrier_fixup);
130
131         instrs[0] = 0x60000000; /* nop */
132         instrs[1] = 0x60000000; /* nop */
133         instrs[2] = 0x60000000; /* nop */
134
135         i = 0;
136         if (types & STF_BARRIER_FALLBACK) {
137                 instrs[i++] = 0x7d4802a6; /* mflr r10           */
138                 instrs[i++] = 0x60000000; /* branch patched below */
139                 instrs[i++] = 0x7d4803a6; /* mtlr r10           */
140         } else if (types & STF_BARRIER_EIEIO) {
141                 instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */
142         } else if (types & STF_BARRIER_SYNC_ORI) {
143                 instrs[i++] = 0x7c0004ac; /* hwsync             */
144                 instrs[i++] = 0xe94d0000; /* ld r10,0(r13)      */
145                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
146         }
147
148         for (i = 0; start < end; start++, i++) {
149                 dest = (void *)start + *start;
150
151                 pr_devel("patching dest %lx\n", (unsigned long)dest);
152
153                 patch_instruction(dest, instrs[0]);
154
155                 if (types & STF_BARRIER_FALLBACK)
156                         patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback,
157                                      BRANCH_SET_LINK);
158                 else
159                         patch_instruction(dest + 1, instrs[1]);
160
161                 patch_instruction(dest + 2, instrs[2]);
162         }
163
164         printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i,
165                 (types == STF_BARRIER_NONE)                  ? "no" :
166                 (types == STF_BARRIER_FALLBACK)              ? "fallback" :
167                 (types == STF_BARRIER_EIEIO)                 ? "eieio" :
168                 (types == (STF_BARRIER_SYNC_ORI))            ? "hwsync"
169                                                            : "unknown");
170 }
171
172 void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
173 {
174         unsigned int instrs[6], *dest;
175         long *start, *end;
176         int i;
177
178         start = PTRRELOC(&__start___stf_exit_barrier_fixup),
179         end = PTRRELOC(&__stop___stf_exit_barrier_fixup);
180
181         instrs[0] = 0x60000000; /* nop */
182         instrs[1] = 0x60000000; /* nop */
183         instrs[2] = 0x60000000; /* nop */
184         instrs[3] = 0x60000000; /* nop */
185         instrs[4] = 0x60000000; /* nop */
186         instrs[5] = 0x60000000; /* nop */
187
188         i = 0;
189         if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) {
190                 if (cpu_has_feature(CPU_FTR_HVMODE)) {
191                         instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */
192                         instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */
193                 } else {
194                         instrs[i++] = 0x7db243a6; /* mtsprg 2,r13       */
195                         instrs[i++] = 0x7db142a6; /* mfsprg r13,1    */
196                 }
197                 instrs[i++] = 0x7c0004ac; /* hwsync             */
198                 instrs[i++] = 0xe9ad0000; /* ld r13,0(r13)      */
199                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
200                 if (cpu_has_feature(CPU_FTR_HVMODE)) {
201                         instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */
202                 } else {
203                         instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */
204                 }
205         } else if (types & STF_BARRIER_EIEIO) {
206                 instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */
207         }
208
209         for (i = 0; start < end; start++, i++) {
210                 dest = (void *)start + *start;
211
212                 pr_devel("patching dest %lx\n", (unsigned long)dest);
213
214                 patch_instruction(dest, instrs[0]);
215                 patch_instruction(dest + 1, instrs[1]);
216                 patch_instruction(dest + 2, instrs[2]);
217                 patch_instruction(dest + 3, instrs[3]);
218                 patch_instruction(dest + 4, instrs[4]);
219                 patch_instruction(dest + 5, instrs[5]);
220         }
221         printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
222                 (types == STF_BARRIER_NONE)                  ? "no" :
223                 (types == STF_BARRIER_FALLBACK)              ? "fallback" :
224                 (types == STF_BARRIER_EIEIO)                 ? "eieio" :
225                 (types == (STF_BARRIER_SYNC_ORI))            ? "hwsync"
226                                                            : "unknown");
227 }
228
229 static int __do_stf_barrier_fixups(void *data)
230 {
231         enum stf_barrier_type *types = data;
232
233         do_stf_entry_barrier_fixups(*types);
234         do_stf_exit_barrier_fixups(*types);
235
236         return 0;
237 }
238
239 void do_stf_barrier_fixups(enum stf_barrier_type types)
240 {
241         /*
242          * The call to the fallback entry flush, and the fallback/sync-ori exit
243          * flush can not be safely patched in/out while other CPUs are executing
244          * them. So call __do_stf_barrier_fixups() on one CPU while all other CPUs
245          * spin in the stop machine core with interrupts hard disabled.
246          */
247         stop_machine(__do_stf_barrier_fixups, &types, NULL);
248 }
249
250 void do_uaccess_flush_fixups(enum l1d_flush_type types)
251 {
252         unsigned int instrs[4], *dest;
253         long *start, *end;
254         int i;
255
256         start = PTRRELOC(&__start___uaccess_flush_fixup);
257         end = PTRRELOC(&__stop___uaccess_flush_fixup);
258
259         instrs[0] = 0x60000000; /* nop */
260         instrs[1] = 0x60000000; /* nop */
261         instrs[2] = 0x60000000; /* nop */
262         instrs[3] = 0x4e800020; /* blr */
263
264         i = 0;
265         if (types == L1D_FLUSH_FALLBACK) {
266                 instrs[3] = 0x60000000; /* nop */
267                 /* fallthrough to fallback flush */
268         }
269
270         if (types & L1D_FLUSH_ORI) {
271                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
272                 instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
273         }
274
275         if (types & L1D_FLUSH_MTTRIG)
276                 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
277
278         for (i = 0; start < end; start++, i++) {
279                 dest = (void *)start + *start;
280
281                 pr_devel("patching dest %lx\n", (unsigned long)dest);
282
283                 patch_instruction(dest, instrs[0]);
284
285                 patch_instruction((dest + 1), instrs[1]);
286                 patch_instruction((dest + 2), instrs[2]);
287                 patch_instruction((dest + 3), instrs[3]);
288         }
289
290         printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
291                 (types == L1D_FLUSH_NONE)       ? "no" :
292                 (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
293                 (types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
294                                                         ? "ori+mttrig type"
295                                                         : "ori type" :
296                 (types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
297                                                 : "unknown");
298 }
299
300 static int __do_entry_flush_fixups(void *data)
301 {
302         enum l1d_flush_type types = *(enum l1d_flush_type *)data;
303         unsigned int instrs[3], *dest;
304         long *start, *end;
305         int i;
306
307         start = PTRRELOC(&__start___entry_flush_fixup);
308         end = PTRRELOC(&__stop___entry_flush_fixup);
309
310         instrs[0] = 0x60000000; /* nop */
311         instrs[1] = 0x60000000; /* nop */
312         instrs[2] = 0x60000000; /* nop */
313
314         i = 0;
315         if (types == L1D_FLUSH_FALLBACK) {
316                 instrs[i++] = 0x7d4802a6; /* mflr r10           */
317                 instrs[i++] = 0x60000000; /* branch patched below */
318                 instrs[i++] = 0x7d4803a6; /* mtlr r10           */
319         }
320
321         if (types & L1D_FLUSH_ORI) {
322                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
323                 instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
324         }
325
326         if (types & L1D_FLUSH_MTTRIG)
327                 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
328
329         for (i = 0; start < end; start++, i++) {
330                 dest = (void *)start + *start;
331
332                 pr_devel("patching dest %lx\n", (unsigned long)dest);
333
334                 patch_instruction(dest, instrs[0]);
335
336                 if (types == L1D_FLUSH_FALLBACK)
337                         patch_branch((dest + 1), (unsigned long)&entry_flush_fallback,
338                                      BRANCH_SET_LINK);
339                 else
340                         patch_instruction((dest + 1), instrs[1]);
341
342                 patch_instruction((dest + 2), instrs[2]);
343         }
344
345         printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
346                 (types == L1D_FLUSH_NONE)       ? "no" :
347                 (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
348                 (types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
349                                                         ? "ori+mttrig type"
350                                                         : "ori type" :
351                 (types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
352                                                 : "unknown");
353
354         return 0;
355 }
356
357 void do_entry_flush_fixups(enum l1d_flush_type types)
358 {
359         /*
360          * The call to the fallback flush can not be safely patched in/out while
361          * other CPUs are executing it. So call __do_entry_flush_fixups() on one
362          * CPU while all other CPUs spin in the stop machine core with interrupts
363          * hard disabled.
364          */
365         stop_machine(__do_entry_flush_fixups, &types, NULL);
366 }
367
368 void do_rfi_flush_fixups(enum l1d_flush_type types)
369 {
370         unsigned int instrs[3], *dest;
371         long *start, *end;
372         int i;
373
374         start = PTRRELOC(&__start___rfi_flush_fixup),
375         end = PTRRELOC(&__stop___rfi_flush_fixup);
376
377         instrs[0] = 0x60000000; /* nop */
378         instrs[1] = 0x60000000; /* nop */
379         instrs[2] = 0x60000000; /* nop */
380
381         if (types & L1D_FLUSH_FALLBACK)
382                 /* b .+16 to fallback flush */
383                 instrs[0] = 0x48000010;
384
385         i = 0;
386         if (types & L1D_FLUSH_ORI) {
387                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
388                 instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
389         }
390
391         if (types & L1D_FLUSH_MTTRIG)
392                 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
393
394         for (i = 0; start < end; start++, i++) {
395                 dest = (void *)start + *start;
396
397                 pr_devel("patching dest %lx\n", (unsigned long)dest);
398
399                 patch_instruction(dest, instrs[0]);
400                 patch_instruction(dest + 1, instrs[1]);
401                 patch_instruction(dest + 2, instrs[2]);
402         }
403
404         printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
405                 (types == L1D_FLUSH_NONE)       ? "no" :
406                 (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
407                 (types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
408                                                         ? "ori+mttrig type"
409                                                         : "ori type" :
410                 (types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
411                                                 : "unknown");
412 }
413
414 void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
415 {
416         unsigned int instr, *dest;
417         long *start, *end;
418         int i;
419
420         start = fixup_start;
421         end = fixup_end;
422
423         instr = 0x60000000; /* nop */
424
425         if (enable) {
426                 pr_info("barrier-nospec: using ORI speculation barrier\n");
427                 instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */
428         }
429
430         for (i = 0; start < end; start++, i++) {
431                 dest = (void *)start + *start;
432
433                 pr_devel("patching dest %lx\n", (unsigned long)dest);
434                 patch_instruction(dest, instr);
435         }
436
437         printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
438 }
439
440 #endif /* CONFIG_PPC_BOOK3S_64 */
441
442 #ifdef CONFIG_PPC_BARRIER_NOSPEC
443 void do_barrier_nospec_fixups(bool enable)
444 {
445         void *start, *end;
446
447         start = PTRRELOC(&__start___barrier_nospec_fixup),
448         end = PTRRELOC(&__stop___barrier_nospec_fixup);
449
450         do_barrier_nospec_fixups_range(enable, start, end);
451 }
452 #endif /* CONFIG_PPC_BARRIER_NOSPEC */
453
454 #ifdef CONFIG_PPC_FSL_BOOK3E
455 void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
456 {
457         unsigned int instr[2], *dest;
458         long *start, *end;
459         int i;
460
461         start = fixup_start;
462         end = fixup_end;
463
464         instr[0] = PPC_INST_NOP;
465         instr[1] = PPC_INST_NOP;
466
467         if (enable) {
468                 pr_info("barrier-nospec: using isync; sync as speculation barrier\n");
469                 instr[0] = PPC_INST_ISYNC;
470                 instr[1] = PPC_INST_SYNC;
471         }
472
473         for (i = 0; start < end; start++, i++) {
474                 dest = (void *)start + *start;
475
476                 pr_devel("patching dest %lx\n", (unsigned long)dest);
477                 patch_instruction(dest, instr[0]);
478                 patch_instruction(dest + 1, instr[1]);
479         }
480
481         printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
482 }
483
484 static void patch_btb_flush_section(long *curr)
485 {
486         unsigned int *start, *end;
487
488         start = (void *)curr + *curr;
489         end = (void *)curr + *(curr + 1);
490         for (; start < end; start++) {
491                 pr_devel("patching dest %lx\n", (unsigned long)start);
492                 patch_instruction(start, PPC_INST_NOP);
493         }
494 }
495
496 void do_btb_flush_fixups(void)
497 {
498         long *start, *end;
499
500         start = PTRRELOC(&__start__btb_flush_fixup);
501         end = PTRRELOC(&__stop__btb_flush_fixup);
502
503         for (; start < end; start += 2)
504                 patch_btb_flush_section(start);
505 }
506 #endif /* CONFIG_PPC_FSL_BOOK3E */
507
508 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
509 {
510         long *start, *end;
511         unsigned int *dest;
512
513         if (!(value & CPU_FTR_LWSYNC))
514                 return ;
515
516         start = fixup_start;
517         end = fixup_end;
518
519         for (; start < end; start++) {
520                 dest = (void *)start + *start;
521                 raw_patch_instruction(dest, PPC_INST_LWSYNC);
522         }
523 }
524
525 static void do_final_fixups(void)
526 {
527 #if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
528         int *src, *dest;
529         unsigned long length;
530
531         if (PHYSICAL_START == 0)
532                 return;
533
534         src = (int *)(KERNELBASE + PHYSICAL_START);
535         dest = (int *)KERNELBASE;
536         length = (__end_interrupts - _stext) / sizeof(int);
537
538         while (length--) {
539                 raw_patch_instruction(dest, *src);
540                 src++;
541                 dest++;
542         }
543 #endif
544 }
545
546 static unsigned long __initdata saved_cpu_features;
547 static unsigned int __initdata saved_mmu_features;
548 #ifdef CONFIG_PPC64
549 static unsigned long __initdata saved_firmware_features;
550 #endif
551
552 void __init apply_feature_fixups(void)
553 {
554         struct cpu_spec *spec = PTRRELOC(*PTRRELOC(&cur_cpu_spec));
555
556         *PTRRELOC(&saved_cpu_features) = spec->cpu_features;
557         *PTRRELOC(&saved_mmu_features) = spec->mmu_features;
558
559         /*
560          * Apply the CPU-specific and firmware specific fixups to kernel text
561          * (nop out sections not relevant to this CPU or this firmware).
562          */
563         do_feature_fixups(spec->cpu_features,
564                           PTRRELOC(&__start___ftr_fixup),
565                           PTRRELOC(&__stop___ftr_fixup));
566
567         do_feature_fixups(spec->mmu_features,
568                           PTRRELOC(&__start___mmu_ftr_fixup),
569                           PTRRELOC(&__stop___mmu_ftr_fixup));
570
571         do_lwsync_fixups(spec->cpu_features,
572                          PTRRELOC(&__start___lwsync_fixup),
573                          PTRRELOC(&__stop___lwsync_fixup));
574
575 #ifdef CONFIG_PPC64
576         saved_firmware_features = powerpc_firmware_features;
577         do_feature_fixups(powerpc_firmware_features,
578                           &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
579 #endif
580         do_final_fixups();
581 }
582
583 void __init setup_feature_keys(void)
584 {
585         /*
586          * Initialise jump label. This causes all the cpu/mmu_has_feature()
587          * checks to take on their correct polarity based on the current set of
588          * CPU/MMU features.
589          */
590         jump_label_init();
591         cpu_feature_keys_init();
592         mmu_feature_keys_init();
593 }
594
595 static int __init check_features(void)
596 {
597         WARN(saved_cpu_features != cur_cpu_spec->cpu_features,
598              "CPU features changed after feature patching!\n");
599         WARN(saved_mmu_features != cur_cpu_spec->mmu_features,
600              "MMU features changed after feature patching!\n");
601 #ifdef CONFIG_PPC64
602         WARN(saved_firmware_features != powerpc_firmware_features,
603              "Firmware features changed after feature patching!\n");
604 #endif
605
606         return 0;
607 }
608 late_initcall(check_features);
609
610 #ifdef CONFIG_FTR_FIXUP_SELFTEST
611
612 #define check(x)        \
613         if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__);
614
615 /* This must be after the text it fixes up, vmlinux.lds.S enforces that atm */
616 static struct fixup_entry fixup;
617
618 static long calc_offset(struct fixup_entry *entry, unsigned int *p)
619 {
620         return (unsigned long)p - (unsigned long)entry;
621 }
622
623 static void test_basic_patching(void)
624 {
625         extern unsigned int ftr_fixup_test1[];
626         extern unsigned int end_ftr_fixup_test1[];
627         extern unsigned int ftr_fixup_test1_orig[];
628         extern unsigned int ftr_fixup_test1_expected[];
629         int size = 4 * (end_ftr_fixup_test1 - ftr_fixup_test1);
630
631         fixup.value = fixup.mask = 8;
632         fixup.start_off = calc_offset(&fixup, ftr_fixup_test1 + 1);
633         fixup.end_off = calc_offset(&fixup, ftr_fixup_test1 + 2);
634         fixup.alt_start_off = fixup.alt_end_off = 0;
635
636         /* Sanity check */
637         check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
638
639         /* Check we don't patch if the value matches */
640         patch_feature_section(8, &fixup);
641         check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
642
643         /* Check we do patch if the value doesn't match */
644         patch_feature_section(0, &fixup);
645         check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0);
646
647         /* Check we do patch if the mask doesn't match */
648         memcpy(ftr_fixup_test1, ftr_fixup_test1_orig, size);
649         check(memcmp(ftr_fixup_test1, ftr_fixup_test1_orig, size) == 0);
650         patch_feature_section(~8, &fixup);
651         check(memcmp(ftr_fixup_test1, ftr_fixup_test1_expected, size) == 0);
652 }
653
654 static void test_alternative_patching(void)
655 {
656         extern unsigned int ftr_fixup_test2[];
657         extern unsigned int end_ftr_fixup_test2[];
658         extern unsigned int ftr_fixup_test2_orig[];
659         extern unsigned int ftr_fixup_test2_alt[];
660         extern unsigned int ftr_fixup_test2_expected[];
661         int size = 4 * (end_ftr_fixup_test2 - ftr_fixup_test2);
662
663         fixup.value = fixup.mask = 0xF;
664         fixup.start_off = calc_offset(&fixup, ftr_fixup_test2 + 1);
665         fixup.end_off = calc_offset(&fixup, ftr_fixup_test2 + 2);
666         fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test2_alt);
667         fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test2_alt + 1);
668
669         /* Sanity check */
670         check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
671
672         /* Check we don't patch if the value matches */
673         patch_feature_section(0xF, &fixup);
674         check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
675
676         /* Check we do patch if the value doesn't match */
677         patch_feature_section(0, &fixup);
678         check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0);
679
680         /* Check we do patch if the mask doesn't match */
681         memcpy(ftr_fixup_test2, ftr_fixup_test2_orig, size);
682         check(memcmp(ftr_fixup_test2, ftr_fixup_test2_orig, size) == 0);
683         patch_feature_section(~0xF, &fixup);
684         check(memcmp(ftr_fixup_test2, ftr_fixup_test2_expected, size) == 0);
685 }
686
687 static void test_alternative_case_too_big(void)
688 {
689         extern unsigned int ftr_fixup_test3[];
690         extern unsigned int end_ftr_fixup_test3[];
691         extern unsigned int ftr_fixup_test3_orig[];
692         extern unsigned int ftr_fixup_test3_alt[];
693         int size = 4 * (end_ftr_fixup_test3 - ftr_fixup_test3);
694
695         fixup.value = fixup.mask = 0xC;
696         fixup.start_off = calc_offset(&fixup, ftr_fixup_test3 + 1);
697         fixup.end_off = calc_offset(&fixup, ftr_fixup_test3 + 2);
698         fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test3_alt);
699         fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test3_alt + 2);
700
701         /* Sanity check */
702         check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
703
704         /* Expect nothing to be patched, and the error returned to us */
705         check(patch_feature_section(0xF, &fixup) == 1);
706         check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
707         check(patch_feature_section(0, &fixup) == 1);
708         check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
709         check(patch_feature_section(~0xF, &fixup) == 1);
710         check(memcmp(ftr_fixup_test3, ftr_fixup_test3_orig, size) == 0);
711 }
712
713 static void test_alternative_case_too_small(void)
714 {
715         extern unsigned int ftr_fixup_test4[];
716         extern unsigned int end_ftr_fixup_test4[];
717         extern unsigned int ftr_fixup_test4_orig[];
718         extern unsigned int ftr_fixup_test4_alt[];
719         extern unsigned int ftr_fixup_test4_expected[];
720         int size = 4 * (end_ftr_fixup_test4 - ftr_fixup_test4);
721         unsigned long flag;
722
723         /* Check a high-bit flag */
724         flag = 1UL << ((sizeof(unsigned long) - 1) * 8);
725         fixup.value = fixup.mask = flag;
726         fixup.start_off = calc_offset(&fixup, ftr_fixup_test4 + 1);
727         fixup.end_off = calc_offset(&fixup, ftr_fixup_test4 + 5);
728         fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_test4_alt);
729         fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_test4_alt + 2);
730
731         /* Sanity check */
732         check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
733
734         /* Check we don't patch if the value matches */
735         patch_feature_section(flag, &fixup);
736         check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
737
738         /* Check we do patch if the value doesn't match */
739         patch_feature_section(0, &fixup);
740         check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0);
741
742         /* Check we do patch if the mask doesn't match */
743         memcpy(ftr_fixup_test4, ftr_fixup_test4_orig, size);
744         check(memcmp(ftr_fixup_test4, ftr_fixup_test4_orig, size) == 0);
745         patch_feature_section(~flag, &fixup);
746         check(memcmp(ftr_fixup_test4, ftr_fixup_test4_expected, size) == 0);
747 }
748
749 static void test_alternative_case_with_branch(void)
750 {
751         extern unsigned int ftr_fixup_test5[];
752         extern unsigned int end_ftr_fixup_test5[];
753         extern unsigned int ftr_fixup_test5_expected[];
754         int size = 4 * (end_ftr_fixup_test5 - ftr_fixup_test5);
755
756         check(memcmp(ftr_fixup_test5, ftr_fixup_test5_expected, size) == 0);
757 }
758
759 static void test_alternative_case_with_external_branch(void)
760 {
761         extern unsigned int ftr_fixup_test6[];
762         extern unsigned int end_ftr_fixup_test6[];
763         extern unsigned int ftr_fixup_test6_expected[];
764         int size = 4 * (end_ftr_fixup_test6 - ftr_fixup_test6);
765
766         check(memcmp(ftr_fixup_test6, ftr_fixup_test6_expected, size) == 0);
767 }
768
769 static void test_alternative_case_with_branch_to_end(void)
770 {
771         extern unsigned int ftr_fixup_test7[];
772         extern unsigned int end_ftr_fixup_test7[];
773         extern unsigned int ftr_fixup_test7_expected[];
774         int size = 4 * (end_ftr_fixup_test7 - ftr_fixup_test7);
775
776         check(memcmp(ftr_fixup_test7, ftr_fixup_test7_expected, size) == 0);
777 }
778
779 static void test_cpu_macros(void)
780 {
781         extern u8 ftr_fixup_test_FTR_macros[];
782         extern u8 ftr_fixup_test_FTR_macros_expected[];
783         unsigned long size = ftr_fixup_test_FTR_macros_expected -
784                              ftr_fixup_test_FTR_macros;
785
786         /* The fixups have already been done for us during boot */
787         check(memcmp(ftr_fixup_test_FTR_macros,
788                      ftr_fixup_test_FTR_macros_expected, size) == 0);
789 }
790
791 static void test_fw_macros(void)
792 {
793 #ifdef CONFIG_PPC64
794         extern u8 ftr_fixup_test_FW_FTR_macros[];
795         extern u8 ftr_fixup_test_FW_FTR_macros_expected[];
796         unsigned long size = ftr_fixup_test_FW_FTR_macros_expected -
797                              ftr_fixup_test_FW_FTR_macros;
798
799         /* The fixups have already been done for us during boot */
800         check(memcmp(ftr_fixup_test_FW_FTR_macros,
801                      ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
802 #endif
803 }
804
805 static void test_lwsync_macros(void)
806 {
807         extern u8 lwsync_fixup_test[];
808         extern u8 end_lwsync_fixup_test[];
809         extern u8 lwsync_fixup_test_expected_LWSYNC[];
810         extern u8 lwsync_fixup_test_expected_SYNC[];
811         unsigned long size = end_lwsync_fixup_test -
812                              lwsync_fixup_test;
813
814         /* The fixups have already been done for us during boot */
815         if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) {
816                 check(memcmp(lwsync_fixup_test,
817                              lwsync_fixup_test_expected_LWSYNC, size) == 0);
818         } else {
819                 check(memcmp(lwsync_fixup_test,
820                              lwsync_fixup_test_expected_SYNC, size) == 0);
821         }
822 }
823
824 static int __init test_feature_fixups(void)
825 {
826         printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
827
828         test_basic_patching();
829         test_alternative_patching();
830         test_alternative_case_too_big();
831         test_alternative_case_too_small();
832         test_alternative_case_with_branch();
833         test_alternative_case_with_external_branch();
834         test_alternative_case_with_branch_to_end();
835         test_cpu_macros();
836         test_fw_macros();
837         test_lwsync_macros();
838
839         return 0;
840 }
841 late_initcall(test_feature_fixups);
842
843 #endif /* CONFIG_FTR_FIXUP_SELFTEST */