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" 1161bd4621SZhangjin 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 */ 23eaa8c9a8SThomas Weißschuh 242dca615aSZhangjin Wu #define _NOLIBC_SYSCALL_CLOBBERLIST \ 252dca615aSZhangjin Wu "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8" 2673f12c6dSFeiyang Chen 2773f12c6dSFeiyang Chen #define my_syscall0(num) \ 2873f12c6dSFeiyang Chen ({ \ 2973f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 3073f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0"); \ 3173f12c6dSFeiyang Chen \ 3273f12c6dSFeiyang Chen __asm__ volatile ( \ 3373f12c6dSFeiyang Chen "syscall 0\n" \ 3473f12c6dSFeiyang Chen : "=r"(_arg1) \ 3573f12c6dSFeiyang Chen : "r"(_num) \ 362dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 3773f12c6dSFeiyang Chen ); \ 3873f12c6dSFeiyang Chen _arg1; \ 3973f12c6dSFeiyang Chen }) 4073f12c6dSFeiyang Chen 4173f12c6dSFeiyang Chen #define my_syscall1(num, arg1) \ 4273f12c6dSFeiyang Chen ({ \ 4373f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 4473f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0") = (long)(arg1); \ 4573f12c6dSFeiyang Chen \ 4673f12c6dSFeiyang Chen __asm__ volatile ( \ 4773f12c6dSFeiyang Chen "syscall 0\n" \ 4873f12c6dSFeiyang Chen : "+r"(_arg1) \ 4973f12c6dSFeiyang Chen : "r"(_num) \ 502dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 5173f12c6dSFeiyang Chen ); \ 5273f12c6dSFeiyang Chen _arg1; \ 5373f12c6dSFeiyang Chen }) 5473f12c6dSFeiyang Chen 5573f12c6dSFeiyang Chen #define my_syscall2(num, arg1, arg2) \ 5673f12c6dSFeiyang Chen ({ \ 5773f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 5873f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0") = (long)(arg1); \ 5973f12c6dSFeiyang Chen register long _arg2 __asm__ ("a1") = (long)(arg2); \ 6073f12c6dSFeiyang Chen \ 6173f12c6dSFeiyang Chen __asm__ volatile ( \ 6273f12c6dSFeiyang Chen "syscall 0\n" \ 6373f12c6dSFeiyang Chen : "+r"(_arg1) \ 6473f12c6dSFeiyang Chen : "r"(_arg2), \ 6573f12c6dSFeiyang Chen "r"(_num) \ 662dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 6773f12c6dSFeiyang Chen ); \ 6873f12c6dSFeiyang Chen _arg1; \ 6973f12c6dSFeiyang Chen }) 7073f12c6dSFeiyang Chen 7173f12c6dSFeiyang Chen #define my_syscall3(num, arg1, arg2, arg3) \ 7273f12c6dSFeiyang Chen ({ \ 7373f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 7473f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0") = (long)(arg1); \ 7573f12c6dSFeiyang Chen register long _arg2 __asm__ ("a1") = (long)(arg2); \ 7673f12c6dSFeiyang Chen register long _arg3 __asm__ ("a2") = (long)(arg3); \ 7773f12c6dSFeiyang Chen \ 7873f12c6dSFeiyang Chen __asm__ volatile ( \ 7973f12c6dSFeiyang Chen "syscall 0\n" \ 8073f12c6dSFeiyang Chen : "+r"(_arg1) \ 8173f12c6dSFeiyang Chen : "r"(_arg2), "r"(_arg3), \ 8273f12c6dSFeiyang Chen "r"(_num) \ 832dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 8473f12c6dSFeiyang Chen ); \ 8573f12c6dSFeiyang Chen _arg1; \ 8673f12c6dSFeiyang Chen }) 8773f12c6dSFeiyang Chen 8873f12c6dSFeiyang Chen #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 8973f12c6dSFeiyang Chen ({ \ 9073f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 9173f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0") = (long)(arg1); \ 9273f12c6dSFeiyang Chen register long _arg2 __asm__ ("a1") = (long)(arg2); \ 9373f12c6dSFeiyang Chen register long _arg3 __asm__ ("a2") = (long)(arg3); \ 9473f12c6dSFeiyang Chen register long _arg4 __asm__ ("a3") = (long)(arg4); \ 9573f12c6dSFeiyang Chen \ 9673f12c6dSFeiyang Chen __asm__ volatile ( \ 9773f12c6dSFeiyang Chen "syscall 0\n" \ 9873f12c6dSFeiyang Chen : "+r"(_arg1) \ 9973f12c6dSFeiyang Chen : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 10073f12c6dSFeiyang Chen "r"(_num) \ 1012dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 10273f12c6dSFeiyang Chen ); \ 10373f12c6dSFeiyang Chen _arg1; \ 10473f12c6dSFeiyang Chen }) 10573f12c6dSFeiyang Chen 10673f12c6dSFeiyang Chen #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 10773f12c6dSFeiyang Chen ({ \ 10873f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 10973f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0") = (long)(arg1); \ 11073f12c6dSFeiyang Chen register long _arg2 __asm__ ("a1") = (long)(arg2); \ 11173f12c6dSFeiyang Chen register long _arg3 __asm__ ("a2") = (long)(arg3); \ 11273f12c6dSFeiyang Chen register long _arg4 __asm__ ("a3") = (long)(arg4); \ 11373f12c6dSFeiyang Chen register long _arg5 __asm__ ("a4") = (long)(arg5); \ 11473f12c6dSFeiyang Chen \ 11573f12c6dSFeiyang Chen __asm__ volatile ( \ 11673f12c6dSFeiyang Chen "syscall 0\n" \ 11773f12c6dSFeiyang Chen : "+r"(_arg1) \ 11873f12c6dSFeiyang Chen : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 11973f12c6dSFeiyang Chen "r"(_num) \ 1202dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 12173f12c6dSFeiyang Chen ); \ 12273f12c6dSFeiyang Chen _arg1; \ 12373f12c6dSFeiyang Chen }) 12473f12c6dSFeiyang Chen 12573f12c6dSFeiyang Chen #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 12673f12c6dSFeiyang Chen ({ \ 12773f12c6dSFeiyang Chen register long _num __asm__ ("a7") = (num); \ 12873f12c6dSFeiyang Chen register long _arg1 __asm__ ("a0") = (long)(arg1); \ 12973f12c6dSFeiyang Chen register long _arg2 __asm__ ("a1") = (long)(arg2); \ 13073f12c6dSFeiyang Chen register long _arg3 __asm__ ("a2") = (long)(arg3); \ 13173f12c6dSFeiyang Chen register long _arg4 __asm__ ("a3") = (long)(arg4); \ 13273f12c6dSFeiyang Chen register long _arg5 __asm__ ("a4") = (long)(arg5); \ 13373f12c6dSFeiyang Chen register long _arg6 __asm__ ("a5") = (long)(arg6); \ 13473f12c6dSFeiyang Chen \ 13573f12c6dSFeiyang Chen __asm__ volatile ( \ 13673f12c6dSFeiyang Chen "syscall 0\n" \ 13773f12c6dSFeiyang Chen : "+r"(_arg1) \ 13873f12c6dSFeiyang Chen : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 13973f12c6dSFeiyang Chen "r"(_num) \ 1402dca615aSZhangjin Wu : _NOLIBC_SYSCALL_CLOBBERLIST \ 14173f12c6dSFeiyang Chen ); \ 14273f12c6dSFeiyang Chen _arg1; \ 14373f12c6dSFeiyang Chen }) 14473f12c6dSFeiyang Chen 14573f12c6dSFeiyang Chen #if __loongarch_grlen == 32 14673f12c6dSFeiyang Chen #define LONG_BSTRINS "bstrins.w" 147fddc8f81SThomas Weißschuh #else /* __loongarch_grlen == 64 */ 14873f12c6dSFeiyang Chen #define LONG_BSTRINS "bstrins.d" 14973f12c6dSFeiyang Chen #endif 15073f12c6dSFeiyang Chen 15173f12c6dSFeiyang Chen /* startup code */ 152*ef32e9b6SThomas Weißschuh void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void) 15373f12c6dSFeiyang Chen { 15473f12c6dSFeiyang Chen __asm__ volatile ( 15561bd4621SZhangjin Wu "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ 15661bd4621SZhangjin Wu LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */ 15761bd4621SZhangjin Wu "bl _start_c\n" /* transfer to c runtime */ 15873f12c6dSFeiyang Chen ); 159*ef32e9b6SThomas Weißschuh __nolibc_entrypoint_epilogue(); 16073f12c6dSFeiyang Chen } 16173f12c6dSFeiyang Chen 162fddc8f81SThomas Weißschuh #endif /* _NOLIBC_ARCH_LOONGARCH_H */ 163