1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub const syscall_arg_t = u64;
6
7pub fn syscall0(
8 number: SYS,
9) u64 {
10 // r0 is both an input register and a clobber. musl and glibc achieve this with
11 // a "+" constraint, which isn't supported in Zig, so instead we separately list
12 // r0 as both an input and an output. (Listing it as an input and a clobber would
13 // cause the C backend to emit invalid code; see #25209.)
14 var r0_out: u64 = undefined;
15 return asm volatile (
16 \\ sc
17 \\ bns+ 1f
18 \\ neg 3, 3
19 \\1:
20 : [ret] "={r3}" (-> u64),
21 [r0_out] "={r0}" (r0_out),
22 : [number] "{r0}" (@backingInt(number)),
23 : .{ .memory = true, .cr0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
24}
25
26pub fn syscall1(
27 number: SYS,
28 arg1: syscall_arg_t,
29) u64 {
30 // r0 is both an input and a clobber.
31 var r0_out: u64 = undefined;
32 return asm volatile (
33 \\ sc
34 \\ bns+ 1f
35 \\ neg 3, 3
36 \\1:
37 : [ret] "={r3}" (-> u64),
38 [r0_out] "={r0}" (r0_out),
39 : [number] "{r0}" (@backingInt(number)),
40 [arg1] "{r3}" (arg1),
41 : .{ .memory = true, .cr0 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
42}
43
44pub fn syscall2(
45 number: SYS,
46 arg1: syscall_arg_t,
47 arg2: syscall_arg_t,
48) u64 {
49 // These registers are both inputs and clobbers.
50 var r0_out: u64 = undefined;
51 var r4_out: u64 = undefined;
52 return asm volatile (
53 \\ sc
54 \\ bns+ 1f
55 \\ neg 3, 3
56 \\1:
57 : [ret] "={r3}" (-> u64),
58 [r0_out] "={r0}" (r0_out),
59 [r4_out] "={r4}" (r4_out),
60 : [number] "{r0}" (@backingInt(number)),
61 [arg1] "{r3}" (arg1),
62 [arg2] "{r4}" (arg2),
63 : .{ .memory = true, .cr0 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
64}
65
66pub fn syscall3(
67 number: SYS,
68 arg1: syscall_arg_t,
69 arg2: syscall_arg_t,
70 arg3: syscall_arg_t,
71) u64 {
72 // These registers are both inputs and clobbers.
73 var r0_out: u64 = undefined;
74 var r4_out: u64 = undefined;
75 var r5_out: u64 = undefined;
76 return asm volatile (
77 \\ sc
78 \\ bns+ 1f
79 \\ neg 3, 3
80 \\1:
81 : [ret] "={r3}" (-> u64),
82 [r0_out] "={r0}" (r0_out),
83 [r4_out] "={r4}" (r4_out),
84 [r5_out] "={r5}" (r5_out),
85 : [number] "{r0}" (@backingInt(number)),
86 [arg1] "{r3}" (arg1),
87 [arg2] "{r4}" (arg2),
88 [arg3] "{r5}" (arg3),
89 : .{ .memory = true, .cr0 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
90}
91
92pub fn syscall4(
93 number: SYS,
94 arg1: syscall_arg_t,
95 arg2: syscall_arg_t,
96 arg3: syscall_arg_t,
97 arg4: syscall_arg_t,
98) u64 {
99 // These registers are both inputs and clobbers.
100 var r0_out: u64 = undefined;
101 var r4_out: u64 = undefined;
102 var r5_out: u64 = undefined;
103 var r6_out: u64 = undefined;
104 return asm volatile (
105 \\ sc
106 \\ bns+ 1f
107 \\ neg 3, 3
108 \\1:
109 : [ret] "={r3}" (-> u64),
110 [r0_out] "={r0}" (r0_out),
111 [r4_out] "={r4}" (r4_out),
112 [r5_out] "={r5}" (r5_out),
113 [r6_out] "={r6}" (r6_out),
114 : [number] "{r0}" (@backingInt(number)),
115 [arg1] "{r3}" (arg1),
116 [arg2] "{r4}" (arg2),
117 [arg3] "{r5}" (arg3),
118 [arg4] "{r6}" (arg4),
119 : .{ .memory = true, .cr0 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
120}
121
122pub fn syscall5(
123 number: SYS,
124 arg1: syscall_arg_t,
125 arg2: syscall_arg_t,
126 arg3: syscall_arg_t,
127 arg4: syscall_arg_t,
128 arg5: syscall_arg_t,
129) u64 {
130 // These registers are both inputs and clobbers.
131 var r0_out: u64 = undefined;
132 var r4_out: u64 = undefined;
133 var r5_out: u64 = undefined;
134 var r6_out: u64 = undefined;
135 var r7_out: u64 = undefined;
136 return asm volatile (
137 \\ sc
138 \\ bns+ 1f
139 \\ neg 3, 3
140 \\1:
141 : [ret] "={r3}" (-> u64),
142 [r0_out] "={r0}" (r0_out),
143 [r4_out] "={r4}" (r4_out),
144 [r5_out] "={r5}" (r5_out),
145 [r6_out] "={r6}" (r6_out),
146 [r7_out] "={r7}" (r7_out),
147 : [number] "{r0}" (@backingInt(number)),
148 [arg1] "{r3}" (arg1),
149 [arg2] "{r4}" (arg2),
150 [arg3] "{r5}" (arg3),
151 [arg4] "{r6}" (arg4),
152 [arg5] "{r7}" (arg5),
153 : .{ .memory = true, .cr0 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
154}
155
156pub fn syscall6(
157 number: SYS,
158 arg1: syscall_arg_t,
159 arg2: syscall_arg_t,
160 arg3: syscall_arg_t,
161 arg4: syscall_arg_t,
162 arg5: syscall_arg_t,
163 arg6: syscall_arg_t,
164) u64 {
165 // These registers are both inputs and clobbers.
166 var r0_out: u64 = undefined;
167 var r4_out: u64 = undefined;
168 var r5_out: u64 = undefined;
169 var r6_out: u64 = undefined;
170 var r7_out: u64 = undefined;
171 var r8_out: u64 = undefined;
172 return asm volatile (
173 \\ sc
174 \\ bns+ 1f
175 \\ neg 3, 3
176 \\1:
177 : [ret] "={r3}" (-> u64),
178 [r0_out] "={r0}" (r0_out),
179 [r4_out] "={r4}" (r4_out),
180 [r5_out] "={r5}" (r5_out),
181 [r6_out] "={r6}" (r6_out),
182 [r7_out] "={r7}" (r7_out),
183 [r8_out] "={r8}" (r8_out),
184 : [number] "{r0}" (@backingInt(number)),
185 [arg1] "{r3}" (arg1),
186 [arg2] "{r4}" (arg2),
187 [arg3] "{r5}" (arg3),
188 [arg4] "{r6}" (arg4),
189 [arg5] "{r7}" (arg5),
190 [arg6] "{r8}" (arg6),
191 : .{ .memory = true, .cr0 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
192}
193
194pub fn clone() callconv(.naked) u64 {
195 // __clone(func, stack, flags, arg, ptid, tls, ctid)
196 // 3, 4, 5, 6, 7, 8, 9
197 //
198 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
199 // 0 3, 4, 5, 6, 7
200 asm volatile (
201 \\ # create initial stack frame for new thread
202 \\ clrrdi 4, 4, 4
203 \\ li 0, 0
204 \\ stdu 0,-32(4)
205 \\
206 \\ # save fn and arg to child stack
207 \\ std 3, 8(4)
208 \\ std 6, 16(4)
209 \\
210 \\ # shuffle args into correct registers and call SYS_clone
211 \\ mr 3, 5
212 \\ #mr 4, 4
213 \\ mr 5, 7
214 \\ mr 6, 8
215 \\ mr 7, 9
216 \\ li 0, 120 # SYS_clone = 120
217 \\ sc
218 \\
219 \\ # if error, negate return (errno)
220 \\ bns+ 1f
221 \\ neg 3, 3
222 \\
223 \\1:
224 \\ # if we're the parent, return
225 \\ cmpwi cr7, 3, 0
226 \\ bnelr cr7
227 \\
228 \\ # we're the child
229 );
230 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
231 \\ .cfi_undefined lr
232 );
233 asm volatile (
234 \\ li 31, 0
235 \\ mtlr 31
236 \\
237 \\ # call fn(arg)
238 \\ ld 3, 16(1)
239 \\ ld 12, 8(1)
240 \\ mtctr 12
241 \\ bctrl
242 \\
243 \\ # call SYS_exit. exit code is already in r3 from fn return value
244 \\ li 0, 1 # SYS_exit = 1
245 \\ sc
246 );
247}
248
249pub fn restore() callconv(.naked) noreturn {
250 asm volatile (
251 \\ li 0, %[number]
252 \\ sc
253 :
254 : [number] "i" (@backingInt(SYS.sigreturn)),
255 );
256}
257
258pub fn restore_rt() callconv(.naked) noreturn {
259 asm volatile (
260 \\ li 0, %[number]
261 \\ sc
262 :
263 : [number] "i" (@backingInt(SYS.rt_sigreturn)),
264 );
265}
266
267pub const VDSO = struct {
268 pub const CGT_SYM = "__kernel_clock_gettime";
269 pub const CGT_VER = "LINUX_2.6.15";
270};
271
272pub const time_t = i64;