lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250713-nolibc-alpha-v1-1-10216333d308@weissschuh.net>
Date: Sun, 13 Jul 2025 22:08:08 +0200
From: Thomas Weißschuh <linux@...ssschuh.net>
To: Willy Tarreau <w@....eu>, Shuah Khan <shuah@...nel.org>, 
 Richard Henderson <richard.henderson@...aro.org>, 
 Matt Turner <mattst88@...il.com>
Cc: linux-kernel@...r.kernel.org, linux-kselftest@...r.kernel.org, 
 linux-alpha@...r.kernel.org, Arnd Bergmann <arnd@...db.de>, 
 John Paul Adrian Glaubitz <glaubitz@...sik.fu-berlin.de>, 
 Thomas Weißschuh <linux@...ssschuh.net>
Subject: [PATCH] tools/nolibc: add support for Alpha

A straightforward new architecture.

Signed-off-by: Thomas Weißschuh <linux@...ssschuh.net>
---
Only tested on QEMU so far.
Testing on real hardware would be very welcome.

Test instructions:
$ cd tools/testings/selftests/nolibc/
$ make -f Makefile.nolibc ARCH=alpha CROSS_COMPILE=alpha-linux- nolibc-test
$ file nolibc-test
nolibc-test: ELF 64-bit LSB executable, Alpha (unofficial), version 1 (SYSV), statically linked, not stripped
$ ./nolibc-test
Running test 'startup'
0 argc = 1                                                        [OK]
...
Total number of errors: 0
Exiting with status 0
---
 tools/include/nolibc/arch-alpha.h              | 164 +++++++++++++++++++++++++
 tools/include/nolibc/arch.h                    |   2 +
 tools/testing/selftests/nolibc/Makefile.nolibc |   5 +
 tools/testing/selftests/nolibc/nolibc-test.c   |   4 +
 tools/testing/selftests/nolibc/run-tests.sh    |   3 +-
 5 files changed, 177 insertions(+), 1 deletion(-)

