guarded_storage.c (2502B)
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 15void guarded_storage_release(struct task_struct *tsk) 16{ 17 kfree(tsk->thread.gs_cb); 18 kfree(tsk->thread.gs_bc_cb); 19} 20 21static 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 39static 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 51static 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 67static 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 77void 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 94static 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 109SYSCALL_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}