xref: /linux/tools/include/nolibc/arch-sh.h (revision b1c21075d30c40762750be0cded9822791df422b)
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * SuperH specific definitions for NOLIBC
4  * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
5  */
6 
7 #ifndef _NOLIBC_ARCH_SH_H
8 #define _NOLIBC_ARCH_SH_H
9 
10 #include "compiler.h"
11 #include "crt.h"
12 
13 /*
14  * Syscalls for SuperH:
15  *   - registers are 32bit wide
16  *   - syscall number is passed in r3
17  *   - arguments are in r4, r5, r6, r7, r0, r1, r2
18  *   - the system call is performed by calling trapa #31
19  *   - syscall return value is in r0
20  */
21 
22 #define my_syscall0(num)                                                      \
23 ({                                                                            \
24 	register long _num __asm__ ("r3") = (num);                            \
25 	register long _ret __asm__ ("r0");                                    \
26 									      \
27 	__asm__ volatile (                                                    \
28 		"trapa #31"                                                   \
29 		: "=r"(_ret)                                                  \
30 		: "r"(_num)                                                   \
31 		: "memory", "cc"                                              \
32 	);                                                                    \
33 	_ret;                                                                 \
34 })
35 
36 #define my_syscall1(num, arg1)                                                \
37 ({                                                                            \
38 	register long _num __asm__ ("r3") = (num);                            \
39 	register long _ret __asm__ ("r0");                                    \
40 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
41 									      \
42 	__asm__ volatile (                                                    \
43 		"trapa #31"                                                   \
44 		: "=r"(_ret)                                                  \
45 		: "r"(_num), "r"(_arg1)                                       \
46 		: "memory", "cc"                                              \
47 	);                                                                    \
48 	_ret;                                                                 \
49 })
50 
51 #define my_syscall2(num, arg1, arg2)                                          \
52 ({                                                                            \
53 	register long _num __asm__ ("r3") = (num);                            \
54 	register long _ret __asm__ ("r0");                                    \
55 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
56 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
57 									      \
58 	__asm__ volatile (                                                    \
59 		"trapa #31"                                                   \
60 		: "=r"(_ret)                                                  \
61 		: "r"(_num), "r"(_arg1), "r"(_arg2)                           \
62 		: "memory", "cc"                                              \
63 	);                                                                    \
64 	_ret;                                                                 \
65 })
66 
67 #define my_syscall3(num, arg1, arg2, arg3)                                    \
68 ({                                                                            \
69 	register long _num __asm__ ("r3") = (num);                            \
70 	register long _ret __asm__ ("r0");                                    \
71 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
72 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
73 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
74 									      \
75 	__asm__ volatile (                                                    \
76 		"trapa #31"                                                   \
77 		: "=r"(_ret)                                                  \
78 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3)               \
79 		: "memory", "cc"                                              \
80 	);                                                                    \
81 	_ret;                                                                 \
82 })
83 
84 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
85 ({                                                                            \
86 	register long _num __asm__ ("r3") = (num);                            \
87 	register long _ret __asm__ ("r0");                                    \
88 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
89 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
90 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
91 	register long _arg4 __asm__ ("r7") = (long)(arg4);                    \
92 									      \
93 	__asm__ volatile (                                                    \
94 		"trapa #31"                                                   \
95 		: "=r"(_ret)                                                  \
96 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4)   \
97 		: "memory", "cc"                                              \
98 	);                                                                    \
99 	_ret;                                                                 \
100 })
101 
102 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
103 ({                                                                            \
104 	register long _num __asm__ ("r3") = (num);                            \
105 	register long _ret __asm__ ("r0");                                    \
106 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
107 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
108 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
109 	register long _arg4 __asm__ ("r7") = (long)(arg4);                    \
110 	register long _arg5 __asm__ ("r0") = (long)(arg5);                    \
111 									      \
112 	__asm__ volatile (                                                    \
113 		"trapa #31"                                                   \
114 		: "=r"(_ret)                                                  \
115 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),  \
116 		  "r"(_arg5)                                                  \
117 		: "memory", "cc"                                              \
118 	);                                                                    \
119 	_ret;                                                                 \
120 })
121 
122 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
123 ({                                                                            \
124 	register long _num __asm__ ("r3") = (num);                            \
125 	register long _ret __asm__ ("r0");                                    \
126 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
127 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
128 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
129 	register long _arg4 __asm__ ("r7") = (long)(arg4);                    \
130 	register long _arg5 __asm__ ("r0") = (long)(arg5);                    \
131 	register long _arg6 __asm__ ("r1") = (long)(arg6);                    \
132 									      \
133 	__asm__ volatile (                                                    \
134 		"trapa #31"                                                   \
135 		: "=r"(_ret)                                                  \
136 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),  \
137 		  "r"(_arg5), "r"(_arg6)                                      \
138 		: "memory", "cc"                                              \
139 	);                                                                    \
140 	_ret;                                                                 \
141 })
142 
143 /* startup code */
144 void _start_wrapper(void);
_start_wrapper(void)145 void __attribute__((weak,noreturn)) __nolibc_entrypoint __no_stack_protector _start_wrapper(void)
146 {
147 	__asm__ volatile (
148 		".global _start\n"           /* The C function will have a prologue,         */
149 		".type _start, @function\n"  /* corrupting "sp"                              */
150 		".weak _start\n"
151 		"_start:\n"
152 
153 		"mov sp, r4\n"               /* save argc pointer to r4, as arg1 of _start_c */
154 		"bsr _start_c\n"             /* transfer to c runtime                        */
155 		"nop\n"                      /* delay slot                                   */
156 
157 		".size _start, .-_start\n"
158 	);
159 	__nolibc_entrypoint_epilogue();
160 }
161 
162 #endif /* _NOLIBC_ARCH_SH_H */
163