xref: /linux/tools/include/nolibc/arch-sh.h (revision 5d7f3375cd574fc83f0cd30839b21455c0e79ae2)
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 #include <linux/unistd.h>
14 
15 /*
16  * Syscalls for SuperH:
17  *   - registers are 32bit wide
18  *   - syscall number is passed in r3
19  *   - arguments are in r4, r5, r6, r7, r0, r1, r2
20  *   - the system call is performed by calling trapa #31
21  *   - syscall return value is in r0
22  */
23 
24 #define __nolibc_syscall0(num)                                                \
25 ({                                                                            \
26 	register long _num __asm__ ("r3") = (num);                            \
27 	register long _ret __asm__ ("r0");                                    \
28 									      \
29 	__asm__ volatile (                                                    \
30 		"trapa #31"                                                   \
31 		: "=r"(_ret)                                                  \
32 		: "r"(_num)                                                   \
33 		: "memory", "cc"                                              \
34 	);                                                                    \
35 	_ret;                                                                 \
36 })
37 
38 #define __nolibc_syscall1(num, arg1)                                          \
39 ({                                                                            \
40 	register long _num __asm__ ("r3") = (num);                            \
41 	register long _ret __asm__ ("r0");                                    \
42 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
43 									      \
44 	__asm__ volatile (                                                    \
45 		"trapa #31"                                                   \
46 		: "=r"(_ret)                                                  \
47 		: "r"(_num), "r"(_arg1)                                       \
48 		: "memory", "cc"                                              \
49 	);                                                                    \
50 	_ret;                                                                 \
51 })
52 
53 #define __nolibc_syscall2(num, arg1, arg2)                                    \
54 ({                                                                            \
55 	register long _num __asm__ ("r3") = (num);                            \
56 	register long _ret __asm__ ("r0");                                    \
57 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
58 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
59 									      \
60 	__asm__ volatile (                                                    \
61 		"trapa #31"                                                   \
62 		: "=r"(_ret)                                                  \
63 		: "r"(_num), "r"(_arg1), "r"(_arg2)                           \
64 		: "memory", "cc"                                              \
65 	);                                                                    \
66 	_ret;                                                                 \
67 })
68 
69 #define __nolibc_syscall3(num, arg1, arg2, arg3)                              \
70 ({                                                                            \
71 	register long _num __asm__ ("r3") = (num);                            \
72 	register long _ret __asm__ ("r0");                                    \
73 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
74 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
75 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
76 									      \
77 	__asm__ volatile (                                                    \
78 		"trapa #31"                                                   \
79 		: "=r"(_ret)                                                  \
80 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3)               \
81 		: "memory", "cc"                                              \
82 	);                                                                    \
83 	_ret;                                                                 \
84 })
85 
86 #define __nolibc_syscall4(num, arg1, arg2, arg3, arg4)                        \
87 ({                                                                            \
88 	register long _num __asm__ ("r3") = (num);                            \
89 	register long _ret __asm__ ("r0");                                    \
90 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
91 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
92 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
93 	register long _arg4 __asm__ ("r7") = (long)(arg4);                    \
94 									      \
95 	__asm__ volatile (                                                    \
96 		"trapa #31"                                                   \
97 		: "=r"(_ret)                                                  \
98 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4)   \
99 		: "memory", "cc"                                              \
100 	);                                                                    \
101 	_ret;                                                                 \
102 })
103 
104 #define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5)                  \
105 ({                                                                            \
106 	register long _num __asm__ ("r3") = (num);                            \
107 	register long _ret __asm__ ("r0");                                    \
108 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
109 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
110 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
111 	register long _arg4 __asm__ ("r7") = (long)(arg4);                    \
112 	register long _arg5 __asm__ ("r0") = (long)(arg5);                    \
113 									      \
114 	__asm__ volatile (                                                    \
115 		"trapa #31"                                                   \
116 		: "=r"(_ret)                                                  \
117 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),  \
118 		  "r"(_arg5)                                                  \
119 		: "memory", "cc"                                              \
120 	);                                                                    \
121 	_ret;                                                                 \
122 })
123 
124 #define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)            \
125 ({                                                                            \
126 	register long _num __asm__ ("r3") = (num);                            \
127 	register long _ret __asm__ ("r0");                                    \
128 	register long _arg1 __asm__ ("r4") = (long)(arg1);                    \
129 	register long _arg2 __asm__ ("r5") = (long)(arg2);                    \
130 	register long _arg3 __asm__ ("r6") = (long)(arg3);                    \
131 	register long _arg4 __asm__ ("r7") = (long)(arg4);                    \
132 	register long _arg5 __asm__ ("r0") = (long)(arg5);                    \
133 	register long _arg6 __asm__ ("r1") = (long)(arg6);                    \
134 									      \
135 	__asm__ volatile (                                                    \
136 		"trapa #31"                                                   \
137 		: "=r"(_ret)                                                  \
138 		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),  \
139 		  "r"(_arg5), "r"(_arg6)                                      \
140 		: "memory", "cc"                                              \
141 	);                                                                    \
142 	_ret;                                                                 \
143 })
144 
145 #ifndef NOLIBC_NO_RUNTIME
146 /* startup code */
147 void _start_wrapper(void);
148 void __attribute__((weak, noreturn)) __nolibc_entrypoint __nolibc_no_stack_protector _start_wrapper(void)
149 {
150 	__asm__ volatile (
151 		".global _start\n"           /* The C function will have a prologue,         */
152 		".type _start, @function\n"  /* corrupting "sp"                              */
153 		".weak _start\n"
154 		"_start:\n"
155 
156 		"mov sp, r4\n"               /* save argc pointer to r4, as arg1 of _start_c */
157 		"bsr _start_c\n"             /* transfer to c runtime                        */
158 		"nop\n"                      /* delay slot                                   */
159 
160 		".size _start, .-_start\n"
161 	);
162 	__nolibc_entrypoint_epilogue();
163 }
164 #endif /* NOLIBC_NO_RUNTIME */
165 
166 static __attribute__((unused))
167 ssize_t _sys_pread(int fd, void *buf, size_t count, off_t offset)
168 {
169 	return __nolibc_syscall6(__NR_pread64, fd, buf, count, 0,
170 				 __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
171 }
172 #define _sys_pread _sys_pread
173 
174 static __attribute__((unused))
175 ssize_t _sys_pwrite(int fd, const void *buf, size_t count, off_t offset)
176 {
177 	return __nolibc_syscall6(__NR_pwrite64, fd, buf, count, 0,
178 				 __NOLIBC_LLARGPART(offset, 0), __NOLIBC_LLARGPART(offset, 1));
179 }
180 #define _sys_pwrite _sys_pwrite
181 
182 #endif /* _NOLIBC_ARCH_SH_H */
183