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 struct sys_stat_struct { 11 unsigned long st_dev; /* Device. */ 12 unsigned long st_ino; /* File serial number. */ 13 unsigned int st_mode; /* File mode. */ 14 unsigned int st_nlink; /* Link count. */ 15 unsigned int st_uid; /* User ID of the file's owner. */ 16 unsigned int st_gid; /* Group ID of the file's group. */ 17 unsigned long st_rdev; /* Device number, if device. */ 18 unsigned long __pad1; 19 long st_size; /* Size of file, in bytes. */ 20 int st_blksize; /* Optimal block size for I/O. */ 21 int __pad2; 22 long st_blocks; /* Number 512-byte blocks allocated. */ 23 long st_atime; /* Time of last access. */ 24 unsigned long st_atime_nsec; 25 long st_mtime; /* Time of last modification. */ 26 unsigned long st_mtime_nsec; 27 long st_ctime; /* Time of last status change. */ 28 unsigned long st_ctime_nsec; 29 unsigned int __unused4; 30 unsigned int __unused5; 31 }; 32 33 #if __riscv_xlen == 64 34 #define PTRLOG "3" 35 #define SZREG "8" 36 #define REG_L "ld" 37 #define REG_S "sd" 38 #elif __riscv_xlen == 32 39 #define PTRLOG "2" 40 #define SZREG "4" 41 #define REG_L "lw" 42 #define REG_S "sw" 43 #endif 44 45 /* Syscalls for RISCV : 46 * - stack is 16-byte aligned 47 * - syscall number is passed in a7 48 * - arguments are in a0, a1, a2, a3, a4, a5 49 * - the system call is performed by calling ecall 50 * - syscall return comes in a0 51 * - the arguments are cast to long and assigned into the target 52 * registers which are then simply passed as registers to the asm code, 53 * so that we don't have to experience issues with register constraints. 54 * 55 * On riscv, select() is not implemented so we have to use pselect6(). 56 */ 57 #define __ARCH_WANT_SYS_PSELECT6 58 59 #define my_syscall0(num) \ 60 ({ \ 61 register long _num __asm__ ("a7") = (num); \ 62 register long _arg1 __asm__ ("a0"); \ 63 \ 64 __asm__ volatile ( \ 65 "ecall\n\t" \ 66 : "=r"(_arg1) \ 67 : "r"(_num) \ 68 : "memory", "cc" \ 69 ); \ 70 _arg1; \ 71 }) 72 73 #define my_syscall1(num, arg1) \ 74 ({ \ 75 register long _num __asm__ ("a7") = (num); \ 76 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 77 \ 78 __asm__ volatile ( \ 79 "ecall\n" \ 80 : "+r"(_arg1) \ 81 : "r"(_num) \ 82 : "memory", "cc" \ 83 ); \ 84 _arg1; \ 85 }) 86 87 #define my_syscall2(num, arg1, arg2) \ 88 ({ \ 89 register long _num __asm__ ("a7") = (num); \ 90 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 91 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 92 \ 93 __asm__ volatile ( \ 94 "ecall\n" \ 95 : "+r"(_arg1) \ 96 : "r"(_arg2), \ 97 "r"(_num) \ 98 : "memory", "cc" \ 99 ); \ 100 _arg1; \ 101 }) 102 103 #define my_syscall3(num, arg1, arg2, arg3) \ 104 ({ \ 105 register long _num __asm__ ("a7") = (num); \ 106 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 107 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 108 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 109 \ 110 __asm__ volatile ( \ 111 "ecall\n\t" \ 112 : "+r"(_arg1) \ 113 : "r"(_arg2), "r"(_arg3), \ 114 "r"(_num) \ 115 : "memory", "cc" \ 116 ); \ 117 _arg1; \ 118 }) 119 120 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 121 ({ \ 122 register long _num __asm__ ("a7") = (num); \ 123 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 124 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 125 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 126 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 127 \ 128 __asm__ volatile ( \ 129 "ecall\n" \ 130 : "+r"(_arg1) \ 131 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 132 "r"(_num) \ 133 : "memory", "cc" \ 134 ); \ 135 _arg1; \ 136 }) 137 138 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 139 ({ \ 140 register long _num __asm__ ("a7") = (num); \ 141 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 142 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 143 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 144 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 145 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 146 \ 147 __asm__ volatile ( \ 148 "ecall\n" \ 149 : "+r"(_arg1) \ 150 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 151 "r"(_num) \ 152 : "memory", "cc" \ 153 ); \ 154 _arg1; \ 155 }) 156 157 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 158 ({ \ 159 register long _num __asm__ ("a7") = (num); \ 160 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 161 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 162 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 163 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 164 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 165 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 166 \ 167 __asm__ volatile ( \ 168 "ecall\n" \ 169 : "+r"(_arg1) \ 170 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 171 "r"(_num) \ 172 : "memory", "cc" \ 173 ); \ 174 _arg1; \ 175 }) 176 177 char **environ __attribute__((weak)); 178 const unsigned long *_auxv __attribute__((weak)); 179 180 #define __ARCH_SUPPORTS_STACK_PROTECTOR 181 182 /* startup code */ 183 void __attribute__((weak,noreturn,optimize("omit-frame-pointer"),no_stack_protector)) _start(void) 184 { 185 __asm__ volatile ( 186 ".option push\n" 187 ".option norelax\n" 188 "lla gp, __global_pointer$\n" 189 ".option pop\n" 190 #ifdef NOLIBC_STACKPROTECTOR 191 "call __stack_chk_init\n" /* initialize stack protector */ 192 #endif 193 REG_L" a0, 0(sp)\n" /* argc (a0) was in the stack */ 194 "add a1, sp, "SZREG"\n" /* argv (a1) = sp */ 195 "slli a2, a0, "PTRLOG"\n" /* envp (a2) = SZREG*argc ... */ 196 "add a2, a2, "SZREG"\n" /* + SZREG (skip null) */ 197 "add a2,a2,a1\n" /* + argv */ 198 199 "add a3, a2, zero\n" /* iterate a3 over envp to find auxv (after NULL) */ 200 "0:\n" /* do { */ 201 REG_L" a4, 0(a3)\n" /* a4 = *a3; */ 202 "add a3, a3, "SZREG"\n" /* a3 += sizeof(void*); */ 203 "bne a4, zero, 0b\n" /* } while (a4); */ 204 "lui a4, %hi(_auxv)\n" /* a4 = &_auxv (high bits) */ 205 REG_S" a3, %lo(_auxv)(a4)\n" /* store a3 into _auxv */ 206 207 "lui a3, %hi(environ)\n" /* a3 = &environ (high bits) */ 208 REG_S" a2,%lo(environ)(a3)\n"/* store envp(a2) into environ */ 209 "andi sp,a1,-16\n" /* sp must be 16-byte aligned */ 210 "call main\n" /* main() returns the status code, we'll exit with it. */ 211 "li a7, 93\n" /* NR_exit == 93 */ 212 "ecall\n" 213 ); 214 __builtin_unreachable(); 215 } 216 217 #endif /* _NOLIBC_ARCH_RISCV_H */ 218