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