1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Jump label s390 support 4 * 5 * Copyright IBM Corp. 2011 6 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> 7 */ 8 #include <linux/uaccess.h> 9 #include <linux/stop_machine.h> 10 #include <linux/jump_label.h> 11 #include <asm/ipl.h> 12 13 struct insn { 14 u16 opcode; 15 s32 offset; 16 } __packed; 17 18 static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn) 19 { 20 /* brcl 0,offset */ 21 insn->opcode = 0xc004; 22 insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1; 23 } 24 25 static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn) 26 { 27 /* brcl 15,offset */ 28 insn->opcode = 0xc0f4; 29 insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1; 30 } 31 32 static void jump_label_bug(struct jump_entry *entry, struct insn *expected, 33 struct insn *new) 34 { 35 unsigned char *ipc = (unsigned char *)jump_entry_code(entry); 36 unsigned char *ipe = (unsigned char *)expected; 37 unsigned char *ipn = (unsigned char *)new; 38 39 pr_emerg("Jump label code mismatch at %pS [%px]\n", ipc, ipc); 40 pr_emerg("Found: %6ph\n", ipc); 41 pr_emerg("Expected: %6ph\n", ipe); 42 pr_emerg("New: %6ph\n", ipn); 43 panic("Corrupted kernel text"); 44 } 45 46 static struct insn orignop = { 47 .opcode = 0xc004, 48 .offset = JUMP_LABEL_NOP_OFFSET >> 1, 49 }; 50 51 static void __jump_label_transform(struct jump_entry *entry, 52 enum jump_label_type type, 53 int init) 54 { 55 void *code = (void *)jump_entry_code(entry); 56 struct insn old, new; 57 58 if (type == JUMP_LABEL_JMP) { 59 jump_label_make_nop(entry, &old); 60 jump_label_make_branch(entry, &new); 61 } else { 62 jump_label_make_branch(entry, &old); 63 jump_label_make_nop(entry, &new); 64 } 65 if (init) { 66 if (memcmp(code, &orignop, sizeof(orignop))) 67 jump_label_bug(entry, &orignop, &new); 68 } else { 69 if (memcmp(code, &old, sizeof(old))) 70 jump_label_bug(entry, &old, &new); 71 } 72 s390_kernel_write(code, &new, sizeof(new)); 73 } 74 75 static void __jump_label_sync(void *dummy) 76 { 77 } 78 79 void arch_jump_label_transform(struct jump_entry *entry, 80 enum jump_label_type type) 81 { 82 __jump_label_transform(entry, type, 0); 83 smp_call_function(__jump_label_sync, NULL, 1); 84 } 85 86 void arch_jump_label_transform_static(struct jump_entry *entry, 87 enum jump_label_type type) 88 { 89 __jump_label_transform(entry, type, 1); 90 } 91