0001
0002 #include <linux/module.h>
0003 #include <linux/cpu.h>
0004 #include <linux/smp.h>
0005 #include <asm/text-patching.h>
0006 #include <asm/alternative.h>
0007 #include <asm/facility.h>
0008 #include <asm/nospec-branch.h>
0009
0010 static int __initdata_or_module alt_instr_disabled;
0011
0012 static int __init disable_alternative_instructions(char *str)
0013 {
0014 alt_instr_disabled = 1;
0015 return 0;
0016 }
0017
0018 early_param("noaltinstr", disable_alternative_instructions);
0019
0020 static void __init_or_module __apply_alternatives(struct alt_instr *start,
0021 struct alt_instr *end)
0022 {
0023 struct alt_instr *a;
0024 u8 *instr, *replacement;
0025
0026
0027
0028
0029
0030 for (a = start; a < end; a++) {
0031 instr = (u8 *)&a->instr_offset + a->instr_offset;
0032 replacement = (u8 *)&a->repl_offset + a->repl_offset;
0033
0034 if (!__test_facility(a->facility, alt_stfle_fac_list))
0035 continue;
0036
0037 if (unlikely(a->instrlen % 2)) {
0038 WARN_ONCE(1, "cpu alternatives instructions length is "
0039 "odd, skipping patching\n");
0040 continue;
0041 }
0042
0043 s390_kernel_write(instr, replacement, a->instrlen);
0044 }
0045 }
0046
0047 void __init_or_module apply_alternatives(struct alt_instr *start,
0048 struct alt_instr *end)
0049 {
0050 if (!alt_instr_disabled)
0051 __apply_alternatives(start, end);
0052 }
0053
0054 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
0055 void __init apply_alternative_instructions(void)
0056 {
0057 apply_alternatives(__alt_instructions, __alt_instructions_end);
0058 }
0059
0060 static void do_sync_core(void *info)
0061 {
0062 sync_core();
0063 }
0064
0065 void text_poke_sync(void)
0066 {
0067 on_each_cpu(do_sync_core, NULL, 1);
0068 }
0069
0070 void text_poke_sync_lock(void)
0071 {
0072 cpus_read_lock();
0073 text_poke_sync();
0074 cpus_read_unlock();
0075 }