xref: /linux/tools/include/nolibc/arch-s390.h (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
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 
13 /* The struct returned by the stat() syscall, equivalent to stat64(). The
14  * syscall returns 116 bytes and stops in the middle of __unused.
15  */
16 
17 struct sys_stat_struct {
18 	unsigned long	st_dev;
19 	unsigned long	st_ino;
20 	unsigned long	st_nlink;
21 	unsigned int	st_mode;
22 	unsigned int	st_uid;
23 	unsigned int	st_gid;
24 	unsigned int	__pad1;
25 	unsigned long	st_rdev;
26 	unsigned long	st_size;
27 	unsigned long	st_atime;
28 	unsigned long	st_atime_nsec;
29 	unsigned long	st_mtime;
30 	unsigned long	st_mtime_nsec;
31 	unsigned long	st_ctime;
32 	unsigned long	st_ctime_nsec;
33 	unsigned long	st_blksize;
34 	long		st_blocks;
35 	unsigned long	__unused[3];
36 };
37 
38 /* Syscalls for s390:
39  *   - registers are 64-bit
40  *   - syscall number is passed in r1
41  *   - arguments are in r2-r7
42  *   - the system call is performed by calling the svc instruction
43  *   - syscall return value is in r2
44  *   - r1 and r2 are clobbered, others are preserved.
45  *
46  * Link s390 ABI: https://github.com/IBM/s390x-abi
47  *
48  */
49 
50 #define my_syscall0(num)						\
51 ({									\
52 	register long _num __asm__ ("1") = (num);			\
53 	register long _rc __asm__ ("2");				\
54 									\
55 	__asm__  volatile (						\
56 		"svc 0\n"						\
57 		: "=d"(_rc)						\
58 		: "d"(_num)						\
59 		: "memory", "cc"					\
60 		);							\
61 	_rc;								\
62 })
63 
64 #define my_syscall1(num, arg1)						\
65 ({									\
66 	register long _num __asm__ ("1") = (num);			\
67 	register long _arg1 __asm__ ("2") = (long)(arg1);		\
68 									\
69 	__asm__  volatile (						\
70 		"svc 0\n"						\
71 		: "+d"(_arg1)						\
72 		: "d"(_num)						\
73 		: "memory", "cc"					\
74 		);							\
75 	_arg1;								\
76 })
77 
78 #define my_syscall2(num, arg1, arg2)					\
79 ({									\
80 	register long _num __asm__ ("1") = (num);			\
81 	register long _arg1 __asm__ ("2") = (long)(arg1);		\
82 	register long _arg2 __asm__ ("3") = (long)(arg2);		\
83 									\
84 	__asm__  volatile (						\
85 		"svc 0\n"						\
86 		: "+d"(_arg1)						\
87 		: "d"(_arg2), "d"(_num)					\
88 		: "memory", "cc"					\
89 		);							\
90 	_arg1;								\
91 })
92 
93 #define my_syscall3(num, arg1, arg2, arg3)				\
94 ({									\
95 	register long _num __asm__ ("1") = (num);			\
96 	register long _arg1 __asm__ ("2") = (long)(arg1);		\
97 	register long _arg2 __asm__ ("3") = (long)(arg2);		\
98 	register long _arg3 __asm__ ("4") = (long)(arg3);		\
99 									\
100 	__asm__  volatile (						\
101 		"svc 0\n"						\
102 		: "+d"(_arg1)						\
103 		: "d"(_arg2), "d"(_arg3), "d"(_num)			\
104 		: "memory", "cc"					\
105 		);							\
106 	_arg1;								\
107 })
108 
109 #define my_syscall4(num, arg1, arg2, arg3, arg4)			\
110 ({									\
111 	register long _num __asm__ ("1") = (num);			\
112 	register long _arg1 __asm__ ("2") = (long)(arg1);		\
113 	register long _arg2 __asm__ ("3") = (long)(arg2);		\
114 	register long _arg3 __asm__ ("4") = (long)(arg3);		\
115 	register long _arg4 __asm__ ("5") = (long)(arg4);		\
116 									\
117 	__asm__  volatile (						\
118 		"svc 0\n"						\
119 		: "+d"(_arg1)						\
120 		: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_num)		\
121 		: "memory", "cc"					\
122 		);							\
123 	_arg1;								\
124 })
125 
126 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)			\
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 									\
135 	__asm__  volatile (						\
136 		"svc 0\n"						\
137 		: "+d"(_arg1)						\
138 		: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5),	\
139 		  "d"(_num)						\
140 		: "memory", "cc"					\
141 		);							\
142 	_arg1;								\
143 })
144 
145 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)		\
146 ({									\
147 	register long _num __asm__ ("1") = (num);			\
148 	register long _arg1 __asm__ ("2") = (long)(arg1);		\
149 	register long _arg2 __asm__ ("3") = (long)(arg2);		\
150 	register long _arg3 __asm__ ("4") = (long)(arg3);		\
151 	register long _arg4 __asm__ ("5") = (long)(arg4);		\
152 	register long _arg5 __asm__ ("6") = (long)(arg5);		\
153 	register long _arg6 __asm__ ("7") = (long)(arg6);		\
154 									\
155 	__asm__  volatile (						\
156 		"svc 0\n"						\
157 		: "+d"(_arg1)						\
158 		: "d"(_arg2), "d"(_arg3), "d"(_arg4), "d"(_arg5),	\
159 		  "d"(_arg6), "d"(_num)					\
160 		: "memory", "cc"					\
161 		);							\
162 	_arg1;								\
163 })
164 
165 char **environ __attribute__((weak));
166 const unsigned long *_auxv __attribute__((weak));
167 
168 /* startup code */
169 void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
170 {
171 	__asm__ volatile (
172 		"lg	%r2,0(%r15)\n"		/* argument count */
173 		"la	%r3,8(%r15)\n"		/* argument pointers */
174 
175 		"xgr	%r0,%r0\n"		/* r0 will be our NULL value */
176 		/* search for envp */
177 		"lgr	%r4,%r3\n"		/* start at argv */
178 		"0:\n"
179 		"clg	%r0,0(%r4)\n"		/* entry zero? */
180 		"la	%r4,8(%r4)\n"		/* advance pointer */
181 		"jnz	0b\n"			/* no -> test next pointer */
182 						/* yes -> r4 now contains start of envp */
183 		"larl	%r1,environ\n"
184 		"stg	%r4,0(%r1)\n"
185 
186 		/* search for auxv */
187 		"lgr	%r5,%r4\n"		/* start at envp */
188 		"1:\n"
189 		"clg	%r0,0(%r5)\n"		/* entry zero? */
190 		"la	%r5,8(%r5)\n"		/* advance pointer */
191 		"jnz	1b\n"			/* no -> test next pointer */
192 		"larl	%r1,_auxv\n"		/* yes -> store value in _auxv */
193 		"stg	%r5,0(%r1)\n"
194 
195 		"aghi	%r15,-160\n"		/* allocate new stackframe */
196 		"xc	0(8,%r15),0(%r15)\n"	/* clear backchain */
197 		"brasl	%r14,main\n"		/* ret value of main is arg to exit */
198 		"lghi	%r1,1\n"		/* __NR_exit */
199 		"svc	0\n"
200 	);
201 	__builtin_unreachable();
202 }
203 
204 struct s390_mmap_arg_struct {
205 	unsigned long addr;
206 	unsigned long len;
207 	unsigned long prot;
208 	unsigned long flags;
209 	unsigned long fd;
210 	unsigned long offset;
211 };
212 
213 static __attribute__((unused))
214 void *sys_mmap(void *addr, size_t length, int prot, int flags, int fd,
215 	       off_t offset)
216 {
217 	struct s390_mmap_arg_struct args = {
218 		.addr = (unsigned long)addr,
219 		.len = (unsigned long)length,
220 		.prot = prot,
221 		.flags = flags,
222 		.fd = fd,
223 		.offset = (unsigned long)offset
224 	};
225 
226 	return (void *)my_syscall1(__NR_mmap, &args);
227 }
228 #define sys_mmap sys_mmap
229 
230 static __attribute__((unused))
231 pid_t sys_fork(void)
232 {
233 	return my_syscall5(__NR_clone, 0, SIGCHLD, 0, 0, 0);
234 }
235 #define sys_fork sys_fork
236 
237 #endif /* _NOLIBC_ARCH_S390_H */
238