arch-mips.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
  2. /*
  3. * MIPS specific definitions for NOLIBC
  4. * Copyright (C) 2017-2022 Willy Tarreau <[email protected]>
  5. */
  6. #ifndef _NOLIBC_ARCH_MIPS_H
  7. #define _NOLIBC_ARCH_MIPS_H
  8. /* O_* macros for fcntl/open are architecture-specific */
  9. #define O_RDONLY 0
  10. #define O_WRONLY 1
  11. #define O_RDWR 2
  12. #define O_APPEND 0x0008
  13. #define O_NONBLOCK 0x0080
  14. #define O_CREAT 0x0100
  15. #define O_TRUNC 0x0200
  16. #define O_EXCL 0x0400
  17. #define O_NOCTTY 0x0800
  18. #define O_DIRECTORY 0x10000
  19. /* The struct returned by the stat() syscall. 88 bytes are returned by the
  20. * syscall.
  21. */
  22. struct sys_stat_struct {
  23. unsigned int st_dev;
  24. long st_pad1[3];
  25. unsigned long st_ino;
  26. unsigned int st_mode;
  27. unsigned int st_nlink;
  28. unsigned int st_uid;
  29. unsigned int st_gid;
  30. unsigned int st_rdev;
  31. long st_pad2[2];
  32. long st_size;
  33. long st_pad3;
  34. long st_atime;
  35. long st_atime_nsec;
  36. long st_mtime;
  37. long st_mtime_nsec;
  38. long st_ctime;
  39. long st_ctime_nsec;
  40. long st_blksize;
  41. long st_blocks;
  42. long st_pad4[14];
  43. };
  44. /* Syscalls for MIPS ABI O32 :
  45. * - WARNING! there's always a delayed slot!
  46. * - WARNING again, the syntax is different, registers take a '$' and numbers
  47. * do not.
  48. * - registers are 32-bit
  49. * - stack is 8-byte aligned
  50. * - syscall number is passed in v0 (starts at 0xfa0).
  51. * - arguments are in a0, a1, a2, a3, then the stack. The caller needs to
  52. * leave some room in the stack for the callee to save a0..a3 if needed.
  53. * - Many registers are clobbered, in fact only a0..a2 and s0..s8 are
  54. * preserved. See: https://www.linux-mips.org/wiki/Syscall as well as
  55. * scall32-o32.S in the kernel sources.
  56. * - the system call is performed by calling "syscall"
  57. * - syscall return comes in v0, and register a3 needs to be checked to know
  58. * if an error occurred, in which case errno is in v0.
  59. * - the arguments are cast to long and assigned into the target registers
  60. * which are then simply passed as registers to the asm code, so that we
  61. * don't have to experience issues with register constraints.
  62. */
  63. #define my_syscall0(num) \
  64. ({ \
  65. register long _num __asm__ ("v0") = (num); \
  66. register long _arg4 __asm__ ("a3"); \
  67. \
  68. __asm__ volatile ( \
  69. "addiu $sp, $sp, -32\n" \
  70. "syscall\n" \
  71. "addiu $sp, $sp, 32\n" \
  72. : "=r"(_num), "=r"(_arg4) \
  73. : "r"(_num) \
  74. : "memory", "cc", "at", "v1", "hi", "lo", \
  75. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
  76. ); \
  77. _arg4 ? -_num : _num; \
  78. })
  79. #define my_syscall1(num, arg1) \
  80. ({ \
  81. register long _num __asm__ ("v0") = (num); \
  82. register long _arg1 __asm__ ("a0") = (long)(arg1); \
  83. register long _arg4 __asm__ ("a3"); \
  84. \
  85. __asm__ volatile ( \
  86. "addiu $sp, $sp, -32\n" \
  87. "syscall\n" \
  88. "addiu $sp, $sp, 32\n" \
  89. : "=r"(_num), "=r"(_arg4) \
  90. : "0"(_num), \
  91. "r"(_arg1) \
  92. : "memory", "cc", "at", "v1", "hi", "lo", \
  93. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
  94. ); \
  95. _arg4 ? -_num : _num; \
  96. })
  97. #define my_syscall2(num, arg1, arg2) \
  98. ({ \
  99. register long _num __asm__ ("v0") = (num); \
  100. register long _arg1 __asm__ ("a0") = (long)(arg1); \
  101. register long _arg2 __asm__ ("a1") = (long)(arg2); \
  102. register long _arg4 __asm__ ("a3"); \
  103. \
  104. __asm__ volatile ( \
  105. "addiu $sp, $sp, -32\n" \
  106. "syscall\n" \
  107. "addiu $sp, $sp, 32\n" \
  108. : "=r"(_num), "=r"(_arg4) \
  109. : "0"(_num), \
  110. "r"(_arg1), "r"(_arg2) \
  111. : "memory", "cc", "at", "v1", "hi", "lo", \
  112. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
  113. ); \
  114. _arg4 ? -_num : _num; \
  115. })
  116. #define my_syscall3(num, arg1, arg2, arg3) \
  117. ({ \
  118. register long _num __asm__ ("v0") = (num); \
  119. register long _arg1 __asm__ ("a0") = (long)(arg1); \
  120. register long _arg2 __asm__ ("a1") = (long)(arg2); \
  121. register long _arg3 __asm__ ("a2") = (long)(arg3); \
  122. register long _arg4 __asm__ ("a3"); \
  123. \
  124. __asm__ volatile ( \
  125. "addiu $sp, $sp, -32\n" \
  126. "syscall\n" \
  127. "addiu $sp, $sp, 32\n" \
  128. : "=r"(_num), "=r"(_arg4) \
  129. : "0"(_num), \
  130. "r"(_arg1), "r"(_arg2), "r"(_arg3) \
  131. : "memory", "cc", "at", "v1", "hi", "lo", \
  132. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
  133. ); \
  134. _arg4 ? -_num : _num; \
  135. })
  136. #define my_syscall4(num, arg1, arg2, arg3, arg4) \
  137. ({ \
  138. register long _num __asm__ ("v0") = (num); \
  139. register long _arg1 __asm__ ("a0") = (long)(arg1); \
  140. register long _arg2 __asm__ ("a1") = (long)(arg2); \
  141. register long _arg3 __asm__ ("a2") = (long)(arg3); \
  142. register long _arg4 __asm__ ("a3") = (long)(arg4); \
  143. \
  144. __asm__ volatile ( \
  145. "addiu $sp, $sp, -32\n" \
  146. "syscall\n" \
  147. "addiu $sp, $sp, 32\n" \
  148. : "=r" (_num), "=r"(_arg4) \
  149. : "0"(_num), \
  150. "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \
  151. : "memory", "cc", "at", "v1", "hi", "lo", \
  152. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
  153. ); \
  154. _arg4 ? -_num : _num; \
  155. })
  156. #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
  157. ({ \
  158. register long _num __asm__ ("v0") = (num); \
  159. register long _arg1 __asm__ ("a0") = (long)(arg1); \
  160. register long _arg2 __asm__ ("a1") = (long)(arg2); \
  161. register long _arg3 __asm__ ("a2") = (long)(arg3); \
  162. register long _arg4 __asm__ ("a3") = (long)(arg4); \
  163. register long _arg5 = (long)(arg5); \
  164. \
  165. __asm__ volatile ( \
  166. "addiu $sp, $sp, -32\n" \
  167. "sw %7, 16($sp)\n" \
  168. "syscall\n " \
  169. "addiu $sp, $sp, 32\n" \
  170. : "=r" (_num), "=r"(_arg4) \
  171. : "0"(_num), \
  172. "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5) \
  173. : "memory", "cc", "at", "v1", "hi", "lo", \
  174. "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9" \
  175. ); \
  176. _arg4 ? -_num : _num; \
  177. })
  178. /* startup code, note that it's called __start on MIPS */
  179. __asm__ (".section .text\n"
  180. ".weak __start\n"
  181. ".set nomips16\n"
  182. ".set push\n"
  183. ".set noreorder\n"
  184. ".option pic0\n"
  185. ".ent __start\n"
  186. "__start:\n"
  187. "lw $a0,($sp)\n" // argc was in the stack
  188. "addiu $a1, $sp, 4\n" // argv = sp + 4
  189. "sll $a2, $a0, 2\n" // a2 = argc * 4
  190. "add $a2, $a2, $a1\n" // envp = argv + 4*argc ...
  191. "addiu $a2, $a2, 4\n" // ... + 4
  192. "li $t0, -8\n"
  193. "and $sp, $sp, $t0\n" // sp must be 8-byte aligned
  194. "addiu $sp,$sp,-16\n" // the callee expects to save a0..a3 there!
  195. "jal main\n" // main() returns the status code, we'll exit with it.
  196. "nop\n" // delayed slot
  197. "move $a0, $v0\n" // retrieve 32-bit exit code from v0
  198. "li $v0, 4001\n" // NR_exit == 4001
  199. "syscall\n"
  200. ".end __start\n"
  201. ".set pop\n"
  202. "");
  203. #endif // _NOLIBC_ARCH_MIPS_H