GNU Linux-libre 4.9.337-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/stop_machine.h>
21 #include <asm/cputable.h>
22 #include <asm/code-patching.h>
23 #include <asm/page.h>
24 #include <asm/sections.h>
25 #include <asm/setup.h>
26 #include <asm/security_features.h>
27 #include <asm/firmware.h>
28 #include <asm/setup.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         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                 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
230 void do_stf_barrier_fixups(enum stf_barrier_type types)
231 {
232         do_stf_entry_barrier_fixups(types);
233         do_stf_exit_barrier_fixups(types);
234 }
235
236 void do_uaccess_flush_fixups(enum l1d_flush_type types)
237 {
238         unsigned int instrs[4], *dest;
239         long *start, *end;
240         int i;
241
242         start = PTRRELOC(&__start___uaccess_flush_fixup);
243         end = PTRRELOC(&__stop___uaccess_flush_fixup);
244
245         instrs[0] = 0x60000000; /* nop */
246         instrs[1] = 0x60000000; /* nop */
247         instrs[2] = 0x60000000; /* nop */
248         instrs[3] = 0x4e800020; /* blr */
249
250         i = 0;
251         if (types == L1D_FLUSH_FALLBACK) {
252                 instrs[3] = 0x60000000; /* nop */
253                 /* fallthrough to fallback flush */
254         }
255
256         if (types & L1D_FLUSH_ORI) {
257                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
258                 instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
259         }
260
261         if (types & L1D_FLUSH_MTTRIG)
262                 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
263
264         for (i = 0; start < end; start++, i++) {
265                 dest = (void *)start + *start;
266
267                 pr_devel("patching dest %lx\n", (unsigned long)dest);
268
269                 patch_instruction(dest, instrs[0]);
270
271                 patch_instruction((dest + 1), instrs[1]);
272                 patch_instruction((dest + 2), instrs[2]);
273                 patch_instruction((dest + 3), instrs[3]);
274         }
275
276         printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
277                 (types == L1D_FLUSH_NONE)       ? "no" :
278                 (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
279                 (types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
280                                                         ? "ori+mttrig type"
281                                                         : "ori type" :
282                 (types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
283                                                 : "unknown");
284 }
285
286 static int __do_entry_flush_fixups(void *data)
287 {
288         enum l1d_flush_type types = *(enum l1d_flush_type *)data;
289         unsigned int instrs[3], *dest;
290         long *start, *end;
291         int i;
292
293         start = PTRRELOC(&__start___entry_flush_fixup);
294         end = PTRRELOC(&__stop___entry_flush_fixup);
295
296         instrs[0] = 0x60000000; /* nop */
297         instrs[1] = 0x60000000; /* nop */
298         instrs[2] = 0x60000000; /* nop */
299
300         i = 0;
301         if (types == L1D_FLUSH_FALLBACK) {
302                 instrs[i++] = 0x7d4802a6; /* mflr r10           */
303                 instrs[i++] = 0x60000000; /* branch patched below */
304                 instrs[i++] = 0x7d4803a6; /* mtlr r10           */
305         }
306
307         if (types & L1D_FLUSH_ORI) {
308                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
309                 instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
310         }
311
312         if (types & L1D_FLUSH_MTTRIG)
313                 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
314
315         for (i = 0; start < end; start++, i++) {
316                 dest = (void *)start + *start;
317
318                 pr_devel("patching dest %lx\n", (unsigned long)dest);
319
320                 patch_instruction(dest, instrs[0]);
321
322                 if (types == L1D_FLUSH_FALLBACK)
323                         patch_branch((dest + 1), (unsigned long)&entry_flush_fallback,
324                                      BRANCH_SET_LINK);
325                 else
326                         patch_instruction((dest + 1), instrs[1]);
327
328                 patch_instruction((dest + 2), instrs[2]);
329         }
330
331         printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
332                 (types == L1D_FLUSH_NONE)       ? "no" :
333                 (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
334                 (types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
335                                                         ? "ori+mttrig type"
336                                                         : "ori type" :
337                 (types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
338                                                 : "unknown");
339
340         return 0;
341 }
342
343 void do_entry_flush_fixups(enum l1d_flush_type types)
344 {
345         /*
346          * The call to the fallback flush can not be safely patched in/out while
347          * other CPUs are executing it. So call __do_entry_flush_fixups() on one
348          * CPU while all other CPUs spin in the stop machine core with interrupts
349          * hard disabled.
350          */
351         stop_machine(__do_entry_flush_fixups, &types, NULL);
352 }
353
354 void do_rfi_flush_fixups(enum l1d_flush_type types)
355 {
356         unsigned int instrs[3], *dest;
357         long *start, *end;
358         int i;
359
360         start = PTRRELOC(&__start___rfi_flush_fixup),
361         end = PTRRELOC(&__stop___rfi_flush_fixup);
362
363         instrs[0] = 0x60000000; /* nop */
364         instrs[1] = 0x60000000; /* nop */
365         instrs[2] = 0x60000000; /* nop */
366
367         if (types & L1D_FLUSH_FALLBACK)
368                 /* b .+16 to fallback flush */
369                 instrs[0] = 0x48000010;
370
371         i = 0;
372         if (types & L1D_FLUSH_ORI) {
373                 instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */
374                 instrs[i++] = 0x63de0000; /* ori 30,30,0 L1d flush*/
375         }
376
377         if (types & L1D_FLUSH_MTTRIG)
378                 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
379
380         for (i = 0; start < end; start++, i++) {
381                 dest = (void *)start + *start;
382
383                 pr_devel("patching dest %lx\n", (unsigned long)dest);
384
385                 patch_instruction(dest, instrs[0]);
386                 patch_instruction(dest + 1, instrs[1]);
387                 patch_instruction(dest + 2, instrs[2]);
388         }
389
390         printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
391                 (types == L1D_FLUSH_NONE)       ? "no" :
392                 (types == L1D_FLUSH_FALLBACK)   ? "fallback displacement" :
393                 (types &  L1D_FLUSH_ORI)        ? (types & L1D_FLUSH_MTTRIG)
394                                                         ? "ori+mttrig type"
395                                                         : "ori type" :
396                 (types &  L1D_FLUSH_MTTRIG)     ? "mttrig type"
397                                                 : "unknown");
398 }
399
400 void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
401 {
402         unsigned int instr, *dest;
403         long *start, *end;
404         int i;
405
406         start = fixup_start;
407         end = fixup_end;
408
409         instr = 0x60000000; /* nop */
410
411         if (enable) {
412                 pr_info("barrier-nospec: using ORI speculation barrier\n");
413                 instr = 0x63ff0000; /* ori 31,31,0 speculation barrier */
414         }
415
416         for (i = 0; start < end; start++, i++) {
417                 dest = (void *)start + *start;
418
419                 pr_devel("patching dest %lx\n", (unsigned long)dest);
420                 patch_instruction(dest, instr);
421         }
422
423         printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
424 }
425
426 #endif /* CONFIG_PPC_BOOK3S_64 */
427
428 #ifdef CONFIG_PPC_BARRIER_NOSPEC
429 void do_barrier_nospec_fixups(bool enable)
430 {
431         void *start, *end;
432
433         start = PTRRELOC(&__start___barrier_nospec_fixup),
434         end = PTRRELOC(&__stop___barrier_nospec_fixup);
435
436         do_barrier_nospec_fixups_range(enable, start, end);
437 }
438 #endif /* CONFIG_PPC_BARRIER_NOSPEC */
439
440 #ifdef CONFIG_PPC_FSL_BOOK3E
441 void do_barrier_nospec_fixups_range(bool enable, void *fixup_start, void *fixup_end)
442 {
443         unsigned int instr[2], *dest;
444         long *start, *end;
445         int i;
446
447         start = fixup_start;
448         end = fixup_end;
449
450         instr[0] = PPC_INST_NOP;
451         instr[1] = PPC_INST_NOP;
452
453         if (enable) {
454                 pr_info("barrier-nospec: using isync; sync as speculation barrier\n");
455                 instr[0] = PPC_INST_ISYNC;
456                 instr[1] = PPC_INST_SYNC;
457         }
458
459         for (i = 0; start < end; start++, i++) {
460                 dest = (void *)start + *start;
461
462                 pr_devel("patching dest %lx\n", (unsigned long)dest);
463                 patch_instruction(dest, instr[0]);
464                 patch_instruction(dest + 1, instr[1]);
465         }
466
467         printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
468 }
469
470 static void patch_btb_flush_section(long *curr)
471 {
472         unsigned int *start, *end;
473
474         start = (void *)curr + *curr;
475         end = (void *)curr + *(curr + 1);
476         for (; start < end; start++) {
477                 pr_devel("patching dest %lx\n", (unsigned long)start);
478                 patch_instruction(start, PPC_INST_NOP);
479         }
480 }
481
482 void do_btb_flush_fixups(void)
483 {
484         long *start, *end;
485
486         start = PTRRELOC(&__start__btb_flush_fixup);
487         end = PTRRELOC(&__stop__btb_flush_fixup);
488
489         for (; start < end; start += 2)
490                 patch_btb_flush_section(start);
491 }
492 #endif /* CONFIG_PPC_FSL_BOOK3E */
493
494 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
495 {
496         long *start, *end;
497         unsigned int *dest;
498
499         if (!(value & CPU_FTR_LWSYNC))
500                 return ;
501
502         start = fixup_start;
503         end = fixup_end;
504
505         for (; start < end; start++) {
506                 dest = (void *)start + *start;
507                 patch_instruction(dest, PPC_INST_LWSYNC);
508         }
509 }
510
511 static void do_final_fixups(void)
512 {
513 #if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
514         int *src, *dest;
515         unsigned long length;
516
517         if (PHYSICAL_START == 0)
518                 return;
519
520         src = (int *)(KERNELBASE + PHYSICAL_START);
521         dest = (int *)KERNELBASE;
522         length = (__end_interrupts - _stext) / sizeof(int);
523
524         while (length--) {
525                 patch_instruction(dest, *src);
526                 src++;
527                 dest++;
528         }
529 #endif
530 }
531
532 static unsigned long __initdata saved_cpu_features;
533 static unsigned int __initdata saved_mmu_features;
534 #ifdef CONFIG_PPC64
535 static unsigned long __initdata saved_firmware_features;
536 #endif
537
538 void __init apply_feature_fixups(void)
539 {
540         struct cpu_spec *spec = PTRRELOC(*PTRRELOC(&cur_cpu_spec));
541
542         *PTRRELOC(&saved_cpu_features) = spec->cpu_features;
543         *PTRRELOC(&saved_mmu_features) = spec->mmu_features;
544
545         /*
546          * Apply the CPU-specific and firmware specific fixups to kernel text
547          * (nop out sections not relevant to this CPU or this firmware).
548          */
549         do_feature_fixups(spec->cpu_features,
550                           PTRRELOC(&__start___ftr_fixup),
551                           PTRRELOC(&__stop___ftr_fixup));
552
553         do_feature_fixups(spec->mmu_features,
554                           PTRRELOC(&__start___mmu_ftr_fixup),
555                           PTRRELOC(&__stop___mmu_ftr_fixup));
556
557         do_lwsync_fixups(spec->cpu_features,
558                          PTRRELOC(&__start___lwsync_fixup),
559                          PTRRELOC(&__stop___lwsync_fixup));
560
561 #ifdef CONFIG_PPC64
562         saved_firmware_features = powerpc_firmware_features;
563         do_feature_fixups(powerpc_firmware_features,
564                           &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
565 #endif
566         do_final_fixups();
567 }
568
569 void __init setup_feature_keys(void)
570 {
571         /*
572          * Initialise jump label. This causes all the cpu/mmu_has_feature()
573          * checks to take on their correct polarity based on the current set of
574          * CPU/MMU features.
575          */
576         jump_label_init();
577         cpu_feature_keys_init();
578         mmu_feature_keys_init();
579 }
580
581 static int __init check_features(void)
582 {
583         WARN(saved_cpu_features != cur_cpu_spec->cpu_features,
584              "CPU features changed after feature patching!\n");
585         WARN(saved_mmu_features != cur_cpu_spec->mmu_features,
586              "MMU features changed after feature patching!\n");
587 #ifdef CONFIG_PPC64
588         WARN(saved_firmware_features != powerpc_firmware_features,
589              "Firmware features changed after feature patching!\n");
590 #endif
591
592         return 0;
593 }
594 late_initcall(check_features);
595
596 #ifdef CONFIG_FTR_FIXUP_SELFTEST
597
598 #define check(x)        \
599         if (!(x)) printk("feature-fixups: test failed at line %d\n", __LINE__);
600
601 /* This must be after the text it fixes up, vmlinux.lds.S enforces that atm */
602 static struct fixup_entry fixup;
603
604 static long calc_offset(struct fixup_entry *entry, unsigned int *p)
605 {
606         return (unsigned long)p - (unsigned long)entry;
607 }
608
609 static void test_basic_patching(void)
610 {
611         extern unsigned int ftr_fixup_test1;
612         extern unsigned int end_ftr_fixup_test1;
613         extern unsigned int ftr_fixup_test1_orig;
614         extern unsigned int ftr_fixup_test1_expected;
615         int size = &end_ftr_fixup_test1 - &ftr_fixup_test1;
616
617         fixup.value = fixup.mask = 8;
618         fixup.start_off = calc_offset(&fixup, &ftr_fixup_test1 + 1);
619         fixup.end_off = calc_offset(&fixup, &ftr_fixup_test1 + 2);
620         fixup.alt_start_off = fixup.alt_end_off = 0;
621
622         /* Sanity check */
623         check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
624
625         /* Check we don't patch if the value matches */
626         patch_feature_section(8, &fixup);
627         check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
628
629         /* Check we do patch if the value doesn't match */
630         patch_feature_section(0, &fixup);
631         check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
632
633         /* Check we do patch if the mask doesn't match */
634         memcpy(&ftr_fixup_test1, &ftr_fixup_test1_orig, size);
635         check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_orig, size) == 0);
636         patch_feature_section(~8, &fixup);
637         check(memcmp(&ftr_fixup_test1, &ftr_fixup_test1_expected, size) == 0);
638 }
639
640 static void test_alternative_patching(void)
641 {
642         extern unsigned int ftr_fixup_test2;
643         extern unsigned int end_ftr_fixup_test2;
644         extern unsigned int ftr_fixup_test2_orig;
645         extern unsigned int ftr_fixup_test2_alt;
646         extern unsigned int ftr_fixup_test2_expected;
647         int size = &end_ftr_fixup_test2 - &ftr_fixup_test2;
648
649         fixup.value = fixup.mask = 0xF;
650         fixup.start_off = calc_offset(&fixup, &ftr_fixup_test2 + 1);
651         fixup.end_off = calc_offset(&fixup, &ftr_fixup_test2 + 2);
652         fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test2_alt);
653         fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test2_alt + 1);
654
655         /* Sanity check */
656         check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
657
658         /* Check we don't patch if the value matches */
659         patch_feature_section(0xF, &fixup);
660         check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
661
662         /* Check we do patch if the value doesn't match */
663         patch_feature_section(0, &fixup);
664         check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
665
666         /* Check we do patch if the mask doesn't match */
667         memcpy(&ftr_fixup_test2, &ftr_fixup_test2_orig, size);
668         check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_orig, size) == 0);
669         patch_feature_section(~0xF, &fixup);
670         check(memcmp(&ftr_fixup_test2, &ftr_fixup_test2_expected, size) == 0);
671 }
672
673 static void test_alternative_case_too_big(void)
674 {
675         extern unsigned int ftr_fixup_test3;
676         extern unsigned int end_ftr_fixup_test3;
677         extern unsigned int ftr_fixup_test3_orig;
678         extern unsigned int ftr_fixup_test3_alt;
679         int size = &end_ftr_fixup_test3 - &ftr_fixup_test3;
680
681         fixup.value = fixup.mask = 0xC;
682         fixup.start_off = calc_offset(&fixup, &ftr_fixup_test3 + 1);
683         fixup.end_off = calc_offset(&fixup, &ftr_fixup_test3 + 2);
684         fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test3_alt);
685         fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test3_alt + 2);
686
687         /* Sanity check */
688         check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
689
690         /* Expect nothing to be patched, and the error returned to us */
691         check(patch_feature_section(0xF, &fixup) == 1);
692         check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
693         check(patch_feature_section(0, &fixup) == 1);
694         check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
695         check(patch_feature_section(~0xF, &fixup) == 1);
696         check(memcmp(&ftr_fixup_test3, &ftr_fixup_test3_orig, size) == 0);
697 }
698
699 static void test_alternative_case_too_small(void)
700 {
701         extern unsigned int ftr_fixup_test4;
702         extern unsigned int end_ftr_fixup_test4;
703         extern unsigned int ftr_fixup_test4_orig;
704         extern unsigned int ftr_fixup_test4_alt;
705         extern unsigned int ftr_fixup_test4_expected;
706         int size = &end_ftr_fixup_test4 - &ftr_fixup_test4;
707         unsigned long flag;
708
709         /* Check a high-bit flag */
710         flag = 1UL << ((sizeof(unsigned long) - 1) * 8);
711         fixup.value = fixup.mask = flag;
712         fixup.start_off = calc_offset(&fixup, &ftr_fixup_test4 + 1);
713         fixup.end_off = calc_offset(&fixup, &ftr_fixup_test4 + 5);
714         fixup.alt_start_off = calc_offset(&fixup, &ftr_fixup_test4_alt);
715         fixup.alt_end_off = calc_offset(&fixup, &ftr_fixup_test4_alt + 2);
716
717         /* Sanity check */
718         check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
719
720         /* Check we don't patch if the value matches */
721         patch_feature_section(flag, &fixup);
722         check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
723
724         /* Check we do patch if the value doesn't match */
725         patch_feature_section(0, &fixup);
726         check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
727
728         /* Check we do patch if the mask doesn't match */
729         memcpy(&ftr_fixup_test4, &ftr_fixup_test4_orig, size);
730         check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_orig, size) == 0);
731         patch_feature_section(~flag, &fixup);
732         check(memcmp(&ftr_fixup_test4, &ftr_fixup_test4_expected, size) == 0);
733 }
734
735 static void test_alternative_case_with_branch(void)
736 {
737         extern unsigned int ftr_fixup_test5;
738         extern unsigned int end_ftr_fixup_test5;
739         extern unsigned int ftr_fixup_test5_expected;
740         int size = &end_ftr_fixup_test5 - &ftr_fixup_test5;
741
742         check(memcmp(&ftr_fixup_test5, &ftr_fixup_test5_expected, size) == 0);
743 }
744
745 static void test_alternative_case_with_external_branch(void)
746 {
747         extern unsigned int ftr_fixup_test6;
748         extern unsigned int end_ftr_fixup_test6;
749         extern unsigned int ftr_fixup_test6_expected;
750         int size = &end_ftr_fixup_test6 - &ftr_fixup_test6;
751
752         check(memcmp(&ftr_fixup_test6, &ftr_fixup_test6_expected, size) == 0);
753 }
754
755 static void test_cpu_macros(void)
756 {
757         extern u8 ftr_fixup_test_FTR_macros;
758         extern u8 ftr_fixup_test_FTR_macros_expected;
759         unsigned long size = &ftr_fixup_test_FTR_macros_expected -
760                              &ftr_fixup_test_FTR_macros;
761
762         /* The fixups have already been done for us during boot */
763         check(memcmp(&ftr_fixup_test_FTR_macros,
764                      &ftr_fixup_test_FTR_macros_expected, size) == 0);
765 }
766
767 static void test_fw_macros(void)
768 {
769 #ifdef CONFIG_PPC64
770         extern u8 ftr_fixup_test_FW_FTR_macros;
771         extern u8 ftr_fixup_test_FW_FTR_macros_expected;
772         unsigned long size = &ftr_fixup_test_FW_FTR_macros_expected -
773                              &ftr_fixup_test_FW_FTR_macros;
774
775         /* The fixups have already been done for us during boot */
776         check(memcmp(&ftr_fixup_test_FW_FTR_macros,
777                      &ftr_fixup_test_FW_FTR_macros_expected, size) == 0);
778 #endif
779 }
780
781 static void test_lwsync_macros(void)
782 {
783         extern u8 lwsync_fixup_test;
784         extern u8 end_lwsync_fixup_test;
785         extern u8 lwsync_fixup_test_expected_LWSYNC;
786         extern u8 lwsync_fixup_test_expected_SYNC;
787         unsigned long size = &end_lwsync_fixup_test -
788                              &lwsync_fixup_test;
789
790         /* The fixups have already been done for us during boot */
791         if (cur_cpu_spec->cpu_features & CPU_FTR_LWSYNC) {
792                 check(memcmp(&lwsync_fixup_test,
793                              &lwsync_fixup_test_expected_LWSYNC, size) == 0);
794         } else {
795                 check(memcmp(&lwsync_fixup_test,
796                              &lwsync_fixup_test_expected_SYNC, size) == 0);
797         }
798 }
799
800 static int __init test_feature_fixups(void)
801 {
802         printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
803
804         test_basic_patching();
805         test_alternative_patching();
806         test_alternative_case_too_big();
807         test_alternative_case_too_small();
808         test_alternative_case_with_branch();
809         test_alternative_case_with_external_branch();
810         test_cpu_macros();
811         test_fw_macros();
812         test_lwsync_macros();
813
814         return 0;
815 }
816 late_initcall(test_feature_fixups);
817
818 #endif /* CONFIG_FTR_FIXUP_SELFTEST */