diff --git a/src/kernel/arch/x86/syscalls.zig b/src/kernel/arch/x86/syscalls.zig index 65caff3..bc3fc59 100644 --- a/src/kernel/arch/x86/syscalls.zig +++ b/src/kernel/arch/x86/syscalls.zig @@ -17,7 +17,7 @@ pub const INTERRUPT: u16 = 0x80; pub const NUM_HANDLERS: u16 = 256; /// A syscall handler -pub const Handler = fn (arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize; +pub const Handler = fn (arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize; /// Errors that syscall utility functions can throw pub const Error = error{ @@ -108,10 +108,10 @@ pub fn registerSyscall(syscall: usize, handler: Handler) Error!void { /// Return: usize /// The return value from the syscall. /// -/// Error: syscalls.Error +/// Error: anyerror /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// -inline fn syscall0(syscall: usize) syscalls.Error!usize { +inline fn syscall0(syscall: usize) anyerror!usize { const res = asm volatile ( \\int $0x80 : [ret] "={eax}" (-> usize), @@ -119,7 +119,7 @@ inline fn syscall0(syscall: usize) syscalls.Error!usize { : "ebx" ); const err = asm ("" - : [ret] "={ebx}" (-> usize), + : [ret] "={ebx}" (-> u16), ); if (err != 0) { return syscalls.fromErrorCode(err); @@ -137,10 +137,10 @@ inline fn syscall0(syscall: usize) syscalls.Error!usize { /// Return: usize /// The return value from the syscall. /// -/// Error: syscalls.Error +/// Error: anyerror /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// -inline fn syscall1(syscall: usize, arg: usize) syscalls.Error!usize { +inline fn syscall1(syscall: usize, arg: usize) anyerror!usize { const res = asm volatile ( \\int $0x80 : [ret] "={eax}" (-> usize), @@ -148,7 +148,7 @@ inline fn syscall1(syscall: usize, arg: usize) syscalls.Error!usize { [arg1] "{ebx}" (arg), ); const err = asm ("" - : [ret] "={ebx}" (-> usize), + : [ret] "={ebx}" (-> u16), ); if (err != 0) { return syscalls.fromErrorCode(err); @@ -167,10 +167,10 @@ inline fn syscall1(syscall: usize, arg: usize) syscalls.Error!usize { /// Return: usize /// The return value from the syscall. /// -/// Error: syscalls.Error +/// Error: anyerror /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// -inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) syscalls.Error!usize { +inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) anyerror!usize { const res = asm volatile ( \\int $0x80 : [ret] "={eax}" (-> usize), @@ -179,7 +179,7 @@ inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) syscalls.Error!usiz [arg2] "{ecx}" (arg2), ); const err = asm ("" - : [ret] "={ebx}" (-> usize), + : [ret] "={ebx}" (-> u16), ); if (err != 0) { return syscalls.fromErrorCode(err); @@ -199,10 +199,10 @@ inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) syscalls.Error!usiz /// Return: usize /// The return value from the syscall. /// -/// Error: syscalls.Error +/// Error: anyerror /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// -inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) syscalls.Error!usize { +inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) anyerror!usize { const res = asm volatile ( \\int $0x80 : [ret] "={eax}" (-> usize), @@ -212,7 +212,7 @@ inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) syscal [arg3] "{edx}" (arg3), ); const err = asm ("" - : [ret] "={ebx}" (-> usize), + : [ret] "={ebx}" (-> u16), ); if (err != 0) { return syscalls.fromErrorCode(err); @@ -233,10 +233,10 @@ inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) syscal /// Return: usize /// The return value from the syscall. /// -/// Error: syscalls.Error +/// Error: anyerror /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// -inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) syscalls.Error!usize { +inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) anyerror!usize { const res = asm volatile ( \\int $0x80 : [ret] "={eax}" (-> usize), @@ -247,7 +247,7 @@ inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: [arg4] "{esi}" (arg4), ); const err = asm ("" - : [ret] "={ebx}" (-> usize), + : [ret] "={ebx}" (-> u16), ); if (err != 0) { return syscalls.fromErrorCode(err); @@ -269,10 +269,10 @@ inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: /// Return: usize /// The return value from the syscall. /// -/// Error: syscalls.Error +/// Error: anyerror /// This function will return the error that the syscall handler returns. See the documentation for the syscall for details. /// -inline fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +inline fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { const res = asm volatile ( \\int $0x80 : [ret] "={eax}" (-> usize), @@ -284,7 +284,7 @@ inline fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: [arg5] "{edi}" (arg5), ); const err = asm ("" - : [ret] "={ebx}" (-> usize), + : [ret] "={ebx}" (-> u16), ); if (err != 0) { return syscalls.fromErrorCode(err); @@ -325,7 +325,7 @@ inline fn syscallArg(ctx: *arch.CpuState, comptime arg_idx: u32) usize { /// fn makeHandler(comptime syscall: syscalls.Syscall) Handler { return struct { - fn func(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { + fn func(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { return syscalls.handle(syscall, arg1, arg2, arg3, arg4, arg5); } }.func; @@ -344,9 +344,11 @@ pub fn init() void { inline for (std.meta.fields(syscalls.Syscall)) |field| { const syscall = @intToEnum(syscalls.Syscall, field.value); - registerSyscall(field.value, makeHandler(syscall)) catch |e| { - panic(@errorReturnTrace(), "Failed to register syscall for '" ++ field.name ++ "': {}\n", .{e}); - }; + if (!syscall.isTest()) { + registerSyscall(field.value, makeHandler(syscall)) catch |e| { + panic(@errorReturnTrace(), "Failed to register syscall for '" ++ field.name ++ "': {}\n", .{e}); + }; + } } switch (build_options.test_mode) { @@ -358,7 +360,7 @@ pub fn init() void { /// Tests var test_int: u32 = 0; -fn testHandler0(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler0(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings _ = arg1; _ = arg2; @@ -369,7 +371,7 @@ fn testHandler0(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) return 0; } -fn testHandler1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings _ = arg2; _ = arg3; @@ -379,7 +381,7 @@ fn testHandler1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) return 1; } -fn testHandler2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings _ = arg3; _ = arg4; @@ -388,7 +390,7 @@ fn testHandler2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) return 2; } -fn testHandler3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings _ = arg4; _ = arg5; @@ -396,26 +398,26 @@ fn testHandler3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) return 3; } -fn testHandler4(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler4(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings _ = arg5; test_int += arg1 + arg2 + arg3 + arg4; return 4; } -fn testHandler5(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler5(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { test_int += arg1 + arg2 + arg3 + arg4 + arg5; return 5; } -fn testHandler6(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize { +fn testHandler6(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings _ = arg1; _ = arg2; _ = arg3; _ = arg4; _ = arg5; - return syscalls.Error.OutOfMemory; + return error.OutOfMemory; } test "registerSyscall returns SyscallExists" { @@ -487,7 +489,7 @@ fn runtimeTests() void { if (syscall0(121)) { panic(@errorReturnTrace(), "FAILURE syscall6\n", .{}); } else |e| { - if (e != syscalls.Error.OutOfMemory) { + if (e != error.OutOfMemory) { panic(@errorReturnTrace(), "FAILURE syscall6 returned the wrong error: {}\n", .{e}); } } diff --git a/src/kernel/syscalls.zig b/src/kernel/syscalls.zig index 8987cd7..4c01cbb 100644 --- a/src/kernel/syscalls.zig +++ b/src/kernel/syscalls.zig @@ -6,53 +6,6 @@ const log = std.log.scoped(.syscalls); /// A compilation of all errors that syscall handlers could return. pub const Error = error{OutOfMemory}; -/// -/// Convert an error code to an instance of Error. The conversion must be synchronised with toErrorCode -/// -/// Arguments: -/// IN code: usize - The erorr code to convert -/// -/// Return: Error -/// The error corresponding to the error code -/// -pub fn fromErrorCode(code: usize) Error { - return switch (code) { - 1 => Error.OutOfMemory, - else => unreachable, - }; -} - -/// -/// Convert an instance of Error to an error code. The conversion must be synchronised with fromErrorCode -/// -/// Arguments: -/// IN err: Error - The erorr to convert -/// -/// Return: usize -/// The error code corresponding to the error -/// -pub fn toErrorCode(err: Error) usize { - return switch (err) { - Error.OutOfMemory => 1, - }; -} - -comptime { - // Make sure toErrorCode and fromErrorCode are synchronised, and that no errors share the same error code - inline for (@typeInfo(Error).ErrorSet.?) |err| { - const error_instance = @field(Error, err.name); - if (fromErrorCode(toErrorCode(error_instance)) != error_instance) { - @compileError("toErrorCode and fromErrorCode are not synchronised for syscall error '" ++ err.name ++ "'\n"); - } - inline for (@typeInfo(Error).ErrorSet.?) |err2| { - const error2_instance = @field(Error, err2.name); - if (error_instance != error2_instance and toErrorCode(error_instance) == toErrorCode(error2_instance)) { - @compileError("Syscall errors '" ++ err.name ++ "' and '" ++ err2.name ++ "' share the same error code\n"); - } - } - } -} - /// All implemented syscalls pub const Syscall = enum { Test1, @@ -75,11 +28,53 @@ pub const Syscall = enum { .Test3 => handleTest3, }; } + + /// + /// Check if the syscall is just used for testing, and therefore shouldn't be exposed at runtime + /// + /// Arguments: + /// IN self: Syscall - The syscall to check + /// + /// Return: bool + /// true if the syscall is only to be used for testing, else false + /// + pub fn isTest(self: @This()) bool { + return switch (self) { + .Test1, .Test2, .Test3 => true, + }; + } }; /// A function that can handle a syscall and return a result or an error pub const Handler = fn (arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize; +/// +/// Convert an error code to an instance of Error. The conversion must be synchronised with toErrorCode +/// Passing an error code that does not correspond to an error results in safety-protected undefined behaviour +/// +/// Arguments: +/// IN code: u16 - The erorr code to convert +/// +/// Return: Error +/// The error corresponding to the error code +/// +pub fn fromErrorCode(code: u16) anyerror { + return @intToError(code); +} + +/// +/// Convert an instance of Error to an error code. The conversion must be synchronised with fromErrorCode +/// +/// Arguments: +/// IN err: Error - The erorr to convert +/// +/// Return: u16 +/// The error code corresponding to the error +/// +pub fn toErrorCode(err: anyerror) u16 { + return @errorToInt(err); +} + /// /// Handle a syscall and return a result or error ///