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