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};