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