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 #include "crt.h" 13 14 /* Syscalls for s390: 15 * - registers are 64-bit 16 * - syscall number is passed in r1 17 * - arguments are in r2-r7 18 * - the system call is performed by calling the svc instruction 19 * - syscall return value is in r2 20 * - r1 and r2 are clobbered, others are preserved. 21 * 22 * Link s390 ABI: https://github.com/IBM/s390x-abi 23 * 24 */ 25 26 #define my_syscall0(num) \ 27 ({ \ 28 register long _num __asm__ ("1") = (num); \ 29 register long _rc __asm__ ("2"); \ 30 \ 31 __asm__ volatile ( \ 32 "svc 0\n" \ 33 : "=d"(_rc) \ 34 : "d"(_num) \ 35 : "memory", "cc" \ 36 ); \ 37 _rc; \ 38 }) 39 40 #define my_syscall1(num, arg1) \ 41 ({ \ 42 register long _num __asm__ ("1") = (num); \ 43 register long _arg1 __asm__ ("2") = (long)(arg1); \ 44 \ 45 __asm__ volatile ( \ 46 "svc 0\n" \ 47 : "+d"(_arg1) \ 48 : "d"(_num) \ 49 : "memory", "cc" \ 50 ); \ 51 _arg1; \ 52 }) 53 54 #define my_syscall2(num, arg1, arg2) \ 55 ({ \ 56 register long _num __asm__ ("1") = (num); \ 57 register long _arg1 __asm__ ("2") = (long)(arg1); \ 58 register long _arg2 __asm__ ("3") = (long)(arg2); \ 59 \ 60 __asm__ volatile ( \ 61 "svc 0\n" \ 62 : "+d"(_arg1) \ 63 : "d"(_arg2), "d"(_num) \ 64 : "memory", "cc" \ 65 ); \ 66 _arg1; \ 67 }) 68 69 #define my_syscall3(num, arg1, arg2, arg3) \ 70 ({ \ 71 register long _num __asm__ ("1") = (num); \ 72 register long _arg1 __asm__ ("2") = (long)(arg1); \ 73 register long _arg2 __asm__ ("3") = (long)(arg2); \ 74 register long _arg3 __asm__ ("4") = (long)(arg3); \ 75 \ 76 __asm__ volatile ( \ 77 "svc 0\n" \ 78 : "+d"(_arg1) \ 79 : "d"(_arg2), "d"(_arg3), "d"(_num) \ 80 : "memory", "cc" \ 81 ); \ 82 _arg1; \ 83 }) 84 85 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 86 ({ \ 87 register long _num __asm__ ("1") = (num); \ 88 register long _arg1 __asm__ ("2") = (long)(arg1); \ 89 register long _arg2 __asm__ ("3") = (long)(arg2); \ 90 register long _arg3 __asm__ ("4") = (long)(arg3); \ 91 register long _arg4 __asm__ ("5") = (long)(arg4); \ 92 \ 93 __asm__ volatile ( \ 94 "svc 0\n" \ 95 : "+d"(_arg1) \ 96 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num) \ 97 : "memory", "cc" \ 98 ); \ 99 _arg1; \ 100 }) 101 102 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 103 ({ \ 104 register long _num __asm__ ("1") = (num); \ 105 register long _arg1 __asm__ ("2") = (long)(arg1); \ 106 register long _arg2 __asm__ ("3") = (long)(arg2); \ 107 register long _arg3 __asm__ ("4") = (long)(arg3); \ 108 register long _arg4 __asm__ ("5") = (long)(arg4); \ 109 register long _arg5 __asm__ ("6") = (long)(arg5); \ 110 \ 111 __asm__ volatile ( \ 112 "svc 0\n" \ 113 : "+d"(_arg1) \ 114 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ 115 "d"(_num) \ 116 : "memory", "cc" \ 117 ); \ 118 _arg1; \ 119 }) 120 121 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 122 ({ \ 123 register long _num __asm__ ("1") = (num); \ 124 register long _arg1 __asm__ ("2") = (long)(arg1); \ 125 register long _arg2 __asm__ ("3") = (long)(arg2); \ 126 register long _arg3 __asm__ ("4") = (long)(arg3); \ 127 register long _arg4 __asm__ ("5") = (long)(arg4); \ 128 register long _arg5 __asm__ ("6") = (long)(arg5); \ 129 register long _arg6 __asm__ ("7") = (long)(arg6); \ 130 \ 131 __asm__ volatile ( \ 132 "svc 0\n" \ 133 : "+d"(_arg1) \ 134 : "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5), \ 135 "d"(_arg6), "d"(_num) \ 136 : "memory", "cc" \ 137 ); \ 138 _arg1; \ 139 }) 140 141 /* startup code */ 142 void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 143 { 144 __asm__ volatile ( 145 "lgr %r2, %r15\n" /* save stack pointer to %r2, as arg1 of _start_c */ 146 "aghi %r15, -160\n" /* allocate new stackframe */ 147 "xc 0(8,%r15), 0(%r15)\n" /* clear backchain */ 148 "brasl %r14, _start_c\n" /* transfer to c runtime */ 149 ); 150 __builtin_unreachable(); 151 } 152 153 struct s390_mmap_arg_struct { 154 unsigned long addr; 155 unsigned long len; 156 unsigned long prot; 157 unsigned long flags; 158 unsigned long fd; 159 unsigned long offset; 160 }; 161 162 static __attribute__((unused)) 163 void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, 164 off_t offset) 165 { 166 struct s390_mmap_arg_struct args = { 167 .addr = (unsigned long)addr, 168 .len = (unsigned long)length, 169 .prot = prot, 170 .flags = flags, 171 .fd = fd, 172 .offset = (unsigned long)offset 173 }; 174 175 return (void *)my_syscall1(__NR_mmap, &args); 176 } 177 #define sys_mmap sys_mmap 178 179 static __attribute__((unused)) 180 pid_t sys_fork(void) 181 { 182 return my_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0); 183 } 184 #define sys_fork sys_fork 185 186 #endif /* _NOLIBC_ARCH_S390_H */ 187