diff --git a/src/kernel/arch/x86/arch.zig b/src/kernel/arch/x86/arch.zig index 5741445..2b4db4f 100644 --- a/src/kernel/arch/x86/arch.zig +++ b/src/kernel/arch/x86/arch.zig @@ -87,6 +87,31 @@ pub const CpuState = packed struct { eflags: u32, user_esp: u32, user_ss: u32, + + pub fn empty() CpuState { + return .{ + .cr3 = undefined, + .gs = undefined, + .fs = undefined, + .es = undefined, + .ds = undefined, + .edi = undefined, + .esi = undefined, + .ebp = undefined, + .esp = undefined, + .ebx = undefined, + .edx = undefined, + .ecx = undefined, + .eax = undefined, + .int_num = undefined, + .error_code = undefined, + .eip = undefined, + .cs = undefined, + .eflags = undefined, + .user_esp = undefined, + .user_ss = undefined, + }; + } }; /// x86's boot payload is the multiboot info passed by grub diff --git a/src/kernel/arch/x86/syscalls.zig b/src/kernel/arch/x86/syscalls.zig index bc3fc59..01ee414 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) anyerror!usize; +pub const Handler = fn (ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize; /// Errors that syscall utility functions can throw pub const Error = error{ @@ -64,7 +64,7 @@ fn handle(ctx: *arch.CpuState) usize { const syscall = ctx.eax; if (isValidSyscall(syscall)) { if (handlers[syscall]) |handler| { - const result = handler(syscallArg(ctx, 0), syscallArg(ctx, 1), syscallArg(ctx, 2), syscallArg(ctx, 3), syscallArg(ctx, 4)); + 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; @@ -297,13 +297,13 @@ inline fn syscall5(syscall: usize, arg1: usize, arg2: usize, arg3: usize, arg4: /// 3 => esi and 4 => edi. /// /// Arguments: -/// IN ctx: *arch.CpuState - The interrupt context from which to get the argument +/// IN ctx: *const arch.CpuState - The interrupt context from which to get the argument /// IN arg_idx: comptime u32 - The argument index to get. Between 0 and 4. /// /// Return: usize /// The syscall argument from the given index. /// -inline fn syscallArg(ctx: *arch.CpuState, comptime arg_idx: u32) usize { +inline fn syscallArg(ctx: *const arch.CpuState, comptime arg_idx: u32) usize { return switch (arg_idx) { 0 => ctx.ebx, 1 => ctx.ecx, @@ -325,8 +325,8 @@ 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) anyerror!usize { - return syscalls.handle(syscall, arg1, arg2, arg3, arg4, arg5); + fn func(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { + return syscalls.handle(syscall, ctx, arg1, arg2, arg3, arg4, arg5); } }.func; } @@ -360,8 +360,9 @@ pub fn init() void { /// Tests var test_int: u32 = 0; -fn testHandler0(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { +fn testHandler0(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings + _ = ctx; _ = arg1; _ = arg2; _ = arg3; @@ -371,8 +372,9 @@ 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) anyerror!usize { +fn testHandler1(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings + _ = ctx; _ = arg2; _ = arg3; _ = arg4; @@ -381,8 +383,9 @@ 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) anyerror!usize { +fn testHandler2(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings + _ = ctx; _ = arg3; _ = arg4; _ = arg5; @@ -390,28 +393,32 @@ 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) anyerror!usize { +fn testHandler3(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings + _ = ctx; _ = arg4; _ = arg5; test_int += arg1 + arg2 + arg3; return 3; } -fn testHandler4(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { +fn testHandler4(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings + _ = ctx; _ = arg5; test_int += arg1 + arg2 + arg3 + arg4; return 4; } -fn testHandler5(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { +fn testHandler5(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { + _ = ctx; test_int += arg1 + arg2 + arg3 + arg4 + arg5; return 5; } -fn testHandler6(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { +fn testHandler6(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) anyerror!usize { // Suppress unused variable warnings + _ = ctx; _ = arg1; _ = arg2; _ = arg3; diff --git a/src/kernel/syscalls.zig b/src/kernel/syscalls.zig index 4c01cbb..bb25793 100644 --- a/src/kernel/syscalls.zig +++ b/src/kernel/syscalls.zig @@ -2,6 +2,7 @@ const std = @import("std"); const scheduler = @import("scheduler.zig"); const panic = @import("panic.zig").panic; const log = std.log.scoped(.syscalls); +const arch = @import("arch.zig").internals; /// A compilation of all errors that syscall handlers could return. pub const Error = error{OutOfMemory}; @@ -46,7 +47,7 @@ pub const Syscall = enum { }; /// 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 (ctx: *const arch.CpuState, 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 @@ -88,12 +89,13 @@ pub fn toErrorCode(err: anyerror) u16 { /// Error: Error /// The error raised by the handler /// -pub fn handle(syscall: Syscall, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { - return try syscall.getHandler()(arg1, arg2, arg3, arg4, arg5); +pub fn handle(syscall: Syscall, ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { + return try syscall.getHandler()(ctx, arg1, arg2, arg3, arg4, arg5); } -pub fn handleTest1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { +pub fn handleTest1(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { // Suppress unused variable warnings + _ = ctx; _ = arg1; _ = arg2; _ = arg3; @@ -102,12 +104,14 @@ pub fn handleTest1(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usi return 0; } -pub fn handleTest2(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { +pub fn handleTest2(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { + _ = ctx; return arg1 + arg2 + arg3 + arg4 + arg5; } -pub fn handleTest3(arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { +pub fn handleTest3(ctx: *const arch.CpuState, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) Error!usize { // Suppress unused variable warnings + _ = ctx; _ = arg1; _ = arg2; _ = arg3; @@ -123,7 +127,8 @@ test "getHandler" { } test "handle" { - try std.testing.expectEqual(@as(usize, 0), try handle(.Test1, 0, 0, 0, 0, 0)); - try std.testing.expectEqual(@as(usize, 1 + 2 + 3 + 4 + 5), try handle(.Test2, 1, 2, 3, 4, 5)); - try std.testing.expectError(Error.OutOfMemory, handle(.Test3, 0, 0, 0, 0, 0)); + const state = arch.CpuState.empty(); + try std.testing.expectEqual(@as(usize, 0), try handle(.Test1, &state, 0, 0, 0, 0, 0)); + try std.testing.expectEqual(@as(usize, 1 + 2 + 3 + 4 + 5), try handle(.Test2, &state, 1, 2, 3, 4, 5)); + try std.testing.expectError(Error.OutOfMemory, handle(.Test3, &state, 0, 0, 0, 0, 0)); } diff --git a/test/mock/kernel/arch_mock.zig b/test/mock/kernel/arch_mock.zig index 65a50b4..a2b38b4 100644 --- a/test/mock/kernel/arch_mock.zig +++ b/test/mock/kernel/arch_mock.zig @@ -54,6 +54,31 @@ pub const CpuState = struct { eflags: u32, user_esp: u32, user_ss: u32, + + pub fn empty() CpuState { + return .{ + .ss = undefined, + .gs = undefined, + .fs = undefined, + .es = undefined, + .ds = undefined, + .edi = undefined, + .esi = undefined, + .ebp = undefined, + .esp = undefined, + .ebx = undefined, + .edx = undefined, + .ecx = undefined, + .eax = undefined, + .int_num = undefined, + .error_code = undefined, + .eip = undefined, + .cs = undefined, + .eflags = undefined, + .user_esp = undefined, + .user_ss = undefined, + }; + } }; pub const VmmPayload = switch (builtin.cpu.arch) {