mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
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 <linux@weissschuh.net> Acked-by: Willy Tarreau <w@1wt.eu> Acked-by: Rob Landley <rob@landley.net> Acked-by: D. Jeff Dionne <jeff@coresemi.io> Tested-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Link: https://lore.kernel.org/r/20250623-nolibc-sh-v2-3-0f5b4b303025@weissschuh.net
This commit is contained in:
parent
358b2511d7
commit
02217ad447
162
tools/include/nolibc/arch-sh.h
Normal file
162
tools/include/nolibc/arch-sh.h
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* SuperH specific definitions for NOLIBC
|
||||
* Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_SH_H
|
||||
#define _NOLIBC_ARCH_SH_H
|
||||
|
||||
#include "compiler.h"
|
||||
#include "crt.h"
|
||||
|
||||
/*
|
||||
* Syscalls for SuperH:
|
||||
* - registers are 32bit wide
|
||||
* - syscall number is passed in r3
|
||||
* - arguments are in r4, r5, r6, r7, r0, r1, r2
|
||||
* - the system call is performed by calling trapa #31
|
||||
* - syscall return value is in r0
|
||||
*/
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
register long _arg1 __asm__ ("r4") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num), "r"(_arg1) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
register long _arg1 __asm__ ("r4") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r5") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num), "r"(_arg1), "r"(_arg2) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
register long _arg1 __asm__ ("r4") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r5") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r6") = (long)(arg3); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
register long _arg1 __asm__ ("r4") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r5") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r6") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r7") = (long)(arg4); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
register long _arg1 __asm__ ("r4") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r5") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r6") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r7") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r0") = (long)(arg5); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"r"(_arg5) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
register long _num __asm__ ("r3") = (num); \
|
||||
register long _ret __asm__ ("r0"); \
|
||||
register long _arg1 __asm__ ("r4") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r5") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r6") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r7") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r0") = (long)(arg5); \
|
||||
register long _arg6 __asm__ ("r1") = (long)(arg6); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"trapa #31" \
|
||||
: "=r"(_ret) \
|
||||
: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"r"(_arg5), "r"(_arg6) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
/* startup code */
|
||||
void _start_wrapper(void);
|
||||
void __attribute__((weak,noreturn)) __nolibc_entrypoint __no_stack_protector _start_wrapper(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
".global _start\n" /* The C function will have a prologue, */
|
||||
".type _start, @function\n" /* corrupting "sp" */
|
||||
".weak _start\n"
|
||||
"_start:\n"
|
||||
|
||||
"mov sp, r4\n" /* save argc pointer to r4, as arg1 of _start_c */
|
||||
"bsr _start_c\n" /* transfer to c runtime */
|
||||
"nop\n" /* delay slot */
|
||||
|
||||
".size _start, .-_start\n"
|
||||
);
|
||||
__nolibc_entrypoint_epilogue();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_ARCH_SH_H */
|
||||
|
|
@ -35,6 +35,8 @@
|
|||
#include "arch-sparc.h"
|
||||
#elif defined(__m68k__)
|
||||
#include "arch-m68k.h"
|
||||
#elif defined(__sh__)
|
||||
#include "arch-sh.h"
|
||||
#else
|
||||
#error Unsupported Architecture
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ ARCH_riscv64 = riscv
|
|||
ARCH_s390x = s390
|
||||
ARCH_sparc32 = sparc
|
||||
ARCH_sparc64 = sparc
|
||||
ARCH_sh4 = sh
|
||||
ARCH := $(or $(ARCH_$(XARCH)),$(XARCH))
|
||||
|
||||
# kernel image names by architecture
|
||||
|
|
@ -89,6 +90,7 @@ IMAGE_loongarch = arch/loongarch/boot/vmlinuz.efi
|
|||
IMAGE_sparc32 = arch/sparc/boot/image
|
||||
IMAGE_sparc64 = arch/sparc/boot/image
|
||||
IMAGE_m68k = vmlinux
|
||||
IMAGE_sh4 = arch/sh/boot/zImage
|
||||
IMAGE = $(objtree)/$(IMAGE_$(XARCH))
|
||||
IMAGE_NAME = $(notdir $(IMAGE))
|
||||
|
||||
|
|
@ -117,11 +119,13 @@ DEFCONFIG_loongarch = defconfig
|
|||
DEFCONFIG_sparc32 = sparc32_defconfig
|
||||
DEFCONFIG_sparc64 = sparc64_defconfig
|
||||
DEFCONFIG_m68k = virt_defconfig
|
||||
DEFCONFIG_sh4 = rts7751r2dplus_defconfig
|
||||
DEFCONFIG = $(DEFCONFIG_$(XARCH))
|
||||
|
||||
EXTRACONFIG_arm = -e CONFIG_NAMESPACES
|
||||
EXTRACONFIG_armthumb = -e CONFIG_NAMESPACES
|
||||
EXTRACONFIG_m68k = -e CONFIG_BLK_DEV_INITRD
|
||||
EXTRACONFIG_sh4 = -e CONFIG_BLK_DEV_INITRD -e CONFIG_CMDLINE_FROM_BOOTLOADER
|
||||
EXTRACONFIG = $(EXTRACONFIG_$(XARCH))
|
||||
|
||||
# optional tests to run (default = all)
|
||||
|
|
@ -152,6 +156,7 @@ QEMU_ARCH_loongarch = loongarch64
|
|||
QEMU_ARCH_sparc32 = sparc
|
||||
QEMU_ARCH_sparc64 = sparc64
|
||||
QEMU_ARCH_m68k = m68k
|
||||
QEMU_ARCH_sh4 = sh4
|
||||
QEMU_ARCH = $(QEMU_ARCH_$(XARCH))
|
||||
|
||||
QEMU_ARCH_USER_ppc64le = ppc64le
|
||||
|
|
@ -191,6 +196,7 @@ QEMU_ARGS_loongarch = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=N
|
|||
QEMU_ARGS_sparc32 = -M SS-5 -m 256M -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS_sparc64 = -M sun4u -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS_m68k = -M virt -append "console=ttyGF0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS_sh4 = -M r2d -serial file:/dev/stdout -append "console=ttySC1,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
|
||||
QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA)
|
||||
|
||||
# OUTPUT is only set when run from the main makefile, otherwise
|
||||
|
|
@ -218,6 +224,7 @@ CFLAGS_mipsn32be = -EB -mabi=n32 -march=mips64r6
|
|||
CFLAGS_mips64le = -EL -mabi=64 -march=mips64r6
|
||||
CFLAGS_mips64be = -EB -mabi=64 -march=mips64r2
|
||||
CFLAGS_sparc32 = $(call cc-option,-m32)
|
||||
CFLAGS_sh4 = -ml -m4
|
||||
ifeq ($(origin XARCH),command line)
|
||||
CFLAGS_XARCH = $(CFLAGS_$(XARCH))
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ all_archs=(
|
|||
loongarch
|
||||
sparc32 sparc64
|
||||
m68k
|
||||
sh4
|
||||
)
|
||||
archs="${all_archs[@]}"
|
||||
|
||||
|
|
@ -187,7 +188,7 @@ test_arch() {
|
|||
echo "Unsupported configuration"
|
||||
return
|
||||
fi
|
||||
if [ "$arch" = "m68k" ] && [ "$llvm" = "1" ]; then
|
||||
if [ "$arch" = "m68k" -o "$arch" = "sh4" ] && [ "$llvm" = "1" ]; then
|
||||
echo "Unsupported configuration"
|
||||
return
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user