Commit | Line | Data |
---|---|---|
5373db88 JG |
1 | /* |
2 | * Jump label s390 support | |
3 | * | |
4 | * Copyright IBM Corp. 2011 | |
5 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | |
6 | */ | |
7 | #include <linux/module.h> | |
8 | #include <linux/uaccess.h> | |
9 | #include <linux/stop_machine.h> | |
10 | #include <linux/jump_label.h> | |
11 | #include <asm/ipl.h> | |
12 | ||
13 | #ifdef HAVE_JUMP_LABEL | |
14 | ||
15 | struct insn { | |
16 | u16 opcode; | |
17 | s32 offset; | |
18 | } __packed; | |
19 | ||
20 | struct insn_args { | |
21 | unsigned long *target; | |
22 | struct insn *insn; | |
23 | ssize_t size; | |
24 | }; | |
25 | ||
26 | static int __arch_jump_label_transform(void *data) | |
27 | { | |
28 | struct insn_args *args = data; | |
29 | int rc; | |
30 | ||
31 | rc = probe_kernel_write(args->target, args->insn, args->size); | |
32 | WARN_ON_ONCE(rc < 0); | |
33 | return 0; | |
34 | } | |
35 | ||
36 | void arch_jump_label_transform(struct jump_entry *entry, | |
37 | enum jump_label_type type) | |
38 | { | |
39 | struct insn_args args; | |
40 | struct insn insn; | |
41 | ||
42 | if (type == JUMP_LABEL_ENABLE) { | |
43 | /* brcl 15,offset */ | |
44 | insn.opcode = 0xc0f4; | |
45 | insn.offset = (entry->target - entry->code) >> 1; | |
46 | } else { | |
47 | /* brcl 0,0 */ | |
48 | insn.opcode = 0xc004; | |
49 | insn.offset = 0; | |
50 | } | |
51 | ||
52 | args.target = (void *) entry->code; | |
53 | args.insn = &insn; | |
54 | args.size = JUMP_LABEL_NOP_SIZE; | |
55 | ||
56 | stop_machine(__arch_jump_label_transform, &args, NULL); | |
57 | } | |
58 | ||
59 | #endif |