License cleanup: add SPDX GPL-2.0 license identifier to files with no license
[linux-block.git] / arch / s390 / kernel / guarded_storage.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
916cda1a
MS
2/*
3 * Copyright IBM Corp. 2016
4 * Author(s): Martin Schwidefsky <schwidefsky@de.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 <asm/guarded_storage.h>
13#include "entry.h"
14
15void exit_thread_gs(void)
16{
17 kfree(current->thread.gs_cb);
18 kfree(current->thread.gs_bc_cb);
19 current->thread.gs_cb = current->thread.gs_bc_cb = NULL;
20}
21
22static int gs_enable(void)
23{
24 struct gs_cb *gs_cb;
25
26 if (!current->thread.gs_cb) {
27 gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
28 if (!gs_cb)
29 return -ENOMEM;
30 gs_cb->gsd = 25;
31 preempt_disable();
32 __ctl_set_bit(2, 4);
33 load_gs_cb(gs_cb);
34 current->thread.gs_cb = gs_cb;
35 preempt_enable();
36 }
37 return 0;
38}
39
40static int gs_disable(void)
41{
42 if (current->thread.gs_cb) {
43 preempt_disable();
44 kfree(current->thread.gs_cb);
45 current->thread.gs_cb = NULL;
46 __ctl_clear_bit(2, 4);
47 preempt_enable();
48 }
49 return 0;
50}
51
52static int gs_set_bc_cb(struct gs_cb __user *u_gs_cb)
53{
54 struct gs_cb *gs_cb;
55
56 gs_cb = current->thread.gs_bc_cb;
57 if (!gs_cb) {
58 gs_cb = kzalloc(sizeof(*gs_cb), GFP_KERNEL);
59 if (!gs_cb)
60 return -ENOMEM;
61 current->thread.gs_bc_cb = gs_cb;
62 }
63 if (copy_from_user(gs_cb, u_gs_cb, sizeof(*gs_cb)))
64 return -EFAULT;
65 return 0;
66}
67
68static int gs_clear_bc_cb(void)
69{
70 struct gs_cb *gs_cb;
71
72 gs_cb = current->thread.gs_bc_cb;
73 current->thread.gs_bc_cb = NULL;
74 kfree(gs_cb);
75 return 0;
76}
77
78void gs_load_bc_cb(struct pt_regs *regs)
79{
80 struct gs_cb *gs_cb;
81
82 preempt_disable();
83 clear_thread_flag(TIF_GUARDED_STORAGE);
84 gs_cb = current->thread.gs_bc_cb;
85 if (gs_cb) {
86 kfree(current->thread.gs_cb);
87 current->thread.gs_bc_cb = NULL;
88 __ctl_set_bit(2, 4);
89 load_gs_cb(gs_cb);
90 current->thread.gs_cb = gs_cb;
91 }
92 preempt_enable();
93}
94
95static int gs_broadcast(void)
96{
97 struct task_struct *sibling;
98
99 read_lock(&tasklist_lock);
100 for_each_thread(current, sibling) {
101 if (!sibling->thread.gs_bc_cb)
102 continue;
103 if (test_and_set_tsk_thread_flag(sibling, TIF_GUARDED_STORAGE))
104 kick_process(sibling);
105 }
106 read_unlock(&tasklist_lock);
107 return 0;
108}
109
110SYSCALL_DEFINE2(s390_guarded_storage, int, command,
111 struct gs_cb __user *, gs_cb)
112{
113 if (!MACHINE_HAS_GS)
114 return -EOPNOTSUPP;
115 switch (command) {
116 case GS_ENABLE:
117 return gs_enable();
118 case GS_DISABLE:
119 return gs_disable();
120 case GS_SET_BC_CB:
121 return gs_set_bc_cb(gs_cb);
122 case GS_CLEAR_BC_CB:
123 return gs_clear_bc_cb();
124 case GS_BROADCAST:
125 return gs_broadcast();
126 default:
127 return -EINVAL;
128 }
129}