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;
/// 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});
}
}

View file

@ -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
///