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