diff options
| author | hachem <im@hachem.wtf> | 2026-10-04 02:02:15 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-10-04 02:02:15 +0200 |
| commit | 7c1bd03a71cccfcf48e79d241787021b0de98e73 (patch) | |
| tree | b7131a1f4eee60d24781d3f549d191e17793c282 /boot/user.zig | |
| parent | 627f05098785327744e666c9149375125499d2ff (diff) | |
feat: add more user programs
Diffstat (limited to 'boot/user.zig')
| -rw-r--r-- | boot/user.zig | 69 |
1 files changed, 47 insertions, 22 deletions
diff --git a/boot/user.zig b/boot/user.zig index 1d0839f..5ba6604 100644 --- a/boot/user.zig +++ b/boot/user.zig @@ -1,15 +1,23 @@ -// the syscall boundary (int 0x80). ring 3 entry itself now lives in the -// scheduler (boot/sched.zig), which iretqs into tasks, this file is just the -// syscall gate + handlers -// +// int 0x80 syscall gate + handlers. ring 3 entry itself lives in sched.zig // see: https://wiki.osdev.org/System_Calls const serial = @import("serial.zig"); const idt = @import("idt.zig"); const sched = @import("sched.zig"); const regs = @import("regs.zig"); +const bridge = @import("bridge"); const Frame = regs.Frame; +// scratch for a filename copied out of the caller. one static buffer is fine, +// syscalls run one at a time (if=0) +var name_buf: [64]u8 = undefined; +fn userName(ptr: u64) []const u8 { + const p: [*]const u8 = @ptrFromInt(ptr); + var i: usize = 0; + while (i < name_buf.len - 1 and p[i] != 0) : (i += 1) name_buf[i] = p[i]; + return name_buf[0..i]; +} + // what the syscall stub leaves on the stack: the gp regs it pushed, then the // frame the cpu pushed on int 0x80. rax holds the syscall number in, and the // handler writes the return value back into it (restored by the stubs pop) @@ -58,42 +66,59 @@ export fn syscallStub() callconv(.naked) void { export fn syscallHandler(frame: *SyscallFrame) callconv(.c) void { switch (frame.rax) { 0 => { // exit(code): code in rdi - sched.exitCurrent(); // mark dead, the next tick reclaims + switches away + sched.exitCurrent(); asm volatile ("sti"); - while (true) asm volatile ("hlt"); // never returns to this task + while (true) asm volatile ("hlt"); }, 1 => { // write(ptr, len): rdi = user pointer, rsi = length const len = frame.rsi; - // the processs address space is active during the syscall, so the - // kernel can read the user pointer directly. cap the length so a - // bogus arg cant run us off into unmapped memory if (len > 0 and len <= 4096) { const bytes: [*]const u8 = @ptrFromInt(frame.rdi); - serial.write(bytes[0..len]); // mirrored -> kernel tasks on_tick renders it + serial.write(bytes[0..len]); } frame.rax = len; // syscall return value }, 2 => { // read(): return a buffered byte, else block for one - // become the foreground reader, if a byte is already queued, take it if (sched.readReady()) |byte| { frame.rax = byte; return; } - // otherwise save a context that resumes right after this int 0x80 - // (with rax = the delivered byte), mark the task blocked, and yield - // the kernel task decodes keys and calls sched.deliverinput to wake us const resume_frame: Frame = .{ - .r15 = frame.r15, .r14 = frame.r14, .r13 = frame.r13, .r12 = frame.r12, - .r11 = frame.r11, .r10 = frame.r10, .r9 = frame.r9, .r8 = frame.r8, - .rbp = frame.rbp, .rdi = frame.rdi, .rsi = frame.rsi, .rdx = frame.rdx, - .rcx = frame.rcx, .rbx = frame.rbx, .rax = frame.rax, - .vector = 0, .error_code = 0, - .rip = frame.rip, .cs = frame.cs, .rflags = frame.rflags, - .rsp = frame.rsp, .ss = frame.ss, + .r15 = frame.r15, + .r14 = frame.r14, + .r13 = frame.r13, + .r12 = frame.r12, + .r11 = frame.r11, + .r10 = frame.r10, + .r9 = frame.r9, + .r8 = frame.r8, + .rbp = frame.rbp, + .rdi = frame.rdi, + .rsi = frame.rsi, + .rdx = frame.rdx, + .rcx = frame.rcx, + .rbx = frame.rbx, + .rax = frame.rax, + .vector = 0, + .error_code = 0, + .rip = frame.rip, + .cs = frame.cs, + .rflags = frame.rflags, + .rsp = frame.rsp, + .ss = frame.ss, }; sched.blockCurrentOnRead(resume_frame); asm volatile ("sti"); - while (true) asm volatile ("hlt"); // yield, resumed via rf when input arrives + while (true) asm volatile ("hlt"); + }, + 4 => { // fs_size(name_ptr): returns size (like obv), or -1 + frame.rax = @bitCast(bridge.fsSize(userName(frame.rdi))); + }, + 5 => { // fs_read(name_ptr, offset, buf_ptr, len): returns bytes read + const len = @min(frame.rcx, 4096); + const name = userName(frame.rdi); + const dst: [*]u8 = @ptrFromInt(frame.rdx); + frame.rax = bridge.fsReadInto(name, frame.rsi, dst[0..len]); }, else => serial.write("[syscall] unknown\r\n"), } |
