aboutsummaryrefslogtreecommitdiff
path: root/src/syscall.zig
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-08-01 13:07:30 +0200
committerHimbeer <himbeer@disroot.org>2024-08-01 13:07:30 +0200
commitc22a1c2214d5f3256684fa08262501cfd70be915 (patch)
tree28ed508137c86d15bb2c7e15a6ec2802d1cea1ed /src/syscall.zig
parent017c63d49f4c6fdd2f762dd7d14323fbbdb7775e (diff)
Flatten 'lib' directory into main 'src' tree
Diffstat (limited to 'src/syscall.zig')
-rw-r--r--src/syscall.zig200
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);
+}