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