]> Git Repo - linux.git/blob - tools/include/nolibc/arch-arm.h
powerpc: implement the new page table range API
[linux.git] / tools / include / nolibc / arch-arm.h
1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3  * ARM specific definitions for NOLIBC
4  * Copyright (C) 2017-2022 Willy Tarreau <[email protected]>
5  */
6
7 #ifndef _NOLIBC_ARCH_ARM_H
8 #define _NOLIBC_ARCH_ARM_H
9
10 #include "compiler.h"
11
12 /* The struct returned by the stat() syscall, 32-bit only, the syscall returns
13  * exactly 56 bytes (stops before the unused array). In big endian, the format
14  * differs as devices are returned as short only.
15  */
16 struct sys_stat_struct {
17 #if defined(__ARMEB__)
18         unsigned short st_dev;
19         unsigned short __pad1;
20 #else
21         unsigned long  st_dev;
22 #endif
23         unsigned long  st_ino;
24         unsigned short st_mode;
25         unsigned short st_nlink;
26         unsigned short st_uid;
27         unsigned short st_gid;
28
29 #if defined(__ARMEB__)
30         unsigned short st_rdev;
31         unsigned short __pad2;
32 #else
33         unsigned long  st_rdev;
34 #endif
35         unsigned long  st_size;
36         unsigned long  st_blksize;
37         unsigned long  st_blocks;
38
39         unsigned long  st_atime;
40         unsigned long  st_atime_nsec;
41         unsigned long  st_mtime;
42         unsigned long  st_mtime_nsec;
43
44         unsigned long  st_ctime;
45         unsigned long  st_ctime_nsec;
46         unsigned long  __unused[2];
47 };
48
49 /* Syscalls for ARM in ARM or Thumb modes :
50  *   - registers are 32-bit
51  *   - stack is 8-byte aligned
52  *     ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html)
53  *   - syscall number is passed in r7
54  *   - arguments are in r0, r1, r2, r3, r4, r5
55  *   - the system call is performed by calling svc #0
56  *   - syscall return comes in r0.
57  *   - only lr is clobbered.
58  *   - the arguments are cast to long and assigned into the target registers
59  *     which are then simply passed as registers to the asm code, so that we
60  *     don't have to experience issues with register constraints.
61  *   - the syscall number is always specified last in order to allow to force
62  *     some registers before (gcc refuses a %-register at the last position).
63  *   - in thumb mode without -fomit-frame-pointer, r7 is also used to store the
64  *     frame pointer, and we cannot directly assign it as a register variable,
65  *     nor can we clobber it. Instead we assign the r6 register and swap it
66  *     with r7 before calling svc, and r6 is marked as clobbered.
67  *     We're just using any regular register which we assign to r7 after saving
68  *     it.
69  *
70  * Also, ARM supports the old_select syscall if newselect is not available
71  */
72 #define __ARCH_WANT_SYS_OLD_SELECT
73
74 #if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \
75     !defined(NOLIBC_OMIT_FRAME_POINTER)
76 /* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */
77 #define _NOLIBC_SYSCALL_REG         "r6"
78 #define _NOLIBC_THUMB_SET_R7        "eor r7, r6\neor r6, r7\neor r7, r6\n"
79 #define _NOLIBC_THUMB_RESTORE_R7    "mov r7, r6\n"
80
81 #else  /* we're in ARM mode */
82 /* in Arm mode we can directly use r7 */
83 #define _NOLIBC_SYSCALL_REG         "r7"
84 #define _NOLIBC_THUMB_SET_R7        ""
85 #define _NOLIBC_THUMB_RESTORE_R7    ""
86
87 #endif /* end THUMB */
88
89 #define my_syscall0(num)                                                      \
90 ({                                                                            \
91         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
92         register long _arg1 __asm__ ("r0");                                   \
93                                                                               \
94         __asm__  volatile (                                                   \
95                 _NOLIBC_THUMB_SET_R7                                          \
96                 "svc #0\n"                                                    \
97                 _NOLIBC_THUMB_RESTORE_R7                                      \
98                 : "=r"(_arg1), "=r"(_num)                                     \
99                 : "r"(_arg1),                                                 \
100                   "r"(_num)                                                   \
101                 : "memory", "cc", "lr"                                        \
102         );                                                                    \
103         _arg1;                                                                \
104 })
105
106 #define my_syscall1(num, arg1)                                                \
107 ({                                                                            \
108         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
109         register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
110                                                                               \
111         __asm__  volatile (                                                   \
112                 _NOLIBC_THUMB_SET_R7                                          \
113                 "svc #0\n"                                                    \
114                 _NOLIBC_THUMB_RESTORE_R7                                      \
115                 : "=r"(_arg1), "=r" (_num)                                    \
116                 : "r"(_arg1),                                                 \
117                   "r"(_num)                                                   \
118                 : "memory", "cc", "lr"                                        \
119         );                                                                    \
120         _arg1;                                                                \
121 })
122
123 #define my_syscall2(num, arg1, arg2)                                          \
124 ({                                                                            \
125         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
126         register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
127         register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
128                                                                               \
129         __asm__  volatile (                                                   \
130                 _NOLIBC_THUMB_SET_R7                                          \
131                 "svc #0\n"                                                    \
132                 _NOLIBC_THUMB_RESTORE_R7                                      \
133                 : "=r"(_arg1), "=r" (_num)                                    \
134                 : "r"(_arg1), "r"(_arg2),                                     \
135                   "r"(_num)                                                   \
136                 : "memory", "cc", "lr"                                        \
137         );                                                                    \
138         _arg1;                                                                \
139 })
140
141 #define my_syscall3(num, arg1, arg2, arg3)                                    \
142 ({                                                                            \
143         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
144         register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
145         register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
146         register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
147                                                                               \
148         __asm__  volatile (                                                   \
149                 _NOLIBC_THUMB_SET_R7                                          \
150                 "svc #0\n"                                                    \
151                 _NOLIBC_THUMB_RESTORE_R7                                      \
152                 : "=r"(_arg1), "=r" (_num)                                    \
153                 : "r"(_arg1), "r"(_arg2), "r"(_arg3),                         \
154                   "r"(_num)                                                   \
155                 : "memory", "cc", "lr"                                        \
156         );                                                                    \
157         _arg1;                                                                \
158 })
159
160 #define my_syscall4(num, arg1, arg2, arg3, arg4)                              \
161 ({                                                                            \
162         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
163         register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
164         register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
165         register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
166         register long _arg4 __asm__ ("r3") = (long)(arg4);                    \
167                                                                               \
168         __asm__  volatile (                                                   \
169                 _NOLIBC_THUMB_SET_R7                                          \
170                 "svc #0\n"                                                    \
171                 _NOLIBC_THUMB_RESTORE_R7                                      \
172                 : "=r"(_arg1), "=r" (_num)                                    \
173                 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4),             \
174                   "r"(_num)                                                   \
175                 : "memory", "cc", "lr"                                        \
176         );                                                                    \
177         _arg1;                                                                \
178 })
179
180 #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                        \
181 ({                                                                            \
182         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
183         register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
184         register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
185         register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
186         register long _arg4 __asm__ ("r3") = (long)(arg4);                    \
187         register long _arg5 __asm__ ("r4") = (long)(arg5);                    \
188                                                                               \
189         __asm__  volatile (                                                   \
190                 _NOLIBC_THUMB_SET_R7                                          \
191                 "svc #0\n"                                                    \
192                 _NOLIBC_THUMB_RESTORE_R7                                      \
193                 : "=r"(_arg1), "=r" (_num)                                    \
194                 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
195                   "r"(_num)                                                   \
196                 : "memory", "cc", "lr"                                        \
197         );                                                                    \
198         _arg1;                                                                \
199 })
200
201 #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                  \
202 ({                                                                            \
203         register long _num  __asm__(_NOLIBC_SYSCALL_REG) = (num);             \
204         register long _arg1 __asm__ ("r0") = (long)(arg1);                    \
205         register long _arg2 __asm__ ("r1") = (long)(arg2);                    \
206         register long _arg3 __asm__ ("r2") = (long)(arg3);                    \
207         register long _arg4 __asm__ ("r3") = (long)(arg4);                    \
208         register long _arg5 __asm__ ("r4") = (long)(arg5);                    \
209         register long _arg6 __asm__ ("r5") = (long)(arg6);                    \
210                                                                               \
211         __asm__  volatile (                                                   \
212                 _NOLIBC_THUMB_SET_R7                                          \
213                 "svc #0\n"                                                    \
214                 _NOLIBC_THUMB_RESTORE_R7                                      \
215                 : "=r"(_arg1), "=r" (_num)                                    \
216                 : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
217                   "r"(_arg6), "r"(_num)                                       \
218                 : "memory", "cc", "lr"                                        \
219         );                                                                    \
220         _arg1;                                                                \
221 })
222
223
224 char **environ __attribute__((weak));
225 const unsigned long *_auxv __attribute__((weak));
226
227 /* startup code */
228 void __attribute__((weak,noreturn,optimize("omit-frame-pointer"))) __no_stack_protector _start(void)
229 {
230         __asm__ volatile (
231 #ifdef _NOLIBC_STACKPROTECTOR
232                 "bl __stack_chk_init\n"       /* initialize stack protector                          */
233 #endif
234                 "pop {%r0}\n"                 /* argc was in the stack                               */
235                 "mov %r1, %sp\n"              /* argv = sp                                           */
236
237                 "add %r2, %r0, $1\n"          /* envp = (argc + 1) ...                               */
238                 "lsl %r2, %r2, $2\n"          /*        * 4        ...                               */
239                 "add %r2, %r2, %r1\n"         /*        + argv                                       */
240                 "ldr %r3, 1f\n"               /* r3 = &environ (see below)                           */
241                 "str %r2, [r3]\n"             /* store envp into environ                             */
242
243                 "mov r4, r2\n"                /* search for auxv (follows NULL after last env)       */
244                 "0:\n"
245                 "mov r5, r4\n"                /* r5 = r4                                             */
246                 "add r4, r4, #4\n"            /* r4 += 4                                             */
247                 "ldr r5,[r5]\n"               /* r5 = *r5 = *(r4-4)                                  */
248                 "cmp r5, #0\n"                /* and stop at NULL after last env                     */
249                 "bne 0b\n"
250                 "ldr %r3, 2f\n"               /* r3 = &_auxv (low bits)                              */
251                 "str r4, [r3]\n"              /* store r4 into _auxv                                 */
252
253                 "mov %r3, $8\n"               /* AAPCS : sp must be 8-byte aligned in the            */
254                 "neg %r3, %r3\n"              /*         callee, and bl doesn't push (lr=pc)         */
255                 "and %r3, %r3, %r1\n"         /* so we do sp = r1(=sp) & r3(=-8);                    */
256                 "mov %sp, %r3\n"
257
258                 "bl main\n"                   /* main() returns the status code, we'll exit with it. */
259                 "movs r7, $1\n"               /* NR_exit == 1                                        */
260                 "svc $0x00\n"
261                 ".align 2\n"                  /* below are the pointers to a few variables           */
262                 "1:\n"
263                 ".word environ\n"
264                 "2:\n"
265                 ".word _auxv\n"
266         );
267         __builtin_unreachable();
268 }
269
270 #endif /* _NOLIBC_ARCH_ARM_H */
This page took 0.050556 seconds and 4 git commands to generate.