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