Improve syscall error conversion

This commit is contained in:
Samuel Tebbs 2022-04-23 20:16:59 +01:00 committed by Sam Tebbs
parent 765c07a457
commit b42357d31d
2 changed files with 76 additions and 79 deletions

View file

@ -17,7 +17,7 @@ pub const INTERRUPT: u16 = 0x80;
pub const NUM_HANDLERS: u16 = 256; pub const NUM_HANDLERS: u16 = 256;
/// A syscall handler /// 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 /// Errors that syscall utility functions can throw
pub const Error = error{ pub const Error = error{
@ -108,10 +108,10 @@ pub fn registerSyscall(syscall: usize, handler: Handler) Error!void {
/// Return: usize /// Return: usize
/// The return value from the syscall. /// 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. /// 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 ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize), : [ret] "={eax}" (-> usize),
@ -119,7 +119,7 @@ inline fn syscall0(syscall: usize) syscalls.Error!usize {
: "ebx" : "ebx"
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize), : [ret] "={ebx}" (-> u16),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -137,10 +137,10 @@ inline fn syscall0(syscall: usize) syscalls.Error!usize {
/// Return: usize /// Return: usize
/// The return value from the syscall. /// 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. /// 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 ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize), : [ret] "={eax}" (-> usize),
@ -148,7 +148,7 @@ inline fn syscall1(syscall: usize, arg: usize) syscalls.Error!usize {
[arg1] "{ebx}" (arg), [arg1] "{ebx}" (arg),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize), : [ret] "={ebx}" (-> u16),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -167,10 +167,10 @@ inline fn syscall1(syscall: usize, arg: usize) syscalls.Error!usize {
/// Return: usize /// Return: usize
/// The return value from the syscall. /// 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. /// 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 ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize), : [ret] "={eax}" (-> usize),
@ -179,7 +179,7 @@ inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) syscalls.Error!usiz
[arg2] "{ecx}" (arg2), [arg2] "{ecx}" (arg2),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize), : [ret] "={ebx}" (-> u16),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -199,10 +199,10 @@ inline fn syscall2(syscall: usize, arg1: usize, arg2: usize) syscalls.Error!usiz
/// Return: usize /// Return: usize
/// The return value from the syscall. /// 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. /// 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 ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize), : [ret] "={eax}" (-> usize),
@ -212,7 +212,7 @@ inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) syscal
[arg3] "{edx}" (arg3), [arg3] "{edx}" (arg3),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize), : [ret] "={ebx}" (-> u16),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -233,10 +233,10 @@ inline fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) syscal
/// Return: usize /// Return: usize
/// The return value from the syscall. /// 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. /// 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 ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize), : [ret] "={eax}" (-> usize),
@ -247,7 +247,7 @@ inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4:
[arg4] "{esi}" (arg4), [arg4] "{esi}" (arg4),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize), : [ret] "={ebx}" (-> u16),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); return syscalls.fromErrorCode(err);
@ -269,10 +269,10 @@ inline fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4:
/// Return: usize /// Return: usize
/// The return value from the syscall. /// 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. /// 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 ( const res = asm volatile (
\\int $0x80 \\int $0x80
: [ret] "={eax}" (-> usize), : [ret] "={eax}" (-> usize),
@ -284,7 +284,7 @@ inline fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4:
[arg5] "{edi}" (arg5), [arg5] "{edi}" (arg5),
); );
const err = asm ("" const err = asm (""
: [ret] "={ebx}" (-> usize), : [ret] "={ebx}" (-> u16),
); );
if (err != 0) { if (err != 0) {
return syscalls.fromErrorCode(err); 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 { fn makeHandler(comptime syscall: syscalls.Syscall) Handler {
return struct { 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); return syscalls.handle(syscall, arg1, arg2, arg3, arg4, arg5);
} }
}.func; }.func;
@ -344,10 +344,12 @@ pub fn init() void {
inline for (std.meta.fields(syscalls.Syscall)) |field| { inline for (std.meta.fields(syscalls.Syscall)) |field| {
const syscall = @intToEnum(syscalls.Syscall, field.value); const syscall = @intToEnum(syscalls.Syscall, field.value);
if (!syscall.isTest()) {
registerSyscall(field.value, makeHandler(syscall)) catch |e| { registerSyscall(field.value, makeHandler(syscall)) catch |e| {
panic(@errorReturnTrace(), "Failed to register syscall for '" ++ field.name ++ "': {}\n", .{e}); panic(@errorReturnTrace(), "Failed to register syscall for '" ++ field.name ++ "': {}\n", .{e});
}; };
} }
}
switch (build_options.test_mode) { switch (build_options.test_mode) {
.Initialisation => runtimeTests(), .Initialisation => runtimeTests(),
@ -358,7 +360,7 @@ pub fn init() void {
/// Tests /// Tests
var test_int: u32 = 0; 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 // Suppress unused variable warnings
_ = arg1; _ = arg1;
_ = arg2; _ = arg2;
@ -369,7 +371,7 @@ fn testHandler0(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize)
return 0; 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 // Suppress unused variable warnings
_ = arg2; _ = arg2;
_ = arg3; _ = arg3;
@ -379,7 +381,7 @@ fn testHandler1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize)
return 1; 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 // Suppress unused variable warnings
_ = arg3; _ = arg3;
_ = arg4; _ = arg4;
@ -388,7 +390,7 @@ fn testHandler2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize)
return 2; 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 // Suppress unused variable warnings
_ = arg4; _ = arg4;
_ = arg5; _ = arg5;
@ -396,26 +398,26 @@ fn testHandler3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize)
return 3; 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 // Suppress unused variable warnings
_ = arg5; _ = arg5;
test_int += arg1 + arg2 + arg3 + arg4; test_int += arg1 + arg2 + arg3 + arg4;
return 4; 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; test_int += arg1 + arg2 + arg3 + arg4 + arg5;
return 5; 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 // Suppress unused variable warnings
_ = arg1; _ = arg1;
_ = arg2; _ = arg2;
_ = arg3; _ = arg3;
_ = arg4; _ = arg4;
_ = arg5; _ = arg5;
return syscalls.Error.OutOfMemory; return error.OutOfMemory;
} }
test "registerSyscall returns SyscallExists" { test "registerSyscall returns SyscallExists" {
@ -487,7 +489,7 @@ fn runtimeTests() void {
if (syscall0(121)) { if (syscall0(121)) {
panic(@errorReturnTrace(), "FAILURE syscall6\n", .{}); panic(@errorReturnTrace(), "FAILURE syscall6\n", .{});
} else |e| { } else |e| {
if (e != syscalls.Error.OutOfMemory) { if (e != error.OutOfMemory) {
panic(@errorReturnTrace(), "FAILURE syscall6 returned the wrong error: {}\n", .{e}); panic(@errorReturnTrace(), "FAILURE syscall6 returned the wrong error: {}\n", .{e});
} }
} }

View file

@ -6,53 +6,6 @@ const log = std.log.scoped(.syscalls);
/// A compilation of all errors that syscall handlers could return. /// A compilation of all errors that syscall handlers could return.
pub const Error = error{OutOfMemory}; 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 /// All implemented syscalls
pub const Syscall = enum { pub const Syscall = enum {
Test1, Test1,
@ -75,11 +28,53 @@ pub const Syscall = enum {
.Test3 => handleTest3, .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 /// 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; 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 /// Handle a syscall and return a result or error
/// ///