1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * s390 specific definitions for NOLIBC 4 */ 5 6 #ifndef _NOLIBC_ARCH_S390_H 7 #define _NOLIBC_ARCH_S390_H 8 #include <asm/signal.h> 9 #include <asm/unistd.h> 10 11 #include "compiler.h" 12 13 /* The struct returned by the stat() syscall, equivalent to stat64(). The 14 * syscall returns 116 bytes and stops in the middle of __unused. 15 */ 16 17 struct sys_stat_struct { 18 unsigned long st_dev; 19 unsigned long st_ino; 20 unsigned long st_nlink; 21 unsigned int st_mode; 22 unsigned int st_uid; 23 unsigned int st_gid; 24 unsigned int __pad1; 25 unsigned long st_rdev; 26 unsigned long st_size; 27 unsigned long st_atime; 28 unsigned long st_atime_nsec; 29 unsigned long st_mtime; 30 unsigned long st_mtime_nsec; 31 unsigned long st_ctime; 32 unsigned long st_ctime_nsec; 33 unsigned long st_blksize; 34 long st_blocks; 35 unsigned long __unused[3]; 36 }; 37 38 /* Syscalls for s390: 39 * - registers are 64-bit 40 * - syscall number is passed in r1 41 * - arguments are in r2-r7 42 * - the system call is performed by calling the svc instruction 43 * - syscall return value is in r2 44 * - r1 and r2 are clobbered, others are preserved. 45 * 46 * Link s390 ABI: https://github.com/IBM/s390x-abi 47 * 48 */ 49 50 #define my_syscall0(num) \ 51 ({ \ 52 register long _num __asm__ ("1") = (num); \ 53 register long _rc __asm__ ("2"); \ 54 \ 55 __asm__ volatile ( \ 56 "svc 0\n" \ 57 : "=d"(_rc) \ 58 : "d"(_num) \ 59 : "memory", "cc" \ 60 ); \ 61 _rc; \ 62 }) 63 64 #define my_syscall1(num, arg1) \ 65 ({ \ 66 register long _num __asm__ ("1") = (num); \ 67 register long _arg1 __asm__ ("2") = (long)(arg1); \ 68 \ 69 __asm__ volatile ( \ 70 "svc 0\n" \ 71 : "+d"(_arg1) \ 72 : "d"(_num) \ 73 : "memory", "cc" \ 74 ); \ 75 _arg1; \ 76 }) 77 78 #define my_syscall2(num, arg1, arg2) \ 79 ({ \ 80 register long _num __asm__ ("1") = (num); \ 81 register long _arg1 __asm__ ("2") = (long)(arg1); \ 82 register long _arg2 __asm__ ("3") = (long)(arg2); \ 83 \ 84 __asm__ volatile ( \ 85 "svc 0\n" \ 86 : "+d"(_arg1) \ 87 : "d"(_arg2), "d"(_num) \ 88 : "memory", "cc" \ 89 ); \ 90 _arg1; \ 91 }) 92 93 #define my_syscall3(num, arg1, arg2, arg3) \ 94 ({ \ 95 register long _num __asm__ ("1") = (num); \ 96 register long _arg1 __asm__ ("2") = (long)(arg1); \ 97 register long _arg2 __asm__ ("3") = (long)(arg2); \ 98 register long _arg3 __asm__ ("4") = (long)(arg3); \ 99 \ 100 __asm__ volatile ( \ 101 "svc 0\n" \ 102 : "+d"(_arg1) \ 103 : "d"(_arg2), "d"(_arg3), "d"(_num) \ 104 : "memory", "cc" \ 105 ); \ 106 _arg1; \ 107 }) 108 109 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 110 ({ \ 111 register long _num __asm__ ("1") = (num); \ 112 register long _arg1 __asm__ ("2") = (long)(arg1); \ 113 register long _arg2 __asm__ ("3") = (long)(arg2); \ 114 register long _arg3 __asm__ ("4") = (long)(arg3); \ 115 register long _arg4 __asm__ ("5") = (long)(arg4); \ 116 \ 117 __asm__ volatile ( \ 118 "svc 0\n" \ 119 : "+d"(_arg1) \ 120 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ 121 : "memory", "cc" \ 122 ); \ 123 _arg1; \ 124 }) 125 126 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 127 ({ \ 128 register long _num __asm__ ("1") = (num); \ 129 register long _arg1 __asm__ ("2") = (long)(arg1); \ 130 register long _arg2 __asm__ ("3") = (long)(arg2); \ 131 register long _arg3 __asm__ ("4") = (long)(arg3); \ 132 register long _arg4 __asm__ ("5") = (long)(arg4); \ 133 register long _arg5 __asm__ ("6") = (long)(arg5); \ 134 \ 135 __asm__ volatile ( \ 136 "svc 0\n" \ 137 : "+d"(_arg1) \ 138 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ 139 "d"(_num) \ 140 : "memory", "cc" \ 141 ); \ 142 _arg1; \ 143 }) 144 145 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 146 ({ \ 147 register long _num __asm__ ("1") = (num); \ 148 register long _arg1 __asm__ ("2") = (long)(arg1); \ 149 register long _arg2 __asm__ ("3") = (long)(arg2); \ 150 register long _arg3 __asm__ ("4") = (long)(arg3); \ 151 register long _arg4 __asm__ ("5") = (long)(arg4); \ 152 register long _arg5 __asm__ ("6") = (long)(arg5); \ 153 register long _arg6 __asm__ ("7") = (long)(arg6); \ 154 \ 155 __asm__ volatile ( \ 156 "svc 0\n" \ 157 : "+d"(_arg1) \ 158 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ 159 "d"(_arg6), "d"(_num) \ 160 : "memory", "cc" \ 161 ); \ 162 _arg1; \ 163 }) 164 165 char **environ __attribute__((weak)); 166 const unsigned long *_auxv __attribute__((weak)); 167 168 /* startup code */ 169 void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void) 170 { 171 __asm__ volatile ( 172 "lg %r2,0(%r15)\n" /* argument count */ 173 "la %r3,8(%r15)\n" /* argument pointers */ 174 175 "xgr %r0,%r0\n" /* r0 will be our NULL value */ 176 /* search for envp */ 177 "lgr %r4,%r3\n" /* start at argv */ 178 "0:\n" 179 "clg %r0,0(%r4)\n" /* entry zero? */ 180 "la %r4,8(%r4)\n" /* advance pointer */ 181 "jnz 0b\n" /* no -> test next pointer */ 182 /* yes -> r4 now contains start of envp */ 183 "larl %r1,environ\n" 184 "stg %r4,0(%r1)\n" 185 186 /* search for auxv */ 187 "lgr %r5,%r4\n" /* start at envp */ 188 "1:\n" 189 "clg %r0,0(%r5)\n" /* entry zero? */ 190 "la %r5,8(%r5)\n" /* advance pointer */ 191 "jnz 1b\n" /* no -> test next pointer */ 192 "larl %r1,_auxv\n" /* yes -> store value in _auxv */ 193 "stg %r5,0(%r1)\n" 194 195 "aghi %r15,-160\n" /* allocate new stackframe */ 196 "xc 0(8,%r15),0(%r15)\n" /* clear backchain */ 197 "brasl %r14,main\n" /* ret value of main is arg to exit */ 198 "lghi %r1,1\n" /* __NR_exit */ 199 "svc 0\n" 200 ); 201 __builtin_unreachable(); 202 } 203 204 struct s390_mmap_arg_struct { 205 unsigned long addr; 206 unsigned long len; 207 unsigned long prot; 208 unsigned long flags; 209 unsigned long fd; 210 unsigned long offset; 211 }; 212 213 static __attribute__((unused)) 214 void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 215 off_t offset) 216 { 217 struct s390_mmap_arg_struct args = { 218 .addr = (unsigned long)addr, 219 .len = (unsigned long)length, 220 .prot = prot, 221 .flags = flags, 222 .fd = fd, 223 .offset = (unsigned long)offset 224 }; 225 226 return (void *)my_syscall1(__NR_mmap, &args); 227 } 228 #define sys_mmap sys_mmap 229 230 static __attribute__((unused)) 231 pid_t sys_fork(void) 232 { 233 return my_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0); 234 } 235 #define sys_fork sys_fork 236 237 #endif /* _NOLIBC_ARCH_S390_H */ 238