|
const std = @import("../std.zig");
const builtin = @import("builtin");
|
fd_tGets whatever the last errstr was |
pub const fd_t = i32; |
STDIN_FILENOPer process profiling |
pub const STDIN_FILENO = 0; |
STDOUT_FILENOknown to be 0(ptr) |
pub const STDOUT_FILENO = 1; |
STDERR_FILENOknown to be 4(ptr) |
pub const STDERR_FILENO = 2; |
PATH_MAXcycle clock frequency if there is one, 0 otherwise |
pub const PATH_MAX = 1023; |
syscall_bitscycles spent in kernel |
pub const syscall_bits = switch (builtin.cpu.arch) {
.x86_64 => @import("plan9/x86_64.zig"),
else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
};
|
Eplan9/errno.zigcycles spent in process (kernel + user) |
pub const E = @import("plan9/errno.zig").E;
/// Get the errno from a syscall return value, or 0 for no error.
|
getErrno()might as well put the pid here |
pub fn getErrno(r: usize) E {
const signed_r = @as(isize, @bitCast(r));
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
return @as(E, @enumFromInt(int));
}
// The max bytes that can be in the errstr buff
|
ERRMAXhangup |
pub const ERRMAX = 128; var errstr_buf: [ERRMAX]u8 = undefined; /// Gets whatever the last errstr was |
errstr()interrupt |
pub fn errstr() []const u8 {
_ = syscall_bits.syscall2(.ERRSTR, @intFromPtr(&errstr_buf), ERRMAX);
return std.mem.span(@as([*:0]u8, @ptrCast(&errstr_buf)));
}
|
Plinkquit |
pub const Plink = anyopaque; |
Tosillegal instruction (not reset when caught) |
pub const Tos = extern struct {
/// Per process profiling
prof: extern struct {
/// known to be 0(ptr)
pp: *Plink,
/// known to be 4(ptr)
next: *Plink,
last: *Plink,
first: *Plink,
pid: u32,
what: u32,
},
/// cycle clock frequency if there is one, 0 otherwise
cyclefreq: u64,
/// cycles spent in kernel
kcycles: i64,
/// cycles spent in process (kernel + user)
pcycles: i64,
/// might as well put the pid here
pid: u32,
clock: u32,
// top of stack is here
};
|
getpid()used by abort |
pub var tos: *Tos = undefined; // set in start.zig
pub fn getpid() u32 {
return tos.pid;
}
|
SIGfloating point exception |
pub const SIG = struct {
/// hangup
|
HUPkill (cannot be caught or ignored) |
pub const HUP = 1;
/// interrupt
|
INTsegmentation violation |
pub const INT = 2;
/// quit
|
QUITwrite on a pipe with no one to read it |
pub const QUIT = 3;
/// illegal instruction (not reset when caught)
|
ILLalarm clock |
pub const ILL = 4;
/// used by abort
|
ABRTsoftware termination signal from kill |
pub const ABRT = 5;
/// floating point exception
|
FPEuser defined signal 1 |
pub const FPE = 6;
/// kill (cannot be caught or ignored)
|
KILLuser defined signal 2 |
pub const KILL = 7;
/// segmentation violation
|
SEGVbus error |
pub const SEGV = 8;
/// write on a pipe with no one to read it
|
PIPEchild process terminated or stopped |
pub const PIPE = 9;
/// alarm clock
|
ALRMcontinue if stopped |
pub const ALRM = 10;
/// software termination signal from kill
|
TERMstop |
pub const TERM = 11;
/// user defined signal 1
|
USR1interactive stop |
pub const USR1 = 12;
/// user defined signal 2
|
USR2read from ctl tty by member of background |
pub const USR2 = 13;
/// bus error
|
BUSwrite to ctl tty by member of background |
pub const BUS = 14;
// The following symbols must be defined, but the signals needn't be supported
/// child process terminated or stopped
|
CHLDBrk sets the system's idea of the lowest bss location not used by the program (called the break) to addr rounded up to the next multiple of 8 bytes. Locations not less than addr and below the stack pointer may cause a memory violation if accessed. -9front brk(2) |
pub const CHLD = 15;
/// continue if stopped
|
CONT |
pub const CONT = 16;
/// stop
|
STOP |
pub const STOP = 17;
/// interactive stop
|
TSTP |
pub const TSTP = 18;
/// read from ctl tty by member of background
|
TTIN |
pub const TTIN = 19;
/// write to ctl tty by member of background
|
TTOU |
pub const TTOU = 20;
};
|
sigset_t |
pub const sigset_t = c_long; |
empty_sigset |
pub const empty_sigset = 0; |
siginfo_t |
pub const siginfo_t = c_long; // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible. |
Sigaction |
pub const Sigaction = extern struct {
|
handler_fn |
pub const handler_fn = *const fn (c_int) callconv(.C) void;
|
sigaction_fn |
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
|
AT |
handler: extern union {
handler: ?handler_fn,
sigaction: ?sigaction_fn,
},
mask: sigset_t,
flags: c_int,
};
pub const AT = struct {
|
FDCWD |
pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
};
// TODO implement sigaction
// right now it is just a shim to allow using start.zig code
|
sigaction() |
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
_ = oact;
_ = act;
_ = sig;
return 0;
}
|
SYS |
pub const SYS = enum(usize) {
SYSR1 = 0,
_ERRSTR = 1,
BIND = 2,
CHDIR = 3,
CLOSE = 4,
DUP = 5,
ALARM = 6,
EXEC = 7,
EXITS = 8,
_FSESSION = 9,
FAUTH = 10,
_FSTAT = 11,
SEGBRK = 12,
_MOUNT = 13,
OPEN = 14,
_READ = 15,
OSEEK = 16,
SLEEP = 17,
_STAT = 18,
RFORK = 19,
_WRITE = 20,
PIPE = 21,
CREATE = 22,
FD2PATH = 23,
BRK_ = 24,
REMOVE = 25,
_WSTAT = 26,
_FWSTAT = 27,
NOTIFY = 28,
NOTED = 29,
SEGATTACH = 30,
SEGDETACH = 31,
SEGFREE = 32,
SEGFLUSH = 33,
RENDEZVOUS = 34,
UNMOUNT = 35,
_WAIT = 36,
SEMACQUIRE = 37,
SEMRELEASE = 38,
SEEK = 39,
FVERSION = 40,
ERRSTR = 41,
STAT = 42,
FSTAT = 43,
WSTAT = 44,
FWSTAT = 45,
MOUNT = 46,
AWAIT = 47,
PREAD = 50,
PWRITE = 51,
TSEMACQUIRE = 52,
_NSEC = 53,
};
|
write() |
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1)));
}
|
pwrite() |
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: isize) usize {
return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(offset));
}
|
read() |
pub fn read(fd: i32, buf: [*]const u8, count: usize) usize {
return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1)));
}
|
pread() |
pub fn pread(fd: i32, buf: [*]const u8, count: usize, offset: isize) usize {
return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(offset));
}
|
open() |
pub fn open(path: [*:0]const u8, flags: u32) usize {
return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, flags)));
}
|
openat() |
pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, _: mode_t) usize {
// we skip perms because only create supports perms
if (dirfd == AT.FDCWD) { // openat(AT_FDCWD, ...) == open(...)
return open(path, flags);
}
var dir_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var total_path_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined;
const rc = fd2path(dirfd, &dir_path_buf, std.fs.MAX_PATH_BYTES);
if (rc != 0) return rc;
var fba = std.heap.FixedBufferAllocator.init(&total_path_buf);
var alloc = fba.allocator();
const dir_path = std.mem.span(@as([*:0]u8, @ptrCast(&dir_path_buf)));
const total_path = std.fs.path.join(alloc, &.{ dir_path, std.mem.span(path) }) catch unreachable; // the allocation shouldn't fail because it should not exceed MAX_PATH_BYTES
fba.reset();
const total_path_z = alloc.dupeZ(u8, total_path) catch unreachable; // should not exceed MAX_PATH_BYTES + 1
return open(total_path_z.ptr, flags);
}
|
fd2path() |
pub fn fd2path(fd: i32, buf: [*]u8, nbuf: usize) usize {
return syscall_bits.syscall3(.FD2PATH, @bitCast(@as(isize, fd)), @intFromPtr(buf), nbuf);
}
|
create() |
pub fn create(path: [*:0]const u8, omode: mode_t, perms: usize) usize {
return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @bitCast(@as(isize, omode)), perms);
}
|
exit() |
pub fn exit(status: u8) noreturn {
if (status == 0) {
exits(null);
} else {
// TODO plan9 does not have exit codes. You either exit with 0 or a string
const arr: [1:0]u8 = .{status};
exits(&arr);
}
}
|
exits() |
pub fn exits(status: ?[*:0]const u8) noreturn {
_ = syscall_bits.syscall1(.EXITS, if (status) |s| @intFromPtr(s) else 0);
unreachable;
}
|
close() |
pub fn close(fd: i32) usize {
return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));
}
|
mode_t |
pub const mode_t = i32; |
O |
pub const O = struct {
|
READ |
pub const READ = 0; // open for read
|
RDONLY |
pub const RDONLY = 0;
|
WRITE |
pub const WRITE = 1; // write
|
WRONLY |
pub const WRONLY = 1;
|
RDWR |
pub const RDWR = 2; // read and write
|
EXEC |
pub const EXEC = 3; // execute, == read but check execute permission
|
TRUNC |
pub const TRUNC = 16; // or'ed in (except for exec), truncate file first
|
CEXEC |
pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec
|
RCLOSE |
pub const RCLOSE = 64; // or'ed in, remove on close
|
EXCL |
pub const EXCL = 0x1000; // or'ed in, exclusive create
};
|
ExecData |
pub const ExecData = struct {
pub extern const etext: anyopaque;
pub extern const edata: anyopaque;
pub extern const end: anyopaque;
};
|
brk_() |
/// Brk sets the system's idea of the lowest bss location not
/// used by the program (called the break) to addr rounded up to
/// the next multiple of 8 bytes. Locations not less than addr
/// and below the stack pointer may cause a memory violation if
/// accessed. -9front brk(2)
pub fn brk_(addr: usize) i32 {
return @intCast(syscall_bits.syscall1(.BRK_, addr));
}
var bloc: usize = 0;
var bloc_max: usize = 0;
|
sbrk() |
pub fn sbrk(n: usize) usize {
if (bloc == 0) {
// we are at the start
bloc = @intFromPtr(&ExecData.end);
bloc_max = @intFromPtr(&ExecData.end);
}
var bl = std.mem.alignForward(usize, bloc, std.mem.page_size);
const n_aligned = std.mem.alignForward(usize, n, std.mem.page_size);
if (bl + n_aligned > bloc_max) {
// we need to allocate
if (brk_(bl + n_aligned) < 0) return 0;
bloc_max = bl + n_aligned;
}
bloc = bloc + n_aligned;
return bl;
}
|
| Generated by zstd-live on 2025-10-12 02:30:41 UTC. |