2 * Jump label s390 support
4 * Copyright IBM Corp. 2011
5 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
7 #include <linux/module.h>
8 #include <linux/uaccess.h>
9 #include <linux/stop_machine.h>
10 #include <linux/jump_label.h>
13 #ifdef HAVE_JUMP_LABEL
21 struct jump_entry
*entry
;
22 enum jump_label_type type
;
25 static void jump_label_make_nop(struct jump_entry
*entry
, struct insn
*insn
)
28 insn
->opcode
= 0xc004;
32 static void jump_label_make_branch(struct jump_entry
*entry
, struct insn
*insn
)
35 insn
->opcode
= 0xc0f4;
36 insn
->offset
= (entry
->target
- entry
->code
) >> 1;
39 static void jump_label_bug(struct jump_entry
*entry
, struct insn
*expected
,
42 unsigned char *ipc
= (unsigned char *)entry
->code
;
43 unsigned char *ipe
= (unsigned char *)expected
;
44 unsigned char *ipn
= (unsigned char *)new;
46 pr_emerg("Jump label code mismatch at %pS [%p]\n", ipc
, ipc
);
47 pr_emerg("Found: %02x %02x %02x %02x %02x %02x\n",
48 ipc
[0], ipc
[1], ipc
[2], ipc
[3], ipc
[4], ipc
[5]);
49 pr_emerg("Expected: %02x %02x %02x %02x %02x %02x\n",
50 ipe
[0], ipe
[1], ipe
[2], ipe
[3], ipe
[4], ipe
[5]);
51 pr_emerg("New: %02x %02x %02x %02x %02x %02x\n",
52 ipn
[0], ipn
[1], ipn
[2], ipn
[3], ipn
[4], ipn
[5]);
53 panic("Corrupted kernel text");
56 static struct insn orignop
= {
58 .offset
= JUMP_LABEL_NOP_OFFSET
>> 1,
61 static void __jump_label_transform(struct jump_entry
*entry
,
62 enum jump_label_type type
,
67 if (type
== JUMP_LABEL_ENABLE
) {
68 jump_label_make_nop(entry
, &old
);
69 jump_label_make_branch(entry
, &new);
71 jump_label_make_branch(entry
, &old
);
72 jump_label_make_nop(entry
, &new);
75 if (memcmp((void *)entry
->code
, &orignop
, sizeof(orignop
)))
76 jump_label_bug(entry
, &orignop
, &new);
78 if (memcmp((void *)entry
->code
, &old
, sizeof(old
)))
79 jump_label_bug(entry
, &old
, &new);
81 s390_kernel_write((void *)entry
->code
, &new, sizeof(new));
84 static int __sm_arch_jump_label_transform(void *data
)
86 struct insn_args
*args
= data
;
88 __jump_label_transform(args
->entry
, args
->type
, 0);
92 void arch_jump_label_transform(struct jump_entry
*entry
,
93 enum jump_label_type type
)
95 struct insn_args args
;
100 stop_machine(__sm_arch_jump_label_transform
, &args
, NULL
);
103 void arch_jump_label_transform_static(struct jump_entry
*entry
,
104 enum jump_label_type type
)
106 __jump_label_transform(entry
, type
, 1);