tools/nolibc/arch: split arch-specific code into individual files
[platform/kernel/linux-rpi.git] / tools / include / nolibc / arch-aarch64.h
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * AARCH64 specific definitions for NOLIBC
4  * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
5  */
6
7 #ifndef _NOLIBC_ARCH_AARCH64_H
8 #define _NOLIBC_ARCH_AARCH64_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          0x40
15 #define O_EXCL           0x80
16 #define O_NOCTTY        0x100
17 #define O_TRUNC         0x200
18 #define O_APPEND        0x400
19 #define O_NONBLOCK      0x800
20 #define O_DIRECTORY    0x4000
21
22 /* The struct returned by the newfstatat() syscall. Differs slightly from the
23  * x86_64's stat one by field ordering, so be careful.
24  */
25 struct sys_stat_struct {
26         unsigned long   st_dev;
27         unsigned long   st_ino;
28         unsigned int    st_mode;
29         unsigned int    st_nlink;
30         unsigned int    st_uid;
31         unsigned int    st_gid;
32
33         unsigned long   st_rdev;
34         unsigned long   __pad1;
35         long            st_size;
36         int             st_blksize;
37         int             __pad2;
38
39         long            st_blocks;
40         long            st_atime;
41         unsigned long   st_atime_nsec;
42         long            st_mtime;
43
44         unsigned long   st_mtime_nsec;
45         long            st_ctime;
46         unsigned long   st_ctime_nsec;
47         unsigned int    __unused[2];
48 };
49
50 /* Syscalls for AARCH64 :
51  *   - registers are 64-bit
52  *   - stack is 16-byte aligned
53  *   - syscall number is passed in x8
54  *   - arguments are in x0, x1, x2, x3, x4, x5
55  *   - the system call is performed by calling svc 0
56  *   - syscall return comes in x0.
57  *   - the arguments are cast to long and assigned into the target registers
58  *     which are then simply passed as registers to the asm code, so that we
59  *     don't have to experience issues with register constraints.
60  *
61  * On aarch64, select() is not implemented so we have to use pselect6().
62  */
63 #define __ARCH_WANT_SYS_PSELECT6
64
65 #define my_syscall0(num)                                                      \
66 ({                                                                            \
67         register long _num  asm("x8") = (num);                                \
68         register long _arg1 asm("x0");                                        \
69                                                                               \
70         asm volatile (                                                        \
71                 "svc #0\n"                                                    \
72                 : "=r"(_arg1)                                                 \
73                 : "r"(_num)                                                   \
74                 : "memory", "cc"                                              \
75         );                                                                    \
76         _arg1;                                                                \
77 })
78
79 #define my_syscall1(num, arg1)                                                \
80 ({                                                                            \
81         register long _num  asm("x8") = (num);                                \
82         register long _arg1 asm("x0") = (long)(arg1);                         \
83                                                                               \
84         asm volatile (                                                        \
85                 "svc #0\n"                                                    \
86                 : "=r"(_arg1)                                                 \
87                 : "r"(_arg1),                                                 \
88                   "r"(_num)                                                   \
89                 : "memory", "cc"                                              \
90         );                                                                    \
91         _arg1;                                                                \
92 })
93
94 #define my_syscall2(num, arg1, arg2)                                          \
95 ({                                                                            \
96         register long _num  asm("x8") = (num);                                \
97         register long _arg1 asm("x0") = (long)(arg1);                         \
98         register long _arg2 asm("x1") = (long)(arg2);                         \
99                                                                               \
100         asm volatile (                                                        \
101                 "svc #0\n"                                                    \
102                 : "=r"(_arg1)                                                 \
103                 : "r"(_arg1), "r"(_arg2),                                     \
104                   "r"(_num)                                                   \
105                 : "memory", "cc"                                              \
106         );                                                                    \
107         _arg1;                                                                \
108 })
109
110 #define my_syscall3(num, arg1, arg2, arg3)                                    \
111 ({                                                                            \
112         register long _num  asm("x8") = (num);                                \
113         register long _arg1 asm("x0") = (long)(arg1);                         \
114         register long _arg2 asm("x1") = (long)(arg2);                         \
115         register long _arg3 asm("x2") = (long)(arg3);                         \
116                                                                               \
117         asm volatile (                                                        \
118                 "svc #0\n"                                                    \
119                 : "=r"(_arg1)                                                 \
120                 : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
121                   "r"(_num)                                                   \
122                 : "memory", "cc"                                              \
123         );                                                                    \
124         _arg1;                                                                \
125 })
126
127 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
128 ({                                                                            \
129         register long _num  asm("x8") = (num);                                \
130         register long _arg1 asm("x0") = (long)(arg1);                         \
131         register long _arg2 asm("x1") = (long)(arg2);                         \
132         register long _arg3 asm("x2") = (long)(arg3);                         \
133         register long _arg4 asm("x3") = (long)(arg4);                         \
134                                                                               \
135         asm volatile (                                                        \
136                 "svc #0\n"                                                    \
137                 : "=r"(_arg1)                                                 \
138                 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
139                   "r"(_num)                                                   \
140                 : "memory", "cc"                                              \
141         );                                                                    \
142         _arg1;                                                                \
143 })
144
145 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
146 ({                                                                            \
147         register long _num  asm("x8") = (num);                                \
148         register long _arg1 asm("x0") = (long)(arg1);                         \
149         register long _arg2 asm("x1") = (long)(arg2);                         \
150         register long _arg3 asm("x2") = (long)(arg3);                         \
151         register long _arg4 asm("x3") = (long)(arg4);                         \
152         register long _arg5 asm("x4") = (long)(arg5);                         \
153                                                                               \
154         asm volatile (                                                        \
155                 "svc #0\n"                                                    \
156                 : "=r" (_arg1)                                                \
157                 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
158                   "r"(_num)                                                   \
159                 : "memory", "cc"                                              \
160         );                                                                    \
161         _arg1;                                                                \
162 })
163
164 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
165 ({                                                                            \
166         register long _num  asm("x8") = (num);                                \
167         register long _arg1 asm("x0") = (long)(arg1);                         \
168         register long _arg2 asm("x1") = (long)(arg2);                         \
169         register long _arg3 asm("x2") = (long)(arg3);                         \
170         register long _arg4 asm("x3") = (long)(arg4);                         \
171         register long _arg5 asm("x4") = (long)(arg5);                         \
172         register long _arg6 asm("x5") = (long)(arg6);                         \
173                                                                               \
174         asm volatile (                                                        \
175                 "svc #0\n"                                                    \
176                 : "=r" (_arg1)                                                \
177                 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
178                   "r"(_arg6), "r"(_num)                                       \
179                 : "memory", "cc"                                              \
180         );                                                                    \
181         _arg1;                                                                \
182 })
183
184 /* startup code */
185 asm(".section .text\n"
186     ".global _start\n"
187     "_start:\n"
188     "ldr x0, [sp]\n"              // argc (x0) was in the stack
189     "add x1, sp, 8\n"             // argv (x1) = sp
190     "lsl x2, x0, 3\n"             // envp (x2) = 8*argc ...
191     "add x2, x2, 8\n"             //           + 8 (skip null)
192     "add x2, x2, x1\n"            //           + argv
193     "and sp, x1, -16\n"           // sp must be 16-byte aligned in the callee
194     "bl main\n"                   // main() returns the status code, we'll exit with it.
195     "mov x8, 93\n"                // NR_exit == 93
196     "svc #0\n"
197     "");
198
199 #endif // _NOLIBC_ARCH_AARCH64_H