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