vxx2 / vlib / builtin / linux_bare / linux_syscalls.v
466 lines · 420 sloc · 11.29 KB · 097cfd748dd0fa33bcbb8e584df57ea9502b3a31
Raw
1module builtin
2
3enum SigIndex {
4 si_signo = 0x00
5 si_code = 0x02
6 si_pid = 0x04
7 si_uid = 0x05
8 si_status = 0x06
9 si_size = 0x80
10}
11
12enum Signo {
13 sighup = 1 // Hangup.
14 sigint = 2 // Interactive attention signal.
15 sigquit = 3 // Quit.
16 sigill = 4 // Illegal instruction.
17 sigtrap = 5 // Trace/breakpoint trap.
18 sigabrt = 6 // Abnormal termination.
19 sigbus = 7
20 sigfpe = 8 // Erroneous arithmetic operation.
21 sigkill = 9 // Killed.
22 sigusr1 = 10
23 sigsegv = 11 // Invalid access to memory.
24 sigusr2 = 12
25 sigpipe = 13 // Broken pipe.
26 sigalrm = 14 // Alarm clock.
27 sigterm = 15 // Termination request.
28 sigstkflt = 16
29 sigchld = 17
30 sigcont = 18
31 sigstop = 19
32 sigtstp = 20
33 sigttin = 21 // Background read from control terminal.
34 sigttou = 22 // Background write to control terminal.
35 sigurg = 23
36 sigxcpu = 24 // CPU time limit exceeded.
37 sigxfsz = 25 // File size limit exceeded.
38 sigvtalrm = 26 // Virtual timer expired.
39 sigprof = 27 // Profiling timer expired.
40 sigwinch = 28
41 sigpoll = 29
42 sigsys = 31
43}
44
45// List of all the errors returned by syscalls
46enum Errno {
47 enoerror = 0x00000000
48 eperm = 0x00000001
49 enoent = 0x00000002
50 esrch = 0x00000003
51 eintr = 0x00000004
52 eio = 0x00000005
53 enxio = 0x00000006
54 e2big = 0x00000007
55 enoexec = 0x00000008
56 ebadf = 0x00000009
57 echild = 0x0000000a
58 eagain = 0x0000000b
59 enomem = 0x0000000c
60 eacces = 0x0000000d
61 efault = 0x0000000e
62 enotblk = 0x0000000f
63 ebusy = 0x00000010
64 eexist = 0x00000011
65 exdev = 0x00000012
66 enodev = 0x00000013
67 enotdir = 0x00000014
68 eisdir = 0x00000015
69 einval = 0x00000016
70 enfile = 0x00000017
71 emfile = 0x00000018
72 enotty = 0x00000019
73 etxtbsy = 0x0000001a
74 efbig = 0x0000001b
75 enospc = 0x0000001c
76 espipe = 0x0000001d
77 erofs = 0x0000001e
78 emlink = 0x0000001f
79 epipe = 0x00000020
80 edom = 0x00000021
81 erange = 0x00000022
82}
83
84enum MemProt {
85 prot_read = 0x1
86 prot_write = 0x2
87 prot_exec = 0x4
88 prot_none = 0x0
89 prot_growsdown = 0x01000000
90 prot_growsup = 0x02000000
91}
92
93enum MapFlags {
94 map_shared = 0x01
95 map_private = 0x02
96 map_shared_validate = 0x03
97 map_type = 0x0f
98 map_fixed = 0x10
99 map_file = 0x00
100 map_anonymous = 0x20
101 map_huge_shift = 26
102 map_huge_mask = 0x3f
103}
104
105// const (
106// fcntlf_dupfd = 0x00000000
107// fcntlf_exlck = 0x00000004
108// fcntlf_getfd = 0x00000001
109// fcntlf_getfl = 0x00000003
110// fcntlf_getlk = 0x00000005
111// fcntlf_getlk64 = 0x0000000c
112// fcntlf_getown = 0x00000009
113// fcntlf_getowner_uids = 0x00000011
114// fcntlf_getown_ex = 0x00000010
115// fcntlf_getsig = 0x0000000b
116// fcntlf_ofd_getlk = 0x00000024
117// fcntlf_ofd_setlk = 0x00000025
118// fcntlf_ofd_setlkw = 0x00000026
119// fcntlf_owner_pgrp = 0x00000002
120// fcntlf_owner_pid = 0x00000001
121// fcntlf_owner_tid = 0x00000000
122// fcntlf_rdlck = 0x00000000
123// fcntlf_setfd = 0x00000002
124// fcntlf_setfl = 0x00000004
125// fcntlf_setlk = 0x00000006
126// fcntlf_setlk64 = 0x0000000d
127// fcntlf_setlkw = 0x00000007
128// fcntlf_setlkw64 = 0x0000000e
129// fcntlf_setown = 0x00000008
130// fcntlf_setown_ex = 0x0000000f
131// fcntlf_setsig = 0x0000000a
132// fcntlf_shlck = 0x00000008
133// fcntlf_unlck = 0x00000002
134// fcntlf_wrlck = 0x00000001
135// fcntllock_ex = 0x00000002
136// fcntllock_mand = 0x00000020
137// fcntllock_nb = 0x00000004
138// fcntllock_read = 0x00000040
139// fcntllock_rw = 0x000000c0
140// fcntllock_sh = 0x00000001
141// fcntllock_un = 0x00000008
142// fcntllock_write = 0x00000080
143// fcntlo_accmode = 0x00000003
144// fcntlo_append = 0x00000400
145// fcntlo_cloexec = 0x00080000
146// fcntlo_creat = 0x00000040
147// fcntlo_direct = 0x00004000
148// fcntlo_directory = 0x00010000
149// fcntlo_dsync = 0x00001000
150// fcntlo_excl = 0x00000080
151// fcntlo_largefile = 0x00008000
152// fcntlo_ndelay = 0x00000800
153// fcntlo_noatime = 0x00040000
154// fcntlo_noctty = 0x00000100
155// fcntlo_nofollow = 0x00020000
156// fcntlo_nonblock = 0x00000800
157// fcntlo_path = 0x00200000
158// fcntlo_rdonly = 0x00000000
159// fcntlo_rdwr = 0x00000002
160// fcntlo_trunc = 0x00000200
161// fcntlo_wronly = 0x00000001
162// )
163
164/*
165Paraphrased from "man 2 waitid" on Linux
166
167 Upon successful return, waitid() fills in the
168 following fields of the siginfo_t structure
169 pointed to by infop:
170
171 si_pid, offset 0x10, int index 0x04:
172 The process ID of the child.
173
174 si_uid: offset 0x14, int index 0x05
175 The real user ID of the child.
176
177 si_signo: offset 0x00, int index 0x00
178 Always set to SIGCHLD.
179
180 si_status: ofset 0x18, int index 0x06
181 1 the exit status of the child, as given to _exit(2)
182 (or exit(3)) (sc_sys.cld_exited)
183 2 the signal that caused the child to terminate, stop,
184 or continue.
185 3 The si_code field can be used to determine how to
186 interpret this field.
187
188 si_code, set to one of (enum Wi_si_code), offset 0x08, int index 0x02:
189 CLD_EXITED (child called _exit(2));
190 CLD_KILLED (child killed by signal);
191 CLD_DUMPED (child killed by signal, and dumped core);
192 CLD_STOPPED (child stopped by signal);
193 CLD_TRAPPED (traced child has trapped);
194 CLD_CONTINUED (child continued by SIGCONT).
195*/
196
197const wp_sys_wnohang = u64(0x00000001)
198const wp_sys_wuntraced = u64(0x00000002)
199const wp_sys_wstopped = u64(0x00000002)
200const wp_sys_wexited = u64(0x00000004)
201const wp_sys_wcontinued = u64(0x00000008)
202const wp_sys_wnowait = u64(0x01000000) // don't reap, just poll status.
203
204const wp_sys___wnothread = u64(0x20000000) // don't wait on children of other threads in this group
205
206const wp_sys___wall = u64(0x40000000) // wait on all children, regardless of type
207
208const wp_sys___wclone = u64(0x80000000)
209
210// First argument to waitid:
211enum WiWhich {
212 p_all = 0
213 p_pid = 1
214 p_pgid = 2
215}
216
217enum WiSiCode {
218 cld_exited = 1 // child has exited
219 cld_killed = 2 // child was killed
220 cld_dumped = 3 // child terminated abnormally
221 cld_trapped = 4 // traced child has trapped
222 cld_stopped = 5 // child has stopped
223 cld_continued = 6 // stopped child has continued
224}
225
226$if !i386 {
227 fn split_int_errno(rc_in u64) (i64, Errno) {
228 rc := i64(rc_in)
229 if rc < 0 {
230 return i64(-1), unsafe { Errno(-rc) }
231 }
232 return rc, Errno.enoerror
233 }
234
235 // 0 sys_read
236 fn sys_read(fd i64, buf &u8, count u64) (i64, Errno) {
237 return split_int_errno(sys_call3(0, u64(fd), u64(buf), count))
238 }
239
240 // 1 sys_write
241 pub fn sys_write(fd i64, buf &u8, count u64) (i64, Errno) {
242 return split_int_errno(sys_call3(1, u64(fd), u64(buf), count))
243 }
244
245 // 2 sys_open
246 fn sys_open(filename &u8, flags i64, mode int) (i64, Errno) {
247 return split_int_errno(sys_call3(2, u64(filename), u64(flags), u64(mode)))
248 }
249
250 // 3 sys_close
251 fn sys_close(fd i64) Errno {
252 return unsafe { Errno(-i64(sys_call1(3, u64(fd)))) }
253 }
254
255 // 9 sys_mmap
256 fn sys_mmap(addr &u8, len u64, prot MemProt, flags MapFlags, fildes i64, off u64) (&u8, Errno) {
257 rc := sys_call6(9, u64(addr), len, u64(prot), u64(flags), fildes, off)
258 a, e := split_int_errno(rc)
259 return unsafe { &u8(a) }, e
260 }
261
262 // 11 sys_munmap
263 fn sys_munmap(addr voidptr, len u64) Errno {
264 return unsafe { Errno(-sys_call2(11, u64(addr), len)) }
265 }
266
267 // 25 sys_mremap
268 fn sys_mremap(old_addr voidptr, old_len u64, new_len u64, flags u64) (&u8, Errno) {
269 rc := sys_call4(25, u64(old_addr), old_len, new_len, flags)
270 a, e := split_int_errno(rc)
271 return unsafe { &u8(a) }, e
272 }
273
274 // 22 sys_pipe
275 fn sys_pipe(filedes &int) Errno {
276 return unsafe { Errno(sys_call1(22, u64(filedes))) }
277 }
278
279 // 24 sys_sched_yield
280 fn sys_sched_yield() Errno {
281 return unsafe { Errno(sys_call0(24)) }
282 }
283
284 // 28 sys_madvise
285 fn sys_madvise(addr voidptr, len u64, advice int) Errno {
286 return unsafe { Errno(sys_call3(28, u64(addr), len, u64(advice))) }
287 }
288
289 // 39 sys_getpid
290 fn sys_getpid() int {
291 return int(sys_call0(39))
292 }
293
294 // 57 sys_fork
295 fn sys_fork() int {
296 return int(sys_call0(57))
297 }
298
299 // 58 sys_vfork
300 fn sys_vfork() int {
301 return int(sys_call0(58))
302 }
303
304 // 33 sys_dup2
305 fn sys_dup2(oldfd int, newfd int) (i64, Errno) {
306 return split_int_errno(sys_call2(33, u64(oldfd), u64(newfd)))
307 }
308
309 // 59 sys_execve
310 fn sys_execve(filename &u8, argv []&u8, envp []&u8) int {
311 return int(sys_call3(59, u64(filename), u64(argv.data), u64(envp.data)))
312 }
313
314 // 60 sys_exit
315 @[noreturn]
316 fn sys_exit(ec int) {
317 sys_call1(60, u64(ec))
318 for {}
319 }
320
321 // 102 sys_getuid
322 fn sys_getuid() int {
323 return int(sys_call0(102))
324 }
325
326 // 247 sys_waitid
327 fn sys_waitid(which WiWhich, pid int, infop &int, options int, ru voidptr) Errno {
328 return unsafe {
329 Errno(sys_call5(247, u64(which), u64(pid), u64(infop), u64(options), u64(ru)))
330 }
331 }
332
333 // The syscall primitives stay defined for every non-i386 arch so the wrappers
334 // above remain resolvable; only the inline asm is amd64-gated. On a non-amd64
335 // target each returns -ENOSYS (38) -- a failed syscall rather than a fake
336 // success -- so e.g. mm_alloc sees the mmap error instead of dereferencing 0.
337 // A real non-x86 freestanding build must supply its own syscall + startup layer.
338 fn sys_call0(scn u64) u64 {
339 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
340 $if amd64 {
341 asm amd64 {
342 syscall
343 ; =a (res)
344 ; 0 (scn)
345 }
346 }
347 return res
348 }
349
350 fn sys_call1(scn u64, arg1 u64) u64 {
351 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
352 $if amd64 {
353 asm amd64 {
354 syscall
355 ; =a (res)
356 ; 0 (scn)
357 D (arg1)
358 }
359 }
360 return res
361 }
362
363 fn sys_call2(scn u64, arg1 u64, arg2 u64) u64 {
364 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
365 $if amd64 {
366 asm amd64 {
367 syscall
368 ; =a (res)
369 ; 0 (scn)
370 D (arg1)
371 S (arg2)
372 }
373 }
374 return res
375 }
376
377 fn sys_call3(scn u64, arg1 u64, arg2 u64, arg3 u64) u64 {
378 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
379 $if amd64 {
380 asm amd64 {
381 syscall
382 ; =a (res)
383 ; 0 (scn)
384 D (arg1)
385 S (arg2)
386 d (arg3)
387 }
388 }
389 return res
390 }
391
392 fn sys_call4(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64) u64 {
393 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
394 $if amd64 {
395 asm amd64 {
396 mov r10, arg4
397 syscall
398 ; =a (res)
399 ; 0 (scn)
400 D (arg1)
401 S (arg2)
402 d (arg3)
403 g (arg4)
404 ; r10
405 }
406 }
407 return res
408 }
409
410 fn sys_call5(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 u64) u64 {
411 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
412 $if amd64 {
413 asm amd64 {
414 mov r10, arg4
415 mov r8, arg5
416 syscall
417 ; =a (res)
418 ; 0 (scn)
419 D (arg1)
420 S (arg2)
421 d (arg3)
422 g (arg4)
423 g (arg5)
424 ; r10
425 r8
426 }
427 }
428 return res
429 }
430
431 fn sys_call6(scn u64, arg1 u64, arg2 u64, arg3 u64, arg4 u64, arg5 i64, arg6 u64) u64 {
432 mut res := u64(-i64(38)) // -ENOSYS, overwritten by the syscall on amd64
433 $if amd64 {
434 asm amd64 {
435 mov r10, arg4
436 mov r8, arg5
437 mov r9, arg6
438 syscall
439 ; =a (res)
440 ; 0 (scn)
441 D (arg1)
442 S (arg2)
443 d (arg3)
444 g (arg4)
445 g (arg5)
446 g (arg6)
447 ; r10
448 r8
449 r9
450 }
451 }
452 return res
453 }
454
455 $if amd64 {
456 asm amd64 {
457 .globl _start
458 _start:
459 call main
460 mov rax, 60
461 xor rdi, rdi
462 syscall
463 ret
464 }
465 }
466}
467