]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
e4b8b3f3 JG |
2 | /* |
3 | * Copyright IBM Corp. 2012 | |
4 | * Author(s): Jan Glauber <jang@linux.vnet.ibm.com> | |
5 | */ | |
6 | ||
7 | #include <linux/kernel.h> | |
8 | #include <linux/syscalls.h> | |
9 | #include <linux/signal.h> | |
10 | #include <linux/mm.h> | |
11 | #include <linux/slab.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/errno.h> | |
14 | #include <linux/kernel_stat.h> | |
68db0cf1 IM |
15 | #include <linux/sched/task_stack.h> |
16 | ||
e4b8b3f3 JG |
17 | #include <asm/runtime_instr.h> |
18 | #include <asm/cpu_mf.h> | |
19 | #include <asm/irq.h> | |
20 | ||
65875530 HC |
21 | #include "entry.h" |
22 | ||
e4b8b3f3 JG |
23 | /* empty control block to disable RI by loading it */ |
24 | struct runtime_instr_cb runtime_instr_empty_cb; | |
25 | ||
8d9047f8 HC |
26 | void runtime_instr_release(struct task_struct *tsk) |
27 | { | |
28 | kfree(tsk->thread.ri_cb); | |
29 | } | |
30 | ||
e4b8b3f3 JG |
31 | static void disable_runtime_instr(void) |
32 | { | |
8d9047f8 HC |
33 | struct task_struct *task = current; |
34 | struct pt_regs *regs; | |
e4b8b3f3 | 35 | |
8d9047f8 HC |
36 | if (!task->thread.ri_cb) |
37 | return; | |
38 | regs = task_pt_regs(task); | |
39 | preempt_disable(); | |
e4b8b3f3 | 40 | load_runtime_instr_cb(&runtime_instr_empty_cb); |
8d9047f8 HC |
41 | kfree(task->thread.ri_cb); |
42 | task->thread.ri_cb = NULL; | |
43 | preempt_enable(); | |
e4b8b3f3 JG |
44 | |
45 | /* | |
46 | * Make sure the RI bit is deleted from the PSW. If the user did not | |
47 | * switch off RI before the system call the process will get a | |
48 | * specification exception otherwise. | |
49 | */ | |
50 | regs->psw.mask &= ~PSW_MASK_RI; | |
51 | } | |
52 | ||
53 | static void init_runtime_instr_cb(struct runtime_instr_cb *cb) | |
54 | { | |
bb59c2da AF |
55 | cb->rla = 0xfff; |
56 | cb->s = 1; | |
57 | cb->k = 1; | |
58 | cb->ps = 1; | |
59 | cb->pc = 1; | |
9eaba29c | 60 | cb->key = PAGE_DEFAULT_KEY >> 4; |
bb59c2da | 61 | cb->v = 1; |
e4b8b3f3 JG |
62 | } |
63 | ||
65875530 HC |
64 | /* |
65 | * The signum argument is unused. In older kernels it was used to | |
66 | * specify a real-time signal. For backwards compatibility user space | |
67 | * should pass a valid real-time signal number (the signum argument | |
68 | * was checked in older kernels). | |
69 | */ | |
70 | SYSCALL_DEFINE2(s390_runtime_instr, int, command, int, signum) | |
e4b8b3f3 JG |
71 | { |
72 | struct runtime_instr_cb *cb; | |
73 | ||
b38feccd | 74 | if (!test_facility(64)) |
e4b8b3f3 JG |
75 | return -EOPNOTSUPP; |
76 | ||
77 | if (command == S390_RUNTIME_INSTR_STOP) { | |
8d9047f8 | 78 | disable_runtime_instr(); |
e4b8b3f3 JG |
79 | return 0; |
80 | } | |
81 | ||
b38feccd | 82 | if (command != S390_RUNTIME_INSTR_START) |
e4b8b3f3 JG |
83 | return -EINVAL; |
84 | ||
85 | if (!current->thread.ri_cb) { | |
86 | cb = kzalloc(sizeof(*cb), GFP_KERNEL); | |
87 | if (!cb) | |
88 | return -ENOMEM; | |
89 | } else { | |
90 | cb = current->thread.ri_cb; | |
91 | memset(cb, 0, sizeof(*cb)); | |
92 | } | |
93 | ||
94 | init_runtime_instr_cb(cb); | |
e4b8b3f3 JG |
95 | |
96 | /* now load the control block to make it available */ | |
97 | preempt_disable(); | |
98 | current->thread.ri_cb = cb; | |
99 | load_runtime_instr_cb(cb); | |
100 | preempt_enable(); | |
101 | return 0; | |
102 | } |