master
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub fn syscall0(number: SYS) u32 {
6 // r0 is both an input register and a clobber. musl and glibc achieve this with
7 // a "+" constraint, which isn't supported in Zig, so instead we separately list
8 // r0 as both an input and an output. (Listing it as an input and a clobber would
9 // cause the C backend to emit invalid code; see #25209.)
10 var r0_out: u32 = undefined;
11 return asm volatile (
12 \\ sc
13 \\ bns+ 1f
14 \\ neg 3, 3
15 \\ 1:
16 : [ret] "={r3}" (-> u32),
17 [r0_out] "={r0}" (r0_out),
18 : [number] "{r0}" (@intFromEnum(number)),
19 : .{ .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 });
20}
21
22pub fn syscall1(number: SYS, arg1: u32) u32 {
23 // r0 is both an input and a clobber.
24 var r0_out: u32 = undefined;
25 return asm volatile (
26 \\ sc
27 \\ bns+ 1f
28 \\ neg 3, 3
29 \\ 1:
30 : [ret] "={r3}" (-> u32),
31 [r0_out] "={r0}" (r0_out),
32 : [number] "{r0}" (@intFromEnum(number)),
33 [arg1] "{r3}" (arg1),
34 : .{ .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 });
35}
36
37pub fn syscall2(number: SYS, arg1: u32, arg2: u32) u32 {
38 // These registers are both inputs and clobbers.
39 var r0_out: u32 = undefined;
40 var r4_out: u32 = undefined;
41 return asm volatile (
42 \\ sc
43 \\ bns+ 1f
44 \\ neg 3, 3
45 \\ 1:
46 : [ret] "={r3}" (-> u32),
47 [r0_out] "={r0}" (r0_out),
48 [r4_out] "={r4}" (r4_out),
49 : [number] "{r0}" (@intFromEnum(number)),
50 [arg1] "{r3}" (arg1),
51 [arg2] "{r4}" (arg2),
52 : .{ .memory = true, .cr0 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
53}
54
55pub fn syscall3(number: SYS, arg1: u32, arg2: u32, arg3: u32) u32 {
56 // These registers are both inputs and clobbers.
57 var r0_out: u32 = undefined;
58 var r4_out: u32 = undefined;
59 var r5_out: u32 = undefined;
60 return asm volatile (
61 \\ sc
62 \\ bns+ 1f
63 \\ neg 3, 3
64 \\ 1:
65 : [ret] "={r3}" (-> u32),
66 [r0_out] "={r0}" (r0_out),
67 [r4_out] "={r4}" (r4_out),
68 [r5_out] "={r5}" (r5_out),
69 : [number] "{r0}" (@intFromEnum(number)),
70 [arg1] "{r3}" (arg1),
71 [arg2] "{r4}" (arg2),
72 [arg3] "{r5}" (arg3),
73 : .{ .memory = true, .cr0 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
74}
75
76pub fn syscall4(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32) u32 {
77 // These registers are both inputs and clobbers.
78 var r0_out: u32 = undefined;
79 var r4_out: u32 = undefined;
80 var r5_out: u32 = undefined;
81 var r6_out: u32 = undefined;
82 return asm volatile (
83 \\ sc
84 \\ bns+ 1f
85 \\ neg 3, 3
86 \\ 1:
87 : [ret] "={r3}" (-> u32),
88 [r0_out] "={r0}" (r0_out),
89 [r4_out] "={r4}" (r4_out),
90 [r5_out] "={r5}" (r5_out),
91 [r6_out] "={r6}" (r6_out),
92 : [number] "{r0}" (@intFromEnum(number)),
93 [arg1] "{r3}" (arg1),
94 [arg2] "{r4}" (arg2),
95 [arg3] "{r5}" (arg3),
96 [arg4] "{r6}" (arg4),
97 : .{ .memory = true, .cr0 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
98}
99
100pub fn syscall5(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32, arg5: u32) u32 {
101 // These registers are both inputs and clobbers.
102 var r0_out: u32 = undefined;
103 var r4_out: u32 = undefined;
104 var r5_out: u32 = undefined;
105 var r6_out: u32 = undefined;
106 var r7_out: u32 = undefined;
107 return asm volatile (
108 \\ sc
109 \\ bns+ 1f
110 \\ neg 3, 3
111 \\ 1:
112 : [ret] "={r3}" (-> u32),
113 [r0_out] "={r0}" (r0_out),
114 [r4_out] "={r4}" (r4_out),
115 [r5_out] "={r5}" (r5_out),
116 [r6_out] "={r6}" (r6_out),
117 [r7_out] "={r7}" (r7_out),
118 : [number] "{r0}" (@intFromEnum(number)),
119 [arg1] "{r3}" (arg1),
120 [arg2] "{r4}" (arg2),
121 [arg3] "{r5}" (arg3),
122 [arg4] "{r6}" (arg4),
123 [arg5] "{r7}" (arg5),
124 : .{ .memory = true, .cr0 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
125}
126
127pub fn syscall6(
128 number: SYS,
129 arg1: u32,
130 arg2: u32,
131 arg3: u32,
132 arg4: u32,
133 arg5: u32,
134 arg6: u32,
135) u32 {
136 // These registers are both inputs and clobbers.
137 var r0_out: u32 = undefined;
138 var r4_out: u32 = undefined;
139 var r5_out: u32 = undefined;
140 var r6_out: u32 = undefined;
141 var r7_out: u32 = undefined;
142 var r8_out: u32 = undefined;
143 return asm volatile (
144 \\ sc
145 \\ bns+ 1f
146 \\ neg 3, 3
147 \\ 1:
148 : [ret] "={r3}" (-> u32),
149 [r0_out] "={r0}" (r0_out),
150 [r4_out] "={r4}" (r4_out),
151 [r5_out] "={r5}" (r5_out),
152 [r6_out] "={r6}" (r6_out),
153 [r7_out] "={r7}" (r7_out),
154 [r8_out] "={r8}" (r8_out),
155 : [number] "{r0}" (@intFromEnum(number)),
156 [arg1] "{r3}" (arg1),
157 [arg2] "{r4}" (arg2),
158 [arg3] "{r5}" (arg3),
159 [arg4] "{r6}" (arg4),
160 [arg5] "{r7}" (arg5),
161 [arg6] "{r8}" (arg6),
162 : .{ .memory = true, .cr0 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .ctr = true, .xer = true });
163}
164
165pub fn clone() callconv(.naked) u32 {
166 // __clone(func, stack, flags, arg, ptid, tls, ctid)
167 // 3, 4, 5, 6, 7, 8, 9
168 //
169 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
170 // 0 3, 4, 5, 6, 7
171 asm volatile (
172 \\ # store non-volatile regs r29, r30 on stack in order to put our
173 \\ # start func and its arg there
174 \\ stwu 29, -16(1)
175 \\ stw 30, 4(1)
176 \\
177 \\ # save r3 (func) into r29, and r6(arg) into r30
178 \\ mr 29, 3
179 \\ mr 30, 6
180 \\
181 \\ # create initial stack frame for new thread
182 \\ clrrwi 4, 4, 4
183 \\ li 0, 0
184 \\ stwu 0, -16(4)
185 \\
186 \\ #move c into first arg
187 \\ mr 3, 5
188 \\ #mr 4, 4
189 \\ mr 5, 7
190 \\ mr 6, 8
191 \\ mr 7, 9
192 \\
193 \\ # move syscall number into r0
194 \\ li 0, 120 # SYS_clone
195 \\
196 \\ sc
197 \\
198 \\ # check for syscall error
199 \\ bns+ 1f # jump to label 1 if no summary overflow.
200 \\ #else
201 \\ neg 3, 3 #negate the result (errno)
202 \\ 1:
203 \\ # compare sc result with 0
204 \\ cmpwi cr7, 3, 0
205 \\
206 \\ # if not 0, restore stack and return
207 \\ beq cr7, 2f
208 \\ lwz 29, 0(1)
209 \\ lwz 30, 4(1)
210 \\ addi 1, 1, 16
211 \\ blr
212 \\
213 \\ #else: we're the child
214 \\ 2:
215 );
216 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
217 \\ .cfi_undefined lr
218 );
219 asm volatile (
220 \\ li 31, 0
221 \\ mtlr 0
222 \\
223 \\ #call funcptr: move arg (d) into r3
224 \\ mr 3, 30
225 \\ #move r29 (funcptr) into CTR reg
226 \\ mtctr 29
227 \\ # call CTR reg
228 \\ bctrl
229 \\ # mov SYS_exit into r0 (the exit param is already in r3)
230 \\ li 0, 1
231 \\ sc
232 );
233}
234
235pub fn restore() callconv(.naked) noreturn {
236 switch (builtin.zig_backend) {
237 .stage2_c => asm volatile (
238 \\ li 0, %[number]
239 \\ sc
240 :
241 : [number] "i" (@intFromEnum(SYS.sigreturn)),
242 ),
243 else => asm volatile (
244 \\ sc
245 :
246 : [number] "{r0}" (@intFromEnum(SYS.sigreturn)),
247 ),
248 }
249}
250
251pub fn restore_rt() callconv(.naked) noreturn {
252 switch (builtin.zig_backend) {
253 .stage2_c => asm volatile (
254 \\ li 0, %[number]
255 \\ sc
256 :
257 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
258 ),
259 else => asm volatile (
260 \\ sc
261 :
262 : [number] "{r0}" (@intFromEnum(SYS.rt_sigreturn)),
263 ),
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 blksize_t = i32;
273pub const nlink_t = u32;
274pub const time_t = i32;
275pub const mode_t = u32;
276pub const off_t = i64;
277pub const ino_t = u64;
278pub const dev_t = u64;
279pub const blkcnt_t = i64;
280
281// The `stat` definition used by the Linux kernel.
282pub const Stat = extern struct {
283 dev: dev_t,
284 ino: ino_t,
285 mode: mode_t,
286 nlink: nlink_t,
287 uid: std.os.linux.uid_t,
288 gid: std.os.linux.gid_t,
289 rdev: dev_t,
290 __rdev_padding: i16,
291 size: off_t,
292 blksize: blksize_t,
293 blocks: blkcnt_t,
294 atim: std.os.linux.timespec,
295 mtim: std.os.linux.timespec,
296 ctim: std.os.linux.timespec,
297 __unused: [2]u32,
298
299 pub fn atime(self: @This()) std.os.linux.timespec {
300 return self.atim;
301 }
302
303 pub fn mtime(self: @This()) std.os.linux.timespec {
304 return self.mtim;
305 }
306
307 pub fn ctime(self: @This()) std.os.linux.timespec {
308 return self.ctim;
309 }
310};