safe-syscall.inc.S 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. /*
  2. * safe-syscall.inc.S : host-specific assembly fragment
  3. * to handle signals occurring at the same time as system calls.
  4. * This is intended to be included by common-user/safe-syscall.S
  5. *
  6. * Written by Richard Henderson <rth@twiddle.net>
  7. * Copyright (C) 2018 Linaro, Inc.
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. */
  12. .global safe_syscall_base
  13. .global safe_syscall_start
  14. .global safe_syscall_end
  15. .type safe_syscall_base, @function
  16. .type safe_syscall_start, @function
  17. .type safe_syscall_end, @function
  18. /*
  19. * This is the entry point for making a system call. The calling
  20. * convention here is that of a C varargs function with the
  21. * first argument an 'int *' to the signal_pending flag, the
  22. * second one the system call number (as a 'long'), and all further
  23. * arguments being syscall arguments (also 'long').
  24. */
  25. safe_syscall_base:
  26. .cfi_startproc
  27. /*
  28. * The syscall calling convention is nearly the same as C:
  29. * we enter with a0 == &signal_pending
  30. * a1 == syscall number
  31. * a2 ... a7 == syscall arguments
  32. * and return the result in a0
  33. * and the syscall instruction needs
  34. * a7 == syscall number
  35. * a0 ... a5 == syscall arguments
  36. * and returns the result in a0
  37. * Shuffle everything around appropriately.
  38. */
  39. mv t0, a0 /* signal_pending pointer */
  40. mv t1, a1 /* syscall number */
  41. mv a0, a2 /* syscall arguments */
  42. mv a1, a3
  43. mv a2, a4
  44. mv a3, a5
  45. mv a4, a6
  46. mv a5, a7
  47. mv a7, t1
  48. /*
  49. * This next sequence of code works in conjunction with the
  50. * rewind_if_safe_syscall_function(). If a signal is taken
  51. * and the interrupted PC is anywhere between 'safe_syscall_start'
  52. * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
  53. * The code sequence must therefore be able to cope with this, and
  54. * the syscall instruction must be the final one in the sequence.
  55. */
  56. safe_syscall_start:
  57. /* If signal_pending is non-zero, don't do the call */
  58. lw t1, 0(t0)
  59. bnez t1, 2f
  60. scall
  61. safe_syscall_end:
  62. /* code path for having successfully executed the syscall */
  63. li t2, -4096
  64. bgtu a0, t2, 0f
  65. ret
  66. /* code path setting errno */
  67. 0: neg a0, a0
  68. tail safe_syscall_set_errno_tail
  69. /* code path when we didn't execute the syscall */
  70. 2: li a0, QEMU_ERESTARTSYS
  71. tail safe_syscall_set_errno_tail
  72. .cfi_endproc
  73. .size safe_syscall_base, .-safe_syscall_base