pluto/src/kernel/arch/x86/syscalls.zig

472 lines
16 KiB
Zig
Raw Normal View History

Initial scheduler Fix TSS Also change to .{} syntax where appropriate. Added the SS segment Fixed spelling Refactoring GDT Multitasking working for now WIP scheduler Refactored Bitmap a bit WIP still Task switching working Handlers return the stack pointer that will be used to restore the tasks stack, normal handlers will return the same stack pointer it was called with where task switching will return the stack pointer of the next task and restore its state using the interrupt stub. Initial scheduler done Created a stage 2 init task Change u32 to usize Move Task to arch specific WIP WIP2 Removed esp from task, replaced with stack_pointer Removed the debug logs Fixed init task stack Change pickNextTask to pointer manipulation This allows less allocations so faster switching Temporary enable interrupts for some runtime tests PIT and RTC need interrupts enabled to run their runtime tests Renamed schedule => pickNextTask, comptime bitmap for pids not task init And some other stuff: No pub for the task anymore Use the leak detector allocator Fmt Fix unit tests And some other stuff :P PR review Moved Task out of arch and have the stack init in the arch file Mocking clean up Removed commented code Renamed createTask to scheduleTask where the user will have to provide a task to schedule Removed redundant pub in log runtime test Removed global allocator for scheduler Cleaner assembly in paging Fmt Added new Scheduler test mode Added new test mode to CI Removed one of the prints Added doc comment, task test for i386 Removed test WIP Runtime tests work Have a global set in one task and reacted to in another. Also test that local variables are preserved after a task switch. Removed new lines Increased line length Move the allocation of the bool above the task creation
2020-07-18 22:46:24 +01:00
const std = @import("std");
2020-08-23 14:32:32 +01:00
const log = std.log.scoped(.x86_syscalls);
Initial scheduler Fix TSS Also change to .{} syntax where appropriate. Added the SS segment Fixed spelling Refactoring GDT Multitasking working for now WIP scheduler Refactored Bitmap a bit WIP still Task switching working Handlers return the stack pointer that will be used to restore the tasks stack, normal handlers will return the same stack pointer it was called with where task switching will return the stack pointer of the next task and restore its state using the interrupt stub. Initial scheduler done Created a stage 2 init task Change u32 to usize Move Task to arch specific WIP WIP2 Removed esp from task, replaced with stack_pointer Removed the debug logs Fixed init task stack Change pickNextTask to pointer manipulation This allows less allocations so faster switching Temporary enable interrupts for some runtime tests PIT and RTC need interrupts enabled to run their runtime tests Renamed schedule => pickNextTask, comptime bitmap for pids not task init And some other stuff: No pub for the task anymore Use the leak detector allocator Fmt Fix unit tests And some other stuff :P PR review Moved Task out of arch and have the stack init in the arch file Mocking clean up Removed commented code Renamed createTask to scheduleTask where the user will have to provide a task to schedule Removed redundant pub in log runtime test Removed global allocator for scheduler Cleaner assembly in paging Fmt Added new Scheduler test mode Added new test mode to CI Removed one of the prints Added doc comment, task test for i386 Removed test WIP Runtime tests work Have a global set in one task and reacted to in another. Also test that local variables are preserved after a task switch. Removed new lines Increased line length Move the allocation of the bool above the task creation
2020-07-18 22:46:24 +01:00
const builtin = @import("builtin");
const is_test = builtin.is_test;
const build_options = @import("build_options");
const mock_path = build_options.arch_mock_path;
const arch = if (is_test) @import(mock_path ++ "arch_mock.zig") else @import("arch.zig");
const testing = std.testing;
const expect = std.testing.expect;
2019-07-31 22:41:22 +01:00
const isr = @import("isr.zig");
const panic = @import("../../panic.zig").panic;
2020-11-22 22:23:54 +00:00
const syscalls = @import("../../syscalls.zig");
2019-07-31 22:41:22 +01:00
/// The isr number associated with syscalls
pub const INTERRUPT: u16 = 0x80;
/// The maximum number of syscall handlers that can be registered
pub const NUM_HANDLERS: u16 = 256;
/// A syscall handler
2020-11-22 22:23:54 +00:00
pub const Handler = fn (ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize;
2019-07-31 22:41:22 +01:00
/// Errors that syscall utility functions can throw
2020-11-22 22:23:54 +00:00
pub const Error = error{
2019-07-31 22:41:22 +01:00
SyscallExists,
InvalidSyscall,
2019-07-31 22:41:22 +01:00
};
2020-11-22 22:23:54 +00:00
comptime {
std.debug.assert(@typeInfo(syscalls.Syscall).Enum.fields.len <= NUM_HANDLERS);
}
2019-07-31 22:41:22 +01:00
/// The array of registered syscalls
2020-11-22 22:23:54 +00:00
var handlers: [NUM_HANDLERS]?Handler = [_]?Handler{null} ** NUM_HANDLERS;
2019-07-31 22:41:22 +01:00
///
/// Returns true if the syscall is valid, else false.
/// A syscall is valid if it's less than NUM_HANDLERS.
///
/// Arguments:
/// IN syscall: u32 - The syscall to check
///
/// Return: bool
/// Whether the syscall number is valid.
///
2019-07-31 22:41:22 +01:00
pub fn isValidSyscall(syscall: u32) bool {
return syscall < NUM_HANDLERS;
}
///
/// Handle a syscall. Gets the syscall number from eax within the context and calls the registered
2020-11-22 22:23:54 +00:00
/// handler. If an error occurs ebx will be set to its error code, or 0 otherwise.
/// The syscall result will be stored in eax. If there isn't a registered handler or the syscall is
/// invalid (>= NUM_HANDLERS) then a warning is logged.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
Initial scheduler Fix TSS Also change to .{} syntax where appropriate. Added the SS segment Fixed spelling Refactoring GDT Multitasking working for now WIP scheduler Refactored Bitmap a bit WIP still Task switching working Handlers return the stack pointer that will be used to restore the tasks stack, normal handlers will return the same stack pointer it was called with where task switching will return the stack pointer of the next task and restore its state using the interrupt stub. Initial scheduler done Created a stage 2 init task Change u32 to usize Move Task to arch specific WIP WIP2 Removed esp from task, replaced with stack_pointer Removed the debug logs Fixed init task stack Change pickNextTask to pointer manipulation This allows less allocations so faster switching Temporary enable interrupts for some runtime tests PIT and RTC need interrupts enabled to run their runtime tests Renamed schedule => pickNextTask, comptime bitmap for pids not task init And some other stuff: No pub for the task anymore Use the leak detector allocator Fmt Fix unit tests And some other stuff :P PR review Moved Task out of arch and have the stack init in the arch file Mocking clean up Removed commented code Renamed createTask to scheduleTask where the user will have to provide a task to schedule Removed redundant pub in log runtime test Removed global allocator for scheduler Cleaner assembly in paging Fmt Added new Scheduler test mode Added new test mode to CI Removed one of the prints Added doc comment, task test for i386 Removed test WIP Runtime tests work Have a global set in one task and reacted to in another. Also test that local variables are preserved after a task switch. Removed new lines Increased line length Move the allocation of the bool above the task creation
2020-07-18 22:46:24 +01:00
/// IN ctx: *arch.CpuState - The cpu context when the syscall was triggered. The
/// syscall number is stored in eax.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The new stack pointer value
///
fn handle(ctx: *arch.CpuState) usize {
2019-07-31 22:41:22 +01:00
// The syscall number is put in eax
const syscall = ctx.eax;
if (isValidSyscall(syscall)) {
if (handlers[syscall]) |handler| {
2020-11-22 22:23:54 +00:00
const result = handler(ctx, syscallArg(ctx, 0), syscallArg(ctx, 1), syscallArg(ctx, 2), syscallArg(ctx, 3), syscallArg(ctx, 4));
if (result) |res| {
ctx.eax = res;
ctx.ebx = 0;
} else |e| {
ctx.ebx = syscalls.toErrorCode(e);
}
2019-07-31 22:41:22 +01:00
} else {
2020-08-23 14:32:32 +01:00
log.warn("Syscall {} triggered but not registered\n", .{syscall});
2019-07-31 22:41:22 +01:00
}
} else {
2020-08-23 14:32:32 +01:00
log.warn("Syscall {} is invalid\n", .{syscall});
2019-07-31 22:41:22 +01:00
}
Initial scheduler Fix TSS Also change to .{} syntax where appropriate. Added the SS segment Fixed spelling Refactoring GDT Multitasking working for now WIP scheduler Refactored Bitmap a bit WIP still Task switching working Handlers return the stack pointer that will be used to restore the tasks stack, normal handlers will return the same stack pointer it was called with where task switching will return the stack pointer of the next task and restore its state using the interrupt stub. Initial scheduler done Created a stage 2 init task Change u32 to usize Move Task to arch specific WIP WIP2 Removed esp from task, replaced with stack_pointer Removed the debug logs Fixed init task stack Change pickNextTask to pointer manipulation This allows less allocations so faster switching Temporary enable interrupts for some runtime tests PIT and RTC need interrupts enabled to run their runtime tests Renamed schedule => pickNextTask, comptime bitmap for pids not task init And some other stuff: No pub for the task anymore Use the leak detector allocator Fmt Fix unit tests And some other stuff :P PR review Moved Task out of arch and have the stack init in the arch file Mocking clean up Removed commented code Renamed createTask to scheduleTask where the user will have to provide a task to schedule Removed redundant pub in log runtime test Removed global allocator for scheduler Cleaner assembly in paging Fmt Added new Scheduler test mode Added new test mode to CI Removed one of the prints Added doc comment, task test for i386 Removed test WIP Runtime tests work Have a global set in one task and reacted to in another. Also test that local variables are preserved after a task switch. Removed new lines Increased line length Move the allocation of the bool above the task creation
2020-07-18 22:46:24 +01:00
return @ptrToInt(ctx);
2019-07-31 22:41:22 +01:00
}
///
2020-11-22 22:23:54 +00:00
/// Register a syscall so it can be called by triggering interrupt 128 and putting its number in eax.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to register the handler with.
/// IN handler: Handler - The handler to register the syscall with.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Errors: Error
/// Error.SyscallExists - If the syscall has already been registered.
/// Error.InvalidSyscall - If the syscall is invalid. See isValidSyscall.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
pub fn registerSyscall(syscall: usize, handler: Handler) Error!void {
2019-07-31 22:41:22 +01:00
if (!isValidSyscall(syscall))
2020-11-22 22:23:54 +00:00
return Error.InvalidSyscall;
2019-07-31 22:41:22 +01:00
if (handlers[syscall]) |_|
2020-11-22 22:23:54 +00:00
return Error.SyscallExists;
2019-07-31 22:41:22 +01:00
handlers[syscall] = handler;
}
///
2020-11-22 22:23:54 +00:00
/// Trigger a syscall with no arguments. Returns the value put in eax by the syscall or the error returned in ebx.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to trigger, put in eax.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The return value from the syscall.
///
2020-11-22 22:23:54 +00:00
/// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
///
2021-02-17 17:12:40 +00:00
fn syscall0(syscall: usize) callconv(.Inline) syscalls.Error!usize {
2020-11-22 22:23:54 +00:00
const res = asm volatile (
2019-07-31 22:41:22 +01:00
\\int $0x80
2020-11-22 22:23:54 +00:00
: [ret] "={eax}" (-> usize)
: [syscall] "{eax}" (syscall)
2020-11-22 22:23:54 +00:00
: "ebx"
);
const err = asm (""
: [ret] "={ebx}" (-> usize)
2019-07-31 22:41:22 +01:00
);
2020-11-22 22:23:54 +00:00
if (err != 0) {
return syscalls.fromErrorCode(err);
}
return res;
2019-07-31 22:41:22 +01:00
}
///
2020-11-22 22:23:54 +00:00
/// Trigger a syscall with one argument. Returns the value put in eax by the syscall or the error returned in ebx.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to trigger, put in eax.
/// IN arg: usize - The argument to pass. Put in ebx.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The return value from the syscall.
///
2020-11-22 22:23:54 +00:00
/// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
///
2021-02-17 17:12:40 +00:00
fn syscall1(syscall: usize, arg: usize) callconv(.Inline) syscalls.Error!usize {
2020-11-22 22:23:54 +00:00
const res = asm volatile (
2019-07-31 22:41:22 +01:00
\\int $0x80
2020-11-22 22:23:54 +00:00
: [ret] "={eax}" (-> usize)
2019-07-31 22:41:22 +01:00
: [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg)
2019-07-31 22:41:22 +01:00
);
2020-11-22 22:23:54 +00:00
const err = asm (""
: [ret] "={ebx}" (-> usize)
);
if (err != 0) {
return syscalls.fromErrorCode(err);
}
return res;
2019-07-31 22:41:22 +01:00
}
///
2020-11-22 22:23:54 +00:00
/// Trigger a syscall with two arguments. Returns the value put in eax by the syscall or the error returned in ebx.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to trigger, put in eax.
/// IN arg1: usize - The first argument to pass. Put in ebx.
/// IN arg2: usize - The second argument to pass. Put in ecx.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The return value from the syscall.
///
2020-11-22 22:23:54 +00:00
/// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
///
2021-02-17 17:12:40 +00:00
fn syscall2(syscall: usize, arg1: usize, arg2: usize) callconv(.Inline) syscalls.Error!usize {
2020-11-22 22:23:54 +00:00
const res = asm volatile (
2019-07-31 22:41:22 +01:00
\\int $0x80
2020-11-22 22:23:54 +00:00
: [ret] "={eax}" (-> usize)
2019-07-31 22:41:22 +01:00
: [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2)
2019-07-31 22:41:22 +01:00
);
2020-11-22 22:23:54 +00:00
const err = asm (""
: [ret] "={ebx}" (-> usize)
);
if (err != 0) {
return syscalls.fromErrorCode(err);
}
return res;
2019-07-31 22:41:22 +01:00
}
///
2020-11-22 22:23:54 +00:00
/// Trigger a syscall with three arguments. Returns the value put in eax by the syscall or the error returned in ebx.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to trigger, put in eax.
/// IN arg1: usize - The first argument to pass. Put in ebx.
/// IN arg2: usize - The second argument to pass. Put in ecx.
/// IN arg3: usize - The third argument to pass. Put in edx.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The return value from the syscall.
///
2020-11-22 22:23:54 +00:00
/// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
///
2021-02-17 17:12:40 +00:00
fn syscall3(syscall: usize, arg1: usize, arg2: usize, arg3: usize) callconv(.Inline) syscalls.Error!usize {
2020-11-22 22:23:54 +00:00
const res = asm volatile (
2019-07-31 22:41:22 +01:00
\\int $0x80
2020-11-22 22:23:54 +00:00
: [ret] "={eax}" (-> usize)
2019-07-31 22:41:22 +01:00
: [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3)
2019-07-31 22:41:22 +01:00
);
2020-11-22 22:23:54 +00:00
const err = asm (""
: [ret] "={ebx}" (-> usize)
);
if (err != 0) {
return syscalls.fromErrorCode(err);
}
return res;
2019-07-31 22:41:22 +01:00
}
///
2020-11-22 22:23:54 +00:00
/// Trigger a syscall with four arguments. Returns the value put in eax by the syscall or the error returned in ebx.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to trigger, put in eax.
/// IN arg1: usize - The first argument to pass. Put in ebx.
/// IN arg2: usize - The second argument to pass. Put in ecx.
/// IN arg3: usize - The third argument to pass. Put in edx.
/// IN arg4: usize - The fourth argument to pass. Put in esi.
2019-07-31 22:41:22 +01:00
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The return value from the syscall.
///
2020-11-22 22:23:54 +00:00
/// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
///
2021-02-17 17:12:40 +00:00
fn syscall4(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) callconv(.Inline) syscalls.Error!usize {
2020-11-22 22:23:54 +00:00
const res = asm volatile (
2019-07-31 22:41:22 +01:00
\\int $0x80
2020-11-22 22:23:54 +00:00
: [ret] "={eax}" (-> usize)
2019-07-31 22:41:22 +01:00
: [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4)
2019-07-31 22:41:22 +01:00
);
2020-11-22 22:23:54 +00:00
const err = asm (""
: [ret] "={ebx}" (-> usize)
);
if (err != 0) {
return syscalls.fromErrorCode(err);
}
return res;
2019-07-31 22:41:22 +01:00
}
///
2020-11-22 22:23:54 +00:00
/// Trigger a syscall with five arguments. Returns the value put in eax by the syscall or the error returned in ebx.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
2020-11-22 22:23:54 +00:00
/// IN syscall: usize - The syscall to trigger, put in eax.
/// IN arg1: usize - The first argument to pass. Put in ebx.
/// IN arg2: usize - The second argument to pass. Put in ecx.
/// IN arg3: usize - The third argument to pass. Put in edx.
/// IN arg4: usize - The fourth argument to pass. Put in esi.
/// IN arg5: usize - The fifth argument to pass. Put in edi.
///
/// Return: usize
/// The return value from the syscall.
///
2020-11-22 22:23:54 +00:00
/// Error: syscalls.Error
/// This function will return the error that the syscall handler returns. See the documentation for the syscall for details.
///
2021-02-17 17:12:40 +00:00
fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) callconv(.Inline) syscalls.Error!usize {
2020-11-22 22:23:54 +00:00
const res = asm volatile (
2019-07-31 22:41:22 +01:00
\\int $0x80
2020-11-22 22:23:54 +00:00
: [ret] "={eax}" (-> usize)
2019-07-31 22:41:22 +01:00
: [syscall] "{eax}" (syscall),
[arg1] "{ebx}" (arg1),
[arg2] "{ecx}" (arg2),
[arg3] "{edx}" (arg3),
[arg4] "{esi}" (arg4),
[arg5] "{edi}" (arg5)
2019-07-31 22:41:22 +01:00
);
2020-11-22 22:23:54 +00:00
const err = asm (""
: [ret] "={ebx}" (-> usize)
);
if (err != 0) {
return syscalls.fromErrorCode(err);
}
return res;
2019-07-31 22:41:22 +01:00
}
///
/// Gets the syscall argument according to the given index. 0 => ebx, 1 => ecx, 2 => edx,
/// 3 => esi and 4 => edi.
2019-07-31 22:41:22 +01:00
///
/// Arguments:
Initial scheduler Fix TSS Also change to .{} syntax where appropriate. Added the SS segment Fixed spelling Refactoring GDT Multitasking working for now WIP scheduler Refactored Bitmap a bit WIP still Task switching working Handlers return the stack pointer that will be used to restore the tasks stack, normal handlers will return the same stack pointer it was called with where task switching will return the stack pointer of the next task and restore its state using the interrupt stub. Initial scheduler done Created a stage 2 init task Change u32 to usize Move Task to arch specific WIP WIP2 Removed esp from task, replaced with stack_pointer Removed the debug logs Fixed init task stack Change pickNextTask to pointer manipulation This allows less allocations so faster switching Temporary enable interrupts for some runtime tests PIT and RTC need interrupts enabled to run their runtime tests Renamed schedule => pickNextTask, comptime bitmap for pids not task init And some other stuff: No pub for the task anymore Use the leak detector allocator Fmt Fix unit tests And some other stuff :P PR review Moved Task out of arch and have the stack init in the arch file Mocking clean up Removed commented code Renamed createTask to scheduleTask where the user will have to provide a task to schedule Removed redundant pub in log runtime test Removed global allocator for scheduler Cleaner assembly in paging Fmt Added new Scheduler test mode Added new test mode to CI Removed one of the prints Added doc comment, task test for i386 Removed test WIP Runtime tests work Have a global set in one task and reacted to in another. Also test that local variables are preserved after a task switch. Removed new lines Increased line length Move the allocation of the bool above the task creation
2020-07-18 22:46:24 +01:00
/// IN ctx: *arch.CpuState - The interrupt context from which to get the argument
2019-07-31 22:41:22 +01:00
/// IN arg_idx: comptime u32 - The argument index to get. Between 0 and 4.
///
2020-11-22 22:23:54 +00:00
/// Return: usize
/// The syscall argument from the given index.
///
2021-02-17 17:12:40 +00:00
fn syscallArg(ctx: *arch.CpuState, comptime arg_idx: u32) callconv(.Inline) usize {
2019-07-31 22:41:22 +01:00
return switch (arg_idx) {
0 => ctx.ebx,
1 => ctx.ecx,
2 => ctx.edx,
3 => ctx.esi,
4 => ctx.edi,
else => @compileError("Arg index must be between 0 and 4"),
2019-07-31 22:41:22 +01:00
};
}
///
2020-11-22 22:23:54 +00:00
/// Construct a handler for a syscall.
///
/// Arguments:
/// IN comptime syscall: Syscall - The syscall to construct the handler for.
///
/// Return: Handler
/// The handler function constructed.
///
fn makeHandler(comptime syscall: syscalls.Syscall) Handler {
return struct {
fn func(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
return syscalls.handle(syscall, arg1, arg2, arg3, arg4, arg5);
}
}.func;
}
///
/// Initialise syscalls. Registers the isr associated with INTERRUPT and sets up handlers for each syscall.
2019-07-31 22:41:22 +01:00
///
2019-11-02 02:00:49 +00:00
pub fn init() void {
2020-08-23 14:32:32 +01:00
log.info("Init\n", .{});
defer log.info("Done\n", .{});
2020-11-22 22:23:54 +00:00
isr.registerIsr(INTERRUPT, handle) catch |e| {
panic(@errorReturnTrace(), "Failed to register syscall ISR: {}\n", .{e});
};
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});
};
}
switch (build_options.test_mode) {
.Initialisation => runtimeTests(),
else => {},
}
2019-07-31 22:41:22 +01:00
}
/// Tests
var test_int: u32 = 0;
2019-07-31 22:41:22 +01:00
2020-11-22 22:23:54 +00:00
fn testHandler0(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += 1;
2019-07-31 22:41:22 +01:00
return 0;
}
2020-11-22 22:23:54 +00:00
fn testHandler1(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += arg1;
2019-07-31 22:41:22 +01:00
return 1;
}
2020-11-22 22:23:54 +00:00
fn testHandler2(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += arg1 + arg2;
return 2;
2019-07-31 22:41:22 +01:00
}
2020-11-22 22:23:54 +00:00
fn testHandler3(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += arg1 + arg2 + arg3;
return 3;
2019-07-31 22:41:22 +01:00
}
2020-11-22 22:23:54 +00:00
fn testHandler4(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += arg1 + arg2 + arg3 + arg4;
return 4;
2019-07-31 22:41:22 +01:00
}
2020-11-22 22:23:54 +00:00
fn testHandler5(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
test_int += arg1 + arg2 + arg3 + arg4 + arg5;
return 5;
2019-07-31 22:41:22 +01:00
}
2020-11-22 22:23:54 +00:00
fn testHandler6(ctx: *arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) syscalls.Error!usize {
return syscalls.Error.OutOfMemory;
}
2019-07-31 22:41:22 +01:00
test "registerSyscall returns SyscallExists" {
2020-11-22 22:23:54 +00:00
try registerSyscall(122, testHandler0);
std.testing.expectError(Error.SyscallExists, registerSyscall(122, testHandler0));
2019-07-31 22:41:22 +01:00
}
fn runtimeTests() void {
2020-11-22 22:23:54 +00:00
registerSyscall(121, testHandler6) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 6: {}\n", .{e});
registerSyscall(122, testHandler0) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 0: {}\n", .{e});
registerSyscall(123, testHandler1) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 1: {}\n", .{e});
registerSyscall(124, testHandler2) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 2: {}\n", .{e});
registerSyscall(125, testHandler3) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 3: {}\n", .{e});
registerSyscall(126, testHandler4) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 4: {}\n", .{e});
registerSyscall(127, testHandler5) catch |e| panic(@errorReturnTrace(), "FAILURE registering handler 5: {}\n", .{e});
if (test_int != 0) {
panic(@errorReturnTrace(), "FAILURE initial test_int not 0: {}\n", .{test_int});
}
2019-07-31 22:41:22 +01:00
2020-11-22 22:23:54 +00:00
if (syscall0(122)) |res| {
if (res != 0 or test_int != 1) {
panic(@errorReturnTrace(), "FAILURE syscall0\n", .{});
}
} else |e| {
panic(@errorReturnTrace(), "FAILURE syscall0 errored: {}\n", .{e});
}
2019-07-31 22:41:22 +01:00
2020-11-22 22:23:54 +00:00
if (syscall1(123, 2)) |res| {
if (res != 1 or test_int != 3) {
panic(@errorReturnTrace(), "FAILURE syscall1\n", .{});
}
} else |e| {
panic(@errorReturnTrace(), "FAILURE syscall1 errored: {}\n", .{e});
}
2019-07-31 22:41:22 +01:00
2020-11-22 22:23:54 +00:00
if (syscall2(124, 2, 3)) |res| {
if (res != 2 or test_int != 8) {
panic(@errorReturnTrace(), "FAILURE syscall2\n", .{});
}
} else |e| {
panic(@errorReturnTrace(), "FAILURE syscall2 errored: {}\n", .{e});
}
2019-07-31 22:41:22 +01:00
2020-11-22 22:23:54 +00:00
if (syscall3(125, 2, 3, 4)) |res| {
if (res != 3 or test_int != 17) {
panic(@errorReturnTrace(), "FAILURE syscall3\n", .{});
}
} else |e| {
panic(@errorReturnTrace(), "FAILURE syscall3 errored: {}\n", .{e});
}
2019-07-31 22:41:22 +01:00
2020-11-22 22:23:54 +00:00
if (syscall4(126, 2, 3, 4, 5)) |res| {
if (res != 4 or test_int != 31) {
panic(@errorReturnTrace(), "FAILURE syscall4\n", .{});
}
} else |e| {
panic(@errorReturnTrace(), "FAILURE syscall4 errored: {}\n", .{e});
}
2020-11-22 22:23:54 +00:00
if (syscall5(127, 2, 3, 4, 5, 6)) |res| {
if (res != 5 or test_int != 51) {
panic(@errorReturnTrace(), "FAILURE syscall5\n", .{});
}
} else |e| {
panic(@errorReturnTrace(), "FAILURE syscall5 errored: {}\n", .{e});
}
if (syscall0(121)) |res| {
panic(@errorReturnTrace(), "FAILURE syscall6\n", .{});
} else |e| {
if (e != syscalls.Error.OutOfMemory) {
panic(@errorReturnTrace(), "FAILURE syscall6 returned the wrong error: {}\n", .{e});
}
}
2019-07-31 22:41:22 +01:00
2020-08-23 14:32:32 +01:00
log.info("Tested all args\n", .{});
2019-07-31 22:41:22 +01:00
}