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