1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * LoongArch specific definitions for NOLIBC 4 * Copyright (C) 2023 Loongson Technology Corporation Limited 5 */ 6 7 #ifndef _NOLIBC_ARCH_LOONGARCH_H 8 #define _NOLIBC_ARCH_LOONGARCH_H 9 10 #include "compiler.h" 11 #include "crt.h" 12 13 /* Syscalls for LoongArch : 14 * - stack is 16-byte aligned 15 * - syscall number is passed in a7 16 * - arguments are in a0, a1, a2, a3, a4, a5 17 * - the system call is performed by calling "syscall 0" 18 * - syscall return comes in a0 19 * - the arguments are cast to long and assigned into the target 20 * registers which are then simply passed as registers to the asm code, 21 * so that we don't have to experience issues with register constraints. 22 * 23 * On LoongArch, select() is not implemented so we have to use pselect6(). 24 */ 25 #define __ARCH_WANT_SYS_PSELECT6 26 #define _NOLIBC_SYSCALL_CLOBBERLIST \ 27 "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8" 28 29 #define my_syscall0(num) \ 30 ({ \ 31 register long _num __asm__ ("a7") = (num); \ 32 register long _arg1 __asm__ ("a0"); \ 33 \ 34 __asm__ volatile ( \ 35 "syscall 0\n" \ 36 : "=r"(_arg1) \ 37 : "r"(_num) \ 38 : _NOLIBC_SYSCALL_CLOBBERLIST \ 39 ); \ 40 _arg1; \ 41 }) 42 43 #define my_syscall1(num, arg1) \ 44 ({ \ 45 register long _num __asm__ ("a7") = (num); \ 46 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 47 \ 48 __asm__ volatile ( \ 49 "syscall 0\n" \ 50 : "+r"(_arg1) \ 51 : "r"(_num) \ 52 : _NOLIBC_SYSCALL_CLOBBERLIST \ 53 ); \ 54 _arg1; \ 55 }) 56 57 #define my_syscall2(num, arg1, arg2) \ 58 ({ \ 59 register long _num __asm__ ("a7") = (num); \ 60 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 61 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 62 \ 63 __asm__ volatile ( \ 64 "syscall 0\n" \ 65 : "+r"(_arg1) \ 66 : "r"(_arg2), \ 67 "r"(_num) \ 68 : _NOLIBC_SYSCALL_CLOBBERLIST \ 69 ); \ 70 _arg1; \ 71 }) 72 73 #define my_syscall3(num, arg1, arg2, arg3) \ 74 ({ \ 75 register long _num __asm__ ("a7") = (num); \ 76 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 77 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 78 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 79 \ 80 __asm__ volatile ( \ 81 "syscall 0\n" \ 82 : "+r"(_arg1) \ 83 : "r"(_arg2), "r"(_arg3), \ 84 "r"(_num) \ 85 : _NOLIBC_SYSCALL_CLOBBERLIST \ 86 ); \ 87 _arg1; \ 88 }) 89 90 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 91 ({ \ 92 register long _num __asm__ ("a7") = (num); \ 93 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 94 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 95 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 96 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 97 \ 98 __asm__ volatile ( \ 99 "syscall 0\n" \ 100 : "+r"(_arg1) \ 101 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 102 "r"(_num) \ 103 : _NOLIBC_SYSCALL_CLOBBERLIST \ 104 ); \ 105 _arg1; \ 106 }) 107 108 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 109 ({ \ 110 register long _num __asm__ ("a7") = (num); \ 111 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 112 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 113 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 114 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 115 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 116 \ 117 __asm__ volatile ( \ 118 "syscall 0\n" \ 119 : "+r"(_arg1) \ 120 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 121 "r"(_num) \ 122 : _NOLIBC_SYSCALL_CLOBBERLIST \ 123 ); \ 124 _arg1; \ 125 }) 126 127 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 128 ({ \ 129 register long _num __asm__ ("a7") = (num); \ 130 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 131 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 132 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 133 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 134 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 135 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 136 \ 137 __asm__ volatile ( \ 138 "syscall 0\n" \ 139 : "+r"(_arg1) \ 140 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 141 "r"(_num) \ 142 : _NOLIBC_SYSCALL_CLOBBERLIST \ 143 ); \ 144 _arg1; \ 145 }) 146 147 #if __loongarch_grlen == 32 148 #define LONG_BSTRINS "bstrins.w" 149 #else /* __loongarch_grlen == 64 */ 150 #define LONG_BSTRINS "bstrins.d" 151 #endif 152 153 /* startup code */ 154 void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 155 { 156 __asm__ volatile ( 157 "move $a0, $sp\n" /* save stack pointer to $a0, as arg1 of _start_c */ 158 LONG_BSTRINS " $sp, $zero, 3, 0\n" /* $sp must be 16-byte aligned */ 159 "bl _start_c\n" /* transfer to c runtime */ 160 ); 161 __builtin_unreachable(); 162 } 163 164 #endif /* _NOLIBC_ARCH_LOONGARCH_H */ 165