]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
tools/nolibc: Add support for SPARC
authorThomas Weißschuh <linux@weissschuh.net>
Wed, 26 Feb 2025 14:05:17 +0000 (15:05 +0100)
committerThomas Weißschuh <linux@weissschuh.net>
Fri, 11 Apr 2025 18:00:20 +0000 (20:00 +0200)
Add support for 32bit and 64bit SPARC to nolibc.

Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
Acked-by: Willy Tarreau <w@1wt.eu>
Tested-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc> # UltraSparc T4 (Niagara4)
Link: https://lore.kernel.org/lkml/20250322-nolibc-sparc-v2-1-89af018c6296@weissschuh.net/
tools/include/nolibc/arch-sparc.h [new file with mode: 0644]
tools/include/nolibc/arch.h
tools/testing/selftests/nolibc/Makefile
tools/testing/selftests/nolibc/run-tests.sh

diff --git a/tools/include/nolibc/arch-sparc.h b/tools/include/nolibc/arch-sparc.h
new file mode 100644 (file)
index 0000000..1435172
--- /dev/null
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
+/*
+ * SPARC (32bit and 64bit) specific definitions for NOLIBC
+ * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
+ */
+
+#ifndef _NOLIBC_ARCH_SPARC_H
+#define _NOLIBC_ARCH_SPARC_H
+
+#include <linux/unistd.h>
+
+#include "compiler.h"
+#include "crt.h"
+
+/*
+ * Syscalls for SPARC:
+ *   - registers are native word size
+ *   - syscall number is passed in g1
+ *   - arguments are in o0-o5
+ *   - the system call is performed by calling a trap instruction
+ *   - syscall return value is in o0
+ *   - syscall error flag is in the carry bit of the processor status register
+ */
+
+#ifdef __arch64__
+
+#define _NOLIBC_SYSCALL "t     0x6d\n"                                       \
+                       "bcs,a  %%xcc, 1f\n"                                  \
+                       "sub    %%g0, %%o0, %%o0\n"                           \
+                       "1:\n"
+
+#else
+
+#define _NOLIBC_SYSCALL "t     0x10\n"                                       \
+                       "bcs,a  1f\n"                                         \
+                       "sub    %%g0, %%o0, %%o0\n"                           \
+                       "1:\n"
+
+#endif /* __arch64__ */
+
+#define my_syscall0(num)                                                      \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0");                                   \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_num)                                                   \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+#define my_syscall1(num, arg1)                                                \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_num)                                                   \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+#define my_syscall2(num, arg1, arg2)                                          \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
+       register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_arg2), "r"(_num)                                       \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+#define my_syscall3(num, arg1, arg2, arg3)                                    \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
+       register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
+       register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_arg2), "r"(_arg3), "r"(_num)                           \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+#define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
+       register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
+       register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
+       register long _arg4 __asm__ ("o3") = (long)(arg4);                    \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_num)               \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
+       register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
+       register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
+       register long _arg4 __asm__ ("o3") = (long)(arg4);                    \
+       register long _arg5 __asm__ ("o4") = (long)(arg5);                    \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_num)   \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
+({                                                                            \
+       register long _num  __asm__ ("g1") = (num);                           \
+       register long _arg1 __asm__ ("o0") = (long)(arg1);                    \
+       register long _arg2 __asm__ ("o1") = (long)(arg2);                    \
+       register long _arg3 __asm__ ("o2") = (long)(arg3);                    \
+       register long _arg4 __asm__ ("o3") = (long)(arg4);                    \
+       register long _arg5 __asm__ ("o4") = (long)(arg5);                    \
+       register long _arg6 __asm__ ("o5") = (long)(arg6);                    \
+                                                                             \
+       __asm__ volatile (                                                    \
+               _NOLIBC_SYSCALL                                               \
+               : "+r"(_arg1)                                                 \
+               : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
+                 "r"(_num)                                                   \
+               : "memory", "cc"                                              \
+       );                                                                    \
+       _arg1;                                                                \
+})
+
+/* startup code */
+void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
+{
+       __asm__ volatile (
+               /*
+                * Save argc pointer to o0, as arg1 of _start_c.
+                * Account for the window save area, which is 16 registers wide.
+                */
+#ifdef __arch64__
+               "add %sp, 128 + 2047, %o0\n" /* on sparc64 / v9 the stack is offset by 2047 */
+#else
+               "add %sp, 64, %o0\n"
+#endif
+               "b,a _start_c\n"     /* transfer to c runtime */
+       );
+       __nolibc_entrypoint_epilogue();
+}
+
+static pid_t getpid(void);
+
+static __attribute__((unused))
+pid_t sys_fork(void)
+{
+       pid_t parent, ret;
+
+       parent = getpid();
+       ret = my_syscall0(__NR_fork);
+
+       /* The syscall returns the parent pid in the child instead of 0 */
+       if (ret == parent)
+               return 0;
+       else
+               return ret;
+}
+#define sys_fork sys_fork
+
+#endif /* _NOLIBC_ARCH_SPARC_H */
index 8a2c143c0fba288147e5a7bf9db38ffb08367616..b8c1da9a88d1593d5a97f60909ede5d0c17699eb 100644 (file)
@@ -33,6 +33,8 @@
 #include "arch-s390.h"
 #elif defined(__loongarch__)
 #include "arch-loongarch.h"
