Merge branch 'work.regset' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull ptrace regset updates from Al Viro: "Internal regset API changes: - regularize copy_regset_{to,from}_user() callers - switch to saner calling conventions for ->get() - kill user_regset_copyout() The ->put() side of things will have to wait for the next cycle, unfortunately. The balance is about -1KLoC and replacements for ->get() instances are a lot saner" * 'work.regset' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (41 commits) regset: kill user_regset_copyout{,_zero}() regset(): kill ->get_size() regset: kill ->get() csky: switch to ->regset_get() xtensa: switch to ->regset_get() parisc: switch to ->regset_get() nds32: switch to ->regset_get() nios2: switch to ->regset_get() hexagon: switch to ->regset_get() h8300: switch to ->regset_get() openrisc: switch to ->regset_get() riscv: switch to ->regset_get() c6x: switch to ->regset_get() ia64: switch to ->regset_get() arc: switch to ->regset_get() arm: switch to ->regset_get() sh: convert to ->regset_get() arm64: switch to ->regset_get() mips: switch to ->regset_get() sparc: switch to ->regset_get() ...
This commit is contained in:
@@ -10,7 +10,7 @@ obj-y = fork.o exec_domain.o panic.o \
|
||||
extable.o params.o \
|
||||
kthread.o sys_ni.o nsproxy.o \
|
||||
notifier.o ksysfs.o cred.o reboot.o \
|
||||
async.o range.o smpboot.o ucount.o
|
||||
async.o range.o smpboot.o ucount.o regset.o
|
||||
|
||||
obj-$(CONFIG_BPFILTER) += usermode_driver.o
|
||||
obj-$(CONFIG_MODULES) += kmod.o
|
||||
|
76
kernel/regset.c
Normal file
76
kernel/regset.c
Normal file
@@ -0,0 +1,76 @@
|
||||
// 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;
|
||||
}
|
Reference in New Issue
Block a user