hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/powerpc/lib/feature-fixups.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
34 *
....@@ -5,11 +6,6 @@
56 * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
67 *
78 * 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.
139 */
1410
1511 #include <linux/types.h>
....@@ -26,6 +22,7 @@
2622 #include <asm/setup.h>
2723 #include <asm/security_features.h>
2824 #include <asm/firmware.h>
25
+#include <asm/inst.h>
2926
3027 struct fixup_entry {
3128 unsigned long mask;
....@@ -36,30 +33,31 @@
3633 long alt_end_off;
3734 };
3835
39
-static unsigned int *calc_addr(struct fixup_entry *fcur, long offset)
36
+static struct ppc_inst *calc_addr(struct fixup_entry *fcur, long offset)
4037 {
4138 /*
4239 * We store the offset to the code as a negative offset from
4340 * the start of the alt_entry, to support the VDSO. This
4441 * routine converts that back into an actual address.
4542 */
46
- return (unsigned int *)((unsigned long)fcur + offset);
43
+ return (struct ppc_inst *)((unsigned long)fcur + offset);
4744 }
4845
49
-static int patch_alt_instruction(unsigned int *src, unsigned int *dest,
50
- unsigned int *alt_start, unsigned int *alt_end)
46
+static int patch_alt_instruction(struct ppc_inst *src, struct ppc_inst *dest,
47
+ struct ppc_inst *alt_start, struct ppc_inst *alt_end)
5148 {
52
- unsigned int instr;
49
+ int err;
50
+ struct ppc_inst instr;
5351
54
- instr = *src;
52
+ instr = ppc_inst_read(src);
5553
5654 if (instr_is_relative_branch(*src)) {
57
- unsigned int *target = (unsigned int *)branch_target(src);
55
+ struct ppc_inst *target = (struct ppc_inst *)branch_target(src);
5856
5957 /* Branch within the section doesn't need translating */
6058 if (target < alt_start || target > alt_end) {
61
- instr = translate_branch(dest, src);
62
- if (!instr)
59
+ err = translate_branch(&instr, dest, src);
60
+ if (err)
6361 return 1;
6462 }
6563 }
....@@ -71,7 +69,7 @@
7169
7270 static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
7371 {
74
- unsigned int *start, *end, *alt_start, *alt_end, *src, *dest;
72
+ struct ppc_inst *start, *end, *alt_start, *alt_end, *src, *dest, nop;
7573
7674 start = calc_addr(fcur, fcur->start_off);
7775 end = calc_addr(fcur, fcur->end_off);
....@@ -87,13 +85,15 @@
8785 src = alt_start;
8886 dest = start;
8987
90
- for (; src < alt_end; src++, dest++) {
88
+ for (; src < alt_end; src = ppc_inst_next(src, src),
89
+ dest = ppc_inst_next(dest, dest)) {
9190 if (patch_alt_instruction(src, dest, alt_start, alt_end))
9291 return 1;
9392 }
9493
95
- for (; dest < end; dest++)
96
- raw_patch_instruction(dest, PPC_INST_NOP);
94
+ nop = ppc_inst(PPC_INST_NOP);
95
+ for (; dest < end; dest = ppc_inst_next(dest, &nop))
96
+ raw_patch_instruction(dest, nop);
9797
9898 return 0;
9999 }
....@@ -119,7 +119,7 @@
119119 }
120120
121121 #ifdef CONFIG_PPC_BOOK3S_64
122
-void do_stf_entry_barrier_fixups(enum stf_barrier_type types)
122
+static void do_stf_entry_barrier_fixups(enum stf_barrier_type types)
123123 {
124124 unsigned int instrs[3], *dest;
125125 long *start, *end;
....@@ -150,15 +150,17 @@
150150
151151 pr_devel("patching dest %lx\n", (unsigned long)dest);
152152
153
- patch_instruction(dest, instrs[0]);
153
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
154154
155155 if (types & STF_BARRIER_FALLBACK)
156
- patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback,
156
+ patch_branch((struct ppc_inst *)(dest + 1),
157
+ (unsigned long)&stf_barrier_fallback,
157158 BRANCH_SET_LINK);
158159 else
159
- patch_instruction(dest + 1, instrs[1]);
160
+ patch_instruction((struct ppc_inst *)(dest + 1),
161
+ ppc_inst(instrs[1]));
160162
161
- patch_instruction(dest + 2, instrs[2]);
163
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
162164 }
163165
164166 printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i,
....@@ -169,7 +171,7 @@
169171 : "unknown");
170172 }
171173
172
-void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
174
+static void do_stf_exit_barrier_fixups(enum stf_barrier_type types)
173175 {
174176 unsigned int instrs[6], *dest;
175177 long *start, *end;
....@@ -211,12 +213,12 @@
211213
212214 pr_devel("patching dest %lx\n", (unsigned long)dest);
213215
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]);
216
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
217
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
218
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
219
+ patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
220
+ patch_instruction((struct ppc_inst *)(dest + 4), ppc_inst(instrs[4]));
221
+ patch_instruction((struct ppc_inst *)(dest + 5), ppc_inst(instrs[5]));
220222 }
221223 printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i,
222224 (types == STF_BARRIER_NONE) ? "no" :
....@@ -280,11 +282,11 @@
280282
281283 pr_devel("patching dest %lx\n", (unsigned long)dest);
282284
283
- patch_instruction(dest, instrs[0]);
285
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
284286
285
- patch_instruction((dest + 1), instrs[1]);
286
- patch_instruction((dest + 2), instrs[2]);
287
- patch_instruction((dest + 3), instrs[3]);
287
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
288
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
289
+ patch_instruction((struct ppc_inst *)(dest + 3), ppc_inst(instrs[3]));
288290 }
289291
290292 printk(KERN_DEBUG "uaccess-flush: patched %d locations (%s flush)\n", i,
....@@ -303,9 +305,6 @@
303305 unsigned int instrs[3], *dest;
304306 long *start, *end;
305307 int i;
306
-
307
- start = PTRRELOC(&__start___entry_flush_fixup);
308
- end = PTRRELOC(&__stop___entry_flush_fixup);
309308
310309 instrs[0] = 0x60000000; /* nop */
311310 instrs[1] = 0x60000000; /* nop */
....@@ -326,21 +325,42 @@
326325 if (types & L1D_FLUSH_MTTRIG)
327326 instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
328327
328
+ start = PTRRELOC(&__start___entry_flush_fixup);
329
+ end = PTRRELOC(&__stop___entry_flush_fixup);
329330 for (i = 0; start < end; start++, i++) {
330331 dest = (void *)start + *start;
331332
332333 pr_devel("patching dest %lx\n", (unsigned long)dest);
333334
334
- patch_instruction(dest, instrs[0]);
335
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
335336
336337 if (types == L1D_FLUSH_FALLBACK)
337
- patch_branch((dest + 1), (unsigned long)&entry_flush_fallback,
338
+ patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&entry_flush_fallback,
338339 BRANCH_SET_LINK);
339340 else
340
- patch_instruction((dest + 1), instrs[1]);
341
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
341342
342
- patch_instruction((dest + 2), instrs[2]);
343
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
343344 }
345
+
346
+ start = PTRRELOC(&__start___scv_entry_flush_fixup);
347
+ end = PTRRELOC(&__stop___scv_entry_flush_fixup);
348
+ for (; start < end; start++, i++) {
349
+ dest = (void *)start + *start;
350
+
351
+ pr_devel("patching dest %lx\n", (unsigned long)dest);
352
+
353
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
354
+
355
+ if (types == L1D_FLUSH_FALLBACK)
356
+ patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&scv_entry_flush_fallback,
357
+ BRANCH_SET_LINK);
358
+ else
359
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
360
+
361
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
362
+ }
363
+
344364
345365 printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
346366 (types == L1D_FLUSH_NONE) ? "no" :
....@@ -396,9 +416,9 @@
396416
397417 pr_devel("patching dest %lx\n", (unsigned long)dest);
398418
399
- patch_instruction(dest, instrs[0]);
400
- patch_instruction(dest + 1, instrs[1]);
401
- patch_instruction(dest + 2, instrs[2]);
419
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
420
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
421
+ patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
402422 }
403423
404424 printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i,
....@@ -431,7 +451,7 @@
431451 dest = (void *)start + *start;
432452
433453 pr_devel("patching dest %lx\n", (unsigned long)dest);
434
- patch_instruction(dest, instr);
454
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instr));
435455 }
436456
437457 printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
....@@ -474,8 +494,8 @@
474494 dest = (void *)start + *start;
475495
476496 pr_devel("patching dest %lx\n", (unsigned long)dest);
477
- patch_instruction(dest, instr[0]);
478
- patch_instruction(dest + 1, instr[1]);
497
+ patch_instruction((struct ppc_inst *)dest, ppc_inst(instr[0]));
498
+ patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instr[1]));
479499 }
480500
481501 printk(KERN_DEBUG "barrier-nospec: patched %d locations\n", i);
....@@ -489,7 +509,7 @@
489509 end = (void *)curr + *(curr + 1);
490510 for (; start < end; start++) {
491511 pr_devel("patching dest %lx\n", (unsigned long)start);
492
- patch_instruction(start, PPC_INST_NOP);
512
+ patch_instruction((struct ppc_inst *)start, ppc_inst(PPC_INST_NOP));
493513 }
494514 }
495515
....@@ -508,7 +528,7 @@
508528 void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end)
509529 {
510530 long *start, *end;
511
- unsigned int *dest;
531
+ struct ppc_inst *dest;
512532
513533 if (!(value & CPU_FTR_LWSYNC))
514534 return ;
....@@ -518,27 +538,27 @@
518538
519539 for (; start < end; start++) {
520540 dest = (void *)start + *start;
521
- raw_patch_instruction(dest, PPC_INST_LWSYNC);
541
+ raw_patch_instruction(dest, ppc_inst(PPC_INST_LWSYNC));
522542 }
523543 }
524544
525545 static void do_final_fixups(void)
526546 {
527547 #if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE)
528
- int *src, *dest;
529
- unsigned long length;
548
+ struct ppc_inst inst, *src, *dest, *end;
530549
531550 if (PHYSICAL_START == 0)
532551 return;
533552
534
- src = (int *)(KERNELBASE + PHYSICAL_START);
535
- dest = (int *)KERNELBASE;
536
- length = (__end_interrupts - _stext) / sizeof(int);
553
+ src = (struct ppc_inst *)(KERNELBASE + PHYSICAL_START);
554
+ dest = (struct ppc_inst *)KERNELBASE;
555
+ end = (void *)src + (__end_interrupts - _stext);
537556
538
- while (length--) {
539
- raw_patch_instruction(dest, *src);
540
- src++;
541
- dest++;
557
+ while (src < end) {
558
+ inst = ppc_inst_read(src);
559
+ raw_patch_instruction(dest, inst);
560
+ src = ppc_inst_next(src, src);
561
+ dest = ppc_inst_next(dest, dest);
542562 }
543563 #endif
544564 }
....@@ -821,6 +841,78 @@
821841 }
822842 }
823843
844
+#ifdef CONFIG_PPC64
845
+static void __init test_prefix_patching(void)
846
+{
847
+ extern unsigned int ftr_fixup_prefix1[];
848
+ extern unsigned int end_ftr_fixup_prefix1[];
849
+ extern unsigned int ftr_fixup_prefix1_orig[];
850
+ extern unsigned int ftr_fixup_prefix1_expected[];
851
+ int size = sizeof(unsigned int) * (end_ftr_fixup_prefix1 - ftr_fixup_prefix1);
852
+
853
+ fixup.value = fixup.mask = 8;
854
+ fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix1 + 1);
855
+ fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix1 + 3);
856
+ fixup.alt_start_off = fixup.alt_end_off = 0;
857
+
858
+ /* Sanity check */
859
+ check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_orig, size) == 0);
860
+
861
+ patch_feature_section(0, &fixup);
862
+ check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_expected, size) == 0);
863
+ check(memcmp(ftr_fixup_prefix1, ftr_fixup_prefix1_orig, size) != 0);
864
+}
865
+
866
+static void __init test_prefix_alt_patching(void)
867
+{
868
+ extern unsigned int ftr_fixup_prefix2[];
869
+ extern unsigned int end_ftr_fixup_prefix2[];
870
+ extern unsigned int ftr_fixup_prefix2_orig[];
871
+ extern unsigned int ftr_fixup_prefix2_expected[];
872
+ extern unsigned int ftr_fixup_prefix2_alt[];
873
+ int size = sizeof(unsigned int) * (end_ftr_fixup_prefix2 - ftr_fixup_prefix2);
874
+
875
+ fixup.value = fixup.mask = 8;
876
+ fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix2 + 1);
877
+ fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix2 + 3);
878
+ fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_prefix2_alt);
879
+ fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_prefix2_alt + 2);
880
+ /* Sanity check */
881
+ check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_orig, size) == 0);
882
+
883
+ patch_feature_section(0, &fixup);
884
+ check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_expected, size) == 0);
885
+ check(memcmp(ftr_fixup_prefix2, ftr_fixup_prefix2_orig, size) != 0);
886
+}
887
+
888
+static void __init test_prefix_word_alt_patching(void)
889
+{
890
+ extern unsigned int ftr_fixup_prefix3[];
891
+ extern unsigned int end_ftr_fixup_prefix3[];
892
+ extern unsigned int ftr_fixup_prefix3_orig[];
893
+ extern unsigned int ftr_fixup_prefix3_expected[];
894
+ extern unsigned int ftr_fixup_prefix3_alt[];
895
+ int size = sizeof(unsigned int) * (end_ftr_fixup_prefix3 - ftr_fixup_prefix3);
896
+
897
+ fixup.value = fixup.mask = 8;
898
+ fixup.start_off = calc_offset(&fixup, ftr_fixup_prefix3 + 1);
899
+ fixup.end_off = calc_offset(&fixup, ftr_fixup_prefix3 + 4);
900
+ fixup.alt_start_off = calc_offset(&fixup, ftr_fixup_prefix3_alt);
901
+ fixup.alt_end_off = calc_offset(&fixup, ftr_fixup_prefix3_alt + 3);
902
+ /* Sanity check */
903
+ check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_orig, size) == 0);
904
+
905
+ patch_feature_section(0, &fixup);
906
+ check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_expected, size) == 0);
907
+ patch_feature_section(0, &fixup);
908
+ check(memcmp(ftr_fixup_prefix3, ftr_fixup_prefix3_orig, size) != 0);
909
+}
910
+#else
911
+static inline void test_prefix_patching(void) {}
912
+static inline void test_prefix_alt_patching(void) {}
913
+static inline void test_prefix_word_alt_patching(void) {}
914
+#endif /* CONFIG_PPC64 */
915
+
824916 static int __init test_feature_fixups(void)
825917 {
826918 printk(KERN_DEBUG "Running feature fixup self-tests ...\n");
....@@ -835,6 +927,9 @@
835927 test_cpu_macros();
836928 test_fw_macros();
837929 test_lwsync_macros();
930
+ test_prefix_patching();
931
+ test_prefix_alt_patching();
932
+ test_prefix_word_alt_patching();
838933
839934 return 0;
840935 }