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