diff options
Diffstat (limited to 'lib/std/os/zen.zig')
| -rw-r--r-- | lib/std/os/zen.zig | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/lib/std/os/zen.zig b/lib/std/os/zen.zig new file mode 100644 index 0000000000..727f55fa6d --- /dev/null +++ b/lib/std/os/zen.zig @@ -0,0 +1,260 @@ +const std = @import("../std.zig"); +const assert = std.debug.assert; + +////////////////////////// +//// IPC structures //// +////////////////////////// + +pub const Message = struct { + sender: MailboxId, + receiver: MailboxId, + code: usize, + args: [5]usize, + payload: ?[]const u8, + + pub fn from(mailbox_id: MailboxId) Message { + return Message{ + .sender = MailboxId.Undefined, + .receiver = mailbox_id, + .code = undefined, + .args = undefined, + .payload = null, + }; + } + + pub fn to(mailbox_id: MailboxId, msg_code: usize, args: ...) Message { + var message = Message{ + .sender = MailboxId.This, + .receiver = mailbox_id, + .code = msg_code, + .args = undefined, + .payload = null, + }; + + assert(args.len <= message.args.len); + comptime var i = 0; + inline while (i < args.len) : (i += 1) { + message.args[i] = args[i]; + } + + return message; + } + + pub fn as(self: Message, sender: MailboxId) Message { + var message = self; + message.sender = sender; + return message; + } + + pub fn withPayload(self: Message, payload: []const u8) Message { + var message = self; + message.payload = payload; + return message; + } +}; + +pub const MailboxId = union(enum) { + Undefined, + This, + Kernel, + Port: u16, + Thread: u16, +}; + +////////////////////////////////////// +//// Ports reserved for servers //// +////////////////////////////////////// + +pub const Server = struct { + pub const Keyboard = MailboxId{ .Port = 0 }; + pub const Terminal = MailboxId{ .Port = 1 }; +}; + +//////////////////////// +//// POSIX things //// +//////////////////////// + +// Standard streams. +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +// FIXME: let's borrow Linux's error numbers for now. +usingnamespace @import("bits/linux/errno.zig"); +// Get the errno from a syscall return value, or 0 for no error. +pub fn getErrno(r: usize) usize { + const signed_r = @bitCast(isize, r); + return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0; +} + +// TODO: implement this correctly. +pub fn read(fd: i32, buf: [*]u8, count: usize) usize { + switch (fd) { + STDIN_FILENO => { + var i: usize = 0; + while (i < count) : (i += 1) { + send(&Message.to(Server.Keyboard, 0)); + + // FIXME: we should be certain that we are receiving from Keyboard. + var message = Message.from(MailboxId.This); + receive(&message); + + buf[i] = @intCast(u8, message.args[0]); + } + }, + else => unreachable, + } + return count; +} + +// TODO: implement this correctly. +pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { + switch (fd) { + STDOUT_FILENO, STDERR_FILENO => { + send(&Message.to(Server.Terminal, 1).withPayload(buf[0..count])); + }, + else => unreachable, + } + return count; +} + +/////////////////////////// +//// Syscall numbers //// +/////////////////////////// + +pub const Syscall = enum(usize) { + exit = 0, + send = 1, + receive = 2, + subscribeIRQ = 3, + inb = 4, + outb = 5, + map = 6, + createThread = 7, +}; + +//////////////////// +//// Syscalls //// +//////////////////// + +pub fn exit(status: i32) noreturn { + _ = syscall1(Syscall.exit, @bitCast(usize, isize(status))); + unreachable; +} + +pub fn send(message: *const Message) void { + _ = syscall1(Syscall.send, @ptrToInt(message)); +} + +pub fn receive(destination: *Message) void { + _ = syscall1(Syscall.receive, @ptrToInt(destination)); +} + +pub fn subscribeIRQ(irq: u8, mailbox_id: *const MailboxId) void { + _ = syscall2(Syscall.subscribeIRQ, irq, @ptrToInt(mailbox_id)); +} + +pub fn inb(port: u16) u8 { + return @intCast(u8, syscall1(Syscall.inb, port)); +} + +pub fn outb(port: u16, value: u8) void { + _ = syscall2(Syscall.outb, port, value); +} + +pub fn map(v_addr: usize, p_addr: usize, size: usize, writable: bool) bool { + return syscall4(Syscall.map, v_addr, p_addr, size, @boolToInt(writable)) != 0; +} + +pub fn createThread(function: fn () void) u16 { + return u16(syscall1(Syscall.createThread, @ptrToInt(function))); +} + +///////////////////////// +//// Syscall stubs //// +///////////////////////// + +inline fn syscall0(number: Syscall) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number) + ); +} + +inline fn syscall1(number: Syscall, arg1: usize) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ecx}" (arg1) + ); +} + +inline fn syscall2(number: Syscall, arg1: usize, arg2: usize) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ecx}" (arg1), + [arg2] "{edx}" (arg2) + ); +} + +inline fn syscall3(number: Syscall, arg1: usize, arg2: usize, arg3: usize) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ecx}" (arg1), + [arg2] "{edx}" (arg2), + [arg3] "{ebx}" (arg3) + ); +} + +inline fn syscall4(number: Syscall, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ecx}" (arg1), + [arg2] "{edx}" (arg2), + [arg3] "{ebx}" (arg3), + [arg4] "{esi}" (arg4) + ); +} + +inline fn syscall5( + number: Syscall, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, +) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ecx}" (arg1), + [arg2] "{edx}" (arg2), + [arg3] "{ebx}" (arg3), + [arg4] "{esi}" (arg4), + [arg5] "{edi}" (arg5) + ); +} + +inline fn syscall6( + number: Syscall, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + return asm volatile ("int $0x80" + : [ret] "={eax}" (-> usize) + : [number] "{eax}" (number), + [arg1] "{ecx}" (arg1), + [arg2] "{edx}" (arg2), + [arg3] "{ebx}" (arg3), + [arg4] "{esi}" (arg4), + [arg5] "{edi}" (arg5), + [arg6] "{ebp}" (arg6) + ); +} |
