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