1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub const syscall_arg_t = u32;
6
7pub fn syscall0(
8 number: SYS,
9) u32 {
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: u32 = undefined;
15 return asm volatile (
16 \\ sc
17 \\ bns+ 1f
18 \\ neg 3, 3
19 \\1:
20 : [ret] "={r3}" (-> u32),
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) u32 {
30 // r0 is both an input and a clobber.
31 var r0_out: u32 = undefined;
32 return asm volatile (
33 \\ sc
34 \\ bns+ 1f
35 \\ neg 3, 3
36 \\1:
37 : [ret] "={r3}" (-> u32),
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) u32 {
49 // These registers are both inputs and clobbers.
50 var r0_out: u32 = undefined;
51 var r4_out: u32 = undefined;
52 return asm volatile (
53 \\ sc
54 \\ bns+ 1f
55 \\ neg 3, 3
56 \\1:
57 : [ret] "={r3}" (-> u32),
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) u32 {
72 // These registers are both inputs and clobbers.
73 var r0_out: u32 = undefined;
74 var r4_out: u32 = undefined;
75 var r5_out: u32 = undefined;
76 return asm volatile (
77 \\ sc
78 \\ bns+ 1f
79 \\ neg 3, 3
80 \\1:
81 : [ret] "={r3}" (-> u32),
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) u32 {
99 // These registers are both inputs and clobbers.
100 var r0_out: u32 = undefined;
101 var r4_out: u32 = undefined;
102 var r5_out: u32 = undefined;
103 var r6_out: u32 = undefined;
104 return asm volatile (
105 \\ sc
106 \\ bns+ 1f
107 \\ neg 3, 3
108 \\1:
109 : [ret] "={r3}" (-> u32),
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) u32 {
130 // These registers are both inputs and clobbers.
131 var r0_out: u32 = undefined;
132 var r4_out: u32 = undefined;
133 var r5_out: u32 = undefined;
134 var r6_out: u32 = undefined;
135 var r7_out: u32 = undefined;
136 return asm volatile (
137 \\ sc
138 \\ bns+ 1f
139 \\ neg 3, 3
140 \\1:
141 : [ret] "={r3}" (-> u32),
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) u32 {
165 // These registers are both inputs and clobbers.
166 var r0_out: u32 = undefined;
167 var r4_out: u32 = undefined;
168 var r5_out: u32 = undefined;
169 var r6_out: u32 = undefined;
170 var r7_out: u32 = undefined;
171 var r8_out: u32 = undefined;
172 return asm volatile (
173 \\ sc
174 \\ bns+ 1f
175 \\ neg 3, 3
176 \\1:
177 : [ret] "={r3}" (-> u32),
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) u32 {
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 \\ # store non-volatile regs r29, r30 on stack in order to put our
202 \\ # start func and its arg there
203 \\ stwu 1, -16(1)
204 \\ stw 29, 8(1)
205 \\ stw 30, 12(1)
206 \\
207 \\ # save r3 (func) into r29, and r6(arg) into r30
208 \\ mr 29, 3
209 \\ mr 30, 6
210 \\
211 \\ # create initial stack frame for new thread
212 \\ clrrwi 4, 4, 4
213 \\ li 0, 0
214 \\ stwu 0, -16(4)
215 \\
216 \\ #move c into first arg
217 \\ mr 3, 5
218 \\ #mr 4, 4
219 \\ mr 5, 7
220 \\ mr 6, 8
221 \\ mr 7, 9
222 \\
223 \\ # move syscall number into r0
224 \\ li 0, 120 # SYS_clone
225 \\
226 \\ sc
227 \\
228 \\ # check for syscall error
229 \\ bns+ 1f # jump to label 1 if no summary overflow.
230 \\ #else
231 \\ neg 3, 3 #negate the result (errno)
232 \\ 1:
233 \\ # compare sc result with 0
234 \\ cmpwi cr7, 3, 0
235 \\
236 \\ # if not 0, restore stack and return
237 \\ beq cr7, 2f
238 \\ lwz 29, 8(1)
239 \\ lwz 30, 12(1)
240 \\ addi 1, 1, 16
241 \\ blr
242 \\
243 \\ #else: we're the child
244 \\ 2:
245 );
246 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
247 \\ .cfi_undefined lr
248 );
249 asm volatile (
250 \\ li 31, 0
251 \\ mtlr 31
252 \\
253 \\ #call funcptr: move arg (d) into r3
254 \\ mr 3, 30
255 \\ #move r29 (funcptr) into CTR reg
256 \\ mtctr 29
257 \\ # call CTR reg
258 \\ bctrl
259 \\ # mov SYS_exit into r0 (the exit param is already in r3)
260 \\ li 0, 1
261 \\ sc
262 );
263}
264
265pub fn restore() callconv(.naked) noreturn {
266 asm volatile (
267 \\ li 0, %[number]
268 \\ sc
269 :
270 : [number] "i" (@backingInt(SYS.sigreturn)),
271 );
272}
273
274pub fn restore_rt() callconv(.naked) noreturn {
275 asm volatile (
276 \\ li 0, %[number]
277 \\ sc
278 :
279 : [number] "i" (@backingInt(SYS.rt_sigreturn)),
280 );
281}
282
283pub const VDSO = struct {
284 pub const CGT_SYM = "__kernel_clock_gettime";
285 pub const CGT_VER = "LINUX_2.6.15";
286};
287
288pub const time_t = i32;