xref: /linux/tools/include/nolibc/arch-s390.h (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
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