1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3 * hexagon specific definitions for NOLIBC
4 * Copyright (C) 2026 Thomas Weißschuh <linux@weissschuh.net>
5 */
6
7 #ifndef _NOLIBC_ARCH_HEXAGON_H
8 #define _NOLIBC_ARCH_HEXAGON_H
9
10 #include <linux/unistd.h>
11
12 #include "compiler.h"
13 #include "crt.h"
14
15 /*
16 * Syscalls for hexagon:
17 * - syscall number is passed in r6
18 * - arguments are in r0, r1, r2, r3, r4, r5
19 * - the system call is performed by calling trap0(#1)
20 * - syscall return value is in r0
21 */
22
23 #define _NOLIBC_SYSCALL_CLOBBERLIST "memory"
24
25 #define __nolibc_syscall0(num) \
26 ({ \
27 register long _num __asm__ ("r6") = (num); \
28 register long _arg1 __asm__ ("r0"); \
29 \
30 __asm__ volatile ( \
31 "trap0(#1)\n" \
32 : "=r"(_arg1) \
33 : "r"(_num) \
34 : _NOLIBC_SYSCALL_CLOBBERLIST \
35 ); \
36 _arg1; \
37 })
38
39 #define __nolibc_syscall1(num, arg1) \
40 ({ \
41 register long _num __asm__ ("r6") = (num); \
42 register long _arg1 __asm__ ("r0") = (long)(arg1); \
43 \
44 __asm__ volatile ( \
45 "trap0(#1)\n" \
46 : "+r"(_arg1) \
47 : "r"(_num) \
48 : _NOLIBC_SYSCALL_CLOBBERLIST \
49 ); \
50 _arg1; \
51 })
52
53 #define __nolibc_syscall2(num, arg1, arg2) \
54 ({ \
55 register long _num __asm__ ("r6") = (num); \
56 register long _arg1 __asm__ ("r0") = (long)(arg1); \
57 register long _arg2 __asm__ ("r1") = (long)(arg2); \
58 \
59 __asm__ volatile ( \
60 "trap0(#1)\n" \
61 : "+r"(_arg1) \
62 : "r"(_arg2), \
63 "r"(_num) \
64 : _NOLIBC_SYSCALL_CLOBBERLIST \
65 ); \
66 _arg1; \
67 })
68
69 #define __nolibc_syscall3(num, arg1, arg2, arg3) \
70 ({ \
71 register long _num __asm__ ("r6") = (num); \
72 register long _arg1 __asm__ ("r0") = (long)(arg1); \
73 register long _arg2 __asm__ ("r1") = (long)(arg2); \
74 register long _arg3 __asm__ ("r2") = (long)(arg3); \
75 \
76 __asm__ volatile ( \
77 "trap0(#1)\n" \
78 : "+r"(_arg1) \
79 : "r"(_arg2), "r"(_arg3), \
80 "r"(_num) \
81 : _NOLIBC_SYSCALL_CLOBBERLIST \
82 ); \
83 _arg1; \
84 })
85
86 #define __nolibc_syscall4(num, arg1, arg2, arg3, arg4) \
87 ({ \
88 register long _num __asm__ ("r6") = (num); \
89 register long _arg1 __asm__ ("r0") = (long)(arg1); \
90 register long _arg2 __asm__ ("r1") = (long)(arg2); \
91 register long _arg3 __asm__ ("r2") = (long)(arg3); \
92 register long _arg4 __asm__ ("r3") = (long)(arg4); \
93 \
94 __asm__ volatile ( \
95 "trap0(#1)\n" \
96 : "+r"(_arg1) \
97 : "r"(_arg2), "r"(_arg3), "r"(_arg4), \
98 "r"(_num) \
99 : _NOLIBC_SYSCALL_CLOBBERLIST \
100 ); \
101 _arg1; \
102 })
103
104 #define __nolibc_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
105 ({ \
106 register long _num __asm__ ("r6") = (num); \
107 register long _arg1 __asm__ ("r0") = (long)(arg1); \
108 register long _arg2 __asm__ ("r1") = (long)(arg2); \
109 register long _arg3 __asm__ ("r2") = (long)(arg3); \
110 register long _arg4 __asm__ ("r3") = (long)(arg4); \
111 register long _arg5 __asm__ ("r4") = (long)(arg5); \
112 \
113 __asm__ volatile ( \
114 "trap0(#1)\n" \
115 : "+r"(_arg1) \
116 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
117 "r"(_num) \
118 : _NOLIBC_SYSCALL_CLOBBERLIST \
119 ); \
120 _arg1; \
121 })
122
123 #define __nolibc_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
124 ({ \
125 register long _num __asm__ ("r6") = (num); \
126 register long _arg1 __asm__ ("r0") = (long)(arg1); \
127 register long _arg2 __asm__ ("r1") = (long)(arg2); \
128 register long _arg3 __asm__ ("r2") = (long)(arg3); \
129 register long _arg4 __asm__ ("r3") = (long)(arg4); \
130 register long _arg5 __asm__ ("r4") = (long)(arg5); \
131 register long _arg6 __asm__ ("r5") = (long)(arg6); \
132 \
133 __asm__ volatile ( \
134 "trap0(#1)\n" \
135 : "+r"(_arg1) \
136 : "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), "r"(_arg6), \
137 "r"(_num) \
138 : _NOLIBC_SYSCALL_CLOBBERLIST \
139 ); \
140 _arg1; \
141 })
142
143 #ifndef NOLIBC_NO_RUNTIME
144 /* startup code */
145 void __attribute__((weak, noreturn))
146 __nolibc_entrypoint __nolibc_no_stack_protector
_start(void)147 _start(void)
148 {
149 __asm__ volatile (
150 "r0 = sp\n" /* save stack pointer to r0, as arg1 of _start_c */
151 "call _start_c\n" /* transfer to c runtime */
152 );
153 __nolibc_entrypoint_epilogue();
154 }
155 #endif /* NOLIBC_NO_RUNTIME */
156
157 #define __NOLIBC_PAD_64BIT_SYSCALL_ARGUMENT_PAIR
158
159 #endif /* _NOLIBC_ARCH_HEXAGON_H */
160