Skip to content

Commit 02217ad

Browse files
committed
tools/nolibc: add support for SuperH
Add support for SuperH/"sh" to nolibc. Only sh4 is tested for now. The startup code is special: __nolibc_entrypoint_epilogue() calls __builtin_unreachable() which emits a call to abort(). To make this work a function prologue is generated to set up a GOT pointer which corrupts "sp". __builtin_unreachable() is necessary for __attribute__((noreturn)). Also depending on compiler flags (for example -fPIC) even more prologue is generated. Work around this by defining a nested function in asm. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70216 Signed-off-by: Thomas Weißschuh <[email protected]> Acked-by: Willy Tarreau <[email protected]> Acked-by: Rob Landley <[email protected]> Acked-by: D. Jeff Dionne <[email protected]> Tested-by: John Paul Adrian Glaubitz <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 358b251 commit 02217ad

File tree

4 files changed

+173
-1
lines changed

4 files changed

+173
-1
lines changed

tools/include/nolibc/arch-sh.h

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2+
/*
3+
* SuperH specific definitions for NOLIBC
4+
* Copyright (C) 2025 Thomas Weißschuh <[email protected]>
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);
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 */

tools/include/nolibc/arch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include "arch-sparc.h"
3636
#elif defined(__m68k__)
3737
#include "arch-m68k.h"
38+
#elif defined(__sh__)
39+
#include "arch-sh.h"
3840
#else
3941
#error Unsupported Architecture
4042
#endif

tools/testing/selftests/nolibc/Makefile.nolibc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ ARCH_riscv64 = riscv
6262
ARCH_s390x = s390
6363
ARCH_sparc32 = sparc
6464
ARCH_sparc64 = sparc
65+
ARCH_sh4 = sh
6566
ARCH := $(or $(ARCH_$(XARCH)),$(XARCH))
6667

6768
# kernel image names by architecture
@@ -89,6 +90,7 @@ IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi
8990
IMAGE_sparc32 = arch/sparc/boot/image
9091
IMAGE_sparc64 = arch/sparc/boot/image
9192
IMAGE_m68k = vmlinux
93+
IMAGE_sh4 = arch/sh/boot/zImage
9294
IMAGE = $(objtree)/$(IMAGE_$(XARCH))
9395
IMAGE_NAME = $(notdir $(IMAGE))
9496

@@ -117,11 +119,13 @@ DEFCONFIG_loongarch = defconfig
117119
DEFCONFIG_sparc32 = sparc32_defconfig
118120
DEFCONFIG_sparc64 = sparc64_defconfig
119121
DEFCONFIG_m68k = virt_defconfig
122+
DEFCONFIG_sh4 = rts7751r2dplus_defconfig
120123
DEFCONFIG = $(DEFCONFIG_$(XARCH))
121124

122125
EXTRACONFIG_arm = -e CONFIG_NAMESPACES
123126
EXTRACONFIG_armthumb = -e CONFIG_NAMESPACES
124127
EXTRACONFIG_m68k = -e CONFIG_BLK_DEV_INITRD
128+
EXTRACONFIG_sh4 = -e CONFIG_BLK_DEV_INITRD -e CONFIG_CMDLINE_FROM_BOOTLOADER
125129
EXTRACONFIG = $(EXTRACONFIG_$(XARCH))
126130

127131
# optional tests to run (default = all)
@@ -152,6 +156,7 @@ QEMU_ARCH_loongarch = loongarch64
152156
QEMU_ARCH_sparc32 = sparc
153157
QEMU_ARCH_sparc64 = sparc64
154158
QEMU_ARCH_m68k = m68k
159+
QEMU_ARCH_sh4 = sh4
155160
QEMU_ARCH = $(QEMU_ARCH_$(XARCH))
156161

157162
QEMU_ARCH_USER_ppc64le = ppc64le
@@ -191,6 +196,7 @@ QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=N
191196
QEMU_ARGS_sparc32 = -M SS-5 -m 256M -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
192197
QEMU_ARGS_sparc64 = -M sun4u -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
193198
QEMU_ARGS_m68k = -M virt -append "console=ttyGF0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
199+
QEMU_ARGS_sh4 = -M r2d -serial file:/dev/stdout -append "console=ttySC1,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
194200
QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA)
195201

196202
# OUTPUT is only set when run from the main makefile, otherwise
@@ -218,6 +224,7 @@ CFLAGS_mipsn32be = -EB -mabi=n32 -march=mips64r6
218224
CFLAGS_mips64le = -EL -mabi=64 -march=mips64r6
219225
CFLAGS_mips64be = -EB -mabi=64 -march=mips64r2
220226
CFLAGS_sparc32 = $(call cc-option,-m32)
227+
CFLAGS_sh4 = -ml -m4
221228
ifeq ($(origin XARCH),command line)
222229
CFLAGS_XARCH = $(CFLAGS_$(XARCH))
223230
endif

tools/testing/selftests/nolibc/run-tests.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ all_archs=(
2727
loongarch
2828
sparc32 sparc64
2929
m68k
30+
sh4
3031
)
3132
archs="${all_archs[@]}"
3233

@@ -187,7 +188,7 @@ test_arch() {
187188
echo "Unsupported configuration"
188189
return
189190
fi
190-
if [ "$arch" = "m68k" ] && [ "$llvm" = "1" ]; then
191+
if [ "$arch" = "m68k" -o "$arch" = "sh4" ] && [ "$llvm" = "1" ]; then
191192
echo "Unsupported configuration"
192193
return
193194
fi

0 commit comments

Comments
 (0)