From d0fbfd3c9f419ceb7112d06d4a3500e9c13f6044 Mon Sep 17 00:00:00 2001 From: Jacob G-W Date: Sun, 16 Jul 2023 21:34:13 -0400 Subject: [PATCH] Plan 9: add more features to std.os.plan9 * Replaces the exit assembly with the function from std. * Reads the top-of-stack struct at program startup that can get information like the pid. * Changes the read and write functions to use the Pread and Pwrite syscalls instead of the depreciated _READ and _WRITE * Changes the openat function to use flags instead of perms. Plan9 does not support perms when opening, just when creating. * Adds an errstr function to read the errstr buf created by the kernel --- lib/std/os/plan9.zig | 60 ++++++++++++++++++++++++++++++++++++-------- lib/std/start.zig | 30 ++++++---------------- 2 files changed, 57 insertions(+), 33 deletions(-) diff --git a/lib/std/os/plan9.zig b/lib/std/os/plan9.zig index 8b294fb414..9334171221 100644 --- a/lib/std/os/plan9.zig +++ b/lib/std/os/plan9.zig @@ -18,6 +18,43 @@ pub fn getErrno(r: usize) E { 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 +pub const ERRMAX = 128; +var errstr_buf: [ERRMAX]u8 = undefined; +/// Gets whatever the last errstr was +pub fn errstr() []const u8 { + _ = syscall_bits.syscall2(.ERRSTR, @intFromPtr(&errstr_buf), ERRMAX); + return std.mem.span(@as([*:0]u8, @ptrCast(&errstr_buf))); +} +pub const Plink = anyopaque; +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 +}; + +pub var tos: *Tos = undefined; // set in start.zig +pub fn getpid() u32 { + return tos.pid; +} pub const SIG = struct { /// hangup pub const HUP = 1; @@ -143,26 +180,27 @@ pub const SYS = enum(usize) { }; pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { - return syscall_bits.syscall3(._WRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count); + return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1))); } -pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, offset); +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)); } pub fn read(fd: i32, buf: [*]const u8, count: usize) usize { - return syscall_bits.syscall3(._READ, @bitCast(@as(isize, fd)), @intFromPtr(buf), count); + return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1))); } -pub fn pread(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, offset); +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)); } -pub fn open(path: [*:0]const u8, omode: mode_t) usize { - return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, omode))); +pub fn open(path: [*:0]const u8, flags: u32) usize { + return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, flags))); } -pub fn openat(dirfd: i32, path: [*:0]const u8, _: u32, omode: mode_t) usize { +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, omode); + 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; @@ -174,7 +212,7 @@ pub fn openat(dirfd: i32, path: [*:0]const u8, _: u32, omode: mode_t) usize { 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, omode); + return open(total_path_z.ptr, flags); } pub fn fd2path(fd: i32, buf: [*]u8, nbuf: usize) usize { diff --git a/lib/std/start.zig b/lib/std/start.zig index f730b0dd90..d2099ca803 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -166,28 +166,7 @@ fn exit2(code: usize) noreturn { else => @compileError("TODO"), }, // exits(0) - .plan9 => switch (builtin.cpu.arch) { - .x86_64 => { - asm volatile ( - \\push $0 - \\push $0 - \\syscall - : - : [syscall_number] "{rbp}" (8), - : "rcx", "r11", "memory" - ); - }, - // TODO once we get stack setting with assembly on - // arm, exit with 0 instead of stack garbage - .aarch64 => { - asm volatile ("svc #0" - : - : [exit] "{x0}" (0x08), - : "memory", "cc" - ); - }, - else => @compileError("TODO"), - }, + .plan9 => std.os.plan9.exits(null), .windows => { ExitProcess(@as(u32, @truncate(code))); }, @@ -254,6 +233,13 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv } fn _start() callconv(.Naked) noreturn { + // TODO set Top of Stack on non x86_64-plan9 + if (native_os == .plan9 and native_arch == .x86_64) { + // from /sys/src/libc/amd64/main9.s + std.os.plan9.tos = asm volatile ("" + : [tos] "={rax}" (-> *std.os.plan9.Tos), + ); + } asm volatile (switch (native_arch) { .x86_64 => \\ xorl %%ebp, %%ebp