regset.c 1.9 KB

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