1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/module.h> |
3 | #include <linux/cpu.h> |
4 | #include <linux/smp.h> |
5 | #include <asm/text-patching.h> |
6 | #include <asm/alternative.h> |
7 | #include <asm/facility.h> |
8 | #include <asm/nospec-branch.h> |
9 | |
10 | static int __initdata_or_module alt_instr_disabled; |
11 | |
12 | static int __init disable_alternative_instructions(char *str) |
13 | { |
14 | alt_instr_disabled = 1; |
15 | return 0; |
16 | } |
17 | |
18 | early_param("noaltinstr" , disable_alternative_instructions); |
19 | |
20 | static void __init_or_module __apply_alternatives(struct alt_instr *start, |
21 | struct alt_instr *end) |
22 | { |
23 | struct alt_instr *a; |
24 | u8 *instr, *replacement; |
25 | |
26 | /* |
27 | * The scan order should be from start to end. A later scanned |
28 | * alternative code can overwrite previously scanned alternative code. |
29 | */ |
30 | for (a = start; a < end; a++) { |
31 | instr = (u8 *)&a->instr_offset + a->instr_offset; |
32 | replacement = (u8 *)&a->repl_offset + a->repl_offset; |
33 | |
34 | if (!__test_facility(a->facility, alt_stfle_fac_list)) |
35 | continue; |
36 | |
37 | if (unlikely(a->instrlen % 2)) { |
38 | WARN_ONCE(1, "cpu alternatives instructions length is " |
39 | "odd, skipping patching\n" ); |
40 | continue; |
41 | } |
42 | |
43 | s390_kernel_write(instr, replacement, a->instrlen); |
44 | } |
45 | } |
46 | |
47 | void __init_or_module apply_alternatives(struct alt_instr *start, |
48 | struct alt_instr *end) |
49 | { |
50 | if (!alt_instr_disabled) |
51 | __apply_alternatives(start, end); |
52 | } |
53 | |
54 | extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; |
55 | void __init apply_alternative_instructions(void) |
56 | { |
57 | apply_alternatives(start: __alt_instructions, end: __alt_instructions_end); |
58 | } |
59 | |
60 | static void do_sync_core(void *info) |
61 | { |
62 | sync_core(); |
63 | } |
64 | |
65 | void text_poke_sync(void) |
66 | { |
67 | on_each_cpu(func: do_sync_core, NULL, wait: 1); |
68 | } |
69 | |
70 | void text_poke_sync_lock(void) |
71 | { |
72 | cpus_read_lock(); |
73 | text_poke_sync(); |
74 | cpus_read_unlock(); |
75 | } |
76 | |