1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * RISCV (32 and 64) specific definitions for NOLIBC 4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu> 5 */ 6 7 #ifndef _NOLIBC_ARCH_RISCV_H 8 #define _NOLIBC_ARCH_RISCV_H 9 10 #include "compiler.h" 11 12 #if __riscv_xlen == 64 13 #define PTRLOG "3" 14 #define SZREG "8" 15 #define REG_L "ld" 16 #define REG_S "sd" 17 #elif __riscv_xlen == 32 18 #define PTRLOG "2" 19 #define SZREG "4" 20 #define REG_L "lw" 21 #define REG_S "sw" 22 #endif 23 24 /* Syscalls for RISCV : 25 * - stack is 16-byte aligned 26 * - syscall number is passed in a7 27 * - arguments are in a0, a1, a2, a3, a4, a5 28 * - the system call is performed by calling ecall 29 * - syscall return comes in a0 30 * - the arguments are cast to long and assigned into the target 31 * registers which are then simply passed as registers to the asm code, 32 * so that we don't have to experience issues with register constraints. 33 * 34 * On riscv, select() is not implemented so we have to use pselect6(). 35 */ 36 #define __ARCH_WANT_SYS_PSELECT6 37 38 #define my_syscall0(num) \ 39 ({ \ 40 register long _num __asm__ ("a7") = (num); \ 41 register long _arg1 __asm__ ("a0"); \ 42 \ 43 __asm__ volatile ( \ 44 "ecall\n\t" \ 45 : "=r"(_arg1) \ 46 : "r"(_num) \ 47 : "memory", "cc" \ 48 ); \ 49 _arg1; \ 50 }) 51 52 #define my_syscall1(num, arg1) \ 53 ({ \ 54 register long _num __asm__ ("a7") = (num); \ 55 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 56 \ 57 __asm__ volatile ( \ 58 "ecall\n" \ 59 : "+r"(_arg1) \ 60 : "r"(_num) \ 61 : "memory", "cc" \ 62 ); \ 63 _arg1; \ 64 }) 65 66 #define my_syscall2(num, arg1, arg2) \ 67 ({ \ 68 register long _num __asm__ ("a7") = (num); \ 69 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 70 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 71 \ 72 __asm__ volatile ( \ 73 "ecall\n" \ 74 : "+r"(_arg1) \ 75 : "r"(_arg2), \ 76 "r"(_num) \ 77 : "memory", "cc" \ 78 ); \ 79 _arg1; \ 80 }) 81 82 #define my_syscall3(num, arg1, arg2, arg3) \ 83 ({ \ 84 register long _num __asm__ ("a7") = (num); \ 85 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 86 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 87 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 88 \ 89 __asm__ volatile ( \ 90 "ecall\n\t" \ 91 : "+r"(_arg1) \ 92 : "r"(_arg2), "r"(_arg3), \ 93 "r"(_num) \ 94 : "memory", "cc" \ 95 ); \ 96 _arg1; \ 97 }) 98 99 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 100 ({ \ 101 register long _num __asm__ ("a7") = (num); \ 102 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 103 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 104 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 105 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 106 \ 107 __asm__ volatile ( \ 108 "ecall\n" \ 109 : "+r"(_arg1) \ 110 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 111 "r"(_num) \ 112 : "memory", "cc" \ 113 ); \ 114 _arg1; \ 115 }) 116 117 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 118 ({ \ 119 register long _num __asm__ ("a7") = (num); \ 120 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 121 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 122 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 123 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 124 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 125 \ 126 __asm__ volatile ( \ 127 "ecall\n" \ 128 : "+r"(_arg1) \ 129 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 130 "r"(_num) \ 131 : "memory", "cc" \ 132 ); \ 133 _arg1; \ 134 }) 135 136 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 137 ({ \ 138 register long _num __asm__ ("a7") = (num); \ 139 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 140 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 141 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 142 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 143 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 144 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 145 \ 146 __asm__ volatile ( \ 147 "ecall\n" \ 148 : "+r"(_arg1) \ 149 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 150 "r"(_num) \ 151 : "memory", "cc" \ 152 ); \ 153 _arg1; \ 154 }) 155 156 char **environ __attribute__((weak)); 157 const unsigned long *_auxv __attribute__((weak)); 158 159 /* startup code */ 160 void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 161 { 162 __asm__ volatile ( 163 ".option push\n" 164 ".option norelax\n" 165 "lla gp, __global_pointer$\n" 166 ".option pop\n" 167 #ifdef _NOLIBC_STACKPROTECTOR 168 "call __stack_chk_init\n" /* initialize stack protector */ 169 #endif 170 REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ 171 "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ 172 "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ 173 "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */ 174 "add a2,a2,a1\n" /* + argv */ 175 176 "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */ 177 "0:\n" /* do { */ 178 REG_L" a4, 0(a3)\n" /* a4 = *a3; */ 179 "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */ 180 "bne a4, zero, 0b\n" /* } while (a4); */ 181 "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */ 182 REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */ 183 184 "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */ 185 REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */ 186 "andi sp,a1,-16\n" /* sp must be 16-byte aligned */ 187 "call main\n" /* main() returns the status code, we'll exit with it. */ 188 "li a7, 93\n" /* NR_exit == 93 */ 189 "ecall\n" 190 ); 191 __builtin_unreachable(); 192 } 193 194 #endif /* _NOLIBC_ARCH_RISCV_H */ 195