| /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ | 
 | /* | 
 |  * s390 specific definitions for NOLIBC | 
 |  */ | 
 |  | 
 | #ifndef _NOLIBC_ARCH_S390_H | 
 | #define _NOLIBC_ARCH_S390_H | 
 | #include <linux/signal.h> | 
 | #include <linux/unistd.h> | 
 |  | 
 | #include "compiler.h" | 
 | #include "crt.h" | 
 | #include "std.h" | 
 |  | 
 | /* Syscalls for s390: | 
 |  *   - registers are 64-bit | 
 |  *   - syscall number is passed in r1 | 
 |  *   - arguments are in r2-r7 | 
 |  *   - the system call is performed by calling the svc instruction | 
 |  *   - syscall return value is in r2 | 
 |  *   - r1 and r2 are clobbered, others are preserved. | 
 |  * | 
 |  * Link s390 ABI: https://github.com/IBM/s390x-abi | 
 |  * | 
 |  */ | 
 |  | 
 | #define my_syscall0(num)						\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _rc __asm__ ("2");				\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "=d"(_rc)						\ | 
 | 		: "d"(_num)						\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_rc;								\ | 
 | }) | 
 |  | 
 | #define my_syscall1(num, arg1)						\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _arg1 __asm__ ("2") = (long)(arg1);		\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "+d"(_arg1)						\ | 
 | 		: "d"(_num)						\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_arg1;								\ | 
 | }) | 
 |  | 
 | #define my_syscall2(num, arg1, arg2)					\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _arg1 __asm__ ("2") = (long)(arg1);		\ | 
 | 	register long _arg2 __asm__ ("3") = (long)(arg2);		\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "+d"(_arg1)						\ | 
 | 		: "d"(_arg2), "d"(_num)					\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_arg1;								\ | 
 | }) | 
 |  | 
 | #define my_syscall3(num, arg1, arg2, arg3)				\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _arg1 __asm__ ("2") = (long)(arg1);		\ | 
 | 	register long _arg2 __asm__ ("3") = (long)(arg2);		\ | 
 | 	register long _arg3 __asm__ ("4") = (long)(arg3);		\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "+d"(_arg1)						\ | 
 | 		: "d"(_arg2), "d"(_arg3), "d"(_num)			\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_arg1;								\ | 
 | }) | 
 |  | 
 | #define my_syscall4(num, arg1, arg2, arg3, arg4)			\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _arg1 __asm__ ("2") = (long)(arg1);		\ | 
 | 	register long _arg2 __asm__ ("3") = (long)(arg2);		\ | 
 | 	register long _arg3 __asm__ ("4") = (long)(arg3);		\ | 
 | 	register long _arg4 __asm__ ("5") = (long)(arg4);		\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "+d"(_arg1)						\ | 
 | 		: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num)		\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_arg1;								\ | 
 | }) | 
 |  | 
 | #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)			\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _arg1 __asm__ ("2") = (long)(arg1);		\ | 
 | 	register long _arg2 __asm__ ("3") = (long)(arg2);		\ | 
 | 	register long _arg3 __asm__ ("4") = (long)(arg3);		\ | 
 | 	register long _arg4 __asm__ ("5") = (long)(arg4);		\ | 
 | 	register long _arg5 __asm__ ("6") = (long)(arg5);		\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "+d"(_arg1)						\ | 
 | 		: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5),	\ | 
 | 		  "d"(_num)						\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_arg1;								\ | 
 | }) | 
 |  | 
 | #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)		\ | 
 | ({									\ | 
 | 	register long _num __asm__ ("1") = (num);			\ | 
 | 	register long _arg1 __asm__ ("2") = (long)(arg1);		\ | 
 | 	register long _arg2 __asm__ ("3") = (long)(arg2);		\ | 
 | 	register long _arg3 __asm__ ("4") = (long)(arg3);		\ | 
 | 	register long _arg4 __asm__ ("5") = (long)(arg4);		\ | 
 | 	register long _arg5 __asm__ ("6") = (long)(arg5);		\ | 
 | 	register long _arg6 __asm__ ("7") = (long)(arg6);		\ | 
 | 									\ | 
 | 	__asm__ volatile (						\ | 
 | 		"svc 0\n"						\ | 
 | 		: "+d"(_arg1)						\ | 
 | 		: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5),	\ | 
 | 		  "d"(_arg6), "d"(_num)					\ | 
 | 		: "memory", "cc"					\ | 
 | 		);							\ | 
 | 	_arg1;								\ | 
 | }) | 
 |  | 
 | /* startup code */ | 
 | void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) | 
 | { | 
 | 	__asm__ volatile ( | 
 | #ifdef __s390x__ | 
 | 		"lgr	%r2, %r15\n"          /* save stack pointer to %r2, as arg1 of _start_c */ | 
 | 		"aghi	%r15, -160\n"         /* allocate new stackframe                        */ | 
 | #else | 
 | 		"lr	%r2, %r15\n" | 
 | 		"ahi	%r15, -96\n" | 
 | #endif | 
 | 		"xc	0(8,%r15), 0(%r15)\n" /* clear backchain                                */ | 
 | 		"brasl	%r14, _start_c\n"     /* transfer to c runtime                          */ | 
 | 	); | 
 | 	__nolibc_entrypoint_epilogue(); | 
 | } | 
 |  | 
 | struct s390_mmap_arg_struct { | 
 | 	unsigned long addr; | 
 | 	unsigned long len; | 
 | 	unsigned long prot; | 
 | 	unsigned long flags; | 
 | 	unsigned long fd; | 
 | 	unsigned long offset; | 
 | }; | 
 |  | 
 | static __attribute__((unused)) | 
 | void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd, | 
 | 	       off_t offset) | 
 | { | 
 | 	struct s390_mmap_arg_struct args = { | 
 | 		.addr = (unsigned long)addr, | 
 | 		.len = (unsigned long)length, | 
 | 		.prot = prot, | 
 | 		.flags = flags, | 
 | 		.fd = fd, | 
 | 		.offset = (unsigned long)offset | 
 | 	}; | 
 |  | 
 | 	return (void *)my_syscall1(__NR_mmap, &args); | 
 | } | 
 | #define sys_mmap sys_mmap | 
 |  | 
 | static __attribute__((unused)) | 
 | pid_t sys_fork(void) | 
 | { | 
 | 	return my_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0); | 
 | } | 
 | #define sys_fork sys_fork | 
 |  | 
 | #endif /* _NOLIBC_ARCH_S390_H */ |