+#elif defined(__sparc__)
+#include "arch-sparc.h"
 #else
 #error Unsupported Architecture
 #endif
index 89ee265f7467e2e5e32edf3eb51b4ec758e8004f..aa05c1faac20d3054b231090b939d050b0231d40 100644 (file)
@@ -56,6 +56,8 @@ ARCH_mips32be    = mips
 ARCH_riscv32     = riscv
 ARCH_riscv64     = riscv
 ARCH_s390x       = s390
+ARCH_sparc32     = sparc
+ARCH_sparc64     = sparc
 ARCH            := $(or $(ARCH_$(XARCH)),$(XARCH))
 
 # kernel image names by architecture
@@ -76,6 +78,8 @@ IMAGE_riscv64    = arch/riscv/boot/Image
 IMAGE_s390x      = arch/s390/boot/bzImage
 IMAGE_s390       = arch/s390/boot/bzImage
 IMAGE_loongarch  = arch/loongarch/boot/vmlinuz.efi
+IMAGE_sparc32    = arch/sparc/boot/image
+IMAGE_sparc64    = arch/sparc/boot/image
 IMAGE            = $(objtree)/$(IMAGE_$(XARCH))
 IMAGE_NAME       = $(notdir $(IMAGE))
 
@@ -97,6 +101,8 @@ DEFCONFIG_riscv64    = defconfig
 DEFCONFIG_s390x      = defconfig
 DEFCONFIG_s390       = defconfig compat.config
 DEFCONFIG_loongarch  = defconfig
+DEFCONFIG_sparc32    = sparc32_defconfig
+DEFCONFIG_sparc64    = sparc64_defconfig
 DEFCONFIG            = $(DEFCONFIG_$(XARCH))
 
 EXTRACONFIG           = $(EXTRACONFIG_$(XARCH))
@@ -122,6 +128,8 @@ QEMU_ARCH_riscv64    = riscv64
 QEMU_ARCH_s390x      = s390x
 QEMU_ARCH_s390       = s390x
 QEMU_ARCH_loongarch  = loongarch64
+QEMU_ARCH_sparc32    = sparc
+QEMU_ARCH_sparc64    = sparc64
 QEMU_ARCH            = $(QEMU_ARCH_$(XARCH))
 
 QEMU_ARCH_USER_ppc64le = ppc64le
@@ -152,6 +160,8 @@ QEMU_ARGS_riscv64    = -M virt -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_T
 QEMU_ARGS_s390x      = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
 QEMU_ARGS_s390       = -M s390-ccw-virtio -append "console=ttyS0 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
 QEMU_ARGS_loongarch  = -M virt -append "console=ttyS0,115200 panic=-1 $(TEST:%=NOLIBC_TEST=%)"
+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            = -m 1G $(QEMU_ARGS_$(XARCH)) $(QEMU_ARGS_BIOS) $(QEMU_ARGS_EXTRA)
 
 # OUTPUT is only set when run from the main makefile, otherwise
@@ -174,6 +184,7 @@ CFLAGS_s390x = -m64
 CFLAGS_s390 = -m31
 CFLAGS_mips32le = -EL -mabi=32 -fPIC
 CFLAGS_mips32be = -EB -mabi=32
+CFLAGS_sparc32 = $(call cc-option,-m32)
 ifeq ($(origin XARCH),command line)
 CFLAGS_XARCH = $(CFLAGS_$(XARCH))
 endif
index 0299a0912d4049dd12217f9835b81d231e1d2bfd..040956a9f5b8dda3e78abc0d4b6073f4fcd9e3ee 100755 (executable)
@@ -25,6 +25,7 @@ all_archs=(
        riscv32 riscv64
        s390x s390
        loongarch
+       sparc32 sparc64
 )
 archs="${all_archs[@]}"
 
@@ -111,6 +112,7 @@ crosstool_arch() {
        loongarch) echo loongarch64;;
        mips*) echo mips;;
        s390*) echo s390;;
+       sparc*) echo sparc64;;
        *) echo "$1";;
        esac
 }