aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/jump_label.c
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2015-01-29 07:45:35 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-01-29 10:33:33 -0500
commit5c6497c50f8d809eac6d01512c291a1f67382abd (patch)
tree30190eca92d8d9509862f147406c0dc4cba0b833 /arch/s390/kernel/jump_label.c
parentdb1177ee6206f957f579fdbfebb2c6a64e82c694 (diff)
s390/jump label: add sanity checks
Add sanity checks to verify that only expected code will be replaced. If the code patterns do not match print the code patterns and panic, since something went terribly wrong. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/jump_label.c')
-rw-r--r--arch/s390/kernel/jump_label.c56
1 files changed, 42 insertions, 14 deletions
diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c
index b987ab2c1541..25aef40584f7 100644
--- a/arch/s390/kernel/jump_label.c
+++ b/arch/s390/kernel/jump_label.c
@@ -22,31 +22,59 @@ struct insn_args {
22 enum jump_label_type type; 22 enum jump_label_type type;
23}; 23};
24 24
25static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn)
26{
27 /* brcl 0,0 */
28 insn->opcode = 0xc004;
29 insn->offset = 0;
30}
31
32static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
33{
34 /* brcl 15,offset */
35 insn->opcode = 0xc0f4;
36 insn->offset = (entry->target - entry->code) >> 1;
37}
38
39static void jump_label_bug(struct jump_entry *entry, struct insn *insn)
40{
41 unsigned char *ipc = (unsigned char *)entry->code;
42 unsigned char *ipe = (unsigned char *)insn;
43
44 pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc, ipc);
45 pr_emerg("Found: %02x %02x %02x %02x %02x %02x\n",
46 ipc[0], ipc[1], ipc[2], ipc[3], ipc[4], ipc[5]);
47 pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
48 ipe[0], ipe[1], ipe[2], ipe[3], ipe[4], ipe[5]);
49 panic("Corrupted kernel text");
50}
51
25static void __jump_label_transform(struct jump_entry *entry, 52static void __jump_label_transform(struct jump_entry *entry,
26 enum jump_label_type type) 53 enum jump_label_type type,
54 int init)
27{ 55{
28 struct insn insn; 56 struct insn old, new;
29 int rc;
30 57
31 if (type == JUMP_LABEL_ENABLE) { 58 if (type == JUMP_LABEL_ENABLE) {
32 /* brcl 15,offset */ 59 jump_label_make_nop(entry, &old);
33 insn.opcode = 0xc0f4; 60 jump_label_make_branch(entry, &new);
34 insn.offset = (entry->target - entry->code) >> 1;
35 } else { 61 } else {
36 /* brcl 0,0 */ 62 if (init)
37 insn.opcode = 0xc004; 63 jump_label_make_nop(entry, &old);
38 insn.offset = 0; 64 else
65 jump_label_make_branch(entry, &old);
66 jump_label_make_nop(entry, &new);
39 } 67 }
40 68 if (memcmp((void *)entry->code, &old, sizeof(old)))
41 rc = probe_kernel_write((void *)entry->code, &insn, JUMP_LABEL_NOP_SIZE); 69 jump_label_bug(entry, &old);
42 WARN_ON_ONCE(rc < 0); 70 probe_kernel_write((void *)entry->code, &new, sizeof(new));
43} 71}
44 72
45static int __sm_arch_jump_label_transform(void *data) 73static int __sm_arch_jump_label_transform(void *data)
46{ 74{
47 struct insn_args *args = data; 75 struct insn_args *args = data;
48 76
49 __jump_label_transform(args->entry, args->type); 77 __jump_label_transform(args->entry, args->type, 0);
50 return 0; 78 return 0;
51} 79}
52 80
@@ -64,7 +92,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
64void arch_jump_label_transform_static(struct jump_entry *entry, 92void arch_jump_label_transform_static(struct jump_entry *entry,
65 enum jump_label_type type) 93 enum jump_label_type type)
66{ 94{
67 __jump_label_transform(entry, type); 95 __jump_label_transform(entry, type, 1);
68} 96}
69 97
70#endif 98#endif