forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
1.9 KiB
76 lines
1.9 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
#include <linux/export.h> |
|
#include <linux/slab.h> |
|
#include <linux/regset.h> |
|
|
|
static int __regset_get(struct task_struct *target, |
|
const struct user_regset *regset, |
|
unsigned int size, |
|
void **data) |
|
{ |
|
void *p = *data, *to_free = NULL; |
|
int res; |
|
|
|
if (!regset->regset_get) |
|
return -EOPNOTSUPP; |
|
if (size > regset->n * regset->size) |
|
size = regset->n * regset->size; |
|
if (!p) { |
|
to_free = p = kzalloc(size, GFP_KERNEL); |
|
if (!p) |
|
return -ENOMEM; |
|
} |
|
res = regset->regset_get(target, regset, |
|
(struct membuf){.p = p, .left = size}); |
|
if (res < 0) { |
|
kfree(to_free); |
|
return res; |
|
} |
|
*data = p; |
|
return size - res; |
|
} |
|
|
|
int regset_get(struct task_struct *target, |
|
const struct user_regset *regset, |
|
unsigned int size, |
|
void *data) |
|
{ |
|
return __regset_get(target, regset, size, &data); |
|
} |
|
EXPORT_SYMBOL(regset_get); |
|
|
|
int regset_get_alloc(struct task_struct *target, |
|
const struct user_regset *regset, |
|
unsigned int size, |
|
void **data) |
|
{ |
|
*data = NULL; |
|
return __regset_get(target, regset, size, data); |
|
} |
|
EXPORT_SYMBOL(regset_get_alloc); |
|
|
|
/** |
|
* copy_regset_to_user - fetch a thread's user_regset data into user memory |
|
* @target: thread to be examined |
|
* @view: &struct user_regset_view describing user thread machine state |
|
* @setno: index in @view->regsets |
|
* @offset: offset into the regset data, in bytes |
|
* @size: amount of data to copy, in bytes |
|
* @data: user-mode pointer to copy into |
|
*/ |
|
int copy_regset_to_user(struct task_struct *target, |
|
const struct user_regset_view *view, |
|
unsigned int setno, |
|
unsigned int offset, unsigned int size, |
|
void __user *data) |
|
{ |
|
const struct user_regset *regset = &view->regsets[setno]; |
|
void *buf; |
|
int ret; |
|
|
|
ret = regset_get_alloc(target, regset, size, &buf); |
|
if (ret > 0) |
|
ret = copy_to_user(data, buf, ret) ? -EFAULT : 0; |
|
kfree(buf); |
|
return ret; |
|
}
|
|
|