Eigenstate : Plan 9

Plan 9 System Calls

The sys package, when compiled for Plan 9, contained an interface to the Plan 9 system calls. This list is more or less complete.

Summary

Overall, this documentation will not attempt to summarize the full behavior of the system calls, but will instead attempt to highlight where system calls diverge from the libc interfaces, which are documented in section 2 of the system manpages.

Unlike the Posixy systems, Plan 9 does return -1 directly from the kernel, and for error checking, the result of the errstr system call must be inspected, just like when writing C.

The most notable divergence is that short zero terminated strings strings such as file names are wrapped up as a byte[:], but are generally converted to strings on the stack before being passed to the kernel. Long buffers that are exposed to C as a char* buf, size_t len pair are exposed to Myrddin code as simply accepting a byte[:].

Exported Symbols

pkg sys =
        type scno   = int64 /* syscall */
        type pid    = int32 /* process id */
        type fdopt  = int32 /* fd options */
        type fd     = int32 /* fd */
        type rflags = int32 /* rfork flags */

        type tos = struct
                prof    : prof
                cyclefreq   : uint64
                kcycles : int64
                pcycles : int64
                pid : pid
                clock   : uint32
        ;;

        type prof = struct
                pp  : byte# /* plink */
                next    : byte# /* plink */
                last    : byte# /* plink */
                first   : byte# /* plink */
                pid : pid   /* plink */
                what    : uint32    /* plink */
        ;;

        const Maxerr    : size = 128

        const Ordonly   : fdopt = 0
        const Owronly   : fdopt = 1
        const Ordwr : fdopt = 2
        const Oexec : fdopt = 3

        const Otrunc    : fdopt = 16
        const Ocexec    : fdopt = 32
        const Orclose   : fdopt = 64
        const Oexcl : fdopt = 0x1000

        const Qtdir : int  = 0x80
        const Qtappend  : int  = 0x40
        const Qtexcl    : int  = 0x20
        const Qtmount   : int  = 0x10
        const Qtauth    : int  = 0x08
        const Qttmp : int  = 0x04
        const Qtfile    : int  = 0x00

        const Dmdir : int = 0x8000000
        const Dmappend  : int = 0x4000000
        const Dmexcl    : int = 0x2000000
        const Dmmount   : int = 0x1000000
        const Dmauth    : int = 0x0800000
        const Dmtmp : int = 0x0400000
        const Dmread    : int = 0x4
        const Dmwrite   : int = 0x2
        const Dmexec    : int = 0x1

        const Rfnameg   : rflags = 1 << 0
        const Rfenvg    : rflags = 1 << 1
        const Rffdg : rflags = 1 << 2
        const Rfnoteg   : rflags = 1 << 3
        const Rfproc    : rflags = 1 << 4
        const Rfmem : rflags = 1 << 5
        const Rfnowait  : rflags = 1 << 6
        const Rfcnameg  : rflags = 1 << 10
        const Rfcenvg   : rflags = 1 << 11
        const Rfcfdg    : rflags = 1 << 12
        const Rfrend    : rflags = 1 << 13
        const Rfnomnt   : rflags = 1 << 14

        const Syssysr1      : scno = 0
        const Sys_errstr    : scno = 1
        const Sysbind       : scno = 2
        const Syschdir      : scno = 3
        const Sysclose      : scno = 4
        const Sysdup        : scno = 5
        const Sysalarm      : scno = 6
        const Sysexec       : scno = 7
        const Sysexits      : scno = 8
        const Sys_fsession  : scno = 9
        const Sysfauth      : scno = 10
        const Sys_fstat     : scno = 11
        const Syssegbrk     : scno = 12
        const Sys_mount     : scno = 13
        const Sysopen       : scno = 14
        const Sys_read      : scno = 15
        const Sysoseek      : scno = 16
        const Syssleep      : scno = 17
        const Sys_stat      : scno = 18
        const Sysrfork      : scno = 19
        const Sys_write     : scno = 20
        const Syspipe       : scno = 21
        const Syscreate     : scno = 22
        const Sysfd2path    : scno = 23
        const Sysbrk_       : scno = 24
        const Sysremove     : scno = 25
        const Sys_wstat     : scno = 26
        const Sys_fwstat    : scno = 27
        const Sysnotify     : scno = 28
        const Sysnoted      : scno = 29
        const Syssegattach  : scno = 30
        const Syssegdetach  : scno = 31
        const Syssegfree    : scno = 32
        const Syssegflush   : scno = 33
        const Sysrendezvous : scno = 34
        const Sysunmount    : scno = 35
        const Sys_wait      : scno = 36
        const Syssemacquire : scno = 37
        const Syssemrelease : scno = 38
        const Sysseek       : scno = 39
        const Sysfversion   : scno = 40
        const Syserrstr     : scno = 41
        const Sysstat       : scno = 42
        const Sysfstat      : scno = 43
        const Syswstat      : scno = 44
        const Sysfwstat     : scno = 45
        const Sysmount      : scno = 46
        const Sysawait      : scno = 47
        const Syspread      : scno = 50
        const Syspwrite     : scno = 51
        const Systsemacquire    : scno = 52
        const Sys_nsec      : scno = 53


        const sysr1 : (-> int64)
        const bind  : (nm : byte[:], old : byte[:] -> int64)
        const chdir : (dir : byte[:] -> int64)
        const close : (fd : fd -> int64)
        const dup   : (old : fd, new : fd -> fd)
        const alarm : (msec : uint32 -> int64)
        const exits : (msg : byte[:] -> int64)
        const fauth : (fd : fd, name : byte[:] -> int64)
        const segbrk    : (saddr : void#, addr : void# -> int64)
        const open  : (path : byte[:], opt : fdopt -> fd)
        const sleep : (msec : uint32 -> int64)
        const rfork : (rflags : rflags -> pid)
        const pipe  : (fds : fd[2]# -> int64)
        const create    : (path : byte[:], opt : fdopt, perm : int -> fd)
        const fd2path   : (fd : fd, path : byte[:] -> int64)
        const remove    : (path : byte[:] -> int64)
        const notify    : (fn : (a : void#, c : char# -> int64) -> int64)
        const noted : (v : int32 -> int64)
        const segattach : (attr : int32, class : byte[:], va : void#, len : uint32 -> int64)
        const segdetach : (va : void# -> int64)
        const segfree   : (va : byte#, len : size -> int64)
        const segflush  : (va : void#, len : uint32 -> int64)
        const unmount   : (name : byte[:], old : byte[:] -> int64)
        const errstr    : (buf : byte[:] -> int64)
        const stat  : (name : byte[:], edir : byte[:] -> int64)
        const fstat : (fd : fd, edir : byte[:] -> int64)
        const wstat : (name : byte[:], edir : byte[:] -> int64)
        const fwstat    : (fd : byte[:],  edir : byte[:] -> int64)
        const seek  : (fd : fd, len : off, ty : int64 -> off)
        const mount : (fd : fd, afd : fd, old : byte[:], flag : int32, aname : byte[:] -> int64)
        const await : (buf : byte[:] -> int64)
        const pread : (fd : fd, buf : byte[:], off : off -> size)
        const pwrite    : (fd : fd, buf : byte[:], off : off -> size)
        const exec  : (bin : byte[:], args : byte[:][:] -> int64)
        const brk_  : (endp : byte# -> int64)
        const nsec  : (-> uint64)

        extern const alloca : (sz : size    -> byte#)

        extern var tosptr   : tos#
        extern var curbrk   : byte#
;;

/* asm stub from syscall.s */
extern const syscall : (scno : scno, args : ... -> int64)
/* asm stubs from util+plan9.s */
extern const cstring    : (str : byte[:] -> byte#)
extern const alloca : (sz : size    -> byte#)


/*
ABI mismatch: Plan 9 aligns all arguments individually to
8 bytes, Myrddin uses natural alignment (min(sizeof(t), 16).
Cast to a 64 bit type to paper over this.
*/
generic a   = {a : @t;  -> a castto(uint64)}
generic s   = {a : @t;  -> a castto(int64)}
generic p   = {a : @t;  -> a castto(byte#)}

const sysr1 = {;        -> syscall(Syssysr1)}
const bind  = {name, old;   -> syscall(Sysbind, cstring(name), cstring(old))}
const chdir     = {dir;     -> syscall(Syschdir, cstring(dir)) }
const close     = {fd;      -> syscall(Sysclose, a(fd))}
const dup   = {ofd, nfd;    -> syscall(Sysdup, a(ofd), a(nfd)) castto(fd)}
const alarm     = {msec;    -> syscall(Sysalarm, a(msec))}
const exits     = {msg;     -> syscall(Sysexits, cstring(msg))}
const fauth     = {fd, aname;   -> syscall(Sysfauth, a(fd), cstring(aname))}
const segbrk    = {saddr, addr; -> syscall(Syssegbrk, a(saddr), a(addr))}
const open  = {path, opt;   -> syscall(Sysopen, cstring(path), a(opt)) castto(fd)}
const sleep     = {msec;    -> syscall(Syssleep, a(msec))}
const rfork     = {rflags;  -> syscall(Sysrfork, a(rflags)) castto(pid)}
const pipe  = {fds;     -> syscall(Syspipe, a(fds))}
const create    = {path, mode, perm;    -> syscall(Syscreate, cstring(path), a(mode), a(perm)) castto(fd)}
const fd2path   = {fd, buf; -> syscall(Sysfd2path, a(fd), p(buf), a(buf.len))}
const remove    = {path;    -> syscall(Sysremove, cstring(path))}
const notify    = {fn;      -> syscall(Sysnotify, fn)}  /* FIXME: this is likely to break when we do closures... */
const noted = {v;       -> syscall(Sysnoted, a(v))}
const segattach = {attr, class, va, len;    -> syscall(Syssegattach, a(attr), cstring(class), a(va), a(len))}
const segdetach = {va;      -> syscall(Syssegdetach, a(va))}
const segfree   = {va, len; -> syscall(Syssegfree, a(va), a(len))}
const segflush  = {va, len; -> syscall(Syssegfree, a(va), a(len))}
const unmount   = {name, old;   -> syscall(Sysunmount, cstring(name), cstring(old))}
const errstr    = {buf;     -> syscall(Syserrstr, p(buf), a(buf.len))}
const stat  = {name, edir;  -> syscall(Sysstat, cstring(name), p(edir), a(edir.len))}
const fstat = {fd, edir;    -> syscall(Sysstat, a(fd), p(edir), a(edir.len))}
const wstat = {name, edir;  -> syscall(Syswstat, cstring(name), p(edir), a(edir.len))}
const fwstat    = {fd, edir;    -> syscall(Sysfwstat, a(fd), p(edir), a(edir.len))}
const mount = {fd, afd, old, flag, aname;   -> syscall(Sysmount, a(fd), a(afd), cstring(old), a(flag), cstring(aname))}
const pread = {fd, buf, off;    -> syscall(Syspread, a(fd), p(buf), a(buf.len), off) castto(size)}
const pwrite    = {fd, buf, off;    -> syscall(Syspwrite, a(fd), p(buf), a(buf.len), s(off)) castto(size)}
const await = {buf; -> syscall(Sysawait, p(buf), a(buf.len))}
const brk_  = {endp;    -> syscall(Sysbrk_, p(endp))}
const nsec  = {;    -> syscall(Sys_nsec) castto(uint64)}
const seek  = {fd, n, ty
        var ret : off
        syscall(Sysseek, a(&ret), a(fd), a(n), a(ty))
        -> ret
}

const exec  = {bin, args
        var p, cargs, i

        /* we need an array of C strings. */
        p = alloca((args.len + 1)*sizeof(byte#))
        cargs = (a(p) castto(byte##))[:args.len + 1]
        for i = 0; i < args.len; i++
                cargs[i] = cstring(args[i])
        ;;
        cargs[args.len] = 0 castto(byte#)
        -> syscall(Sysexec, cstring(bin), a(cargs))
}