xref: /linux/tools/include/nolibc/arch-loongarch.h (revision 2dca615ade6765404607a9cfe4db648d9263d975)
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"
11818924d1SThomas Weißschuh 
1273f12c6dSFeiyang Chen /* Syscalls for LoongArch :
1373f12c6dSFeiyang Chen  *   - stack is 16-byte aligned
1473f12c6dSFeiyang Chen  *   - syscall number is passed in a7
1573f12c6dSFeiyang Chen  *   - arguments are in a0, a1, a2, a3, a4, a5
1673f12c6dSFeiyang Chen  *   - the system call is performed by calling "syscall 0"
1773f12c6dSFeiyang Chen  *   - syscall return comes in a0
1873f12c6dSFeiyang Chen  *   - the arguments are cast to long and assigned into the target
1973f12c6dSFeiyang Chen  *     registers which are then simply passed as registers to the asm code,
2073f12c6dSFeiyang Chen  *     so that we don't have to experience issues with register constraints.
2173f12c6dSFeiyang Chen  *
2273f12c6dSFeiyang Chen  * On LoongArch, select() is not implemented so we have to use pselect6().
2373f12c6dSFeiyang Chen  */
2473f12c6dSFeiyang Chen #define __ARCH_WANT_SYS_PSELECT6
25*2dca615aSZhangjin Wu #define _NOLIBC_SYSCALL_CLOBBERLIST \
26*2dca615aSZhangjin Wu 	"memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8"
2773f12c6dSFeiyang Chen 
2873f12c6dSFeiyang Chen #define my_syscall0(num)                                                      \
2973f12c6dSFeiyang Chen ({                                                                            \
3073f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
3173f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0");                                   \
3273f12c6dSFeiyang Chen 									      \
3373f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
3473f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
3573f12c6dSFeiyang Chen 		: "=r"(_arg1)                                                 \
3673f12c6dSFeiyang Chen 		: "r"(_num)                                                   \
37*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
3873f12c6dSFeiyang Chen 	);                                                                    \
3973f12c6dSFeiyang Chen 	_arg1;                                                                \
4073f12c6dSFeiyang Chen })
4173f12c6dSFeiyang Chen 
4273f12c6dSFeiyang Chen #define my_syscall1(num, arg1)                                                \
4373f12c6dSFeiyang Chen ({                                                                            \
4473f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
4573f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);		      \
4673f12c6dSFeiyang Chen 									      \
4773f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
4873f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
4973f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
5073f12c6dSFeiyang Chen 		: "r"(_num)                                                   \
51*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
5273f12c6dSFeiyang Chen 	);                                                                    \
5373f12c6dSFeiyang Chen 	_arg1;                                                                \
5473f12c6dSFeiyang Chen })
5573f12c6dSFeiyang Chen 
5673f12c6dSFeiyang Chen #define my_syscall2(num, arg1, arg2)                                          \
5773f12c6dSFeiyang Chen ({                                                                            \
5873f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
5973f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
6073f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
6173f12c6dSFeiyang Chen 									      \
6273f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
6373f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
6473f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
6573f12c6dSFeiyang Chen 		: "r"(_arg2),                                                 \
6673f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
67*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
6873f12c6dSFeiyang Chen 	);                                                                    \
6973f12c6dSFeiyang Chen 	_arg1;                                                                \
7073f12c6dSFeiyang Chen })
7173f12c6dSFeiyang Chen 
7273f12c6dSFeiyang Chen #define my_syscall3(num, arg1, arg2, arg3)                                    \
7373f12c6dSFeiyang Chen ({                                                                            \
7473f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
7573f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
7673f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
7773f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
7873f12c6dSFeiyang Chen 									      \
7973f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
8073f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
8173f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
8273f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3),                                     \
8373f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
84*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
8573f12c6dSFeiyang Chen 	);                                                                    \
8673f12c6dSFeiyang Chen 	_arg1;                                                                \
8773f12c6dSFeiyang Chen })
8873f12c6dSFeiyang Chen 
8973f12c6dSFeiyang Chen #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
9073f12c6dSFeiyang Chen ({                                                                            \
9173f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
9273f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
9373f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
9473f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
9573f12c6dSFeiyang Chen 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
9673f12c6dSFeiyang Chen 									      \
9773f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
9873f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
9973f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
10073f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3), "r"(_arg4),                         \
10173f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
102*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
10373f12c6dSFeiyang Chen 	);                                                                    \
10473f12c6dSFeiyang Chen 	_arg1;                                                                \
10573f12c6dSFeiyang Chen })
10673f12c6dSFeiyang Chen 
10773f12c6dSFeiyang Chen #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
10873f12c6dSFeiyang Chen ({                                                                            \
10973f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
11073f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
11173f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
11273f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
11373f12c6dSFeiyang Chen 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
11473f12c6dSFeiyang Chen 	register long _arg5 __asm__ ("a4") = (long)(arg5);                    \
11573f12c6dSFeiyang Chen 									      \
11673f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
11773f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
11873f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
11973f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5),             \
12073f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
121*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
12273f12c6dSFeiyang Chen 	);                                                                    \
12373f12c6dSFeiyang Chen 	_arg1;                                                                \
12473f12c6dSFeiyang Chen })
12573f12c6dSFeiyang Chen 
12673f12c6dSFeiyang Chen #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
12773f12c6dSFeiyang Chen ({                                                                            \
12873f12c6dSFeiyang Chen 	register long _num  __asm__ ("a7") = (num);                           \
12973f12c6dSFeiyang Chen 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
13073f12c6dSFeiyang Chen 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
13173f12c6dSFeiyang Chen 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
13273f12c6dSFeiyang Chen 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
13373f12c6dSFeiyang Chen 	register long _arg5 __asm__ ("a4") = (long)(arg5);                    \
13473f12c6dSFeiyang Chen 	register long _arg6 __asm__ ("a5") = (long)(arg6);                    \
13573f12c6dSFeiyang Chen 									      \
13673f12c6dSFeiyang Chen 	__asm__ volatile (                                                    \
13773f12c6dSFeiyang Chen 		"syscall 0\n"                                                 \
13873f12c6dSFeiyang Chen 		: "+r"(_arg1)                                                 \
13973f12c6dSFeiyang Chen 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
14073f12c6dSFeiyang Chen 		  "r"(_num)                                                   \
141*2dca615aSZhangjin Wu 		: _NOLIBC_SYSCALL_CLOBBERLIST                                 \
14273f12c6dSFeiyang Chen 	);                                                                    \
14373f12c6dSFeiyang Chen 	_arg1;                                                                \
14473f12c6dSFeiyang Chen })
14573f12c6dSFeiyang Chen 
14673f12c6dSFeiyang Chen char **environ __attribute__((weak));
14773f12c6dSFeiyang Chen const unsigned long *_auxv __attribute__((weak));
14873f12c6dSFeiyang Chen 
14973f12c6dSFeiyang Chen #if __loongarch_grlen == 32
15073f12c6dSFeiyang Chen #define LONGLOG      "2"
15173f12c6dSFeiyang Chen #define SZREG        "4"
15273f12c6dSFeiyang Chen #define REG_L        "ld.w"
15373f12c6dSFeiyang Chen #define LONG_S       "st.w"
15473f12c6dSFeiyang Chen #define LONG_ADD     "add.w"
15573f12c6dSFeiyang Chen #define LONG_ADDI    "addi.w"
15673f12c6dSFeiyang Chen #define LONG_SLL     "slli.w"
15773f12c6dSFeiyang Chen #define LONG_BSTRINS "bstrins.w"
158fddc8f81SThomas Weißschuh #else /* __loongarch_grlen == 64 */
15973f12c6dSFeiyang Chen #define LONGLOG      "3"
16073f12c6dSFeiyang Chen #define SZREG        "8"
16173f12c6dSFeiyang Chen #define REG_L        "ld.d"
16273f12c6dSFeiyang Chen #define LONG_S       "st.d"
16373f12c6dSFeiyang Chen #define LONG_ADD     "add.d"
16473f12c6dSFeiyang Chen #define LONG_ADDI    "addi.d"
16573f12c6dSFeiyang Chen #define LONG_SLL     "slli.d"
16673f12c6dSFeiyang Chen #define LONG_BSTRINS "bstrins.d"
16773f12c6dSFeiyang Chen #endif
16873f12c6dSFeiyang Chen 
16973f12c6dSFeiyang Chen /* startup code */
170e76b70deSThomas Weißschuh void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
17173f12c6dSFeiyang Chen {
17273f12c6dSFeiyang Chen 	__asm__ volatile (
173818924d1SThomas Weißschuh #ifdef _NOLIBC_STACKPROTECTOR
174ca2d0437SThomas Weißschuh 		"bl __stack_chk_init\n"               /* initialize stack protector                          */
175ca2d0437SThomas Weißschuh #endif
176fddc8f81SThomas Weißschuh 		REG_L        " $a0, $sp, 0\n"         /* argc (a0) was in the stack                          */
177fddc8f81SThomas Weißschuh 		LONG_ADDI    " $a1, $sp, "SZREG"\n"   /* argv (a1) = sp + SZREG                              */
178fddc8f81SThomas Weißschuh 		LONG_SLL     " $a2, $a0, "LONGLOG"\n" /* envp (a2) = SZREG*argc ...                          */
179fddc8f81SThomas Weißschuh 		LONG_ADDI    " $a2, $a2, "SZREG"\n"   /*             + SZREG (skip null)                     */
180fddc8f81SThomas Weißschuh 		LONG_ADD     " $a2, $a2, $a1\n"       /*             + argv                                  */
18173f12c6dSFeiyang Chen 
182fddc8f81SThomas Weißschuh 		"move          $a3, $a2\n"            /* iterate a3 over envp to find auxv (after NULL)      */
183fddc8f81SThomas Weißschuh 		"0:\n"                                /* do {                                                */
184fddc8f81SThomas Weißschuh 		REG_L        " $a4, $a3, 0\n"         /*   a4 = *a3;                                         */
185fddc8f81SThomas Weißschuh 		LONG_ADDI    " $a3, $a3, "SZREG"\n"   /*   a3 += sizeof(void*);                              */
186fddc8f81SThomas Weißschuh 		"bne           $a4, $zero, 0b\n"      /* } while (a4);                                       */
187fddc8f81SThomas Weißschuh 		"la.pcrel      $a4, _auxv\n"          /* a4 = &_auxv                                         */
188fddc8f81SThomas Weißschuh 		LONG_S       " $a3, $a4, 0\n"         /* store a3 into _auxv                                 */
18973f12c6dSFeiyang Chen 
190fddc8f81SThomas Weißschuh 		"la.pcrel      $a3, environ\n"        /* a3 = &environ                                       */
191fddc8f81SThomas Weißschuh 		LONG_S       " $a2, $a3, 0\n"         /* store envp(a2) into environ                         */
192fddc8f81SThomas Weißschuh 		LONG_BSTRINS " $sp, $zero, 3, 0\n"    /* sp must be 16-byte aligned                          */
193fddc8f81SThomas Weißschuh 		"bl            main\n"                /* main() returns the status code, we'll exit with it. */
194fddc8f81SThomas Weißschuh 		"li.w          $a7, 93\n"             /* NR_exit == 93                                       */
19573f12c6dSFeiyang Chen 		"syscall       0\n"
19673f12c6dSFeiyang Chen 	);
19773f12c6dSFeiyang Chen 	__builtin_unreachable();
19873f12c6dSFeiyang Chen }
19973f12c6dSFeiyang Chen 
200fddc8f81SThomas Weißschuh #endif /* _NOLIBC_ARCH_LOONGARCH_H */
201