19fa1db4cSMartin Schwidefsky // SPDX-License-Identifier: GPL-2.0
2686140a1SVasily Gorbik #include <linux/module.h>
3e16d02eeSHeiko Carstens #include <linux/cpu.h>
4e16d02eeSHeiko Carstens #include <linux/smp.h>
5e16d02eeSHeiko Carstens #include <asm/text-patching.h>
6686140a1SVasily Gorbik #include <asm/alternative.h>
7686140a1SVasily Gorbik #include <asm/facility.h>
86e179d64SMartin Schwidefsky #include <asm/nospec-branch.h>
9686140a1SVasily Gorbik
10686140a1SVasily Gorbik static int __initdata_or_module alt_instr_disabled;
11686140a1SVasily Gorbik
disable_alternative_instructions(char * str)12686140a1SVasily Gorbik static int __init disable_alternative_instructions(char *str)
13686140a1SVasily Gorbik {
14686140a1SVasily Gorbik alt_instr_disabled = 1;
15686140a1SVasily Gorbik return 0;
16686140a1SVasily Gorbik }
17686140a1SVasily Gorbik
18686140a1SVasily Gorbik early_param("noaltinstr", disable_alternative_instructions);
19686140a1SVasily Gorbik
__apply_alternatives(struct alt_instr * start,struct alt_instr * end)20686140a1SVasily Gorbik static void __init_or_module __apply_alternatives(struct alt_instr *start,
21686140a1SVasily Gorbik struct alt_instr *end)
22686140a1SVasily Gorbik {
23686140a1SVasily Gorbik struct alt_instr *a;
24686140a1SVasily Gorbik u8 *instr, *replacement;
25686140a1SVasily Gorbik
26686140a1SVasily Gorbik /*
27686140a1SVasily Gorbik * The scan order should be from start to end. A later scanned
28686140a1SVasily Gorbik * alternative code can overwrite previously scanned alternative code.
29686140a1SVasily Gorbik */
30686140a1SVasily Gorbik for (a = start; a < end; a++) {
31686140a1SVasily Gorbik instr = (u8 *)&a->instr_offset + a->instr_offset;
32686140a1SVasily Gorbik replacement = (u8 *)&a->repl_offset + a->repl_offset;
33686140a1SVasily Gorbik
3417e89e13SSven Schnelle if (!__test_facility(a->facility, alt_stfle_fac_list))
35686140a1SVasily Gorbik continue;
36686140a1SVasily Gorbik
37*e6ed91fdSHeiko Carstens if (unlikely(a->instrlen % 2)) {
38686140a1SVasily Gorbik WARN_ONCE(1, "cpu alternatives instructions length is "
39686140a1SVasily Gorbik "odd, skipping patching\n");
40686140a1SVasily Gorbik continue;
41686140a1SVasily Gorbik }
42686140a1SVasily Gorbik
43*e6ed91fdSHeiko Carstens s390_kernel_write(instr, replacement, a->instrlen);
44686140a1SVasily Gorbik }
45686140a1SVasily Gorbik }
46686140a1SVasily Gorbik
apply_alternatives(struct alt_instr * start,struct alt_instr * end)47686140a1SVasily Gorbik void __init_or_module apply_alternatives(struct alt_instr *start,
48686140a1SVasily Gorbik struct alt_instr *end)
49686140a1SVasily Gorbik {
50686140a1SVasily Gorbik if (!alt_instr_disabled)
51686140a1SVasily Gorbik __apply_alternatives(start, end);
52686140a1SVasily Gorbik }
53686140a1SVasily Gorbik
54686140a1SVasily Gorbik extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
apply_alternative_instructions(void)55686140a1SVasily Gorbik void __init apply_alternative_instructions(void)
56686140a1SVasily Gorbik {
57686140a1SVasily Gorbik apply_alternatives(__alt_instructions, __alt_instructions_end);
58686140a1SVasily Gorbik }
59e16d02eeSHeiko Carstens
do_sync_core(void * info)60e16d02eeSHeiko Carstens static void do_sync_core(void *info)
61e16d02eeSHeiko Carstens {
62e16d02eeSHeiko Carstens sync_core();
63e16d02eeSHeiko Carstens }
64e16d02eeSHeiko Carstens
text_poke_sync(void)65e16d02eeSHeiko Carstens void text_poke_sync(void)
66e16d02eeSHeiko Carstens {
67e16d02eeSHeiko Carstens on_each_cpu(do_sync_core, NULL, 1);
68e16d02eeSHeiko Carstens }
69e16d02eeSHeiko Carstens
text_poke_sync_lock(void)70e16d02eeSHeiko Carstens void text_poke_sync_lock(void)
71e16d02eeSHeiko Carstens {
72e16d02eeSHeiko Carstens cpus_read_lock();
73e16d02eeSHeiko Carstens text_poke_sync();
74e16d02eeSHeiko Carstens cpus_read_unlock();
75e16d02eeSHeiko Carstens }
76