1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* !! 2 #include <linux/kernel.h> 3 * Jump label s390 support !! 3 #include <linux/types.h> 4 * !! 4 #include <linux/mutex.h> 5 * Copyright IBM Corp. 2011 !! 5 #include <linux/cpu.h> 6 * Author(s): Jan Glauber <jang@linux.vnet.ibm !! 6 7 */ << 8 #include <linux/uaccess.h> << 9 #include <linux/jump_label.h> 7 #include <linux/jump_label.h> 10 #include <linux/module.h> !! 8 #include <linux/memory.h> 11 #include <asm/text-patching.h> << 12 #include <asm/ipl.h> << 13 << 14 struct insn { << 15 u16 opcode; << 16 s32 offset; << 17 } __packed; << 18 9 19 static void jump_label_make_nop(struct jump_en !! 10 #include <asm/cacheflush.h> 20 { << 21 /* brcl 0,offset */ << 22 insn->opcode = 0xc004; << 23 insn->offset = (jump_entry_target(entr << 24 } << 25 11 26 static void jump_label_make_branch(struct jump !! 12 void arch_jump_label_transform(struct jump_entry *entry, >> 13 enum jump_label_type type) 27 { 14 { 28 /* brcl 15,offset */ !! 15 u32 *insn = (u32 *) (unsigned long) entry->code; 29 insn->opcode = 0xc0f4; !! 16 u32 val; 30 insn->offset = (jump_entry_target(entr << 31 } << 32 17 33 static void jump_label_bug(struct jump_entry * !! 18 if (type == JUMP_LABEL_JMP) { 34 struct insn *new) !! 19 s32 off = (s32)entry->target - (s32)entry->code; 35 { !! 20 bool use_v9_branch = false; 36 unsigned char *ipc = (unsigned char *) << 37 unsigned char *ipe = (unsigned char *) << 38 unsigned char *ipn = (unsigned char *) << 39 << 40 pr_emerg("Jump label code mismatch at << 41 pr_emerg("Found: %6ph\n", ipc); << 42 pr_emerg("Expected: %6ph\n", ipe); << 43 pr_emerg("New: %6ph\n", ipn); << 44 panic("Corrupted kernel text"); << 45 } << 46 21 47 static void jump_label_transform(struct jump_e !! 22 BUG_ON(off & 3); 48 enum jump_lab << 49 { << 50 void *code = (void *)jump_entry_code(e << 51 struct insn old, new; << 52 23 53 if (type == JUMP_LABEL_JMP) { !! 24 #ifdef CONFIG_SPARC64 54 jump_label_make_nop(entry, &ol !! 25 if (off <= 0xfffff && off >= -0x100000) 55 jump_label_make_branch(entry, !! 26 use_v9_branch = true; >> 27 #endif >> 28 if (use_v9_branch) { >> 29 /* WDISP19 - target is . + immed << 2 */ >> 30 /* ba,pt %xcc, . + off */ >> 31 val = 0x10680000 | (((u32) off >> 2) & 0x7ffff); >> 32 } else { >> 33 /* WDISP22 - target is . + immed << 2 */ >> 34 BUG_ON(off > 0x7fffff); >> 35 BUG_ON(off < -0x800000); >> 36 /* ba . + off */ >> 37 val = 0x10800000 | (((u32) off >> 2) & 0x3fffff); >> 38 } 56 } else { 39 } else { 57 jump_label_make_branch(entry, !! 40 val = 0x01000000; 58 jump_label_make_nop(entry, &ne << 59 } 41 } 60 if (memcmp(code, &old, sizeof(old))) << 61 jump_label_bug(entry, &old, &n << 62 s390_kernel_write(code, &new, sizeof(n << 63 } << 64 42 65 void arch_jump_label_transform(struct jump_ent !! 43 mutex_lock(&text_mutex); 66 enum jump_label !! 44 *insn = val; 67 { !! 45 flushi(insn); 68 jump_label_transform(entry, type); !! 46 mutex_unlock(&text_mutex); 69 text_poke_sync(); << 70 } << 71 << 72 bool arch_jump_label_transform_queue(struct ju << 73 enum jump << 74 { << 75 jump_label_transform(entry, type); << 76 return true; << 77 } << 78 << 79 void arch_jump_label_transform_apply(void) << 80 { << 81 text_poke_sync(); << 82 } 47 } 83 48
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.