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