master
  1const builtin = @import("builtin");
  2const std = @import("../../std.zig");
  3const SYS = std.os.linux.SYS;
  4
  5pub fn syscall0(number: SYS) u64 {
  6    return asm volatile ("svc 0"
  7        : [ret] "={r2}" (-> u64),
  8        : [number] "{r1}" (@intFromEnum(number)),
  9        : .{ .memory = true });
 10}
 11
 12pub fn syscall1(number: SYS, arg1: u64) u64 {
 13    return asm volatile ("svc 0"
 14        : [ret] "={r2}" (-> u64),
 15        : [number] "{r1}" (@intFromEnum(number)),
 16          [arg1] "{r2}" (arg1),
 17        : .{ .memory = true });
 18}
 19
 20pub fn syscall2(number: SYS, arg1: u64, arg2: u64) u64 {
 21    return asm volatile ("svc 0"
 22        : [ret] "={r2}" (-> u64),
 23        : [number] "{r1}" (@intFromEnum(number)),
 24          [arg1] "{r2}" (arg1),
 25          [arg2] "{r3}" (arg2),
 26        : .{ .memory = true });
 27}
 28
 29pub fn syscall3(number: SYS, arg1: u64, arg2: u64, arg3: u64) u64 {
 30    return asm volatile ("svc 0"
 31        : [ret] "={r2}" (-> u64),
 32        : [number] "{r1}" (@intFromEnum(number)),
 33          [arg1] "{r2}" (arg1),
 34          [arg2] "{r3}" (arg2),
 35          [arg3] "{r4}" (arg3),
 36        : .{ .memory = true });
 37}
 38
 39pub fn syscall4(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64) u64 {
 40    return asm volatile ("svc 0"
 41        : [ret] "={r2}" (-> u64),
 42        : [number] "{r1}" (@intFromEnum(number)),
 43          [arg1] "{r2}" (arg1),
 44          [arg2] "{r3}" (arg2),
 45          [arg3] "{r4}" (arg3),
 46          [arg4] "{r5}" (arg4),
 47        : .{ .memory = true });
 48}
 49
 50pub fn syscall5(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) u64 {
 51    return asm volatile ("svc 0"
 52        : [ret] "={r2}" (-> u64),
 53        : [number] "{r1}" (@intFromEnum(number)),
 54          [arg1] "{r2}" (arg1),
 55          [arg2] "{r3}" (arg2),
 56          [arg3] "{r4}" (arg3),
 57          [arg4] "{r5}" (arg4),
 58          [arg5] "{r6}" (arg5),
 59        : .{ .memory = true });
 60}
 61
 62pub fn syscall6(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64, arg6: u64) u64 {
 63    return asm volatile ("svc 0"
 64        : [ret] "={r2}" (-> u64),
 65        : [number] "{r1}" (@intFromEnum(number)),
 66          [arg1] "{r2}" (arg1),
 67          [arg2] "{r3}" (arg2),
 68          [arg3] "{r4}" (arg3),
 69          [arg4] "{r5}" (arg4),
 70          [arg5] "{r6}" (arg5),
 71          [arg6] "{r7}" (arg6),
 72        : .{ .memory = true });
 73}
 74
 75pub fn clone() callconv(.naked) u64 {
 76    asm volatile (
 77        \\# int clone(
 78        \\#    fn,      a = r2
 79        \\#    stack,   b = r3
 80        \\#    flags,   c = r4
 81        \\#    arg,     d = r5
 82        \\#    ptid,    e = r6
 83        \\#    tls,     f = *(r15+160)
 84        \\#    ctid)    g = *(r15+168)
 85        \\#
 86        \\# pseudo C code:
 87        \\# tid = syscall(SYS_clone,b,c,e,g,f);
 88        \\# if (!tid) syscall(SYS_exit, a(d));
 89        \\# return tid;
 90        \\
 91        \\# preserve call-saved register used as syscall arg
 92        \\stg  %%r6, 48(%%r15)
 93        \\
 94        \\# create initial stack frame for new thread
 95        \\nill %%r3, 0xfff8
 96        \\aghi %%r3, -160
 97        \\lghi %%r0, 0
 98        \\stg  %%r0, 0(%%r3)
 99        \\
100        \\# save fn and arg to child stack
101        \\stg  %%r2,  8(%%r3)
102        \\stg  %%r5, 16(%%r3)
103        \\
104        \\# shuffle args into correct registers and call SYS_clone
105        \\lgr  %%r2, %%r3
106        \\lgr  %%r3, %%r4
107        \\lgr  %%r4, %%r6
108        \\lg   %%r5, 168(%%r15)
109        \\lg   %%r6, 160(%%r15)
110        \\svc  120
111        \\
112        \\# restore call-saved register
113        \\lg   %%r6, 48(%%r15)
114        \\
115        \\# if error or if we're the parent, return
116        \\ltgr %%r2, %%r2
117        \\bnzr %%r14
118        \\
119        \\# we're the child
120    );
121    if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
122        \\.cfi_undefined %%r14
123    );
124    asm volatile (
125        \\lghi %%r11, 0
126        \\lghi %%r14, 0
127        \\
128        \\# call fn(arg)
129        \\lg   %%r1,  8(%%r15)
130        \\lg   %%r2, 16(%%r15)
131        \\basr %%r14, %%r1
132        \\
133        \\# call SYS_exit. exit code is already in r2 from fn return value
134        \\svc  1
135        \\
136    );
137}
138
139pub fn restore() callconv(.naked) noreturn {
140    asm volatile (
141        \\svc 0
142        :
143        : [number] "{r1}" (@intFromEnum(SYS.sigreturn)),
144    );
145}
146
147pub fn restore_rt() callconv(.naked) noreturn {
148    asm volatile (
149        \\svc 0
150        :
151        : [number] "{r1}" (@intFromEnum(SYS.rt_sigreturn)),
152    );
153}
154
155pub const blksize_t = i64;
156pub const nlink_t = u64;
157pub const time_t = i64;
158pub const mode_t = u32;
159pub const off_t = i64;
160pub const ino_t = u64;
161pub const dev_t = u64;
162pub const blkcnt_t = i64;
163
164// The `stat` definition used by the Linux kernel.
165pub const Stat = extern struct {
166    dev: dev_t,
167    ino: ino_t,
168    nlink: nlink_t,
169    mode: mode_t,
170    uid: std.os.linux.uid_t,
171    gid: std.os.linux.gid_t,
172    rdev: dev_t,
173    size: off_t,
174    atim: std.os.linux.timespec,
175    mtim: std.os.linux.timespec,
176    ctim: std.os.linux.timespec,
177    blksize: blksize_t,
178    blocks: blkcnt_t,
179    __unused: [3]c_ulong,
180
181    pub fn atime(self: @This()) std.os.linux.timespec {
182        return self.atim;
183    }
184
185    pub fn mtime(self: @This()) std.os.linux.timespec {
186        return self.mtim;
187    }
188
189    pub fn ctime(self: @This()) std.os.linux.timespec {
190        return self.ctim;
191    }
192};
193
194pub const VDSO = struct {
195    pub const CGT_SYM = "__kernel_clock_gettime";
196    pub const CGT_VER = "LINUX_2.6.29";
197};