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 #include "crt.h" 12 13 /* Syscalls for RISCV : 14 * - stack is 16-byte aligned 15 * - syscall number is passed in a7 16 * - arguments are in a0, a1, a2, a3, a4, a5 17 * - the system call is performed by calling ecall 18 * - syscall return comes in a0 19 * - the arguments are cast to long and assigned into the target 20 * registers which are then simply passed as registers to the asm code, 21 * so that we don't have to experience issues with register constraints. 22 */ 23 24 #define my_syscall0(num) \ 25 ({ \ 26 register long _num __asm__ ("a7") = (num); \ 27 register long _arg1 __asm__ ("a0"); \ 28 \ 29 __asm__ volatile ( \ 30 "ecall\n\t" \ 31 : "=r"(_arg1) \ 32 : "r"(_num) \ 33 : "memory", "cc" \ 34 ); \ 35 _arg1; \ 36 }) 37 38 #define my_syscall1(num, arg1) \ 39 ({ \ 40 register long _num __asm__ ("a7") = (num); \ 41 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 42 \ 43 __asm__ volatile ( \ 44 "ecall\n" \ 45 : "+r"(_arg1) \ 46 : "r"(_num) \ 47 : "memory", "cc" \ 48 ); \ 49 _arg1; \ 50 }) 51 52 #define my_syscall2(num, arg1, arg2) \ 53 ({ \ 54 register long _num __asm__ ("a7") = (num); \ 55 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 56 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 57 \ 58 __asm__ volatile ( \ 59 "ecall\n" \ 60 : "+r"(_arg1) \ 61 : "r"(_arg2), \ 62 "r"(_num) \ 63 : "memory", "cc" \ 64 ); \ 65 _arg1; \ 66 }) 67 68 #define my_syscall3(num, arg1, arg2, arg3) \ 69 ({ \ 70 register long _num __asm__ ("a7") = (num); \ 71 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 72 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 73 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 74 \ 75 __asm__ volatile ( \ 76 "ecall\n\t" \ 77 : "+r"(_arg1) \ 78 : "r"(_arg2), "r"(_arg3), \ 79 "r"(_num) \ 80 : "memory", "cc" \ 81 ); \ 82 _arg1; \ 83 }) 84 85 #define my_syscall4(num, arg1, arg2, arg3, arg4) \ 86 ({ \ 87 register long _num __asm__ ("a7") = (num); \ 88 register long _arg1 __asm__ ("a0") = (long)(arg1); \ 89 register long _arg2 __asm__ ("a1") = (long)(arg2); \ 90 register long _arg3 __asm__ ("a2") = (long)(arg3); \ 91 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 92 \ 93 __asm__ volatile ( \ 94 "ecall\n" \ 95 : "+r"(_arg1) \ 96 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \ 97 "r"(_num) \ 98 : "memory", "cc" \ 99 ); \ 100 _arg1; \ 101 }) 102 103 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \ 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 register long _arg4 __asm__ ("a3") = (long)(arg4); \ 110 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 111 \ 112 __asm__ volatile ( \ 113 "ecall\n" \ 114 : "+r"(_arg1) \ 115 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \ 116 "r"(_num) \ 117 : "memory", "cc" \ 118 ); \ 119 _arg1; \ 120 }) 121 122 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \ 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 register long _arg5 __asm__ ("a4") = (long)(arg5); \ 130 register long _arg6 __asm__ ("a5") = (long)(arg6); \ 131 \ 132 __asm__ volatile ( \ 133 "ecall\n" \ 134 : "+r"(_arg1) \ 135 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \ 136 "r"(_num) \ 137 : "memory", "cc" \ 138 ); \ 139 _arg1; \ 140 }) 141 142 /* startup code */ 143 void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void) 144 { 145 __asm__ volatile ( 146 ".option push\n" 147 ".option norelax\n" 148 "lla gp, __global_pointer$\n" 149 ".option pop\n" 150 "mv a0, sp\n" /* save stack pointer to a0, as arg1 of _start_c */ 151 "andi sp, a0, -16\n" /* sp must be 16-byte aligned */ 152 "call _start_c\n" /* transfer to c runtime */ 153 ); 154 __builtin_unreachable(); 155 } 156 157 #endif /* _NOLIBC_ARCH_RISCV_H */ 158