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