1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/export.h> 3 #include <linux/slab.h> 4 #include <linux/regset.h> 5 6 static int __regset_get(struct task_struct *target, 7 const struct user_regset *regset, 8 unsigned int size, 9 void **data) 10 { 11 void *p = *data, *to_free = NULL; 12 int res; 13 14 if (!regset->regset_get) 15 return -EOPNOTSUPP; 16 if (size > regset->n * regset->size) 17 size = regset->n * regset->size; 18 if (!p) { 19 to_free = p = kzalloc(size, GFP_KERNEL); 20 if (!p) 21 return -ENOMEM; 22 } 23 res = regset->regset_get(target, regset, 24 (struct membuf){.p = p, .left = size}); 25 if (res < 0) { 26 kfree(to_free); 27 return res; 28 } 29 *data = p; 30 return size - res; 31 } 32 33 int regset_get(struct task_struct *target, 34 const struct user_regset *regset, 35 unsigned int size, 36 void *data) 37 { 38 return __regset_get(target, regset, size, &data); 39 } 40 EXPORT_SYMBOL(regset_get); 41 42 int regset_get_alloc(struct task_struct *target, 43 const struct user_regset *regset, 44 unsigned int size, 45 void **data) 46 { 47 *data = NULL; 48 return __regset_get(target, regset, size, data); 49 } 50 EXPORT_SYMBOL(regset_get_alloc); 51 52 /** 53 * copy_regset_to_user - fetch a thread's user_regset data into user memory 54 * @target: thread to be examined 55 * @view: &struct user_regset_view describing user thread machine state 56 * @setno: index in @view->regsets 57 * @offset: offset into the regset data, in bytes 58 * @size: amount of data to copy, in bytes 59 * @data: user-mode pointer to copy into 60 */ 61 int copy_regset_to_user(struct task_struct *target, 62 const struct user_regset_view *view, 63 unsigned int setno, 64 unsigned int offset, unsigned int size, 65 void __user *data) 66 { 67 const struct user_regset *regset = &view->regsets[setno]; 68 void *buf; 69 int ret; 70 71 ret = regset_get_alloc(target, regset, size, &buf); 72 if (ret > 0) 73 ret = copy_to_user(data, buf, ret) ? -EFAULT : 0; 74 kfree(buf); 75 return ret; 76 } 77