xref: /linux/tools/include/nolibc/arch-arm64.h (revision b1c21075d30c40762750be0cded9822791df422b)
1*01e8a6d0SThomas Weißschuh /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2*01e8a6d0SThomas Weißschuh /*
3*01e8a6d0SThomas Weißschuh  * ARM64 specific definitions for NOLIBC
4*01e8a6d0SThomas Weißschuh  * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
5*01e8a6d0SThomas Weißschuh  */
6*01e8a6d0SThomas Weißschuh 
7*01e8a6d0SThomas Weißschuh #ifndef _NOLIBC_ARCH_ARM64_H
8*01e8a6d0SThomas Weißschuh #define _NOLIBC_ARCH_ARM64_H
9*01e8a6d0SThomas Weißschuh 
10*01e8a6d0SThomas Weißschuh #include "compiler.h"
11*01e8a6d0SThomas Weißschuh #include "crt.h"
12*01e8a6d0SThomas Weißschuh 
13*01e8a6d0SThomas Weißschuh /* Syscalls for ARM64 :
14*01e8a6d0SThomas Weißschuh  *   - registers are 64-bit
15*01e8a6d0SThomas Weißschuh  *   - stack is 16-byte aligned
16*01e8a6d0SThomas Weißschuh  *   - syscall number is passed in x8
17*01e8a6d0SThomas Weißschuh  *   - arguments are in x0, x1, x2, x3, x4, x5
18*01e8a6d0SThomas Weißschuh  *   - the system call is performed by calling svc 0
19*01e8a6d0SThomas Weißschuh  *   - syscall return comes in x0.
20*01e8a6d0SThomas Weißschuh  *   - the arguments are cast to long and assigned into the target registers
21*01e8a6d0SThomas Weißschuh  *     which are then simply passed as registers to the asm code, so that we
22*01e8a6d0SThomas Weißschuh  *     don't have to experience issues with register constraints.
23*01e8a6d0SThomas Weißschuh  */
24*01e8a6d0SThomas Weißschuh 
25*01e8a6d0SThomas Weißschuh #define my_syscall0(num)                                                      \
26*01e8a6d0SThomas Weißschuh ({                                                                            \
27*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
28*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0");                                   \
29*01e8a6d0SThomas Weißschuh 									      \
30*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
31*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
32*01e8a6d0SThomas Weißschuh 		: "=r"(_arg1)                                                 \
33*01e8a6d0SThomas Weißschuh 		: "r"(_num)                                                   \
34*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
35*01e8a6d0SThomas Weißschuh 	);                                                                    \
36*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
37*01e8a6d0SThomas Weißschuh })
38*01e8a6d0SThomas Weißschuh 
39*01e8a6d0SThomas Weißschuh #define my_syscall1(num, arg1)                                                \
40*01e8a6d0SThomas Weißschuh ({                                                                            \
41*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
42*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
43*01e8a6d0SThomas Weißschuh 									      \
44*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
45*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
46*01e8a6d0SThomas Weißschuh 		: "=r"(_arg1)                                                 \
47*01e8a6d0SThomas Weißschuh 		: "r"(_arg1),                                                 \
48*01e8a6d0SThomas Weißschuh 		  "r"(_num)                                                   \
49*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
50*01e8a6d0SThomas Weißschuh 	);                                                                    \
51*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
52*01e8a6d0SThomas Weißschuh })
53*01e8a6d0SThomas Weißschuh 
54*01e8a6d0SThomas Weißschuh #define my_syscall2(num, arg1, arg2)                                          \
55*01e8a6d0SThomas Weißschuh ({                                                                            \
56*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
57*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
58*01e8a6d0SThomas Weißschuh 	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
59*01e8a6d0SThomas Weißschuh 									      \
60*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
61*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
62*01e8a6d0SThomas Weißschuh 		: "=r"(_arg1)                                                 \
63*01e8a6d0SThomas Weißschuh 		: "r"(_arg1), "r"(_arg2),                                     \
64*01e8a6d0SThomas Weißschuh 		  "r"(_num)                                                   \
65*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
66*01e8a6d0SThomas Weißschuh 	);                                                                    \
67*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
68*01e8a6d0SThomas Weißschuh })
69*01e8a6d0SThomas Weißschuh 
70*01e8a6d0SThomas Weißschuh #define my_syscall3(num, arg1, arg2, arg3)                                    \
71*01e8a6d0SThomas Weißschuh ({                                                                            \
72*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
73*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
74*01e8a6d0SThomas Weißschuh 	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
75*01e8a6d0SThomas Weißschuh 	register long _arg3 __asm__ ("x2") = (long)(arg3);                    \
76*01e8a6d0SThomas Weißschuh 									      \
77*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
78*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
79*01e8a6d0SThomas Weißschuh 		: "=r"(_arg1)                                                 \
80*01e8a6d0SThomas Weißschuh 		: "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
81*01e8a6d0SThomas Weißschuh 		  "r"(_num)                                                   \
82*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
83*01e8a6d0SThomas Weißschuh 	);                                                                    \
84*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
85*01e8a6d0SThomas Weißschuh })
86*01e8a6d0SThomas Weißschuh 
87*01e8a6d0SThomas Weißschuh #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
88*01e8a6d0SThomas Weißschuh ({                                                                            \
89*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
90*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
91*01e8a6d0SThomas Weißschuh 	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
92*01e8a6d0SThomas Weißschuh 	register long _arg3 __asm__ ("x2") = (long)(arg3);                    \
93*01e8a6d0SThomas Weißschuh 	register long _arg4 __asm__ ("x3") = (long)(arg4);                    \
94*01e8a6d0SThomas Weißschuh 									      \
95*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
96*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
97*01e8a6d0SThomas Weißschuh 		: "=r"(_arg1)                                                 \
98*01e8a6d0SThomas Weißschuh 		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
99*01e8a6d0SThomas Weißschuh 		  "r"(_num)                                                   \
100*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
101*01e8a6d0SThomas Weißschuh 	);                                                                    \
102*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
103*01e8a6d0SThomas Weißschuh })
104*01e8a6d0SThomas Weißschuh 
105*01e8a6d0SThomas Weißschuh #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
106*01e8a6d0SThomas Weißschuh ({                                                                            \
107*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
108*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
109*01e8a6d0SThomas Weißschuh 	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
110*01e8a6d0SThomas Weißschuh 	register long _arg3 __asm__ ("x2") = (long)(arg3);                    \
111*01e8a6d0SThomas Weißschuh 	register long _arg4 __asm__ ("x3") = (long)(arg4);                    \
112*01e8a6d0SThomas Weißschuh 	register long _arg5 __asm__ ("x4") = (long)(arg5);                    \
113*01e8a6d0SThomas Weißschuh 									      \
114*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
115*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
116*01e8a6d0SThomas Weißschuh 		: "=r" (_arg1)                                                \
117*01e8a6d0SThomas Weißschuh 		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
118*01e8a6d0SThomas Weißschuh 		  "r"(_num)                                                   \
119*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
120*01e8a6d0SThomas Weißschuh 	);                                                                    \
121*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
122*01e8a6d0SThomas Weißschuh })
123*01e8a6d0SThomas Weißschuh 
124*01e8a6d0SThomas Weißschuh #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
125*01e8a6d0SThomas Weißschuh ({                                                                            \
126*01e8a6d0SThomas Weißschuh 	register long _num  __asm__ ("x8") = (num);                           \
127*01e8a6d0SThomas Weißschuh 	register long _arg1 __asm__ ("x0") = (long)(arg1);                    \
128*01e8a6d0SThomas Weißschuh 	register long _arg2 __asm__ ("x1") = (long)(arg2);                    \
129*01e8a6d0SThomas Weißschuh 	register long _arg3 __asm__ ("x2") = (long)(arg3);                    \
130*01e8a6d0SThomas Weißschuh 	register long _arg4 __asm__ ("x3") = (long)(arg4);                    \
131*01e8a6d0SThomas Weißschuh 	register long _arg5 __asm__ ("x4") = (long)(arg5);                    \
132*01e8a6d0SThomas Weißschuh 	register long _arg6 __asm__ ("x5") = (long)(arg6);                    \
133*01e8a6d0SThomas Weißschuh 									      \
134*01e8a6d0SThomas Weißschuh 	__asm__ volatile (                                                    \
135*01e8a6d0SThomas Weißschuh 		"svc #0\n"                                                    \
136*01e8a6d0SThomas Weißschuh 		: "=r" (_arg1)                                                \
137*01e8a6d0SThomas Weißschuh 		: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
138*01e8a6d0SThomas Weißschuh 		  "r"(_arg6), "r"(_num)                                       \
139*01e8a6d0SThomas Weißschuh 		: "memory", "cc"                                              \
140*01e8a6d0SThomas Weißschuh 	);                                                                    \
141*01e8a6d0SThomas Weißschuh 	_arg1;                                                                \
142*01e8a6d0SThomas Weißschuh })
143*01e8a6d0SThomas Weißschuh 
144*01e8a6d0SThomas Weißschuh /* startup code */
_start(void)145*01e8a6d0SThomas Weißschuh void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)
146*01e8a6d0SThomas Weißschuh {
147*01e8a6d0SThomas Weißschuh 	__asm__ volatile (
148*01e8a6d0SThomas Weißschuh 		"mov x0, sp\n"          /* save stack pointer to x0, as arg1 of _start_c */
149*01e8a6d0SThomas Weißschuh 		"bl  _start_c\n"        /* transfer to c runtime                         */
150*01e8a6d0SThomas Weißschuh 	);
151*01e8a6d0SThomas Weißschuh 	__nolibc_entrypoint_epilogue();
152*01e8a6d0SThomas Weißschuh }
153*01e8a6d0SThomas Weißschuh #endif /* _NOLIBC_ARCH_ARM64_H */
154