syscall.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 2012 ARM Ltd.
  4. */
  5. #ifndef __ASM_SYSCALL_H
  6. #define __ASM_SYSCALL_H
  7. #include <uapi/linux/audit.h>
  8. #include <linux/compat.h>
  9. #include <linux/err.h>
  10. typedef long (*syscall_fn_t)(const struct pt_regs *regs);
  11. extern const syscall_fn_t sys_call_table[];
  12. #ifdef CONFIG_COMPAT
  13. extern const syscall_fn_t compat_sys_call_table[];
  14. #endif
  15. static inline int syscall_get_nr(struct task_struct *task,
  16. struct pt_regs *regs)
  17. {
  18. return regs->syscallno;
  19. }
  20. static inline void syscall_rollback(struct task_struct *task,
  21. struct pt_regs *regs)
  22. {
  23. regs->regs[0] = regs->orig_x0;
  24. }
  25. static inline long syscall_get_return_value(struct task_struct *task,
  26. struct pt_regs *regs)
  27. {
  28. unsigned long val = regs->regs[0];
  29. if (is_compat_thread(task_thread_info(task)))
  30. val = sign_extend64(val, 31);
  31. return val;
  32. }
  33. static inline long syscall_get_error(struct task_struct *task,
  34. struct pt_regs *regs)
  35. {
  36. unsigned long error = syscall_get_return_value(task, regs);
  37. return IS_ERR_VALUE(error) ? error : 0;
  38. }
  39. static inline void syscall_set_return_value(struct task_struct *task,
  40. struct pt_regs *regs,
  41. int error, long val)
  42. {
  43. if (error)
  44. val = error;
  45. if (is_compat_thread(task_thread_info(task)))
  46. val = lower_32_bits(val);
  47. regs->regs[0] = val;
  48. }
  49. static inline void syscall_set_nr(struct task_struct *task,
  50. struct pt_regs *regs,
  51. int nr)
  52. {
  53. regs->syscallno = nr;
  54. if (nr == -1) {
  55. /*
  56. * When the syscall number is set to -1, the syscall will be
  57. * skipped. In this case the syscall return value has to be
  58. * set explicitly, otherwise the first syscall argument is
  59. * returned as the syscall return value.
  60. */
  61. syscall_set_return_value(task, regs, -ENOSYS, 0);
  62. }
  63. }
  64. static inline void syscall_get_arguments(struct task_struct *task,
  65. struct pt_regs *regs,
  66. unsigned long *args)
  67. {
  68. args[0] = regs->orig_x0;
  69. args[1] = regs->regs[1];
  70. args[2] = regs->regs[2];
  71. args[3] = regs->regs[3];
  72. args[4] = regs->regs[4];
  73. args[5] = regs->regs[5];
  74. }
  75. static inline void syscall_set_arguments(struct task_struct *task,
  76. struct pt_regs *regs,
  77. const unsigned long *args)
  78. {
  79. regs->regs[0] = args[0];
  80. regs->regs[1] = args[1];
  81. regs->regs[2] = args[2];
  82. regs->regs[3] = args[3];
  83. regs->regs[4] = args[4];
  84. regs->regs[5] = args[5];
  85. /*
  86. * Also copy the first argument into orig_x0
  87. * so that syscall_get_arguments() would return it
  88. * instead of the previous value.
  89. */
  90. regs->orig_x0 = regs->regs[0];
  91. }
  92. /*
  93. * We don't care about endianness (__AUDIT_ARCH_LE bit) here because
  94. * AArch64 has the same system calls both on little- and big- endian.
  95. */
  96. static inline int syscall_get_arch(struct task_struct *task)
  97. {
  98. if (is_compat_thread(task_thread_info(task)))
  99. return AUDIT_ARCH_ARM;
  100. return AUDIT_ARCH_AARCH64;
  101. }
  102. int syscall_trace_enter(struct pt_regs *regs);
  103. void syscall_trace_exit(struct pt_regs *regs);
  104. #endif /* __ASM_SYSCALL_H */