diff options
author | Himbeer <himbeer@disroot.org> | 2024-08-01 13:07:30 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-08-01 13:07:30 +0200 |
commit | c22a1c2214d5f3256684fa08262501cfd70be915 (patch) | |
tree | 28ed508137c86d15bb2c7e15a6ec2802d1cea1ed /src/syscall.zig | |
parent | 017c63d49f4c6fdd2f762dd7d14323fbbdb7775e (diff) |
Flatten 'lib' directory into main 'src' tree
Diffstat (limited to 'src/syscall.zig')
-rw-r--r-- | src/syscall.zig | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/src/syscall.zig b/src/syscall.zig new file mode 100644 index 0000000..6b94e16 --- /dev/null +++ b/src/syscall.zig @@ -0,0 +1,200 @@ +// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +const std = @import("std"); +const Console = @import("Console.zig"); +const TrapFrame = @import("TrapFrame.zig"); +const channel = @import("channel.zig"); +const hwinfo = @import("hwinfo.zig"); +const mem = @import("mem.zig"); +const paging = @import("paging.zig"); +const process = @import("process.zig"); +const riscv = @import("riscv.zig"); + +pub const Error = error{ + ZeroAddressSupplied, +}; + +pub const HandleError = error{ + UnknownSyscall, +}; + +pub fn handler(proc: *process.Info, trap_frame: *TrapFrame) !void { + switch (trap_frame.general_purpose_registers[17]) { + 100000 => trap_frame.setReturnValue(errorName(trap_frame)), + 100001 => trap_frame.setReturnValue(consoleWrite(trap_frame)), + 100002 => trap_frame.setReturnValue(launch(trap_frame)), + 100003 => trap_frame.setReturnValue(end(proc)), + 100004 => trap_frame.setReturnValue(terminate(proc, trap_frame)), + 100005 => trap_frame.setReturnValue(processId(proc)), + 100006 => trap_frame.setReturnValue(threadId(proc)), + 100008 => trap_frame.setReturnValue(devicesByKind(trap_frame)), + 100009 => trap_frame.setReturnValue(join(proc, trap_frame)), + 100010 => trap_frame.setReturnValue(leave(proc, trap_frame)), + 100011 => trap_frame.setReturnValue(pass(trap_frame)), + 100012 => trap_frame.setReturnValue(receive(proc, trap_frame)), + else => return HandleError.UnknownSyscall, + } +} + +pub const ErrorNameError = error{ErrorCodeOutOfRange}; + +// errorName(code: u16, buffer: [*]u8, len: usize) !usize +fn errorName(trap_frame: *const TrapFrame) !usize { + const code_wide = trap_frame.general_purpose_registers[10]; + const buffer_opt: ?[*]u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]); + const buffer_ptr = buffer_opt orelse return Error.ZeroAddressSupplied; + const len = trap_frame.general_purpose_registers[12]; + + const code = std.math.cast(u16, code_wide) orelse { + return ErrorNameError.ErrorCodeOutOfRange; + }; + const buffer = buffer_ptr[0..len]; + + if (code == 0) return 0; + + const error_name = @errorName(@errorFromInt(code)); + + const n = @min(buffer.len, error_name.len); + + paging.setUserMemoryAccess(true); + defer paging.setUserMemoryAccess(false); + + @memcpy(buffer[0..n], error_name[0..n]); + return n; +} + +// consoleWrite(bytes: [*]const u8, len: usize) !usize +fn consoleWrite(trap_frame: *const TrapFrame) !usize { + const vaddr = trap_frame.general_purpose_registers[10]; + const len = trap_frame.general_purpose_registers[11]; + + const procmem: *paging.Table = @ptrFromInt(riscv.satp.read().ppn << 12); + + const flags = paging.EntryFlags.userReadOnly; + const paddr = procmem.translate(vaddr, flags) orelse { + const faulter: *volatile u8 = @ptrFromInt(vaddr); + _ = faulter.*; + unreachable; + }; + + const bytes_ptr: [*]const u8 = @ptrFromInt(paddr); + const bytes = bytes_ptr[0..len]; + + const w = Console.autoChoose().?.writer(); + return w.write(bytes); +} + +// launch(bytes: [*]align(@alignOf(std.elf.Elf64_Ehdr)) const u8, len: usize) !usize +fn launch(trap_frame: *const TrapFrame) !usize { + const alignment = @alignOf(std.elf.Elf64_Ehdr); + const bytes_addr = trap_frame.general_purpose_registers[10]; + const bytes_opt: ?[*]const u8 = @ptrFromInt(bytes_addr); + const bytes_noalign = bytes_opt orelse return Error.ZeroAddressSupplied; + const bytes_ptr = try std.math.alignCast(alignment, bytes_noalign); + const len = trap_frame.general_purpose_registers[11]; + + const bytes = bytes_ptr[0..len]; + + paging.setUserMemoryAccess(true); + defer paging.setUserMemoryAccess(false); + + const new_proc = try process.create(mem.page_allocator, bytes); + return new_proc.id; +} + +// end() noreturn +fn end(proc: *process.Info) noreturn { + proc.terminate(); + process.schedule() catch |err| { + std.debug.panic("schedule error: {}", .{err}); + }; +} + +pub const TerminateError = error{ + PidOutOfRange, + ProcessNotFound, +}; + +// terminate(pid: u16, tid: usize) !void +fn terminate(proc: *const process.Info, trap_frame: *const TrapFrame) !void { + const pid_wide = trap_frame.general_purpose_registers[10]; + const pid = std.math.cast(u16, pid_wide) orelse { + return TerminateError.PidOutOfRange; + }; + const tid = trap_frame.general_purpose_registers[11]; + + const target = process.findThread(pid, tid) orelse { + return TerminateError.ProcessNotFound; + }; + target.terminate(); + + if (target.shouldTerminate(proc)) { + process.schedule() catch |err| { + std.debug.panic("schedule error: {}", .{err}); + }; + } +} + +// processId() u16 +fn processId(proc: *const process.Info) usize { + return proc.id; +} + +// threadId() usize +fn threadId(proc: *const process.Info) usize { + return proc.thread_id; +} + +// devicesByKind(kind: hwinfo.DevKind, devices: [*]hwinfo.Dev, len: usize) !usize +fn devicesByKind(trap_frame: *const TrapFrame) !usize { + const kind: hwinfo.DevKind = @enumFromInt(trap_frame.general_purpose_registers[10]); + const devices: [*]hwinfo.Dev = @ptrFromInt(trap_frame.general_purpose_registers[11]); + const len = trap_frame.general_purpose_registers[12]; + + var i: usize = 0; + var devs = try hwinfo.byKind(kind); + while (try devs.next()) |dev| { + if (i >= len) break; + + devices[i] = dev; + i += 1; + } + + return i; +} + +// join(channel_id: usize) !void +fn join(proc: *const process.Info, trap_frame: *const TrapFrame) !void { + const id = trap_frame.general_purpose_registers[10]; + return channel.join(proc.id, id); +} + +// leave(channel_id: usize) void +fn leave(proc: *const process.Info, trap_frame: *const TrapFrame) void { + const id = trap_frame.general_purpose_registers[10]; + channel.leave(proc.id, id); +} + +// pass(channel_id: usize, bytes: [*]const u8, len: usize) !void +fn pass(trap_frame: *const TrapFrame) !void { + const id = trap_frame.general_purpose_registers[10]; + const bytes_ptr: [*]const u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]); + const len = trap_frame.general_purpose_registers[12]; + + const bytes = bytes_ptr[0..len]; + const copy = try channel.allocator().alloc(u8, bytes.len); + @memcpy(copy, bytes); + try channel.pass(id, copy); +} + +// receive(channel_id: usize, buffer: [*]u8, len: usize) !usize +fn receive(proc: *const process.Info, trap_frame: *const TrapFrame) !usize { + const id = trap_frame.general_purpose_registers[10]; + const buffer_ptr: [*]u8 = @ptrFromInt(trap_frame.general_purpose_registers[11]); + const len = trap_frame.general_purpose_registers[12]; + + const buffer = buffer_ptr[0..len]; + return channel.receive(proc.id, id, buffer); +} |