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 */ 142void __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 153struct 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 162static __attribute__((unused)) 163void *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 179static __attribute__((unused)) 180pid_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