173f12c6dSFeiyang Chen /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
273f12c6dSFeiyang Chen /*
373f12c6dSFeiyang Chen  * LoongArch specific definitions for NOLIBC
473f12c6dSFeiyang Chen  * Copyright (C) 2023 Loongson Technology Corporation Limited
573f12c6dSFeiyang Chen  */
673f12c6dSFeiyang Chen 
773f12c6dSFeiyang Chen #ifndef _NOLIBC_ARCH_LOONGARCH_H
873f12c6dSFeiyang Chen #define _NOLIBC_ARCH_LOONGARCH_H
973f12c6dSFeiyang Chen 
10818924d1SThomas Weißschuh #include "compiler.h"
11*61bd4621SZhangjin Wu #include "crt.h"
12818924d1SThomas Weißschuh 
1373f12c6dSFeiyang Chen /* Syscalls for LoongArch :
1473f12c6dSFeiyang Chen  *   - stack is 16-byte aligned
1573f12c6dSFeiyang Chen  *   - syscall number is passed in a7
1673f12c6dSFeiyang Chen  *   - arguments are in a0, a1, a2, a3, a4, a5
1773f12c6dSFeiyang Chen  *   - the system call is performed by calling "syscall 0"
1873f12c6dSFeiyang Chen  *   - syscall return comes in a0
1973f12c6dSFeiyang Chen  *   - the arguments are cast to long and assigned into the target
2073f12c6dSFeiyang Chen  *     registers which are then simply passed as registers to the asm code,
2173f12c6dSFeiyang Chen  *     so that we don't have to experience issues with register constraints.
2273f12c6dSFeiyang Chen  *
2373f12c6dSFeiyang Chen  * On LoongArch, select() is not implemented so we have to use pselect6().
2473f12c6dSFeiyang Chen  */
2573f12c6dSFeiyang Chen #define __ARCH_WANT_SYS_PSELECT6
262dca615aSZhangjin Wu #define _NOLIBC_SYSCALL_CLOBBERLIST \
272dca615aSZhangjin Wu 	"memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8"
2873f12c6dSFeiyang Chen 
2973f12c6dSFeiyang Chen #define my_syscall0(num)                                                      \
3073f12c6dSFeiyang Chen ({                                                                            \
3173f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
3273f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0");                                   \
3373f12c6dSFeiyang Chen 									      \
3473f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
3573f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
3673f12c6dSFeiyang Chen 		: "=r"(_arg1)                                                 \
3773f12c6dSFeiyang Chen 		: "r"(_num)                                                   \
382dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
3973f12c6dSFeiyang Chen 	);                                                                    \
4073f12c6dSFeiyang Chen 	_arg1;                                                                \
4173f12c6dSFeiyang Chen })
4273f12c6dSFeiyang Chen 
4373f12c6dSFeiyang Chen #define my_syscall1(num, arg1)                                                \
4473f12c6dSFeiyang Chen ({                                                                            \
4573f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
4673f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);		      \
4773f12c6dSFeiyang Chen 									      \
4873f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
4973f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
5073f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
5173f12c6dSFeiyang Chen 		: "r"(_num)                                                   \
522dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
5373f12c6dSFeiyang Chen 	);                                                                    \
5473f12c6dSFeiyang Chen 	_arg1;                                                                \
5573f12c6dSFeiyang Chen })
5673f12c6dSFeiyang Chen 
5773f12c6dSFeiyang Chen #define my_syscall2(num, arg1, arg2)                                          \
5873f12c6dSFeiyang Chen ({                                                                            \
5973f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
6073f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
6173f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
6273f12c6dSFeiyang Chen 									      \
6373f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
6473f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
6573f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
6673f12c6dSFeiyang Chen 		: "r"(_arg2),                                                 \
6773f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
682dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
6973f12c6dSFeiyang Chen 	);                                                                    \
7073f12c6dSFeiyang Chen 	_arg1;                                                                \
7173f12c6dSFeiyang Chen })
7273f12c6dSFeiyang Chen 
7373f12c6dSFeiyang Chen #define my_syscall3(num, arg1, arg2, arg3)                                    \
7473f12c6dSFeiyang Chen ({                                                                            \
7573f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
7673f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
7773f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
7873f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
7973f12c6dSFeiyang Chen 									      \
8073f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
8173f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
8273f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
8373f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3),                                     \
8473f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
852dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
8673f12c6dSFeiyang Chen 	);                                                                    \
8773f12c6dSFeiyang Chen 	_arg1;                                                                \
8873f12c6dSFeiyang Chen })
8973f12c6dSFeiyang Chen 
9073f12c6dSFeiyang Chen #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
9173f12c6dSFeiyang Chen ({                                                                            \
9273f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
9373f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
9473f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
9573f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
9673f12c6dSFeiyang Chen 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
9773f12c6dSFeiyang Chen 									      \
9873f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
9973f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
10073f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
10173f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3), "r"(_arg4),                         \
10273f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
1032dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
10473f12c6dSFeiyang Chen 	);                                                                    \
10573f12c6dSFeiyang Chen 	_arg1;                                                                \
10673f12c6dSFeiyang Chen })
10773f12c6dSFeiyang Chen 
10873f12c6dSFeiyang Chen #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
10973f12c6dSFeiyang Chen ({                                                                            \
11073f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
11173f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
11273f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
11373f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
11473f12c6dSFeiyang Chen 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
11573f12c6dSFeiyang Chen 	register long _arg5 __asm__ ("a4") = (long)(arg5);                    \
11673f12c6dSFeiyang Chen 									      \
11773f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
11873f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
11973f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
12073f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5),             \
12173f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
1222dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
12373f12c6dSFeiyang Chen 	);                                                                    \
12473f12c6dSFeiyang Chen 	_arg1;                                                                \
12573f12c6dSFeiyang Chen })
12673f12c6dSFeiyang Chen 
12773f12c6dSFeiyang Chen #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
12873f12c6dSFeiyang Chen ({                                                                            \
12973f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
13073f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
13173f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
13273f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
13373f12c6dSFeiyang Chen 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
13473f12c6dSFeiyang Chen 	register long _arg5 __asm__ ("a4") = (long)(arg5);                    \
13573f12c6dSFeiyang Chen 	register long _arg6 __asm__ ("a5") = (long)(arg6);                    \
13673f12c6dSFeiyang Chen 									      \
13773f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
13873f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
13973f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
14073f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
14173f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
1422dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
14373f12c6dSFeiyang Chen 	);                                                                    \
14473f12c6dSFeiyang Chen 	_arg1;                                                                \
14573f12c6dSFeiyang Chen })
14673f12c6dSFeiyang Chen 
14773f12c6dSFeiyang Chen #if __loongarch_grlen == 32
14873f12c6dSFeiyang Chen #define LONG_BSTRINS "bstrins.w"
149fddc8f81SThomas Weißschuh #else /* __loongarch_grlen == 64 */
15073f12c6dSFeiyang Chen #define LONG_BSTRINS "bstrins.d"
15173f12c6dSFeiyang Chen #endif
15273f12c6dSFeiyang Chen 
15373f12c6dSFeiyang Chen /* startup code */
_start(void)154bff60150SZhangjin Wu void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
15573f12c6dSFeiyang Chen {
15673f12c6dSFeiyang Chen 	__asm__ volatile (
157*61bd4621SZhangjin Wu 		"move          $a0, $sp\n"         /* save stack pointer to $a0, as arg1 of _start_c */
158*61bd4621SZhangjin Wu 		LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned                    */
159*61bd4621SZhangjin Wu 		"bl            _start_c\n"         /* transfer to c runtime                          */
16073f12c6dSFeiyang Chen 	);
16173f12c6dSFeiyang Chen 	__builtin_unreachable();
16273f12c6dSFeiyang Chen }
16373f12c6dSFeiyang Chen 
164fddc8f81SThomas Weißschuh #endif /* _NOLIBC_ARCH_LOONGARCH_H */
165