xref: /linux/tools/include/nolibc/arch-sparc.h (revision 015a99fa76650e7d6efa3e36f20c0f5b346fe9ce)
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * SPARC (32bit and 64bit) specific definitions for NOLIBC
4  * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
5  */
6 
7 #ifndef _NOLIBC_ARCH_SPARC_H
8 #define _NOLIBC_ARCH_SPARC_H
9 
10 #include <linux/unistd.h>
11 
12 #include "compiler.h"
13 #include "crt.h"
14 
15 /*
16  * Syscalls for SPARC:
17  *   - registers are native word size
18  *   - syscall number is passed in g1
19  *   - arguments are in o0-o5
20  *   - the system call is performed by calling a trap instruction
21  *   - syscall return value is in o0
22  *   - syscall error flag is in the carry bit of the processor status register
23  */
24 
25 #ifdef __arch64__
26 
27 #define _NOLIBC_SYSCALL "t	0x6d\n"                                       \
28 			"bcs,a	%%xcc, 1f\n"                                  \
29 			"sub	%%g0, %%o0, %%o0\n"                           \
30 			"1:\n"
31 
32 #else
33 
34 #define _NOLIBC_SYSCALL "t	0x10\n"                                       \
35 			"bcs,a	1f\n"                                         \
36 			"sub	%%g0, %%o0, %%o0\n"                           \
37 			"1:\n"
38 
39 #endif /* __arch64__ */
40 
41 #define my_syscall0(num)                                                      \
42 ({                                                                            \
43 	register long _num  __asm__ ("g1") = (num);                           \
44 	register long _arg1 __asm__ ("o0");                                   \
45 									      \
46 	__asm__ volatile (                                                    \
47 		_NOLIBC_SYSCALL                                               \
48 		: "+r"(_arg1)                                                 \
49 		: "r"(_num)                                                   \
50 		: "memory", "cc"                                              \
51 	);                                                                    \
52 	_arg1;                                                                \
53 })
54 
55 #define my_syscall1(num, arg1)                                                \
56 ({                                                                            \
57 	register long _num  __asm__ ("g1") = (num);                           \
58 	register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
59 									      \
60 	__asm__ volatile (                                                    \
61 		_NOLIBC_SYSCALL                                               \
62 		: "+r"(_arg1)                                                 \
63 		: "r"(_num)                                                   \
64 		: "memory", "cc"                                              \
65 	);                                                                    \
66 	_arg1;                                                                \
67 })
68 
69 #define my_syscall2(num, arg1, arg2)                                          \
70 ({                                                                            \
71 	register long _num  __asm__ ("g1") = (num);                           \
72 	register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
73 	register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
74 									      \
75 	__asm__ volatile (                                                    \
76 		_NOLIBC_SYSCALL                                               \
77 		: "+r"(_arg1)                                                 \
78 		: "r"(_arg2), "r"(_num)                                       \
79 		: "memory", "cc"                                              \
80 	);                                                                    \
81 	_arg1;                                                                \
82 })
83 
84 #define my_syscall3(num, arg1, arg2, arg3)                                    \
85 ({                                                                            \
86 	register long _num  __asm__ ("g1") = (num);                           \
87 	register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
88 	register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
89 	register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
90 									      \
91 	__asm__ volatile (                                                    \
92 		_NOLIBC_SYSCALL                                               \
93 		: "+r"(_arg1)                                                 \
94 		: "r"(_arg2), "r"(_arg3), "r"(_num)                           \
95 		: "memory", "cc"                                              \
96 	);                                                                    \
97 	_arg1;                                                                \
98 })
99 
100 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
101 ({                                                                            \
102 	register long _num  __asm__ ("g1") = (num);                           \
103 	register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
104 	register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
105 	register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
106 	register long _arg4 __asm__ ("o3") = (long)(arg4);                    \
107 									      \
108 	__asm__ volatile (                                                    \
109 		_NOLIBC_SYSCALL                                               \
110 		: "+r"(_arg1)                                                 \
111 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_num)               \
112 		: "memory", "cc"                                              \
113 	);                                                                    \
114 	_arg1;                                                                \
115 })
116 
117 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
118 ({                                                                            \
119 	register long _num  __asm__ ("g1") = (num);                           \
120 	register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
121 	register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
122 	register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
123 	register long _arg4 __asm__ ("o3") = (long)(arg4);                    \
124 	register long _arg5 __asm__ ("o4") = (long)(arg5);                    \
125 									      \
126 	__asm__ volatile (                                                    \
127 		_NOLIBC_SYSCALL                                               \
128 		: "+r"(_arg1)                                                 \
129 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_num)   \
130 		: "memory", "cc"                                              \
131 	);                                                                    \
132 	_arg1;                                                                \
133 })
134 
135 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
136 ({                                                                            \
137 	register long _num  __asm__ ("g1") = (num);                           \
138 	register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
139 	register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
140 	register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
141 	register long _arg4 __asm__ ("o3") = (long)(arg4);                    \
142 	register long _arg5 __asm__ ("o4") = (long)(arg5);                    \
143 	register long _arg6 __asm__ ("o5") = (long)(arg6);                    \
144 									      \
145 	__asm__ volatile (                                                    \
146 		_NOLIBC_SYSCALL                                               \
147 		: "+r"(_arg1)                                                 \
148 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
149 		  "r"(_num)                                                   \
150 		: "memory", "cc"                                              \
151 	);                                                                    \
152 	_arg1;                                                                \
153 })
154 
155 /* startup code */
_start(void)156 void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
157 {
158 	__asm__ volatile (
159 		/*
160 		 * Save argc pointer to o0, as arg1 of _start_c.
161 		 * Account for the window save area, which is 16 registers wide.
162 		 */
163 #ifdef __arch64__
164 		"add %sp, 128 + 2047, %o0\n" /* on sparc64 / v9 the stack is offset by 2047 */
165 #else
166 		"add %sp, 64, %o0\n"
167 #endif
168 		"b,a _start_c\n"     /* transfer to c runtime */
169 	);
170 	__nolibc_entrypoint_epilogue();
171 }
172 
173 static pid_t getpid(void);
174 
175 static __attribute__((unused))
sys_fork(void)176 pid_t sys_fork(void)
177 {
178 	pid_t parent, ret;
179 
180 	parent = getpid();
181 	ret = my_syscall0(__NR_fork);
182 
183 	/* The syscall returns the parent pid in the child instead of 0 */
184 	if (ret == parent)
185 		return 0;
186 	else
187 		return ret;
188 }
189 #define sys_fork sys_fork
190 
191 #endif /* _NOLIBC_ARCH_SPARC_H */
192