tools/nolibc/arch: mark the _start symbol as weak
[platform/kernel/linux-rpi.git] / tools / include / nolibc / arch-riscv.h
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     ".global _start\n"
189     "_start:\n"
190     ".option push\n"
191     ".option norelax\n"
192     "lla   gp, __global_pointer$\n"
193     ".option pop\n"
194     "ld    a0, 0(sp)\n"          // argc (a0) was in the stack
195     "add   a1, sp, "SZREG"\n"    // argv (a1) = sp
196     "slli  a2, a0, "PTRLOG"\n"   // envp (a2) = SZREG*argc ...
197     "add   a2, a2, "SZREG"\n"    //             + SZREG (skip null)
198     "add   a2,a2,a1\n"           //             + argv
199     "andi  sp,a1,-16\n"          // sp must be 16-byte aligned
200     "call  main\n"               // main() returns the status code, we'll exit with it.
201     "li a7, 93\n"                // NR_exit == 93
202     "ecall\n"
203     "");
204
205 #endif // _NOLIBC_ARCH_RISCV_H