master
  1const builtin = @import("builtin");
  2const std = @import("../../std.zig");
  3const SYS = std.os.linux.SYS;
  4
  5pub fn syscall0(number: SYS) u32 {
  6    return asm volatile (
  7        \\ syscall
  8        \\ beq $a3, $zero, 1f
  9        \\ blez $v0, 1f
 10        \\ subu $v0, $zero, $v0
 11        \\1:
 12        : [ret] "={$2}" (-> u32),
 13        : [number] "{$2}" (@intFromEnum(number)),
 14        : .{ .r1 = true, .r3 = true, .r4 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
 15}
 16
 17pub fn syscall_pipe(fd: *[2]i32) u32 {
 18    return asm volatile (
 19        \\ syscall
 20        \\ beq $a3, $zero, 1f
 21        \\ blez $v0, 2f
 22        \\ subu $v0, $zero, $v0
 23        \\ b 2f
 24        \\1:
 25        \\ sw $v0, 0($a0)
 26        \\ sw $v1, 4($a0)
 27        \\2:
 28        : [ret] "={$2}" (-> u32),
 29        : [number] "{$2}" (@intFromEnum(SYS.pipe)),
 30          [fd] "{$4}" (fd),
 31        : .{ .r1 = true, .r3 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
 32}
 33
 34pub fn syscall1(number: SYS, arg1: u32) u32 {
 35    return asm volatile (
 36        \\ syscall
 37        \\ beq $a3, $zero, 1f
 38        \\ blez $v0, 1f
 39        \\ subu $v0, $zero, $v0
 40        \\1:
 41        : [ret] "={$2}" (-> u32),
 42        : [number] "{$2}" (@intFromEnum(number)),
 43          [arg1] "{$4}" (arg1),
 44        : .{ .r1 = true, .r3 = true, .r5 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
 45}
 46
 47pub fn syscall2(number: SYS, arg1: u32, arg2: u32) u32 {
 48    return asm volatile (
 49        \\ syscall
 50        \\ beq $a3, $zero, 1f
 51        \\ blez $v0, 1f
 52        \\ subu $v0, $zero, $v0
 53        \\1:
 54        : [ret] "={$2}" (-> u32),
 55        : [number] "{$2}" (@intFromEnum(number)),
 56          [arg1] "{$4}" (arg1),
 57          [arg2] "{$5}" (arg2),
 58        : .{ .r1 = true, .r3 = true, .r6 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
 59}
 60
 61pub fn syscall3(number: SYS, arg1: u32, arg2: u32, arg3: u32) u32 {
 62    return asm volatile (
 63        \\ syscall
 64        \\ beq $a3, $zero, 1f
 65        \\ blez $v0, 1f
 66        \\ subu $v0, $zero, $v0
 67        \\1:
 68        : [ret] "={$2}" (-> u32),
 69        : [number] "{$2}" (@intFromEnum(number)),
 70          [arg1] "{$4}" (arg1),
 71          [arg2] "{$5}" (arg2),
 72          [arg3] "{$6}" (arg3),
 73        : .{ .r1 = true, .r3 = true, .r7 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
 74}
 75
 76pub fn syscall4(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32) u32 {
 77    return asm volatile (
 78        \\ syscall
 79        \\ beq $a3, $zero, 1f
 80        \\ blez $v0, 1f
 81        \\ subu $v0, $zero, $v0
 82        \\1:
 83        : [ret] "={$2}" (-> u32),
 84        : [number] "{$2}" (@intFromEnum(number)),
 85          [arg1] "{$4}" (arg1),
 86          [arg2] "{$5}" (arg2),
 87          [arg3] "{$6}" (arg3),
 88          [arg4] "{$7}" (arg4),
 89        : .{ .r1 = true, .r3 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
 90}
 91
 92// NOTE: The o32 calling convention requires the callee to reserve 16 bytes for
 93// the first four arguments even though they're passed in $a0-$a3.
 94
 95pub fn syscall5(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32, arg5: u32) u32 {
 96    return asm volatile (
 97        \\ subu $sp, $sp, 24
 98        \\ sw %[arg5], 16($sp)
 99        \\ syscall
100        \\ addu $sp, $sp, 24
101        \\ beq $a3, $zero, 1f
102        \\ blez $v0, 1f
103        \\ subu $v0, $zero, $v0
104        \\1:
105        : [ret] "={$2}" (-> u32),
106        : [number] "{$2}" (@intFromEnum(number)),
107          [arg1] "{$4}" (arg1),
108          [arg2] "{$5}" (arg2),
109          [arg3] "{$6}" (arg3),
110          [arg4] "{$7}" (arg4),
111          [arg5] "r" (arg5),
112        : .{ .r1 = true, .r3 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
113}
114
115pub fn syscall6(
116    number: SYS,
117    arg1: u32,
118    arg2: u32,
119    arg3: u32,
120    arg4: u32,
121    arg5: u32,
122    arg6: u32,
123) u32 {
124    return asm volatile (
125        \\ subu $sp, $sp, 24
126        \\ sw %[arg5], 16($sp)
127        \\ sw %[arg6], 20($sp)
128        \\ syscall
129        \\ addu $sp, $sp, 24
130        \\ beq $a3, $zero, 1f
131        \\ blez $v0, 1f
132        \\ subu $v0, $zero, $v0
133        \\1:
134        : [ret] "={$2}" (-> u32),
135        : [number] "{$2}" (@intFromEnum(number)),
136          [arg1] "{$4}" (arg1),
137          [arg2] "{$5}" (arg2),
138          [arg3] "{$6}" (arg3),
139          [arg4] "{$7}" (arg4),
140          [arg5] "r" (arg5),
141          [arg6] "r" (arg6),
142        : .{ .r1 = true, .r3 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
143}
144
145pub fn syscall7(
146    number: SYS,
147    arg1: u32,
148    arg2: u32,
149    arg3: u32,
150    arg4: u32,
151    arg5: u32,
152    arg6: u32,
153    arg7: u32,
154) u32 {
155    return asm volatile (
156        \\ subu $sp, $sp, 32
157        \\ sw %[arg5], 16($sp)
158        \\ sw %[arg6], 20($sp)
159        \\ sw %[arg7], 24($sp)
160        \\ syscall
161        \\ addu $sp, $sp, 32
162        \\ beq $a3, $zero, 1f
163        \\ blez $v0, 1f
164        \\ subu $v0, $zero, $v0
165        \\1:
166        : [ret] "={$2}" (-> u32),
167        : [number] "{$2}" (@intFromEnum(number)),
168          [arg1] "{$4}" (arg1),
169          [arg2] "{$5}" (arg2),
170          [arg3] "{$6}" (arg3),
171          [arg4] "{$7}" (arg4),
172          [arg5] "r" (arg5),
173          [arg6] "r" (arg6),
174          [arg7] "r" (arg7),
175        : .{ .r1 = true, .r3 = true, .r8 = true, .r9 = true, .r10 = true, .r11 = true, .r12 = true, .r13 = true, .r14 = true, .r15 = true, .r24 = true, .r25 = true, .hi = true, .lo = true, .memory = true });
176}
177
178pub fn clone() callconv(.naked) u32 {
179    // __clone(func, stack, flags, arg, ptid, tls, ctid)
180    //         a0,   a1,    a2,    a3,  +0,   +4,  +8
181    //
182    // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
183    //         v0         a0,    a1,    a2,   a3,  +0
184    asm volatile (
185        \\ # Save function pointer and argument pointer on new thread stack
186        \\ and $a1, $a1, -8
187        \\ subu $a1, $a1, 16
188        \\ sw $a0, 0($a1)
189        \\ sw $a3, 4($a1)
190        \\
191        \\ # Shuffle (fn,sp,fl,arg,ptid,tls,ctid) to (fl,sp,ptid,tls,ctid)
192        \\ move $a0, $a2
193        \\ lw $a2, 16($sp)
194        \\ lw $a3, 20($sp)
195        \\ lw $t1, 24($sp)
196        \\ subu $sp, $sp, 16
197        \\ sw $t1, 16($sp)
198        \\ li $v0, 4120 # SYS_clone
199        \\ syscall
200        \\ beq $a3, $zero, 1f
201        \\ blez $v0, 2f
202        \\ subu $v0, $zero, $v0
203        \\ b 2f
204        \\1:
205        \\ beq $v0, $zero, 3f
206        \\2:
207        \\ addu $sp, $sp, 16
208        \\ jr $ra
209        \\3:
210    );
211    if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
212        \\ .cfi_undefined $ra
213    );
214    asm volatile (
215        \\ move $fp, $zero
216        \\ move $ra, $zero
217        \\
218        \\ lw $t9, 0($sp)
219        \\ lw $a0, 4($sp)
220        \\ jalr $t9
221        \\
222        \\ move $a0, $v0
223        \\ li $v0, 4001 # SYS_exit
224        \\ syscall
225    );
226}
227
228pub const VDSO = struct {
229    pub const CGT_SYM = "__vdso_clock_gettime";
230    pub const CGT_VER = "LINUX_2.6";
231};
232
233pub const blksize_t = u32;
234pub const nlink_t = u32;
235pub const time_t = i32;
236pub const mode_t = u32;
237pub const off_t = i64;
238pub const ino_t = u64;
239pub const dev_t = u64;
240pub const blkcnt_t = i64;
241
242// The `stat64` definition used by the Linux kernel.
243pub const Stat = extern struct {
244    dev: dev_t,
245    __pad0: [2]u32, // -1 because our dev_t is u64 (kernel dev_t is really u32).
246    ino: ino_t,
247    mode: mode_t,
248    nlink: nlink_t,
249    uid: std.os.linux.uid_t,
250    gid: std.os.linux.gid_t,
251    rdev: dev_t,
252    __pad1: [2]u32,
253    size: off_t,
254    atim: std.os.linux.timespec,
255    mtim: std.os.linux.timespec,
256    ctim: std.os.linux.timespec,
257    blksize: blksize_t,
258    __pad3: u32,
259    blocks: blkcnt_t,
260
261    pub fn atime(self: @This()) std.os.linux.timespec {
262        return self.atim;
263    }
264
265    pub fn mtime(self: @This()) std.os.linux.timespec {
266        return self.mtim;
267    }
268
269    pub fn ctime(self: @This()) std.os.linux.timespec {
270        return self.ctim;
271    }
272};