1 // SPDX-License-Identifier: GPL-2.0 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 15 void 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 22 static 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 40 static 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 52 static 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 68 static 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 78 void 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 95 static 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 110 SYSCALL_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 } 130