Add support for OpenRISC / or1k to nolibc. _start() uses the same wrapper construct as in arch-sh.h. libgcc is necessary as OpenRISC is missing 64-bit multiplication.
Signed-off-by: Thomas Weißschuh <[email protected]> --- tools/include/nolibc/Makefile | 2 +- tools/include/nolibc/arch-openrisc.h | 176 +++++++++++++++++++++++++ tools/include/nolibc/arch.h | 2 + tools/testing/selftests/nolibc/Makefile.nolibc | 5 + tools/testing/selftests/nolibc/run-tests.sh | 4 +- 5 files changed, 187 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 872c318f50d4..2cb4d610fe53 100644 --- a/tools/include/nolibc/Makefile +++ b/tools/include/nolibc/Makefile @@ -17,7 +17,7 @@ endif # it defaults to this nolibc directory. OUTPUT ?= $(CURDIR)/ -architectures := arm arm64 loongarch m68k mips powerpc riscv s390 sh sparc x86 +architectures := arm arm64 loongarch m68k mips openrisc powerpc riscv s390 sh sparc x86 arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures))) all_files := \ alloca.h \ diff --git a/tools/include/nolibc/arch-openrisc.h b/tools/include/nolibc/arch-openrisc.h new file mode 100644 index 000000000000..de2df1715504 --- /dev/null +++ b/tools/include/nolibc/arch-openrisc.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * openrisc specific definitions for NOLIBC + * Copyright (C) 2026 Thomas Weißschuh <[email protected]> + */ + +#ifndef _NOLIBC_ARCH_OPENRISC_H +#define _NOLIBC_ARCH_OPENRISC_H + +#include "compiler.h" +#include "crt.h" + +/* + * Syscalls for SuperH: + * - syscall number is passed in r11 + * - arguments are in r3, r4, r5, r6, r7, r8 + * - the system call is performed by calling l.sys 1 + * - syscall return value is in r11 + */ + +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "r12", "r13", "r15", "r17", "r19", "r21", "r23", "r25", "r27", "r29", "r31", "memory" + +#define __nolibc_syscall0(num) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num) \ + : "r3", "r4", "r5", "r6", "r7", "r8", \ + _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall1(num, arg1) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num), "r"(_arg1) \ + : "r4", "r5", "r6", "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall2(num, arg1, arg2) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num), "r"(_arg1), "r"(_arg2) \ + : "r5", "r6", "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3) \ + : "r6", "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4) \ + : "r7", "r8", _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + register long _arg5 __asm__ ("r7") = (long)(arg5); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_arg5) \ + : "r8", _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _num __asm__ ("r11") = (num); \ + register long _ret __asm__ ("r11"); \ + register long _arg1 __asm__ ("r3") = (long)(arg1); \ + register long _arg2 __asm__ ("r4") = (long)(arg2); \ + register long _arg3 __asm__ ("r5") = (long)(arg3); \ + register long _arg4 __asm__ ("r6") = (long)(arg4); \ + register long _arg5 __asm__ ("r7") = (long)(arg5); \ + register long _arg6 __asm__ ("r8") = (long)(arg6); \ + \ + __asm__ volatile ( \ + "l.sys 1\n" \ + "l.nop\n" \ + : "=r"(_ret) \ + : "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_arg5), "r"(_arg6) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#ifndef NOLIBC_NO_RUNTIME +/* startup code */ +void _start_wrapper(void); +void __attribute__((weak,noreturn)) +__nolibc_entrypoint __nolibc_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" + + "l.or r3,sp,sp\n" /* save stack pointer to 3, as arg1 of _start_c */ + "l.jal _start_c\n" /* transfer to c runtime */ + "l.nop\n" + + ".size _start, .-_start\n" + ); + __nolibc_entrypoint_epilogue(); +} +#endif /* NOLIBC_NO_RUNTIME */ + +#endif /* _NOLIBC_ARCH_OPENRISC_H */ diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index a3adaf433f2c..55009dcafe9e 100644 --- a/tools/include/nolibc/arch.h +++ b/tools/include/nolibc/arch.h @@ -28,6 +28,8 @@ #include "arch-m68k.h" #elif defined(__sh__) #include "arch-sh.h" +#elif defined(__or1k__) +#include "arch-openrisc.h" #else #error Unsupported Architecture #endif diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index f30bc68470cc..91f5a284f4e6 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -92,6 +92,7 @@ IMAGE_sparc32 = arch/sparc/boot/image IMAGE_sparc64 = arch/sparc/boot/image IMAGE_m68k = vmlinux IMAGE_sh4 = arch/sh/boot/zImage +IMAGE_openrisc = vmlinux IMAGE = $(objtree)/$(IMAGE_$(XARCH)) IMAGE_NAME = $(notdir $(IMAGE)) @@ -121,6 +122,7 @@ DEFCONFIG_sparc32 = sparc32_defconfig DEFCONFIG_sparc64 = sparc64_defconfig DEFCONFIG_m68k = virt_defconfig DEFCONFIG_sh4 = rts7751r2dplus_defconfig +DEFCONFIG_openrisc = virt_defconfig DEFCONFIG = $(DEFCONFIG_$(XARCH)) EXTRACONFIG_x32 = -e CONFIG_X86_X32_ABI @@ -159,6 +161,7 @@ QEMU_ARCH_sparc32 = sparc QEMU_ARCH_sparc64 = sparc64 QEMU_ARCH_m68k = m68k QEMU_ARCH_sh4 = sh4 +QEMU_ARCH_openrisc = or1k QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) QEMU_ARCH_USER_ppc64le = ppc64le @@ -199,6 +202,7 @@ QEMU_ARGS_sparc32 = -M SS-5 -m 256M -append "console=ttyS0,115200 panic=-1 $( 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_openrisc = -M virt -m 512M -append "console=ttyS0 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 @@ -233,6 +237,7 @@ CFLAGS_XARCH = $(CFLAGS_$(XARCH)) endif LDLIBS_ppc = $(if $(LLVM),,-lgcc) +LDLIBS_openrisc = $(if $(LLVM),,-lgcc) LDLIBS = $(LDLIBS_$(XARCH)) include Makefile.include diff --git a/tools/testing/selftests/nolibc/run-tests.sh b/tools/testing/selftests/nolibc/run-tests.sh index cd439096fdf3..c25ee4be2df4 100755 --- a/tools/testing/selftests/nolibc/run-tests.sh +++ b/tools/testing/selftests/nolibc/run-tests.sh @@ -21,6 +21,7 @@ all_archs=( i386 x86_64 x32 arm64 arm armthumb mips32le mips32be mipsn32le mipsn32be mips64le mips64be + openrisc ppc ppc64 ppc64le riscv32 riscv64 s390x @@ -107,6 +108,7 @@ crosstool_arch() { case "$1" in arm64) echo aarch64;; armthumb) echo arm;; + openrisc) echo or1k;; ppc) echo powerpc;; ppc64) echo powerpc64;; ppc64le) echo powerpc64;; @@ -185,7 +187,7 @@ test_arch() { exit 1 esac printf '%-15s' "$arch:" - if [ "$arch" = "m68k" -o "$arch" = "sh4" ] && [ "$llvm" = "1" ]; then + if [ "$arch" = "m68k" -o "$arch" = "sh4" -o "$arch" = "openrisc" ] && [ "$llvm" = "1" ]; then echo "Unsupported configuration" return fi --- base-commit: 8bf37d924968cf26ab95f644c981a28086e372af change-id: 20260415-nolibc-openrisc-a1ab91c41fe5 Best regards, -- Thomas Weißschuh <[email protected]>

