tools/nolibc: Add support for SPARC

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/
This commit is contained in:
Thomas Weißschuh
2025-02-26 15:05:17 +01:00
parent fd293cb81a
commit 8e1930296f
4 changed files with 206 additions and 0 deletions

View File

@@ -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 */

View 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

View 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

View File

@@ -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
}