xref: /linux/tools/include/nolibc/arch-parisc.h (revision bb29b957eaaa15be33243550d9ee576c2d601669)
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * parisc/hppa (32-bit) specific definitions for NOLIBC
4  * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
5  */
6 
7 #ifndef _NOLIBC_ARCH_PARISC_H
8 #define _NOLIBC_ARCH_PARISC_H
9 
10 #include <linux/unistd.h>
11 
12 #include "compiler.h"
13 #include "crt.h"
14 
15 /* Syscalls for parisc :
16  *   - syscall number is passed in r20
17  *   - arguments are in r26 to r21
18  *   - the system call is performed by calling "ble 0x100(%sr2, %r0)",
19  *     the instruction after that is in the delay slot and executed before
20  *     the jump to 0x100 actually happens, use it to load the syscall number
21  *   - syscall return comes in r28
22  *   - the arguments are cast to long and assigned into the target
23  *     registers which are then simply passed as registers to the asm code,
24  *     so that we don't have to experience issues with register constraints.
25  */
26 
27 #define _NOLIBC_SYSCALL_CLOBBERLIST \
28 	"memory", "%r1", "%r2", "%r4", "%r20", "%r29", "%r31"
29 
30 #define __nolibc_syscall0(num)                                                \
31 ({                                                                            \
32 	register long _ret __asm__ ("r28");                                   \
33 									      \
34 	__asm__ volatile (                                                    \
35 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
36 		"copy %1, %%r20\n\t"                                          \
37 		: "=r"(_ret)                                                  \
38 		: "r"(num)                                                    \
39 		: _NOLIBC_SYSCALL_CLOBBERLIST,                                \
40 		  "%r21", "%r22", "%r23", "%r24", "%r25", "%r26"              \
41 	);                                                                    \
42 	_ret;                                                                 \
43 })
44 
45 #define __nolibc_syscall1(num, arg1)                                          \
46 ({                                                                            \
47 	register long _ret __asm__ ("r28");                                   \
48 	register long _arg1 __asm__ ("r26") = (long)(arg1);		      \
49 									      \
50 	__asm__ volatile (                                                    \
51 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
52 		"copy %2, %%r20\n\t"                                          \
53 		: "=r"(_ret),                                                 \
54 		  "+r"(_arg1)                                                 \
55 		: "r"(num)                                                    \
56 		: _NOLIBC_SYSCALL_CLOBBERLIST,                                \
57 		  "%r21", "%r22", "%r23", "%r24", "%r25"                      \
58 	);                                                                    \
59 	_ret;                                                                 \
60 })
61 
62 #define __nolibc_syscall2(num, arg1, arg2)                                    \
63 ({                                                                            \
64 	register long _ret __asm__ ("r28");                                   \
65 	register long _arg1 __asm__ ("r26") = (long)(arg1);		      \
66 	register long _arg2 __asm__ ("r25") = (long)(arg2);		      \
67 									      \
68 	__asm__ volatile (                                                    \
69 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
70 		"copy %3, %%r20\n\t"                                          \
71 		: "=r"(_ret),                                                 \
72 		  "+r"(_arg1), "+r"(_arg2)                                    \
73 		: "r"(num)                                                    \
74 		: _NOLIBC_SYSCALL_CLOBBERLIST,                                \
75 		  "%r21", "%r22", "%r23", "%r24"                              \
76 	);                                                                    \
77 	_ret;                                                                 \
78 })
79 
80 #define __nolibc_syscall3(num, arg1, arg2, arg3)                              \
81 ({                                                                            \
82 	register long _ret __asm__ ("r28");                                   \
83 	register long _arg1 __asm__ ("r26") = (long)(arg1);		      \
84 	register long _arg2 __asm__ ("r25") = (long)(arg2);		      \
85 	register long _arg3 __asm__ ("r24") = (long)(arg3);		      \
86 									      \
87 	__asm__ volatile (                                                    \
88 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
89 		"copy %4, %%r20\n\t"                                          \
90 		: "=r"(_ret),                                                 \
91 		  "+r"(_arg1), "+r"(_arg2), "+r"(_arg3)                       \
92 		: "r"(num)                                                    \
93 		: _NOLIBC_SYSCALL_CLOBBERLIST,                                \
94 		  "%r21", "%r22", "%r23"                                      \
95 	);                                                                    \
96 	_ret;                                                                 \
97 })
98 
99 #define __nolibc_syscall4(num, arg1, arg2, arg3, arg4)                        \
100 ({                                                                            \
101 	register long _ret __asm__ ("r28");                                   \
102 	register long _arg1 __asm__ ("r26") = (long)(arg1);		      \
103 	register long _arg2 __asm__ ("r25") = (long)(arg2);		      \
104 	register long _arg3 __asm__ ("r24") = (long)(arg3);		      \
105 	register long _arg4 __asm__ ("r23") = (long)(arg4);		      \
106 									      \
107 	__asm__ volatile (                                                    \
108 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
109 		"copy %5, %%r20\n\t"                                          \
110 		: "=r"(_ret),                                                 \
111 		  "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4)          \
112 		: "r"(num)                                                    \
113 		: _NOLIBC_SYSCALL_CLOBBERLIST,                                \
114 		  "%r21", "%r22"                                              \
115 	);                                                                    \
116 	_ret;                                                                 \
117 })
118 
119 #define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5)                  \
120 ({                                                                            \
121 	register long _ret __asm__ ("r28");                                   \
122 	register long _arg1 __asm__ ("r26") = (long)(arg1);		      \
123 	register long _arg2 __asm__ ("r25") = (long)(arg2);		      \
124 	register long _arg3 __asm__ ("r24") = (long)(arg3);		      \
125 	register long _arg4 __asm__ ("r23") = (long)(arg4);		      \
126 	register long _arg5 __asm__ ("r22") = (long)(arg5);		      \
127 									      \
128 	__asm__ volatile (                                                    \
129 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
130 		"copy %6, %%r20\n\t"                                          \
131 		: "=r"(_ret),                                                 \
132 		  "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4),         \
133 		  "+r"(_arg5)                                                 \
134 		: "r"(num)                                                    \
135 		: _NOLIBC_SYSCALL_CLOBBERLIST,                                \
136 		  "%r21"                                                      \
137 	);                                                                    \
138 	_ret;                                                                 \
139 })
140 
141 #define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)            \
142 ({                                                                            \
143 	register long _ret __asm__ ("r28");                                   \
144 	register long _arg1 __asm__ ("r26") = (long)(arg1);		      \
145 	register long _arg2 __asm__ ("r25") = (long)(arg2);		      \
146 	register long _arg3 __asm__ ("r24") = (long)(arg3);		      \
147 	register long _arg4 __asm__ ("r23") = (long)(arg4);		      \
148 	register long _arg5 __asm__ ("r22") = (long)(arg5);		      \
149 	register long _arg6 __asm__ ("r21") = (long)(arg6);		      \
150 									      \
151 	__asm__ volatile (                                                    \
152 		"ble 0x100(%%sr2, %%r0)\n\t"                                  \
153 		"copy %7, %%r20\n\t"                                          \
154 		: "=r"(_ret),                                                 \
155 		  "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4),         \
156 		  "+r"(_arg5), "+r"(_arg6)                                    \
157 		: "r"(num)                                                    \
158 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
159 	);                                                                    \
160 	_ret;                                                                 \
161 })
162 
163 #ifndef NOLIBC_NO_RUNTIME
164 /* startup code */
165 void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start(void)
166 {
167 	__asm__ volatile (
168 #ifdef __LP64__
169 		".import __gp\n"               /* Set up the dp register */
170 		"ldil L%__gp, %dp\n"
171 		"ldo R%__gp(%dp), %dp\n"
172 #else
173 		".import $global$\n"           /* Set up the dp register */
174 		"ldil L%$global$, %dp\n"
175 		"ldo R%$global$(%dp), %dp\n"
176 #endif
177 
178 		"b _start_c\n"                 /* Call _start_c, the load below is executed first */
179 
180 		"ldo -4(%r24), %r26\n"         /* The sp register is special on parisc.
181 						* r24 points to argv. Subtract 4 to get &argc.
182 						* Pass that as first argument to _start_c.
183 						*/
184 	);
185 	__nolibc_entrypoint_epilogue();
186 }
187 #endif /* NOLIBC_NO_RUNTIME */
188 
189 #ifdef __LP64__
190 /*
191  * This override is normally only meant for 32-bit architectures.
192  * But parisc 64-bit has __NR_ftruncate64, so this path is taken.
193  * Add an unused second argument to satisfy the calling convention.
194  */
195 static __attribute__((unused))
196 int _sys_ftruncate64(int fd, uint64_t length, uint64_t unused)
197 {
198 	(void)unused;
199 
200 	return __nolibc_syscall2(__NR_ftruncate64, fd, length);
201 }
202 #define _sys_ftruncate64 _sys_ftruncate64
203 #endif
204 
205 #endif /* _NOLIBC_ARCH_PARISC_H */
206