1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 1 2 /* 3 * MIPS specific definitions for NOLIBC 4 * Copyright (C) 2017-2022 Willy Tarreau <w@1w 5 */ 6 7 #ifndef _NOLIBC_ARCH_MIPS_H 8 #define _NOLIBC_ARCH_MIPS_H 9 10 #include "compiler.h" 11 #include "crt.h" 12 13 #if !defined(_ABIO32) 14 #error Unsupported MIPS ABI 15 #endif 16 17 /* Syscalls for MIPS ABI O32 : 18 * - WARNING! there's always a delayed slot! 19 * - WARNING again, the syntax is different, 20 * do not. 21 * - registers are 32-bit 22 * - stack is 8-byte aligned 23 * - syscall number is passed in v0 (starts 24 * - arguments are in a0, a1, a2, a3, then t 25 * leave some room in the stack for the ca 26 * - Many registers are clobbered, in fact o 27 * preserved. See: https://www.linux-mips. 28 * scall32-o32.S in the kernel sources. 29 * - the system call is performed by calling 30 * - syscall return comes in v0, and registe 31 * if an error occurred, in which case err 32 * - the arguments are cast to long and assi 33 * which are then simply passed as registe 34 * don't have to experience issues with re 35 */ 36 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) 42 ({ 43 register long _num __asm__ ("v0") = (n 44 register long _arg4 __asm__ ("a3"); 45 46 __asm__ volatile ( 47 "addiu $sp, $sp, -32\n" 48 "syscall\n" 49 "addiu $sp, $sp, 32\n" 50 : "=r"(_num), "=r"(_arg4) 51 : "r"(_num) 52 : _NOLIBC_SYSCALL_CLOBBERLIST 53 ); 54 _arg4 ? -_num : _num; 55 }) 56 57 #define my_syscall1(num, arg1) 58 ({ 59 register long _num __asm__ ("v0") = (n 60 register long _arg1 __asm__ ("a0") = ( 61 register long _arg4 __asm__ ("a3"); 62 63 __asm__ volatile ( 64 "addiu $sp, $sp, -32\n" 65 "syscall\n" 66 "addiu $sp, $sp, 32\n" 67 : "=r"(_num), "=r"(_arg4) 68 : ""(_num), 69 "r"(_arg1) 70 : _NOLIBC_SYSCALL_CLOBBERLIST 71 ); 72 _arg4 ? -_num : _num; 73 }) 74 75 #define my_syscall2(num, arg1, arg2) 76 ({ 77 register long _num __asm__ ("v0") = (n 78 register long _arg1 __asm__ ("a0") = ( 79 register long _arg2 __asm__ ("a1") = ( 80 register long _arg4 __asm__ ("a3"); 81 82 __asm__ volatile ( 83 "addiu $sp, $sp, -32\n" 84 "syscall\n" 85 "addiu $sp, $sp, 32\n" 86 : "=r"(_num), "=r"(_arg4) 87 : ""(_num), 88 "r"(_arg1), "r"(_arg2) 89 : _NOLIBC_SYSCALL_CLOBBERLIST 90 ); 91 _arg4 ? -_num : _num; 92 }) 93 94 #define my_syscall3(num, arg1, arg2, arg3) 95 ({ 96 register long _num __asm__ ("v0") = ( 97 register long _arg1 __asm__ ("a0") = ( 98 register long _arg2 __asm__ ("a1") = ( 99 register long _arg3 __asm__ ("a2") = ( 100 register long _arg4 __asm__ ("a3"); 101 102 __asm__ volatile ( 103 "addiu $sp, $sp, -32\n" 104 "syscall\n" 105 "addiu $sp, $sp, 32\n" 106 : "=r"(_num), "=r"(_arg4) 107 : ""(_num), 108 "r"(_arg1), "r"(_arg2), "r"( 109 : _NOLIBC_SYSCALL_CLOBBERLIST 110 ); 111 _arg4 ? -_num : _num; 112 }) 113 114 #define my_syscall4(num, arg1, arg2, arg3, arg 115 ({ 116 register long _num __asm__ ("v0") = (n 117 register long _arg1 __asm__ ("a0") = ( 118 register long _arg2 __asm__ ("a1") = ( 119 register long _arg3 __asm__ ("a2") = ( 120 register long _arg4 __asm__ ("a3") = ( 121 122 __asm__ volatile ( 123 "addiu $sp, $sp, -32\n" 124 "syscall\n" 125 "addiu $sp, $sp, 32\n" 126 : "=r" (_num), "=r"(_arg4) 127 : ""(_num), 128 "r"(_arg1), "r"(_arg2), "r"( 129 : _NOLIBC_SYSCALL_CLOBBERLIST 130 ); 131 _arg4 ? -_num : _num; 132 }) 133 134 #define my_syscall5(num, arg1, arg2, arg3, arg 135 ({ 136 register long _num __asm__ ("v0") = (n 137 register long _arg1 __asm__ ("a0") = ( 138 register long _arg2 __asm__ ("a1") = ( 139 register long _arg3 __asm__ ("a2") = ( 140 register long _arg4 __asm__ ("a3") = ( 141 register long _arg5 = (long)(arg5); 142 143 __asm__ volatile ( 144 "addiu $sp, $sp, -32\n" 145 "sw %7, 16($sp)\n" 146 "syscall\n" 147 "addiu $sp, $sp, 32\n" 148 : "=r" (_num), "=r"(_arg4) 149 : ""(_num), 150 "r"(_arg1), "r"(_arg2), "r"( 151 : _NOLIBC_SYSCALL_CLOBBERLIST 152 ); 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 ); 178 _arg4 ? -_num : _num; 179 }) 180 181 /* startup code, note that it's called __start 182 void __attribute__((weak, noreturn, optimize(" 183 { 184 __asm__ volatile ( 185 ".set push\n" 186 ".set noreorder\n" 187 "bal 1f\n" /* pr 188 "nop\n" 189 "1:\n" 190 ".cpload $ra\n" 191 "move $a0, $sp\n" /* sa 192 "addiu $sp, $sp, -4\n" /* sp 193 ".cprestore 0\n" 194 "li $t0, -8\n" 195 "and $sp, $sp, $t0\n" /* $s 196 "addiu $sp, $sp, -16\n" /* th 197 "jal _start_c\n" /* tr 198 " nop\n" /* de 199 ".set pop\n" 200 ); 201 __builtin_unreachable(); 202 } 203 204 #endif /* _NOLIBC_ARCH_MIPS_H */ 205
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.