0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/uaccess.h>
0009 #include <linux/jump_label.h>
0010 #include <linux/module.h>
0011 #include <asm/text-patching.h>
0012 #include <asm/ipl.h>
0013
0014 struct insn {
0015 u16 opcode;
0016 s32 offset;
0017 } __packed;
0018
0019 static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn)
0020 {
0021
0022 insn->opcode = 0xc004;
0023 insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1;
0024 }
0025
0026 static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
0027 {
0028
0029 insn->opcode = 0xc0f4;
0030 insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1;
0031 }
0032
0033 static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
0034 struct insn *new)
0035 {
0036 unsigned char *ipc = (unsigned char *)jump_entry_code(entry);
0037 unsigned char *ipe = (unsigned char *)expected;
0038 unsigned char *ipn = (unsigned char *)new;
0039
0040 pr_emerg("Jump label code mismatch at %pS [%px]\n", ipc, ipc);
0041 pr_emerg("Found: %6ph\n", ipc);
0042 pr_emerg("Expected: %6ph\n", ipe);
0043 pr_emerg("New: %6ph\n", ipn);
0044 panic("Corrupted kernel text");
0045 }
0046
0047 static void jump_label_transform(struct jump_entry *entry,
0048 enum jump_label_type type)
0049 {
0050 void *code = (void *)jump_entry_code(entry);
0051 struct insn old, new;
0052
0053 if (type == JUMP_LABEL_JMP) {
0054 jump_label_make_nop(entry, &old);
0055 jump_label_make_branch(entry, &new);
0056 } else {
0057 jump_label_make_branch(entry, &old);
0058 jump_label_make_nop(entry, &new);
0059 }
0060 if (memcmp(code, &old, sizeof(old)))
0061 jump_label_bug(entry, &old, &new);
0062 s390_kernel_write(code, &new, sizeof(new));
0063 }
0064
0065 void arch_jump_label_transform(struct jump_entry *entry,
0066 enum jump_label_type type)
0067 {
0068 jump_label_transform(entry, type);
0069 text_poke_sync();
0070 }
0071
0072 bool arch_jump_label_transform_queue(struct jump_entry *entry,
0073 enum jump_label_type type)
0074 {
0075 jump_label_transform(entry, type);
0076 return true;
0077 }
0078
0079 void arch_jump_label_transform_apply(void)
0080 {
0081 text_poke_sync();
0082 }