diff --git a/tools/include/nolibc/arch-alpha.h b/tools/include/nolibc/arch-alpha.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b9bb6c749b931f30ce7bd6cd125622828405604
--- /dev/null
+++ b/tools/include/nolibc/arch-alpha.h
@@ -0,0 +1,164 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * Alpha specific definitions for NOLIBC
+ * Copyright (C) 2025 Thomas Weißschuh <linux@...ssschuh.net>
+ */
+
+#ifndef _NOLIBC_ARCH_ALPHA_H
+#define _NOLIBC_ARCH_ALPHA_H
+
+#include "compiler.h"
+#include "crt.h"
+
+/*
+ * Syscalls for Alpha:
+ *   - registers are 64-bit
+ *   - syscall number is passed in $0/v0
+ *   - the system call is performed by calling callsys
+ *   - syscall return comes in $0/v0, error flag in $19/a4
+ *   - arguments are passed in $16/a0 to $21/a5
+ *   - GCC does not support symbol register names
+ */
+
+#define my_syscall0(num)                                                      \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num)                                                   \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+#define my_syscall1(num, arg1)                                                \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+	register long _arg1 __asm__ ("$16") = (long)(arg1);                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num), "r"(_arg1)                                       \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+#define my_syscall2(num, arg1, arg2)                                          \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+	register long _arg1 __asm__ ("$16") = (long)(arg1);                   \
+	register long _arg2 __asm__ ("$17") = (long)(arg2);                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num), "r"(_arg1), "r"(_arg2)                           \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+#define my_syscall3(num, arg1, arg2, arg3)                                    \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+	register long _arg1 __asm__ ("$16") = (long)(arg1);                   \
+	register long _arg2 __asm__ ("$17") = (long)(arg2);                   \
+	register long _arg3 __asm__ ("$18") = (long)(arg3);                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3)               \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+	register long _arg1 __asm__ ("$16") = (long)(arg1);                   \
+	register long _arg2 __asm__ ("$17") = (long)(arg2);                   \
+	register long _arg3 __asm__ ("$18") = (long)(arg3);                   \
+	register long _arg4 __asm__ ("$19") = (long)(arg4);                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4)   \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+	register long _arg1 __asm__ ("$16") = (long)(arg1);                   \
+	register long _arg2 __asm__ ("$17") = (long)(arg2);                   \
+	register long _arg3 __asm__ ("$18") = (long)(arg3);                   \
+	register long _arg4 __asm__ ("$19") = (long)(arg4);                   \
+	register long _arg5 __asm__ ("$20") = (long)(arg5);                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),  \
+		  "r"(_arg5)                                                  \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
+({                                                                            \
+	register long _num __asm__ ("$0") = (num);                            \
+	register long _ret __asm__ ("$0");                                    \
+	register long _err __asm__ ("$19");                                   \
+	register long _arg1 __asm__ ("$16") = (long)(arg1);                   \
+	register long _arg2 __asm__ ("$17") = (long)(arg2);                   \
+	register long _arg3 __asm__ ("$18") = (long)(arg3);                   \
+	register long _arg4 __asm__ ("$19") = (long)(arg4);                   \
+	register long _arg5 __asm__ ("$20") = (long)(arg5);                   \
+	register long _arg6 __asm__ ("$21") = (long)(arg6);                   \
+									      \
+	__asm__ volatile (                                                    \
+		"callsys"                                                     \
+		: "=r"(_ret), "=r"(_err)                                      \
+		: "r"(_num), "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),  \
+		  "r"(_arg5), "r"(_arg6)                                      \
+		: "memory", "cc"                                              \
+	);                                                                    \
+	_err ? -_ret : _ret;                                                  \
+})
+
+/* startup code */
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+{
+	__asm__ volatile (
+		"br $gp, 0f\n"               /* setup $gp, so that 'lda' works                */
+		"0: ldgp $gp, 0($gp)\n"
+		"lda $27, _start_c\n"        /* setup current function address for _start_c   */
+		"mov $sp, $16\n"             /* save argc pointer to $16, as arg1 of _start_c */
+		"br  _start_c\n"             /* transfer to c runtime                         */
+	);
+	__nolibc_entrypoint_epilogue();
+}
+
+#endif /* _NOLIBC_ARCH_ALPHA_H */
diff --git a/tools/include/nolibc/arch.h b/tools/include/nolibc/arch.h
index 426c89198135564acca44c485e5c2d8ba36a6fe9..72585d4c04e2896a275faadf881e98286f914fb3 100644
--- a/tools/include/nolibc/arch.h
+++ b/tools/include/nolibc/arch.h
@@ -37,6 +37,8 @@
 #include "arch-m68k.h"
 #elif defined(__sh__)
 #include "arch-sh.h"
+#elif defined(__alpha__)
+#include "arch-alpha.h"
 #else
 #error Unsupported Architecture
 #endif
diff --git a/tools/testing/selftests/nolibc/Makefile.nolibc b/tools/testing/selftests/nolibc/Makefile.nolibc
index 0fb759ba992ee6b1693b88f1b2e77463afa9f38b..0da33fe99bd630ec5100b5beed939d524af2b3d4 100644
--- a/tools/testing/selftests/nolibc/Makefile.nolibc
+++ b/tools/testing/selftests/nolibc/Makefile.nolibc
@@ -93,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_alpha      = vmlinux
 IMAGE            = $(objtree)/$(IMAGE_$(XARCH))
 IMAGE_NAME       = $(notdir $(IMAGE))
 
@@ -123,6 +124,7 @@ DEFCONFIG_sparc32    = sparc32_defconfig
 DEFCONFIG_sparc64    = sparc64_defconfig
 DEFCONFIG_m68k       = virt_defconfig
 DEFCONFIG_sh4        = rts7751r2dplus_defconfig
+DEFCONFIG_alpha      = defconfig
 DEFCONFIG            = $(DEFCONFIG_$(XARCH))
 
 EXTRACONFIG_x32       = -e CONFIG_X86_X32_ABI
@@ -130,6 +132,7 @@ 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_alpha     = -e CONFIG_BLK_DEV_INITRD
 EXTRACONFIG           = $(EXTRACONFIG_$(XARCH))
 
 # optional tests to run (default = all)
@@ -162,6 +165,7 @@ QEMU_ARCH_sparc32    = sparc
 QEMU_ARCH_sparc64    = sparc64
 QEMU_ARCH_m68k       = m68k
 QEMU_ARCH_sh4        = sh4
+QEMU_ARCH_alpha      = alpha
 QEMU_ARCH            = $(QEMU_ARCH_$(XARCH))
 
 QEMU_ARCH_USER_ppc64le = ppc64le
@@ -203,6 +207,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_alpha      = -M clipper -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
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index a297ee0d6d0754dfcd9f9e5609d42c7442dabc4e..bbbb2a485f220fed69556baaf2603d9cf24a1c36 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -709,6 +709,10 @@ int run_startup(int min, int max)
 	/* checking NULL for argv/argv0, environ and _auxv is not enough, let's compare with sbrk(0) or &end */
 	extern char end;
 	char *brk = sbrk(0) != (void *)-1 ? sbrk(0) : &end;
+#if defined(__alpha__)
+	/* the ordering above does not work on an alpha kernel */
+	brk = NULL;
+#endif
 	/* differ from nolibc, both glibc and musl have no global _auxv */
 	const unsigned long *test_auxv = (void *)-1;
 #ifdef NOLIBC
diff --git a/tools/testing/selftests/nolibc/run-tests.sh b/tools/testing/selftests/nolibc/run-tests.sh
index e8af1fb505cf3573b4a6b37228dee764fe2e5277..8ce57d7006594c531f471d777d579c4f08d87efe 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
+	alpha
 )
 archs="${all_archs[@]}"
 
@@ -189,7 +190,7 @@ test_arch() {
 		echo "Unsupported configuration"
 		return
 	fi
-	if [ "$arch" = "m68k" -o "$arch" = "sh4" ] && [ "$llvm" = "1" ]; then
+	if [ "$arch" = "m68k" -o "$arch" = "sh4" -o "$arch" = "alpha" ] && [ "$llvm" = "1" ]; then
 		echo "Unsupported configuration"
 		return
 	fi

---
base-commit: b9e50363178a40c76bebaf2f00faa2b0b6baf8d1
change-id: 20250609-nolibc-alpha-33e79644544c

Best regards,
-- 
Thomas Weißschuh <linux@...ssschuh.net>


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