xref: /openbmc/linux/tools/include/nolibc/arch-riscv.h (revision 56d294a50cf34990dec8886bef3f1a1386d56ac6)
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 #define REG_L  "ld"
37 #define REG_S  "sd"
38 #elif __riscv_xlen == 32
39 #define PTRLOG "2"
40 #define SZREG  "4"
41 #define REG_L  "lw"
42 #define REG_S  "sw"
43 #endif
44 
45 /* Syscalls for RISCV :
46  *   - stack is 16-byte aligned
47  *   - syscall number is passed in a7
48  *   - arguments are in a0, a1, a2, a3, a4, a5
49  *   - the system call is performed by calling ecall
50  *   - syscall return comes in a0
51  *   - the arguments are cast to long and assigned into the target
52  *     registers which are then simply passed as registers to the asm code,
53  *     so that we don't have to experience issues with register constraints.
54  *
55  * On riscv, select() is not implemented so we have to use pselect6().
56  */
57 #define __ARCH_WANT_SYS_PSELECT6
58 
59 #define my_syscall0(num)                                                      \
60 ({                                                                            \
61 	register long _num  __asm__ ("a7") = (num);                           \
62 	register long _arg1 __asm__ ("a0");                                   \
63 									      \
64 	__asm__  volatile (                                                   \
65 		"ecall\n\t"                                                   \
66 		: "=r"(_arg1)                                                 \
67 		: "r"(_num)                                                   \
68 		: "memory", "cc"                                              \
69 	);                                                                    \
70 	_arg1;                                                                \
71 })
72 
73 #define my_syscall1(num, arg1)                                                \
74 ({                                                                            \
75 	register long _num  __asm__ ("a7") = (num);                           \
76 	register long _arg1 __asm__ ("a0") = (long)(arg1);		      \
77 									      \
78 	__asm__  volatile (                                                   \
79 		"ecall\n"                                                     \
80 		: "+r"(_arg1)                                                 \
81 		: "r"(_num)                                                   \
82 		: "memory", "cc"                                              \
83 	);                                                                    \
84 	_arg1;                                                                \
85 })
86 
87 #define my_syscall2(num, arg1, arg2)                                          \
88 ({                                                                            \
89 	register long _num  __asm__ ("a7") = (num);                           \
90 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
91 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
92 									      \
93 	__asm__  volatile (                                                   \
94 		"ecall\n"                                                     \
95 		: "+r"(_arg1)                                                 \
96 		: "r"(_arg2),                                                 \
97 		  "r"(_num)                                                   \
98 		: "memory", "cc"                                              \
99 	);                                                                    \
100 	_arg1;                                                                \
101 })
102 
103 #define my_syscall3(num, arg1, arg2, arg3)                                    \
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 									      \
110 	__asm__  volatile (                                                   \
111 		"ecall\n\t"                                                   \
112 		: "+r"(_arg1)                                                 \
113 		: "r"(_arg2), "r"(_arg3),                                     \
114 		  "r"(_num)                                                   \
115 		: "memory", "cc"                                              \
116 	);                                                                    \
117 	_arg1;                                                                \
118 })
119 
120 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
121 ({                                                                            \
122 	register long _num  __asm__ ("a7") = (num);                           \
123 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
124 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
125 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
126 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
127 									      \
128 	__asm__  volatile (                                                   \
129 		"ecall\n"                                                     \
130 		: "+r"(_arg1)                                                 \
131 		: "r"(_arg2), "r"(_arg3), "r"(_arg4),                         \
132 		  "r"(_num)                                                   \
133 		: "memory", "cc"                                              \
134 	);                                                                    \
135 	_arg1;                                                                \
136 })
137 
138 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
139 ({                                                                            \
140 	register long _num  __asm__ ("a7") = (num);                           \
141 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
142 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
143 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
144 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
145 	register long _arg5 __asm__ ("a4") = (long)(arg5);                    \
146 									      \
147 	__asm__  volatile (                                                   \
148 		"ecall\n"                                                     \
149 		: "+r"(_arg1)                                                 \
150 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5),             \
151 		  "r"(_num)                                                   \
152 		: "memory", "cc"                                              \
153 	);                                                                    \
154 	_arg1;                                                                \
155 })
156 
157 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
158 ({                                                                            \
159 	register long _num  __asm__ ("a7") = (num);                           \
160 	register long _arg1 __asm__ ("a0") = (long)(arg1);                    \
161 	register long _arg2 __asm__ ("a1") = (long)(arg2);                    \
162 	register long _arg3 __asm__ ("a2") = (long)(arg3);                    \
163 	register long _arg4 __asm__ ("a3") = (long)(arg4);                    \
164 	register long _arg5 __asm__ ("a4") = (long)(arg5);                    \
165 	register long _arg6 __asm__ ("a5") = (long)(arg6);                    \
166 									      \
167 	__asm__  volatile (                                                   \
168 		"ecall\n"                                                     \
169 		: "+r"(_arg1)                                                 \
170 		: "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
171 		  "r"(_num)                                                   \
172 		: "memory", "cc"                                              \
173 	);                                                                    \
174 	_arg1;                                                                \
175 })
176 
177 char **environ __attribute__((weak));
178 const unsigned long *_auxv __attribute__((weak));
179 
180 #define __ARCH_SUPPORTS_STACK_PROTECTOR
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