1 | // SPDX-License-Identifier: GPL-2.0 |
---|---|
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> |
15 | #include <linux/sched/task_stack.h> |
16 | |
17 | #include <asm/runtime_instr.h> |
18 | #include <asm/cpu_mf.h> |
19 | #include <asm/irq.h> |
20 | |
21 | #include "entry.h" |
22 | |
23 | /* empty control block to disable RI by loading it */ |
24 | struct runtime_instr_cb runtime_instr_empty_cb; |
25 | |
26 | void runtime_instr_release(struct task_struct *tsk) |
27 | { |
28 | kfree(objp: tsk->thread.ri_cb); |
29 | } |
30 | |
31 | static void disable_runtime_instr(void) |
32 | { |
33 | struct task_struct *task = current; |
34 | struct pt_regs *regs; |
35 | |
36 | if (!task->thread.ri_cb) |
37 | return; |
38 | regs = task_pt_regs(task); |
39 | preempt_disable(); |
40 | load_runtime_instr_cb(&runtime_instr_empty_cb); |
41 | kfree(objp: task->thread.ri_cb); |
42 | task->thread.ri_cb = NULL; |
43 | preempt_enable(); |
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 | { |
55 | cb->rla = 0xfff; |
56 | cb->s = 1; |
57 | cb->k = 1; |
58 | cb->ps = 1; |
59 | cb->pc = 1; |
60 | cb->key = PAGE_DEFAULT_KEY >> 4; |
61 | cb->v = 1; |
62 | } |
63 | |
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) |
71 | { |
72 | struct runtime_instr_cb *cb; |
73 | |
74 | if (!test_facility(64)) |
75 | return -EOPNOTSUPP; |
76 | |
77 | if (command == S390_RUNTIME_INSTR_STOP) { |
78 | disable_runtime_instr(); |
79 | return 0; |
80 | } |
81 | |
82 | if (command != S390_RUNTIME_INSTR_START) |
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); |
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 | } |
103 |