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