// SPDX-FileCopyrightText: 2024 Himbeer // // SPDX-License-Identifier: AGPL-3.0-or-later const builtin = @import("builtin"); const root = @import("root"); const std = @import("std"); pub const hwinfo = @import("hwinfo.zig"); pub const max_args = 6; const Result = struct { value: usize, error_code: usize, }; const SyscallError = error{Kernel}; fn _start() callconv(.C) noreturn { if (!@hasDecl(root, "main")) @compileError("no main function"); root.main(); end(); } comptime { if (!builtin.is_test) @export(_start, .{ .name = "_start" }); } fn autoCast(value: anytype) usize { return switch (@typeInfo(@TypeOf(value))) { .Type => @compileError("cannot pass type to system call"), .Void => @compileError("cannot pass void to system call"), .NoReturn => @compileError("cannot pass noreturn to system call"), .Pointer => @intFromPtr(value), else => value, }; } fn ecall(number: usize, args: anytype) Result { var registers = [_]usize{0} ** max_args; inline for (args, 0..) |arg, i| { if (i >= max_args) @compileError("too many arguments to system call"); registers[i] = autoCast(arg); } var result: Result = undefined; asm volatile ( \\ ecall \\ sd a0, 0(%[value]) \\ sd a1, 0(%[error_code]) : : [value] "r" (&result.value), [error_code] "r" (&result.error_code), [a0] "{a0}" (registers[0]), [a1] "{a1}" (registers[1]), [a2] "{a2}" (registers[2]), [a3] "{a3}" (registers[3]), [a4] "{a4}" (registers[4]), [a5] "{a5}" (registers[5]), [number] "{a7}" (number), ); return result; } pub fn errorName(code: u16, buffer: []u8) !usize { const result = ecall(100000, .{ code, buffer.ptr, buffer.len, }); if (result.error_code != 0) return SyscallError.Kernel; return result.value; } pub fn consoleWrite(bytes: []const u8) !usize { const result = ecall(100001, .{ bytes.ptr, bytes.len }); if (result.error_code != 0) return SyscallError.Kernel; return result.value; } pub fn launch(bytes: []align(@alignOf(std.elf.Elf64_Ehdr)) const u8) !usize { const result = ecall(100002, .{ bytes.ptr, bytes.len }); if (result.error_code != 0) return SyscallError.Kernel; return result.value; } pub fn end() noreturn { _ = ecall(100003, .{}); unreachable; } pub fn terminate(pid: u16, thread: usize) !void { const result = ecall(100004, .{ pid, thread }); if (result.error_code != 0) return SyscallError.Kernel; } pub fn processId() u16 { const result = ecall(100005, .{}); return result.value; } pub fn threadId() usize { const result = ecall(100006, .{}); return result.value; } pub fn rawUserinit() []const u8 { var ptr: [*]const u8 = undefined; const result = ecall(100007, .{&ptr}); return ptr[0..result.value]; } pub fn devicesByKind(kind: hwinfo.DevKind, devices: []hwinfo.Dev) !usize { const result = ecall(100008, .{ kind, devices.ptr, devices.len }); if (result.error_code != 0) return SyscallError.Kernel; return result.value; }