1271661c1SWilly Tarreau /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2271661c1SWilly Tarreau /*
3271661c1SWilly Tarreau * AARCH64 specific definitions for NOLIBC
4271661c1SWilly Tarreau * Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
5271661c1SWilly Tarreau */
6271661c1SWilly Tarreau
7271661c1SWilly Tarreau #ifndef _NOLIBC_ARCH_AARCH64_H
8271661c1SWilly Tarreau #define _NOLIBC_ARCH_AARCH64_H
9271661c1SWilly Tarreau
10818924d1SThomas Weißschuh #include "compiler.h"
11*ded8af47SZhangjin Wu #include "crt.h"
12818924d1SThomas Weißschuh
13271661c1SWilly Tarreau /* Syscalls for AARCH64 :
14271661c1SWilly Tarreau * - registers are 64-bit
15271661c1SWilly Tarreau * - stack is 16-byte aligned
16271661c1SWilly Tarreau * - syscall number is passed in x8
17271661c1SWilly Tarreau * - arguments are in x0, x1, x2, x3, x4, x5
18271661c1SWilly Tarreau * - the system call is performed by calling svc 0
19271661c1SWilly Tarreau * - syscall return comes in x0.
20271661c1SWilly Tarreau * - the arguments are cast to long and assigned into the target registers
21271661c1SWilly Tarreau * which are then simply passed as registers to the asm code, so that we
22271661c1SWilly Tarreau * don't have to experience issues with register constraints.
23271661c1SWilly Tarreau *
24271661c1SWilly Tarreau * On aarch64, select() is not implemented so we have to use pselect6().
25271661c1SWilly Tarreau */
26271661c1SWilly Tarreau #define __ARCH_WANT_SYS_PSELECT6
27271661c1SWilly Tarreau
28271661c1SWilly Tarreau #define my_syscall0(num) \
29271661c1SWilly Tarreau ({ \
3037d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
3137d62758SAmmar Faizi register long _arg1 __asm__ ("x0"); \
32271661c1SWilly Tarreau \
3337d62758SAmmar Faizi __asm__ volatile ( \
34271661c1SWilly Tarreau "svc #0\n" \
35271661c1SWilly Tarreau : "=r"(_arg1) \
36271661c1SWilly Tarreau : "r"(_num) \
37271661c1SWilly Tarreau : "memory", "cc" \
38271661c1SWilly Tarreau ); \
39271661c1SWilly Tarreau _arg1; \
40271661c1SWilly Tarreau })
41271661c1SWilly Tarreau
42271661c1SWilly Tarreau #define my_syscall1(num, arg1) \
43271661c1SWilly Tarreau ({ \
4437d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
4537d62758SAmmar Faizi register long _arg1 __asm__ ("x0") = (long)(arg1); \
46271661c1SWilly Tarreau \
4737d62758SAmmar Faizi __asm__ volatile ( \
48271661c1SWilly Tarreau "svc #0\n" \
49271661c1SWilly Tarreau : "=r"(_arg1) \
50271661c1SWilly Tarreau : "r"(_arg1), \
51271661c1SWilly Tarreau "r"(_num) \
52271661c1SWilly Tarreau : "memory", "cc" \
53271661c1SWilly Tarreau ); \
54271661c1SWilly Tarreau _arg1; \
55271661c1SWilly Tarreau })
56271661c1SWilly Tarreau
57271661c1SWilly Tarreau #define my_syscall2(num, arg1, arg2) \
58271661c1SWilly Tarreau ({ \
5937d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
6037d62758SAmmar Faizi register long _arg1 __asm__ ("x0") = (long)(arg1); \
6137d62758SAmmar Faizi register long _arg2 __asm__ ("x1") = (long)(arg2); \
62271661c1SWilly Tarreau \
6337d62758SAmmar Faizi __asm__ volatile ( \
64271661c1SWilly Tarreau "svc #0\n" \
65271661c1SWilly Tarreau : "=r"(_arg1) \
66271661c1SWilly Tarreau : "r"(_arg1), "r"(_arg2), \
67271661c1SWilly Tarreau "r"(_num) \
68271661c1SWilly Tarreau : "memory", "cc" \
69271661c1SWilly Tarreau ); \
70271661c1SWilly Tarreau _arg1; \
71271661c1SWilly Tarreau })
72271661c1SWilly Tarreau
73271661c1SWilly Tarreau #define my_syscall3(num, arg1, arg2, arg3) \
74271661c1SWilly Tarreau ({ \
7537d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
7637d62758SAmmar Faizi register long _arg1 __asm__ ("x0") = (long)(arg1); \
7737d62758SAmmar Faizi register long _arg2 __asm__ ("x1") = (long)(arg2); \
7837d62758SAmmar Faizi register long _arg3 __asm__ ("x2") = (long)(arg3); \
79271661c1SWilly Tarreau \
8037d62758SAmmar Faizi __asm__ volatile ( \
81271661c1SWilly Tarreau "svc #0\n" \
82271661c1SWilly Tarreau : "=r"(_arg1) \
83271661c1SWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), \
84271661c1SWilly Tarreau "r"(_num) \
85271661c1SWilly Tarreau : "memory", "cc" \
86271661c1SWilly Tarreau ); \
87271661c1SWilly Tarreau _arg1; \
88271661c1SWilly Tarreau })
89271661c1SWilly Tarreau
90271661c1SWilly Tarreau #define my_syscall4(num, arg1, arg2, arg3, arg4) \
91271661c1SWilly Tarreau ({ \
9237d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
9337d62758SAmmar Faizi register long _arg1 __asm__ ("x0") = (long)(arg1); \
9437d62758SAmmar Faizi register long _arg2 __asm__ ("x1") = (long)(arg2); \
9537d62758SAmmar Faizi register long _arg3 __asm__ ("x2") = (long)(arg3); \
9637d62758SAmmar Faizi register long _arg4 __asm__ ("x3") = (long)(arg4); \
97271661c1SWilly Tarreau \
9837d62758SAmmar Faizi __asm__ volatile ( \
99271661c1SWilly Tarreau "svc #0\n" \
100271661c1SWilly Tarreau : "=r"(_arg1) \
101271661c1SWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
102271661c1SWilly Tarreau "r"(_num) \
103271661c1SWilly Tarreau : "memory", "cc" \
104271661c1SWilly Tarreau ); \
105271661c1SWilly Tarreau _arg1; \
106271661c1SWilly Tarreau })
107271661c1SWilly Tarreau
108271661c1SWilly Tarreau #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
109271661c1SWilly Tarreau ({ \
11037d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
11137d62758SAmmar Faizi register long _arg1 __asm__ ("x0") = (long)(arg1); \
11237d62758SAmmar Faizi register long _arg2 __asm__ ("x1") = (long)(arg2); \
11337d62758SAmmar Faizi register long _arg3 __asm__ ("x2") = (long)(arg3); \
11437d62758SAmmar Faizi register long _arg4 __asm__ ("x3") = (long)(arg4); \
11537d62758SAmmar Faizi register long _arg5 __asm__ ("x4") = (long)(arg5); \
116271661c1SWilly Tarreau \
11737d62758SAmmar Faizi __asm__ volatile ( \
118271661c1SWilly Tarreau "svc #0\n" \
119271661c1SWilly Tarreau : "=r" (_arg1) \
120271661c1SWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
121271661c1SWilly Tarreau "r"(_num) \
122271661c1SWilly Tarreau : "memory", "cc" \
123271661c1SWilly Tarreau ); \
124271661c1SWilly Tarreau _arg1; \
125271661c1SWilly Tarreau })
126271661c1SWilly Tarreau
127271661c1SWilly Tarreau #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
128271661c1SWilly Tarreau ({ \
12937d62758SAmmar Faizi register long _num __asm__ ("x8") = (num); \
13037d62758SAmmar Faizi register long _arg1 __asm__ ("x0") = (long)(arg1); \
13137d62758SAmmar Faizi register long _arg2 __asm__ ("x1") = (long)(arg2); \
13237d62758SAmmar Faizi register long _arg3 __asm__ ("x2") = (long)(arg3); \
13337d62758SAmmar Faizi register long _arg4 __asm__ ("x3") = (long)(arg4); \
13437d62758SAmmar Faizi register long _arg5 __asm__ ("x4") = (long)(arg5); \
13537d62758SAmmar Faizi register long _arg6 __asm__ ("x5") = (long)(arg6); \
136271661c1SWilly Tarreau \
13737d62758SAmmar Faizi __asm__ volatile ( \
138271661c1SWilly Tarreau "svc #0\n" \
139271661c1SWilly Tarreau : "=r" (_arg1) \
140271661c1SWilly Tarreau : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
141271661c1SWilly Tarreau "r"(_arg6), "r"(_num) \
142271661c1SWilly Tarreau : "memory", "cc" \
143271661c1SWilly Tarreau ); \
144271661c1SWilly Tarreau _arg1; \
145271661c1SWilly Tarreau })
146271661c1SWilly Tarreau
147271661c1SWilly Tarreau /* startup code */
_start(void)148bff60150SZhangjin Wu void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
1497f854858SWilly Tarreau {
1507f854858SWilly Tarreau __asm__ volatile (
151*ded8af47SZhangjin Wu "mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */
152*ded8af47SZhangjin Wu "and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */
153*ded8af47SZhangjin Wu "bl _start_c\n" /* transfer to c runtime */
1547f854858SWilly Tarreau );
1557f854858SWilly Tarreau __builtin_unreachable();
1567f854858SWilly Tarreau }
157fddc8f81SThomas Weißschuh #endif /* _NOLIBC_ARCH_AARCH64_H */
158