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