Greg Kroah-Hartman | b244131 | 2017-11-01 15:07:57 +0100 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 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> |
Ingo Molnar | 68db0cf | 2017-02-08 18:51:37 +0100 | [diff] [blame] | 15 | #include <linux/sched/task_stack.h> |
| 16 | |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 17 | #include <asm/runtime_instr.h> |
| 18 | #include <asm/cpu_mf.h> |
| 19 | #include <asm/irq.h> |
| 20 | |
Heiko Carstens | 6587553 | 2018-01-27 12:40:13 +0100 | [diff] [blame] | 21 | #include "entry.h" |
| 22 | |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 23 | /* empty control block to disable RI by loading it */ |
| 24 | struct runtime_instr_cb runtime_instr_empty_cb; |
| 25 | |
Heiko Carstens | 8d9047f | 2017-09-11 11:24:22 +0200 | [diff] [blame] | 26 | void runtime_instr_release(struct task_struct *tsk) |
| 27 | { |
| 28 | kfree(tsk->thread.ri_cb); |
| 29 | } |
| 30 | |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 31 | static void disable_runtime_instr(void) |
| 32 | { |
Heiko Carstens | 8d9047f | 2017-09-11 11:24:22 +0200 | [diff] [blame] | 33 | struct task_struct *task = current; |
| 34 | struct pt_regs *regs; |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 35 | |
Heiko Carstens | 8d9047f | 2017-09-11 11:24:22 +0200 | [diff] [blame] | 36 | if (!task->thread.ri_cb) |
| 37 | return; |
| 38 | regs = task_pt_regs(task); |
| 39 | preempt_disable(); |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 40 | load_runtime_instr_cb(&runtime_instr_empty_cb); |
Heiko Carstens | 8d9047f | 2017-09-11 11:24:22 +0200 | [diff] [blame] | 41 | kfree(task->thread.ri_cb); |
| 42 | task->thread.ri_cb = NULL; |
| 43 | preempt_enable(); |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 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 | { |
Alice Frosi | bb59c2d | 2017-09-14 12:35:45 +0200 | [diff] [blame] | 55 | cb->rla = 0xfff; |
| 56 | cb->s = 1; |
| 57 | cb->k = 1; |
| 58 | cb->ps = 1; |
| 59 | cb->pc = 1; |
Heiko Carstens | 9eaba29 | 2020-08-12 18:55:41 +0200 | [diff] [blame] | 60 | cb->key = PAGE_DEFAULT_KEY >> 4; |
Alice Frosi | bb59c2d | 2017-09-14 12:35:45 +0200 | [diff] [blame] | 61 | cb->v = 1; |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 62 | } |
| 63 | |
Heiko Carstens | 6587553 | 2018-01-27 12:40:13 +0100 | [diff] [blame] | 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) |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 71 | { |
| 72 | struct runtime_instr_cb *cb; |
| 73 | |
Martin Schwidefsky | b38fecc | 2015-11-02 14:03:46 +0100 | [diff] [blame] | 74 | if (!test_facility(64)) |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 75 | return -EOPNOTSUPP; |
| 76 | |
| 77 | if (command == S390_RUNTIME_INSTR_STOP) { |
Heiko Carstens | 8d9047f | 2017-09-11 11:24:22 +0200 | [diff] [blame] | 78 | disable_runtime_instr(); |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 79 | return 0; |
| 80 | } |
| 81 | |
Martin Schwidefsky | b38fecc | 2015-11-02 14:03:46 +0100 | [diff] [blame] | 82 | if (command != S390_RUNTIME_INSTR_START) |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 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); |
Jan Glauber | e4b8b3f | 2012-07-31 10:52:05 +0200 | [diff] [blame] | 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 | } |