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