On Tue, Apr 28, 2026 at 05:48:51PM +0200, Thomas Weißschuh wrote: > 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.
There are a few minor issues with this patch. Could you give any background for this? What are you working on? Just getting more coverage in the test suite? Do you have any results for or1k, considering one of the issues I highlighted before I am not sure this will compile as is. > 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" \ We do not need l.nop for l.sys instructions. They do not have a delay-slot line branches. > + : "=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 */ What is sp here? There is no sp alias in OpenRISC, should it be r1? Does this compile? > + "l.jal _start_c\n" /* transfer to c runtime > */ > + "l.nop\n" The l.or can go in the delay slot. Also, preferrably we use spaces between args, and a space to indicate a delay slot e.g. "l.jal _start_c\n" "l.or r3, r1, r1\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 The rest looks ok to me. Thanks, -Stafford

