mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-28 09:53:15 -04:00
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:
191
tools/include/nolibc/arch-sparc.h
Normal file
191
tools/include/nolibc/arch-sparc.h
Normal 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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user