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