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