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 #elif __riscv_xlen == 32 37 #define PTRLOG "2" 38 #define SZREG "4" 39 #endif 40 41 /* Syscalls for RISCV : 42 * - stack is 16-byte aligned 43 * - syscall number is passed in a7 44 * - arguments are in a0, a1, a2, a3, a4, a5 45 * - the system call is performed by calling ecall 46 * - syscall return comes in a0 47 * - the arguments are cast to long and assigned into the target 48 * registers which are then simply passed as registers to the asm code, 49 * so that we don't have to experience issues with register constraints. 50 * 51 * On riscv, select() is not implemented so we have to use pselect6(). 52 */ 53 #define __ARCH_WANT_SYS_PSELECT6 54 55 #define my_syscall0(num) \ 56 ({ \ 57 register long _num __asm__ ("a7") = (num); \ 58 register long _arg1 __asm__ ("a0"); \ 59 \ 60 __asm__ volatile ( \ 61 "ecall\n\t" \ 62 : "=r"(_arg1) \ 63 : "r"(_num) \ 64 : "memory", "cc" \ 65 ); \ 66 _arg1; \ 67 }) 68 69 #define my_syscall1(num, arg1) \ 70 ({ \ 71 register long _num __asm__ ("a7") = (num); \ 72 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 73 \ 74 __asm__ volatile ( \ 75 "ecall\n" \ 76 : "+r"(_arg1) \ 77 : "r"(_num) \ 78 : "memory", "cc" \ 79 ); \ 80 _arg1; \ 81 }) 82 83 #define my_syscall2(num, arg1, arg2) \ 84 ({ \ 85 register long _num __asm__ ("a7") = (num); \ 86 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 87 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 88 \ 89 __asm__ volatile ( \ 90 "ecall\n" \ 91 : "+r"(_arg1) \ 92 : "r"(_arg2), \ 93 "r"(_num) \ 94 : "memory", "cc" \ 95 ); \ 96 _arg1; \ 97 }) 98 99 #define my_syscall3(num, arg1, arg2, arg3) \ 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 \ 106 __asm__ volatile ( \ 107 "ecall\n\t" \ 108 : "+r"(_arg1) \ 109 : "r"(_arg2), "r"(_arg3), \ 110 "r"(_num) \ 111 : "memory", "cc" \ 112 ); \ 113 _arg1; \ 114 }) 115 116 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 117 ({ \ 118 register long _num __asm__ ("a7") = (num); \ 119 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 120 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 121 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 122 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 123 \ 124 __asm__ volatile ( \ 125 "ecall\n" \ 126 : "+r"(_arg1) \ 127 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 128 "r"(_num) \ 129 : "memory", "cc" \ 130 ); \ 131 _arg1; \ 132 }) 133 134 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 135 ({ \ 136 register long _num __asm__ ("a7") = (num); \ 137 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 138 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 139 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 140 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 141 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 142 \ 143 __asm__ volatile ( \ 144 "ecall\n" \ 145 : "+r"(_arg1) \ 146 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 147 "r"(_num) \ 148 : "memory", "cc" \ 149 ); \ 150 _arg1; \ 151 }) 152 153 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 154 ({ \ 155 register long _num __asm__ ("a7") = (num); \ 156 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 157 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 158 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 159 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 160 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 161 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 162 \ 163 __asm__ volatile ( \ 164 "ecall\n" \ 165 : "+r"(_arg1) \ 166 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 167 "r"(_num) \ 168 : "memory", "cc" \ 169 ); \ 170 _arg1; \ 171 }) 172 173 char **environ __attribute__((weak)); 174 const unsigned long *_auxv __attribute__((weak)); 175 176 /* startup code */ 177 void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) _start(void) 178 { 179 __asm__ volatile ( 180 ".option push\n" 181 ".option norelax\n" 182 "lla gp, __global_pointer$\n" 183 ".option pop\n" 184 "lw a0, 0(sp)\n" // argc (a0) was in the stack 185 "add a1, sp, "SZREG"\n" // argv (a1) = sp 186 "slli a2, a0, "PTRLOG"\n" // envp (a2) = SZREG*argc ... 187 "add a2, a2, "SZREG"\n" // + SZREG (skip null) 188 "add a2,a2,a1\n" // + argv 189 190 "add a3, a2, zero\n" // iterate a3 over envp to find auxv (after NULL) 191 "0:\n" // do { 192 "ld a4, 0(a3)\n" // a4 = *a3; 193 "add a3, a3, "SZREG"\n" // a3 += sizeof(void*); 194 "bne a4, zero, 0b\n" // } while (a4); 195 "lui a4, %hi(_auxv)\n" // a4 = &_auxv (high bits) 196 "sd a3, %lo(_auxv)(a4)\n" // store a3 into _auxv 197 198 "lui a3, %hi(environ)\n" // a3 = &environ (high bits) 199 "sd a2,%lo(environ)(a3)\n" // store envp(a2) into environ 200 "andi sp,a1,-16\n" // sp must be 16-byte aligned 201 "call main\n" // main() returns the status code, we'll exit with it. 202 "li a7, 93\n" // NR_exit == 93 203 "ecall\n" 204 ); 205 __builtin_unreachable(); 206 } 207 208 #endif // _NOLIBC_ARCH_RISCV_H 209