158 lines · c
1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */2/*3 * RISCV (32 and 64) specific definitions for NOLIBC4 * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>5 */6 7#ifndef _NOLIBC_ARCH_RISCV_H8#define _NOLIBC_ARCH_RISCV_H9 10#include "compiler.h"11#include "crt.h"12 13/* Syscalls for RISCV :14 * - stack is 16-byte aligned15 * - syscall number is passed in a716 * - arguments are in a0, a1, a2, a3, a4, a517 * - the system call is performed by calling ecall18 * - syscall return comes in a019 * - the arguments are cast to long and assigned into the target20 * 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 */143void __attribute__((weak, noreturn)) __nolibc_entrypoint __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 __nolibc_entrypoint_epilogue();155}156 157#endif /* _NOLIBC_ARCH_RISCV_H */158