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