* [PATCH v3 0/2] tools/nolibc: add support for 32-bit parisc
@ 2026-04-08 20:05 Thomas Weißschuh
2026-04-08 20:05 ` [PATCH v3 1/2] selftests/nolibc: avoid function pointer comparisons Thomas Weißschuh
2026-04-08 20:05 ` [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh
0 siblings, 2 replies; 6+ messages in thread
From: Thomas Weißschuh @ 2026-04-08 20:05 UTC (permalink / raw)
To: James E.J. Bottomley, Helge Deller, Willy Tarreau
Cc: linux-kernel, linux-parisc, Thomas Weißschuh
Extend nolibc to target the 32-bit parisc architecture.
64-bit is not yet supported.
Based on nolibc/for-next.
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
Changes in v3:
- Drop all changes to the parisc build system
- Link to v2: https://patch.msgid.link/20260408-nolibc-hppa-v2-0-7fe404cb61e3@weissschuh.net
Changes in v2:
- Fix CROSS32CC fallback when not using CROSS_COMPILE
- Link to v1: https://patch.msgid.link/20260407-nolibc-hppa-v1-0-f70b4509c44a@weissschuh.net
---
Thomas Weißschuh (2):
selftests/nolibc: avoid function pointer comparisons
tools/nolibc: add support for 32-bit parisc
tools/include/nolibc/Makefile | 2 +-
tools/include/nolibc/arch-parisc.h | 178 +++++++++++++++++++++++++
tools/include/nolibc/arch.h | 2 +
tools/testing/selftests/nolibc/Makefile.nolibc | 6 +
tools/testing/selftests/nolibc/nolibc-test.c | 13 +-
tools/testing/selftests/nolibc/run-tests.sh | 8 +-
6 files changed, 203 insertions(+), 6 deletions(-)
---
base-commit: 65191c9bf8fdd00f8fe90e2caab330418eefb786
change-id: 20250804-nolibc-hppa-8c137b00ecf2
Best regards,
--
Thomas Weißschuh <linux@weissschuh.net>
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v3 1/2] selftests/nolibc: avoid function pointer comparisons 2026-04-08 20:05 [PATCH v3 0/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh @ 2026-04-08 20:05 ` Thomas Weißschuh 2026-04-08 20:05 ` [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh 1 sibling, 0 replies; 6+ messages in thread From: Thomas Weißschuh @ 2026-04-08 20:05 UTC (permalink / raw) To: James E.J. Bottomley, Helge Deller, Willy Tarreau Cc: linux-kernel, linux-parisc, Thomas Weißschuh The upcoming parisc support would require libgcc to implement function pointer comparisons. As we try to avoid the libgcc dependency rework the logic to work without such comparisons. Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> --- tools/testing/selftests/nolibc/nolibc-test.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index d3c4facb54c0..de4e87586d75 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -647,20 +647,25 @@ int expect_str_buf_eq(size_t expr, const char *buf, size_t val, int llen, const return 0; } +enum strtox_func { + strtox_func_strtol, + strtox_func_strtoul, +}; + #define EXPECT_STRTOX(cond, func, input, base, expected, chars, expected_errno) \ - do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strtox(llen, func, input, base, expected, chars, expected_errno); } while (0) + do { if (!(cond)) result(llen, SKIPPED); else ret += expect_strtox(llen, strtox_func_ ## func, input, base, expected, chars, expected_errno); } while (0) static __attribute__((unused)) -int expect_strtox(int llen, void *func, const char *input, int base, intmax_t expected, int expected_chars, int expected_errno) +int expect_strtox(int llen, enum strtox_func func, const char *input, int base, intmax_t expected, int expected_chars, int expected_errno) { char *endptr; int actual_errno, actual_chars; intmax_t r; errno = 0; - if (func == strtol) { + if (func == strtox_func_strtol) { r = strtol(input, &endptr, base); - } else if (func == strtoul) { + } else if (func == strtox_func_strtoul) { r = strtoul(input, &endptr, base); } else { result(llen, FAIL); -- 2.53.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc 2026-04-08 20:05 [PATCH v3 0/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh 2026-04-08 20:05 ` [PATCH v3 1/2] selftests/nolibc: avoid function pointer comparisons Thomas Weißschuh @ 2026-04-08 20:05 ` Thomas Weißschuh 2026-04-08 22:15 ` Helge Deller 1 sibling, 1 reply; 6+ messages in thread From: Thomas Weißschuh @ 2026-04-08 20:05 UTC (permalink / raw) To: James E.J. Bottomley, Helge Deller, Willy Tarreau Cc: linux-kernel, linux-parisc, Thomas Weißschuh Extend nolibc to target the 32-bit parisc architecture. 64-bit is not yet supported. Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> --- tools/include/nolibc/Makefile | 2 +- tools/include/nolibc/arch-parisc.h | 178 +++++++++++++++++++++++++ tools/include/nolibc/arch.h | 2 + tools/testing/selftests/nolibc/Makefile.nolibc | 6 + tools/testing/selftests/nolibc/run-tests.sh | 8 +- 5 files changed, 194 insertions(+), 2 deletions(-) diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile index 7455097cff69..81187126bf93 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 parisc powerpc riscv s390 sh sparc x86 arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures))) all_files := \ byteswap.h \ diff --git a/tools/include/nolibc/arch-parisc.h b/tools/include/nolibc/arch-parisc.h new file mode 100644 index 000000000000..8580be5c9c58 --- /dev/null +++ b/tools/include/nolibc/arch-parisc.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * parisc/hppa (32-bit) specific definitions for NOLIBC + * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net> + */ + +#ifndef _NOLIBC_ARCH_PARISC_H +#define _NOLIBC_ARCH_PARISC_H + +#if defined(__LP64__) +#error 64-bit not supported +#endif + +#include "compiler.h" +#include "crt.h" + +/* Syscalls for parisc : + * - syscall number is passed in r20 + * - arguments are in r26 to r21 + * - the system call is performed by calling "ble 0x100(%sr2, %r0)", + * the instruction after that is executed first, use it to load the number + * - syscall return comes in r28 + * - the arguments are cast to long and assigned into the target + * registers which are then simply passed as registers to the asm code, + * so that we don't have to experience issues with register constraints. + */ + +#define _NOLIBC_SYSCALL_CLOBBERLIST \ + "memory", "%r1", "%r2", "%r4", "%r20", "%r29", "%r31" + +#define __nolibc_syscall0(num) \ +({ \ + register long _ret __asm__ ("r28"); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %1, %%r20\n\t" \ + : "=r"(_ret) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall1(num, arg1) \ +({ \ + register long _ret __asm__ ("r28"); \ + register long _arg1 __asm__ ("r26") = (long)(arg1); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %2, %%r20\n\t" \ + : "=r"(_ret), \ + "+r"(_arg1) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall2(num, arg1, arg2) \ +({ \ + register long _ret __asm__ ("r28"); \ + register long _arg1 __asm__ ("r26") = (long)(arg1); \ + register long _arg2 __asm__ ("r25") = (long)(arg2); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %3, %%r20\n\t" \ + : "=r"(_ret), \ + "+r"(_arg1), "+r"(_arg2) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ +({ \ + register long _ret __asm__ ("r28"); \ + register long _arg1 __asm__ ("r26") = (long)(arg1); \ + register long _arg2 __asm__ ("r25") = (long)(arg2); \ + register long _arg3 __asm__ ("r24") = (long)(arg3); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %4, %%r20\n\t" \ + : "=r"(_ret), \ + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ +({ \ + register long _ret __asm__ ("r28"); \ + register long _arg1 __asm__ ("r26") = (long)(arg1); \ + register long _arg2 __asm__ ("r25") = (long)(arg2); \ + register long _arg3 __asm__ ("r24") = (long)(arg3); \ + register long _arg4 __asm__ ("r23") = (long)(arg4); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %5, %%r20\n\t" \ + : "=r"(_ret), \ + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ +({ \ + register long _ret __asm__ ("r28"); \ + register long _arg1 __asm__ ("r26") = (long)(arg1); \ + register long _arg2 __asm__ ("r25") = (long)(arg2); \ + register long _arg3 __asm__ ("r24") = (long)(arg3); \ + register long _arg4 __asm__ ("r23") = (long)(arg4); \ + register long _arg5 __asm__ ("r22") = (long)(arg5); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %6, %%r20\n\t" \ + : "=r"(_ret), \ + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4), \ + "+r"(_arg5) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ +({ \ + register long _ret __asm__ ("r28"); \ + register long _arg1 __asm__ ("r26") = (long)(arg1); \ + register long _arg2 __asm__ ("r25") = (long)(arg2); \ + register long _arg3 __asm__ ("r24") = (long)(arg3); \ + register long _arg4 __asm__ ("r23") = (long)(arg4); \ + register long _arg5 __asm__ ("r22") = (long)(arg5); \ + register long _arg6 __asm__ ("r21") = (long)(arg6); \ + \ + __asm__ volatile ( \ + "ble 0x100(%%sr2, %%r0)\n\t" \ + "ldi %7, %%r20\n\t" \ + : "=r"(_ret), \ + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4), \ + "+r"(_arg5), "+r"(_arg6) \ + : "i"(num) \ + : _NOLIBC_SYSCALL_CLOBBERLIST \ + ); \ + _ret; \ +}) + +#ifndef NOLIBC_NO_RUNTIME +/* startup code */ +void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) +{ + __asm__ volatile ( + ".import $global$\n" /* Set up the dp register */ + "ldil L%$global$, %dp\n" + "ldo R%$global$(%r27), %dp\n" + + "ldo -4(%r24), %r26\n" /* The sp register is special on parisc. + * r24 points to argv. Subtract 4 to get &argc. + * Pass that as first argument to _start_c. + */ + + "b,n _start_c\n" + ); + __nolibc_entrypoint_epilogue(); +} +#endif /* NOLIBC_NO_RUNTIME */ + +#endif /* _NOLIBC_ARCH_PARISC_H */ diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h index a3adaf433f2c..6dc45a78e972 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(__hppa__) +#include "arch-parisc.h" #else #error Unsupported Architecture #endif diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc index f30bc68470cc..e9494f3cbc03 100644 --- a/tools/testing/selftests/nolibc/Makefile.nolibc +++ b/tools/testing/selftests/nolibc/Makefile.nolibc @@ -64,6 +64,7 @@ ARCH_s390x = s390 ARCH_sparc32 = sparc ARCH_sparc64 = sparc ARCH_sh4 = sh +ARCH_parisc32 = parisc ARCH := $(or $(ARCH_$(XARCH)),$(XARCH)) # kernel image names by architecture @@ -92,6 +93,7 @@ IMAGE_sparc32 = arch/sparc/boot/image IMAGE_sparc64 = arch/sparc/boot/image IMAGE_m68k = vmlinux IMAGE_sh4 = arch/sh/boot/zImage +IMAGE_parisc32 = vmlinux IMAGE = $(objtree)/$(IMAGE_$(XARCH)) IMAGE_NAME = $(notdir $(IMAGE)) @@ -121,6 +123,7 @@ DEFCONFIG_sparc32 = sparc32_defconfig DEFCONFIG_sparc64 = sparc64_defconfig DEFCONFIG_m68k = virt_defconfig DEFCONFIG_sh4 = rts7751r2dplus_defconfig +DEFCONFIG_parisc32 = defconfig DEFCONFIG = $(DEFCONFIG_$(XARCH)) EXTRACONFIG_x32 = -e CONFIG_X86_X32_ABI @@ -159,6 +162,7 @@ QEMU_ARCH_sparc32 = sparc QEMU_ARCH_sparc64 = sparc64 QEMU_ARCH_m68k = m68k QEMU_ARCH_sh4 = sh4 +QEMU_ARCH_parisc32 = hppa QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) QEMU_ARCH_USER_ppc64le = ppc64le @@ -199,6 +203,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_parisc32 = -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 @@ -215,6 +220,7 @@ CFLAGS_i386 = $(call cc-option,-m32) CFLAGS_x32 = -mx32 CFLAGS_arm = -marm CFLAGS_armthumb = -mthumb -march=armv6t2 +CFLAGS_parisc32 = -mfast-indirect-calls CFLAGS_ppc = -m32 -mbig-endian -mno-vsx $(call cc-option,-mmultiple) CFLAGS_ppc64 = -m64 -mbig-endian -mno-vsx $(call cc-option,-mmultiple) CFLAGS_ppc64le = -m64 -mlittle-endian -mno-vsx $(call cc-option,-mabi=elfv2) diff --git a/tools/testing/selftests/nolibc/run-tests.sh b/tools/testing/selftests/nolibc/run-tests.sh index 3917cfb8fdc4..e64f95e8f984 100755 --- a/tools/testing/selftests/nolibc/run-tests.sh +++ b/tools/testing/selftests/nolibc/run-tests.sh @@ -28,6 +28,7 @@ all_archs=( sparc32 sparc64 m68k sh4 + parisc32 ) archs="${all_archs[@]}" @@ -116,6 +117,7 @@ crosstool_arch() { s390*) echo s390;; sparc*) echo sparc64;; x32*) echo x86_64;; + parisc32) echo hppa;; *) echo "$1";; esac } @@ -173,6 +175,10 @@ test_arch() { fi MAKE=(make -f Makefile.nolibc -j"${nproc}" XARCH="${arch}" CROSS_COMPILE="${cross_compile}" LLVM="${llvm}" O="${build_dir}") + if [ "$arch" = "parisc32" ]; then + MAKE+=("CROSS32CC=${cross_compile}gcc") + fi + case "$test_mode" in 'system') test_target=run @@ -185,7 +191,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" = "parisc32" ] && [ "$llvm" = "1" ]; then echo "Unsupported configuration" return fi -- 2.53.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc 2026-04-08 20:05 ` [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh @ 2026-04-08 22:15 ` Helge Deller 2026-04-09 8:38 ` Thomas Weißschuh 0 siblings, 1 reply; 6+ messages in thread From: Helge Deller @ 2026-04-08 22:15 UTC (permalink / raw) To: Thomas Weißschuh Cc: Helge Deller, Willy Tarreau, linux-kernel, linux-parisc Just some (untested) suggestions. Nothing critical: * Thomas Weißschuh <linux@weissschuh.net>: > Extend nolibc to target the 32-bit parisc architecture. > 64-bit is not yet supported. > > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> > --- > tools/include/nolibc/Makefile | 2 +- > tools/include/nolibc/arch-parisc.h | 178 +++++++++++++++++++++++++ > tools/include/nolibc/arch.h | 2 + > tools/testing/selftests/nolibc/Makefile.nolibc | 6 + > tools/testing/selftests/nolibc/run-tests.sh | 8 +- > 5 files changed, 194 insertions(+), 2 deletions(-) > > diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile > index 7455097cff69..81187126bf93 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 parisc powerpc riscv s390 sh sparc x86 > arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures))) > all_files := \ > byteswap.h \ > diff --git a/tools/include/nolibc/arch-parisc.h b/tools/include/nolibc/arch-parisc.h > new file mode 100644 > index 000000000000..8580be5c9c58 > --- /dev/null > +++ b/tools/include/nolibc/arch-parisc.h > @@ -0,0 +1,178 @@ > +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ > +/* > + * parisc/hppa (32-bit) specific definitions for NOLIBC > + * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net> > + */ > + > +#ifndef _NOLIBC_ARCH_PARISC_H > +#define _NOLIBC_ARCH_PARISC_H > + > +#if defined(__LP64__) > +#error 64-bit not supported > +#endif > + > +#include "compiler.h" > +#include "crt.h" > + > +/* Syscalls for parisc : > + * - syscall number is passed in r20 > + * - arguments are in r26 to r21 > + * - the system call is performed by calling "ble 0x100(%sr2, %r0)", > + * the instruction after that is executed first, use it to load the number better: the instruction after that is in the delay slot and executed before the jump to 0x100 actually happens. > + * - syscall return comes in r28 > + * - the arguments are cast to long and assigned into the target > + * registers which are then simply passed as registers to the asm code, > + * so that we don't have to experience issues with register constraints. side-note: this is actually really tricky. I've seen cases, where the syscalls were not using the given registers, because the callers were too complicated and the compiler could not guarantee to actually use the given register. > + */ > + > +#define _NOLIBC_SYSCALL_CLOBBERLIST \ > + "memory", "%r1", "%r2", "%r4", "%r20", "%r29", "%r31" > + > +#define __nolibc_syscall0(num) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %1, %%r20\n\t" \ > + : "=r"(_ret) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#define __nolibc_syscall1(num, arg1) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + register long _arg1 __asm__ ("r26") = (long)(arg1); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %2, %%r20\n\t" \ > + : "=r"(_ret), \ > + "+r"(_arg1) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#define __nolibc_syscall2(num, arg1, arg2) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + register long _arg1 __asm__ ("r26") = (long)(arg1); \ > + register long _arg2 __asm__ ("r25") = (long)(arg2); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %3, %%r20\n\t" \ > + : "=r"(_ret), \ > + "+r"(_arg1), "+r"(_arg2) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#define __nolibc_syscall3(num, arg1, arg2, arg3) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + register long _arg1 __asm__ ("r26") = (long)(arg1); \ > + register long _arg2 __asm__ ("r25") = (long)(arg2); \ > + register long _arg3 __asm__ ("r24") = (long)(arg3); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %4, %%r20\n\t" \ > + : "=r"(_ret), \ > + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + register long _arg1 __asm__ ("r26") = (long)(arg1); \ > + register long _arg2 __asm__ ("r25") = (long)(arg2); \ > + register long _arg3 __asm__ ("r24") = (long)(arg3); \ > + register long _arg4 __asm__ ("r23") = (long)(arg4); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %5, %%r20\n\t" \ > + : "=r"(_ret), \ > + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + register long _arg1 __asm__ ("r26") = (long)(arg1); \ > + register long _arg2 __asm__ ("r25") = (long)(arg2); \ > + register long _arg3 __asm__ ("r24") = (long)(arg3); \ > + register long _arg4 __asm__ ("r23") = (long)(arg4); \ > + register long _arg5 __asm__ ("r22") = (long)(arg5); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %6, %%r20\n\t" \ > + : "=r"(_ret), \ > + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4), \ > + "+r"(_arg5) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ > +({ \ > + register long _ret __asm__ ("r28"); \ > + register long _arg1 __asm__ ("r26") = (long)(arg1); \ > + register long _arg2 __asm__ ("r25") = (long)(arg2); \ > + register long _arg3 __asm__ ("r24") = (long)(arg3); \ > + register long _arg4 __asm__ ("r23") = (long)(arg4); \ > + register long _arg5 __asm__ ("r22") = (long)(arg5); \ > + register long _arg6 __asm__ ("r21") = (long)(arg6); \ > + \ > + __asm__ volatile ( \ > + "ble 0x100(%%sr2, %%r0)\n\t" \ > + "ldi %7, %%r20\n\t" \ > + : "=r"(_ret), \ > + "+r"(_arg1), "+r"(_arg2), "+r"(_arg3), "+r"(_arg4), \ > + "+r"(_arg5), "+r"(_arg6) \ > + : "i"(num) \ > + : _NOLIBC_SYSCALL_CLOBBERLIST \ > + ); \ > + _ret; \ > +}) > + > +#ifndef NOLIBC_NO_RUNTIME > +/* startup code */ > +void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) > +{ > + __asm__ volatile ( > + ".import $global$\n" /* Set up the dp register */ > + "ldil L%$global$, %dp\n" > + "ldo R%$global$(%r27), %dp\n" > + > + "ldo -4(%r24), %r26\n" /* The sp register is special on parisc. > + * r24 points to argv. Subtract 4 to get &argc. > + * Pass that as first argument to _start_c. > + */ > + > + "b,n _start_c\n" you can change that to "b _start_c\" (without ",n") and move it one line up before the "ldo -4..." instruction. It's a little bit faster". The ldo is then in the delay slot. > + ); > + __nolibc_entrypoint_epilogue(); > +} > +#endif /* NOLIBC_NO_RUNTIME */ > + > +#endif /* _NOLIBC_ARCH_PARISC_H */ > diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h > index a3adaf433f2c..6dc45a78e972 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(__hppa__) > +#include "arch-parisc.h" > #else > #error Unsupported Architecture > #endif > diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc > index f30bc68470cc..e9494f3cbc03 100644 > --- a/tools/testing/selftests/nolibc/Makefile.nolibc > +++ b/tools/testing/selftests/nolibc/Makefile.nolibc > @@ -64,6 +64,7 @@ ARCH_s390x = s390 > ARCH_sparc32 = sparc > ARCH_sparc64 = sparc > ARCH_sh4 = sh > +ARCH_parisc32 = parisc > ARCH := $(or $(ARCH_$(XARCH)),$(XARCH)) > > # kernel image names by architecture > @@ -92,6 +93,7 @@ IMAGE_sparc32 = arch/sparc/boot/image > IMAGE_sparc64 = arch/sparc/boot/image > IMAGE_m68k = vmlinux > IMAGE_sh4 = arch/sh/boot/zImage > +IMAGE_parisc32 = vmlinux > IMAGE = $(objtree)/$(IMAGE_$(XARCH)) > IMAGE_NAME = $(notdir $(IMAGE)) > > @@ -121,6 +123,7 @@ DEFCONFIG_sparc32 = sparc32_defconfig > DEFCONFIG_sparc64 = sparc64_defconfig > DEFCONFIG_m68k = virt_defconfig > DEFCONFIG_sh4 = rts7751r2dplus_defconfig > +DEFCONFIG_parisc32 = defconfig > DEFCONFIG = $(DEFCONFIG_$(XARCH)) > > EXTRACONFIG_x32 = -e CONFIG_X86_X32_ABI > @@ -159,6 +162,7 @@ QEMU_ARCH_sparc32 = sparc > QEMU_ARCH_sparc64 = sparc64 > QEMU_ARCH_m68k = m68k > QEMU_ARCH_sh4 = sh4 > +QEMU_ARCH_parisc32 = hppa > QEMU_ARCH = $(QEMU_ARCH_$(XARCH)) > > QEMU_ARCH_USER_ppc64le = ppc64le > @@ -199,6 +203,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_parisc32 = -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" You could change that to (untested): QEMU_ARGS_parisc32 = -M B160L -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" -nographic > QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA) > > # OUTPUT is only set when run from the main makefile, otherwise > @@ -215,6 +220,7 @@ CFLAGS_i386 = $(call cc-option,-m32) > CFLAGS_x32 = -mx32 > CFLAGS_arm = -marm > CFLAGS_armthumb = -mthumb -march=armv6t2 > +CFLAGS_parisc32 = -mfast-indirect-calls would be good if we could go without this... But for the beginning it's ok. Helge ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc 2026-04-08 22:15 ` Helge Deller @ 2026-04-09 8:38 ` Thomas Weißschuh 2026-04-09 11:11 ` Helge Deller 0 siblings, 1 reply; 6+ messages in thread From: Thomas Weißschuh @ 2026-04-09 8:38 UTC (permalink / raw) To: Helge Deller; +Cc: Helge Deller, Willy Tarreau, linux-kernel, linux-parisc On 2026-04-09 00:15:54+0200, Helge Deller wrote: > * Thomas Weißschuh <linux@weissschuh.net>: > > Extend nolibc to target the 32-bit parisc architecture. > > 64-bit is not yet supported. > > > > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> > > --- > > tools/include/nolibc/Makefile | 2 +- > > tools/include/nolibc/arch-parisc.h | 178 +++++++++++++++++++++++++ > > tools/include/nolibc/arch.h | 2 + > > tools/testing/selftests/nolibc/Makefile.nolibc | 6 + > > tools/testing/selftests/nolibc/run-tests.sh | 8 +- > > 5 files changed, 194 insertions(+), 2 deletions(-) > > > > diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile > > index 7455097cff69..81187126bf93 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 parisc powerpc riscv s390 sh sparc x86 > > arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures))) > > all_files := \ > > byteswap.h \ > > diff --git a/tools/include/nolibc/arch-parisc.h b/tools/include/nolibc/arch-parisc.h > > new file mode 100644 > > index 000000000000..8580be5c9c58 > > --- /dev/null > > +++ b/tools/include/nolibc/arch-parisc.h > > @@ -0,0 +1,178 @@ > > +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ > > +/* > > + * parisc/hppa (32-bit) specific definitions for NOLIBC > > + * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net> > > + */ > > + > > +#ifndef _NOLIBC_ARCH_PARISC_H > > +#define _NOLIBC_ARCH_PARISC_H > > + > > +#if defined(__LP64__) > > +#error 64-bit not supported > > +#endif > > + > > +#include "compiler.h" > > +#include "crt.h" > > + > > +/* Syscalls for parisc : > > + * - syscall number is passed in r20 > > + * - arguments are in r26 to r21 > > + * - the system call is performed by calling "ble 0x100(%sr2, %r0)", > > + * the instruction after that is executed first, use it to load the number > better: > the instruction after that is in the delay slot and executed before the jump > to 0x100 actually happens. Ack. > > + * - syscall return comes in r28 > > + * - the arguments are cast to long and assigned into the target > > + * registers which are then simply passed as registers to the asm code, > > + * so that we don't have to experience issues with register constraints. > > side-note: > this is actually really tricky. > I've seen cases, where the syscalls were not using the given registers, > because the callers were too complicated and the compiler could not guarantee > to actually use the given register. This is weird. We are using the same pattern for all other architectures, too and so far that worked fine. Was it a compiler bug? (...) > > +#ifndef NOLIBC_NO_RUNTIME > > +/* startup code */ > > +void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) > > +{ > > + __asm__ volatile ( > > + ".import $global$\n" /* Set up the dp register */ > > + "ldil L%$global$, %dp\n" > > + "ldo R%$global$(%r27), %dp\n" > > + > > + "ldo -4(%r24), %r26\n" /* The sp register is special on parisc. > > + * r24 points to argv. Subtract 4 to get &argc. > > + * Pass that as first argument to _start_c. > > + */ > > + > > + "b,n _start_c\n" > > you can change that to "b _start_c\" (without ",n") and move it > one line up before the "ldo -4..." instruction. It's a little bit faster". > The ldo is then in the delay slot. Ack. > > + ); > > + __nolibc_entrypoint_epilogue(); > > +} > > +#endif /* NOLIBC_NO_RUNTIME */ (...) > > QEMU_ARCH_USER_ppc64le = ppc64le > > @@ -199,6 +203,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_parisc32 = -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" > > You could change that to (untested): > QEMU_ARGS_parisc32 = -M B160L -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" -nographic Will try. > > QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA) > > > > # OUTPUT is only set when run from the main makefile, otherwise > > @@ -215,6 +220,7 @@ CFLAGS_i386 = $(call cc-option,-m32) > > CFLAGS_x32 = -mx32 > > CFLAGS_arm = -marm > > CFLAGS_armthumb = -mthumb -march=armv6t2 > > +CFLAGS_parisc32 = -mfast-indirect-calls > > would be good if we could go without this... > But for the beginning it's ok. Why? As nolibc is compiled again for each application, any users which don't want this don't get it. For nolibc-test it avoids a dependency on libgcc. Thomas ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc 2026-04-09 8:38 ` Thomas Weißschuh @ 2026-04-09 11:11 ` Helge Deller 0 siblings, 0 replies; 6+ messages in thread From: Helge Deller @ 2026-04-09 11:11 UTC (permalink / raw) To: Thomas Weißschuh, Helge Deller Cc: Willy Tarreau, linux-kernel, linux-parisc On 4/9/26 10:38, Thomas Weißschuh wrote: > On 2026-04-09 00:15:54+0200, Helge Deller wrote: >> * Thomas Weißschuh <linux@weissschuh.net>: >>> Extend nolibc to target the 32-bit parisc architecture. >>> 64-bit is not yet supported. >>> >>> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net> >>> --- >>> tools/include/nolibc/Makefile | 2 +- >>> tools/include/nolibc/arch-parisc.h | 178 +++++++++++++++++++++++++ >>> tools/include/nolibc/arch.h | 2 + >>> tools/testing/selftests/nolibc/Makefile.nolibc | 6 + >>> tools/testing/selftests/nolibc/run-tests.sh | 8 +- >>> 5 files changed, 194 insertions(+), 2 deletions(-) >>> >>> diff --git a/tools/include/nolibc/Makefile b/tools/include/nolibc/Makefile >>> index 7455097cff69..81187126bf93 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 parisc powerpc riscv s390 sh sparc x86 >>> arch_files := arch.h $(addsuffix .h, $(addprefix arch-, $(architectures))) >>> all_files := \ >>> byteswap.h \ >>> diff --git a/tools/include/nolibc/arch-parisc.h b/tools/include/nolibc/arch-parisc.h >>> new file mode 100644 >>> index 000000000000..8580be5c9c58 >>> --- /dev/null >>> +++ b/tools/include/nolibc/arch-parisc.h >>> @@ -0,0 +1,178 @@ >>> +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ >>> +/* >>> + * parisc/hppa (32-bit) specific definitions for NOLIBC >>> + * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net> >>> + */ >>> + >>> +#ifndef _NOLIBC_ARCH_PARISC_H >>> +#define _NOLIBC_ARCH_PARISC_H >>> + >>> +#if defined(__LP64__) >>> +#error 64-bit not supported >>> +#endif >>> + >>> +#include "compiler.h" >>> +#include "crt.h" >>> + >>> +/* Syscalls for parisc : >>> + * - syscall number is passed in r20 >>> + * - arguments are in r26 to r21 >>> + * - the system call is performed by calling "ble 0x100(%sr2, %r0)", >>> + * the instruction after that is executed first, use it to load the number >> better: >> the instruction after that is in the delay slot and executed before the jump >> to 0x100 actually happens. > > Ack. > >>> + * - syscall return comes in r28 >>> + * - the arguments are cast to long and assigned into the target >>> + * registers which are then simply passed as registers to the asm code, >>> + * so that we don't have to experience issues with register constraints. >> >> side-note: >> this is actually really tricky. >> I've seen cases, where the syscalls were not using the given registers, >> because the callers were too complicated and the compiler could not guarantee >> to actually use the given register. > > This is weird. We are using the same pattern for all other > architectures, too and so far that worked fine. > Was it a compiler bug? No, it can happen if too many registers are in use and if you e.g. hand over arg0 = a+x-z, arg1 = 100-z/3, .... (I mean if you put in multiple calculations). For now I would ignore it. > (...) > >>> +#ifndef NOLIBC_NO_RUNTIME >>> +/* startup code */ >>> +void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) >>> +{ >>> + __asm__ volatile ( >>> + ".import $global$\n" /* Set up the dp register */ >>> + "ldil L%$global$, %dp\n" >>> + "ldo R%$global$(%r27), %dp\n" >>> + >>> + "ldo -4(%r24), %r26\n" /* The sp register is special on parisc. >>> + * r24 points to argv. Subtract 4 to get &argc. >>> + * Pass that as first argument to _start_c. >>> + */ >>> + >>> + "b,n _start_c\n" >> >> you can change that to "b _start_c\" (without ",n") and move it >> one line up before the "ldo -4..." instruction. It's a little bit faster". >> The ldo is then in the delay slot. > > Ack. > >>> + ); >>> + __nolibc_entrypoint_epilogue(); >>> +} >>> +#endif /* NOLIBC_NO_RUNTIME */ > > (...) > >>> QEMU_ARCH_USER_ppc64le = ppc64le >>> @@ -199,6 +203,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_parisc32 = -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)" >> >> You could change that to (untested): >> QEMU_ARGS_parisc32 = -M B160L -append "panic=-1 $(TEST:%=NOLIBC_TEST=%)" -nographic > > Will try. I tried. You are using "-display none" which is nearly the same. The difference is: With "-display none", you will see the output starting when the kernel switches to serial port". With "-nographics" you will see everything from the start of the virtual computer, e.g. BIOS messages, boot loader and initial kernel messages. For your usecase either is OK. >>> QEMU_ARGS = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA) >>> >>> # OUTPUT is only set when run from the main makefile, otherwise >>> @@ -215,6 +220,7 @@ CFLAGS_i386 = $(call cc-option,-m32) >>> CFLAGS_x32 = -mx32 >>> CFLAGS_arm = -marm >>> CFLAGS_armthumb = -mthumb -march=armv6t2 >>> +CFLAGS_parisc32 = -mfast-indirect-calls >> >> would be good if we could go without this... >> But for the beginning it's ok. > > Why? As nolibc is compiled again for each application, any users which > don't want this don't get it. For nolibc-test it avoids a dependency on > libgcc. Yeah, but I think we can avoid libgcc other ways too. I will try once it's upstreamed.. Helge ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-09 11:11 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-08 20:05 [PATCH v3 0/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh 2026-04-08 20:05 ` [PATCH v3 1/2] selftests/nolibc: avoid function pointer comparisons Thomas Weißschuh 2026-04-08 20:05 ` [PATCH v3 2/2] tools/nolibc: add support for 32-bit parisc Thomas Weißschuh 2026-04-08 22:15 ` Helge Deller 2026-04-09 8:38 ` Thomas Weißschuh 2026-04-09 11:11 ` Helge Deller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox