master
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub fn syscall0(number: SYS) u64 {
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: u64 = undefined;
11 return asm volatile (
12 \\ sc
13 \\ bns+ 1f
14 \\ neg 3, 3
15 \\ 1:
16 : [ret] "={r3}" (-> u64),
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: u64) u64 {
23 // r0 is both an input and a clobber.
24 var r0_out: u64 = undefined;
25 return asm volatile (
26 \\ sc
27 \\ bns+ 1f
28 \\ neg 3, 3
29 \\ 1:
30 : [ret] "={r3}" (-> u64),
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: u64, arg2: u64) u64 {
38 // These registers are both inputs and clobbers.
39 var r0_out: u64 = undefined;
40 var r4_out: u64 = undefined;
41 return asm volatile (
42 \\ sc
43 \\ bns+ 1f
44 \\ neg 3, 3
45 \\ 1:
46 : [ret] "={r3}" (-> u64),
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: u64, arg2: u64, arg3: u64) u64 {
56 // These registers are both inputs and clobbers.
57 var r0_out: u64 = undefined;
58 var r4_out: u64 = undefined;
59 var r5_out: u64 = undefined;
60 return asm volatile (
61 \\ sc
62 \\ bns+ 1f
63 \\ neg 3, 3
64 \\ 1:
65 : [ret] "={r3}" (-> u64),
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: u64, arg2: u64, arg3: u64, arg4: u64) u64 {
77 // These registers are both inputs and clobbers.
78 var r0_out: u64 = undefined;
79 var r4_out: u64 = undefined;
80 var r5_out: u64 = undefined;
81 var r6_out: u64 = undefined;
82 return asm volatile (
83 \\ sc
84 \\ bns+ 1f
85 \\ neg 3, 3
86 \\ 1:
87 : [ret] "={r3}" (-> u64),
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: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) u64 {
101 // These registers are both inputs and clobbers.
102 var r0_out: u64 = undefined;
103 var r4_out: u64 = undefined;
104 var r5_out: u64 = undefined;
105 var r6_out: u64 = undefined;
106 var r7_out: u64 = undefined;
107 return asm volatile (
108 \\ sc
109 \\ bns+ 1f
110 \\ neg 3, 3
111 \\ 1:
112 : [ret] "={r3}" (-> u64),
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: u64,
130 arg2: u64,
131 arg3: u64,
132 arg4: u64,
133 arg5: u64,
134 arg6: u64,
135) u64 {
136 // These registers are both inputs and clobbers.
137 var r0_out: u64 = undefined;
138 var r4_out: u64 = undefined;
139 var r5_out: u64 = undefined;
140 var r6_out: u64 = undefined;
141 var r7_out: u64 = undefined;
142 var r8_out: u64 = undefined;
143 return asm volatile (
144 \\ sc
145 \\ bns+ 1f
146 \\ neg 3, 3
147 \\ 1:
148 : [ret] "={r3}" (-> u64),
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) u64 {
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 \\ # create initial stack frame for new thread
173 \\ clrrdi 4, 4, 4
174 \\ li 0, 0
175 \\ stdu 0,-32(4)
176 \\
177 \\ # save fn and arg to child stack
178 \\ std 3, 8(4)
179 \\ std 6, 16(4)
180 \\
181 \\ # shuffle args into correct registers and call SYS_clone
182 \\ mr 3, 5
183 \\ #mr 4, 4
184 \\ mr 5, 7
185 \\ mr 6, 8
186 \\ mr 7, 9
187 \\ li 0, 120 # SYS_clone = 120
188 \\ sc
189 \\
190 \\ # if error, negate return (errno)
191 \\ bns+ 1f
192 \\ neg 3, 3
193 \\
194 \\1:
195 \\ # if we're the parent, return
196 \\ cmpwi cr7, 3, 0
197 \\ bnelr cr7
198 \\
199 \\ # we're the child
200 );
201 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
202 \\ .cfi_undefined lr
203 );
204 asm volatile (
205 \\ li 31, 0
206 \\ mtlr 0
207 \\
208 \\ # call fn(arg)
209 \\ ld 3, 16(1)
210 \\ ld 12, 8(1)
211 \\ mtctr 12
212 \\ bctrl
213 \\
214 \\ # call SYS_exit. exit code is already in r3 from fn return value
215 \\ li 0, 1 # SYS_exit = 1
216 \\ sc
217 );
218}
219
220pub fn restore() callconv(.naked) noreturn {
221 switch (builtin.zig_backend) {
222 .stage2_c => asm volatile (
223 \\ li 0, %[number]
224 \\ sc
225 :
226 : [number] "i" (@intFromEnum(SYS.sigreturn)),
227 ),
228 else => asm volatile (
229 \\ sc
230 :
231 : [number] "{r0}" (@intFromEnum(SYS.sigreturn)),
232 ),
233 }
234}
235
236pub fn restore_rt() callconv(.naked) noreturn {
237 switch (builtin.zig_backend) {
238 .stage2_c => asm volatile (
239 \\ li 0, %[number]
240 \\ sc
241 :
242 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
243 ),
244 else => asm volatile (
245 \\ sc
246 :
247 : [number] "{r0}" (@intFromEnum(SYS.rt_sigreturn)),
248 ),
249 }
250}
251
252pub const VDSO = struct {
253 pub const CGT_SYM = "__kernel_clock_gettime";
254 pub const CGT_VER = "LINUX_2.6.15";
255};
256
257pub const blksize_t = i64;
258pub const nlink_t = u64;
259pub const time_t = i64;
260pub const mode_t = u32;
261pub const off_t = i64;
262pub const ino_t = u64;
263pub const dev_t = u64;
264pub const blkcnt_t = i64;
265
266// The `stat` definition used by the Linux kernel.
267pub const Stat = extern struct {
268 dev: dev_t,
269 ino: ino_t,
270 nlink: nlink_t,
271 mode: mode_t,
272 uid: std.os.linux.uid_t,
273 gid: std.os.linux.gid_t,
274 rdev: dev_t,
275 size: off_t,
276 blksize: blksize_t,
277 blocks: blkcnt_t,
278 atim: std.os.linux.timespec,
279 mtim: std.os.linux.timespec,
280 ctim: std.os.linux.timespec,
281 __unused: [3]u64,
282
283 pub fn atime(self: @This()) std.os.linux.timespec {
284 return self.atim;
285 }
286
287 pub fn mtime(self: @This()) std.os.linux.timespec {
288 return self.mtim;
289 }
290
291 pub fn ctime(self: @This()) std.os.linux.timespec {
292 return self.ctim;
293 }
294};