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 struct sys_stat_struct { 13 unsigned long st_dev; /* Device. */ 14 unsigned long st_ino; /* File serial number. */ 15 unsigned int st_mode; /* File mode. */ 16 unsigned int st_nlink; /* Link count. */ 17 unsigned int st_uid; /* User ID of the file's owner. */ 18 unsigned int st_gid; /* Group ID of the file's group. */ 19 unsigned long st_rdev; /* Device number, if device. */ 20 unsigned long __pad1; 21 long st_size; /* Size of file, in bytes. */ 22 int st_blksize; /* Optimal block size for I/O. */ 23 int __pad2; 24 long st_blocks; /* Number 512-byte blocks allocated. */ 25 long st_atime; /* Time of last access. */ 26 unsigned long st_atime_nsec; 27 long st_mtime; /* Time of last modification. */ 28 unsigned long st_mtime_nsec; 29 long st_ctime; /* Time of last status change. */ 30 unsigned long st_ctime_nsec; 31 unsigned int __unused4; 32 unsigned int __unused5; 33 }; 34 35 #if __riscv_xlen == 64 36 #define PTRLOG "3" 37 #define SZREG "8" 38 #define REG_L "ld" 39 #define REG_S "sd" 40 #elif __riscv_xlen == 32 41 #define PTRLOG "2" 42 #define SZREG "4" 43 #define REG_L "lw" 44 #define REG_S "sw" 45 #endif 46 47 /* Syscalls for RISCV : 48 * - stack is 16-byte aligned 49 * - syscall number is passed in a7 50 * - arguments are in a0, a1, a2, a3, a4, a5 51 * - the system call is performed by calling ecall 52 * - syscall return comes in a0 53 * - the arguments are cast to long and assigned into the target 54 * registers which are then simply passed as registers to the asm code, 55 * so that we don't have to experience issues with register constraints. 56 * 57 * On riscv, select() is not implemented so we have to use pselect6(). 58 */ 59 #define __ARCH_WANT_SYS_PSELECT6 60 61 #define my_syscall0(num) \ 62 ({ \ 63 register long _num __asm__ ("a7") = (num); \ 64 register long _arg1 __asm__ ("a0"); \ 65 \ 66 __asm__ volatile ( \ 67 "ecall\n\t" \ 68 : "=r"(_arg1) \ 69 : "r"(_num) \ 70 : "memory", "cc" \ 71 ); \ 72 _arg1; \ 73 }) 74 75 #define my_syscall1(num, arg1) \ 76 ({ \ 77 register long _num __asm__ ("a7") = (num); \ 78 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 79 \ 80 __asm__ volatile ( \ 81 "ecall\n" \ 82 : "+r"(_arg1) \ 83 : "r"(_num) \ 84 : "memory", "cc" \ 85 ); \ 86 _arg1; \ 87 }) 88 89 #define my_syscall2(num, arg1, arg2) \ 90 ({ \ 91 register long _num __asm__ ("a7") = (num); \ 92 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 93 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 94 \ 95 __asm__ volatile ( \ 96 "ecall\n" \ 97 : "+r"(_arg1) \ 98 : "r"(_arg2), \ 99 "r"(_num) \ 100 : "memory", "cc" \ 101 ); \ 102 _arg1; \ 103 }) 104 105 #define my_syscall3(num, arg1, arg2, arg3) \ 106 ({ \ 107 register long _num __asm__ ("a7") = (num); \ 108 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 109 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 110 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 111 \ 112 __asm__ volatile ( \ 113 "ecall\n\t" \ 114 : "+r"(_arg1) \ 115 : "r"(_arg2), "r"(_arg3), \ 116 "r"(_num) \ 117 : "memory", "cc" \ 118 ); \ 119 _arg1; \ 120 }) 121 122 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 123 ({ \ 124 register long _num __asm__ ("a7") = (num); \ 125 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 126 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 127 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 128 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 129 \ 130 __asm__ volatile ( \ 131 "ecall\n" \ 132 : "+r"(_arg1) \ 133 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 134 "r"(_num) \ 135 : "memory", "cc" \ 136 ); \ 137 _arg1; \ 138 }) 139 140 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 141 ({ \ 142 register long _num __asm__ ("a7") = (num); \ 143 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 144 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 145 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 146 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 147 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 148 \ 149 __asm__ volatile ( \ 150 "ecall\n" \ 151 : "+r"(_arg1) \ 152 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 153 "r"(_num) \ 154 : "memory", "cc" \ 155 ); \ 156 _arg1; \ 157 }) 158 159 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 160 ({ \ 161 register long _num __asm__ ("a7") = (num); \ 162 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 163 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 164 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 165 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 166 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 167 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 168 \ 169 __asm__ volatile ( \ 170 "ecall\n" \ 171 : "+r"(_arg1) \ 172 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 173 "r"(_num) \ 174 : "memory", "cc" \ 175 ); \ 176 _arg1; \ 177 }) 178 179 char **environ __attribute__((weak)); 180 const unsigned long *_auxv __attribute__((weak)); 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