master
  1const builtin = @import("builtin");
  2const std = @import("../../std.zig");
  3const SYS = std.os.linux.SYS;
  4
  5pub fn syscall_pipe(fd: *[2]i32) u64 {
  6    return asm volatile (
  7        \\ mov %[arg], %%g3
  8        \\ t 0x6d
  9        \\ bcc,pt %%xcc, 1f
 10        \\ nop
 11        \\ # Return the error code
 12        \\ ba 2f
 13        \\ neg %%o0
 14        \\1:
 15        \\ st %%o0, [%%g3+0]
 16        \\ st %%o1, [%%g3+4]
 17        \\ clr %%o0
 18        \\2:
 19        : [ret] "={o0}" (-> u64),
 20        : [number] "{g1}" (@intFromEnum(SYS.pipe)),
 21          [arg] "r" (fd),
 22        : .{ .memory = true, .g3 = true });
 23}
 24
 25pub fn syscall_fork() u64 {
 26    // Linux/sparc64 fork() returns two values in %o0 and %o1:
 27    // - On the parent's side, %o0 is the child's PID and %o1 is 0.
 28    // - On the child's side, %o0 is the parent's PID and %o1 is 1.
 29    // We need to clear the child's %o0 so that the return values
 30    // conform to the libc convention.
 31    return asm volatile (
 32        \\ t 0x6d
 33        \\ bcc,pt %%xcc, 1f
 34        \\ nop
 35        \\ ba 2f
 36        \\ neg %%o0
 37        \\ 1:
 38        \\ # Clear the child's %%o0
 39        \\ dec %%o1
 40        \\ and %%o1, %%o0, %%o0
 41        \\ 2:
 42        : [ret] "={o0}" (-> u64),
 43        : [number] "{g1}" (@intFromEnum(SYS.fork)),
 44        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
 45}
 46
 47pub fn syscall0(number: SYS) u64 {
 48    return asm volatile (
 49        \\ t 0x6d
 50        \\ bcc,pt %%xcc, 1f
 51        \\ nop
 52        \\ neg %%o0
 53        \\ 1:
 54        : [ret] "={o0}" (-> u64),
 55        : [number] "{g1}" (@intFromEnum(number)),
 56        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
 57}
 58
 59pub fn syscall1(number: SYS, arg1: u64) u64 {
 60    return asm volatile (
 61        \\ t 0x6d
 62        \\ bcc,pt %%xcc, 1f
 63        \\ nop
 64        \\ neg %%o0
 65        \\ 1:
 66        : [ret] "={o0}" (-> u64),
 67        : [number] "{g1}" (@intFromEnum(number)),
 68          [arg1] "{o0}" (arg1),
 69        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
 70}
 71
 72pub fn syscall2(number: SYS, arg1: u64, arg2: u64) u64 {
 73    return asm volatile (
 74        \\ t 0x6d
 75        \\ bcc,pt %%xcc, 1f
 76        \\ nop
 77        \\ neg %%o0
 78        \\ 1:
 79        : [ret] "={o0}" (-> u64),
 80        : [number] "{g1}" (@intFromEnum(number)),
 81          [arg1] "{o0}" (arg1),
 82          [arg2] "{o1}" (arg2),
 83        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
 84}
 85
 86pub fn syscall3(number: SYS, arg1: u64, arg2: u64, arg3: u64) u64 {
 87    return asm volatile (
 88        \\ t 0x6d
 89        \\ bcc,pt %%xcc, 1f
 90        \\ nop
 91        \\ neg %%o0
 92        \\ 1:
 93        : [ret] "={o0}" (-> u64),
 94        : [number] "{g1}" (@intFromEnum(number)),
 95          [arg1] "{o0}" (arg1),
 96          [arg2] "{o1}" (arg2),
 97          [arg3] "{o2}" (arg3),
 98        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
 99}
100
101pub fn syscall4(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64) u64 {
102    return asm volatile (
103        \\ t 0x6d
104        \\ bcc,pt %%xcc, 1f
105        \\ nop
106        \\ neg %%o0
107        \\ 1:
108        : [ret] "={o0}" (-> u64),
109        : [number] "{g1}" (@intFromEnum(number)),
110          [arg1] "{o0}" (arg1),
111          [arg2] "{o1}" (arg2),
112          [arg3] "{o2}" (arg3),
113          [arg4] "{o3}" (arg4),
114        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
115}
116
117pub fn syscall5(number: SYS, arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) u64 {
118    return asm volatile (
119        \\ t 0x6d
120        \\ bcc,pt %%xcc, 1f
121        \\ nop
122        \\ neg %%o0
123        \\ 1:
124        : [ret] "={o0}" (-> u64),
125        : [number] "{g1}" (@intFromEnum(number)),
126          [arg1] "{o0}" (arg1),
127          [arg2] "{o1}" (arg2),
128          [arg3] "{o2}" (arg3),
129          [arg4] "{o3}" (arg4),
130          [arg5] "{o4}" (arg5),
131        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
132}
133
134pub fn syscall6(
135    number: SYS,
136    arg1: u64,
137    arg2: u64,
138    arg3: u64,
139    arg4: u64,
140    arg5: u64,
141    arg6: u64,
142) u64 {
143    return asm volatile (
144        \\ t 0x6d
145        \\ bcc,pt %%xcc, 1f
146        \\ nop
147        \\ neg %%o0
148        \\ 1:
149        : [ret] "={o0}" (-> u64),
150        : [number] "{g1}" (@intFromEnum(number)),
151          [arg1] "{o0}" (arg1),
152          [arg2] "{o1}" (arg2),
153          [arg3] "{o2}" (arg3),
154          [arg4] "{o3}" (arg4),
155          [arg5] "{o4}" (arg5),
156          [arg6] "{o5}" (arg6),
157        : .{ .memory = true, .xcc = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
158}
159
160pub fn clone() callconv(.naked) u64 {
161    // __clone(func, stack, flags, arg, ptid, tls, ctid)
162    //         i0,   i1,    i2,    i3,  i4,   i5,  sp
163    //
164    // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
165    //         g1         o0,    o1,    o2,   o3,  o4
166    asm volatile (
167        \\ save %%sp, -192, %%sp
168        \\ # Save the func pointer and the arg pointer
169        \\ mov %%i0, %%g2
170        \\ mov %%i3, %%g3
171        \\ # Shuffle the arguments
172        \\ mov 217, %%g1 // SYS_clone
173        \\ mov %%i2, %%o0
174        \\ # Add some extra space for the initial frame
175        \\ sub %%i1, 176 + 2047, %%o1
176        \\ mov %%i4, %%o2
177        \\ mov %%i5, %%o3
178        \\ ldx [%%fp + 0x8af], %%o4
179        \\ t 0x6d
180        \\ bcs,pn %%xcc, 1f
181        \\ nop
182        \\ # The child pid is returned in o0 while o1 tells if this
183        \\ # process is # the child (=1) or the parent (=0).
184        \\ brnz %%o1, 2f
185        \\ nop
186        \\ # Parent process, return the child pid
187        \\ mov %%o0, %%i0
188        \\ ret
189        \\ restore
190        \\1:
191        \\ # The syscall failed
192        \\ sub %%g0, %%o0, %%i0
193        \\ ret
194        \\ restore
195        \\2:
196        \\ # Child process
197    );
198    if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
199        \\ .cfi_undefined %%i7
200    );
201    asm volatile (
202        \\ mov %%g0, %%fp
203        \\ mov %%g0, %%i7
204        \\
205        \\ # call func(arg)
206        \\ mov %%g0, %%fp
207        \\ call %%g2
208        \\ mov %%g3, %%o0
209        \\ # Exit
210        \\ mov 1, %%g1 // SYS_exit
211        \\ t 0x6d
212    );
213}
214
215pub const restore = restore_rt;
216
217// Need to use C ABI here instead of naked
218// to prevent an infinite loop when calling rt_sigreturn.
219pub fn restore_rt() callconv(.c) void {
220    return asm volatile ("t 0x6d"
221        :
222        : [number] "{g1}" (@intFromEnum(SYS.rt_sigreturn)),
223        : .{ .memory = true, .xcc = true, .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o7 = true });
224}
225
226pub const VDSO = struct {
227    pub const CGT_SYM = "__vdso_clock_gettime";
228    pub const CGT_VER = "LINUX_2.6";
229};
230
231pub const off_t = i64;
232pub const ino_t = u64;
233pub const time_t = i64;
234pub const mode_t = u32;
235pub const dev_t = u64;
236pub const nlink_t = u32;
237pub const blksize_t = i64;
238pub const blkcnt_t = i64;
239
240// The `stat64` definition used by the kernel.
241pub const Stat = extern struct {
242    dev: dev_t,
243    ino: ino_t,
244    nlink: nlink_t,
245    _pad: i32,
246
247    mode: mode_t,
248    uid: std.os.linux.uid_t,
249    gid: std.os.linux.gid_t,
250    __pad0: u32,
251
252    rdev: dev_t,
253    size: i64,
254    blksize: blksize_t,
255    blocks: blkcnt_t,
256
257    atim: std.os.linux.timespec,
258    mtim: std.os.linux.timespec,
259    ctim: std.os.linux.timespec,
260    __unused: [3]u64,
261
262    pub fn atime(self: @This()) std.os.linux.timespec {
263        return self.atim;
264    }
265
266    pub fn mtime(self: @This()) std.os.linux.timespec {
267        return self.mtim;
268    }
269
270    pub fn ctime(self: @This()) std.os.linux.timespec {
271        return self.ctim;
272    }
273};