diff options
Diffstat (limited to 'system')
| -rw-r--r-- | system/ash/ash.zig | 110 | ||||
| -rw-r--r-- | system/ash/ash.zon | 9 | ||||
| -rw-r--r-- | system/libraries/akiba/akiba.zig | 10 | ||||
| -rw-r--r-- | system/libraries/akiba/akiba.zon | 6 | ||||
| -rw-r--r-- | system/libraries/akiba/io.zig | 168 | ||||
| -rw-r--r-- | system/libraries/akiba/kata.zig | 38 | ||||
| -rw-r--r-- | system/libraries/akiba/start.zig | 31 | ||||
| -rw-r--r-- | system/libraries/akiba/sys.zig | 40 | ||||
| -rw-r--r-- | system/pulse/pulse.zig | 22 | ||||
| -rw-r--r-- | system/pulse/pulse.zon | 8 |
10 files changed, 47 insertions, 395 deletions
diff --git a/system/ash/ash.zig b/system/ash/ash.zig index 013de87..5149ab8 100644 --- a/system/ash/ash.zig +++ b/system/ash/ash.zig @@ -1,6 +1,11 @@ //! Ash - Akiba Shell -const akiba = @import("akiba"); +const colors = @import("colors"); +const format = @import("format"); +const io = @import("io"); +const kata = @import("kata"); +const string = @import("string"); +const sys = @import("sys"); const MAX_INPUT = 256; const MAX_ARGS = 16; @@ -14,41 +19,35 @@ var letter_buffer: [256]u8 = undefined; var arg_ptrs: [MAX_ARGS][*:0]const u8 = undefined; var arg_storage: [MAX_ARGS][128]u8 = undefined; -const Color = struct { - const white: u32 = 0x00FFFFFF; - const green: u32 = 0x0088FF88; - const red: u32 = 0x00FF4444; -}; - export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 { _ = pc; _ = pv; while (true) { - const location = akiba.io.getlocation(&location_buffer) catch "/"; - const stack_name = get_stack_name(location); + const location = io.getlocation(&location_buffer) catch "/"; + const stack_name = string.getStackName(location); - _ = akiba.io.mark(akiba.io.stream, "(", Color.white) catch {}; - _ = akiba.io.mark(akiba.io.stream, stack_name, Color.green) catch {}; - _ = akiba.io.mark(akiba.io.stream, ") >>> ", Color.white) catch {}; + format.print("("); + format.color(stack_name, colors.green); + format.print(") >>> "); input_len = 0; while (true) { - const char = akiba.io.getchar() catch continue; + const char = io.getchar() catch continue; if (char == '\n') { - _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch {}; + format.print("\n"); break; } else if (char == '\x08') { if (input_len > 0) { input_len -= 1; - _ = akiba.io.mark(akiba.io.stream, "\x08", Color.white) catch {}; + format.print("\x08"); } } else if (char >= 32 and char <= 126 and input_len < MAX_INPUT - 1) { input_buffer[input_len] = char; input_len += 1; char_buffer[0] = char; - _ = akiba.io.mark(akiba.io.stream, &char_buffer, Color.white) catch {}; + format.print(&char_buffer); } } @@ -87,99 +86,40 @@ fn execute_command(input: []const u8) void { if (argc == 0) return; - const cmd = arg_storage[0][0..find_null(&arg_storage[0])]; + const cmd = arg_storage[0][0..string.findNull(&arg_storage[0])]; var path_buf: [512]u8 = undefined; + const path = string.concat3(&path_buf, "/binaries/", cmd, ".akiba"); - const path = build_path(&path_buf, "/binaries/", cmd, ".akiba"); if (try_spawn_with_args(path, arg_ptrs[0..argc])) { process_letters(); return; } - _ = akiba.io.mark(akiba.io.stream, "ash: binary not found: ", Color.red) catch {}; - _ = akiba.io.mark(akiba.io.stream, cmd, Color.white) catch {}; - _ = akiba.io.mark(akiba.io.stream, ".\n", Color.white) catch {}; + format.color("ash: binary not found: ", colors.red); + format.print(cmd); + format.println("."); } fn try_spawn_with_args(path: []const u8, argv: [][*:0]const u8) bool { - const pid = akiba.kata.spawn_with_args(path, argv) catch { + const pid = kata.spawnWithArgs(path, argv) catch { return false; }; - _ = akiba.kata.wait(pid) catch {}; + _ = kata.wait(pid) catch {}; return true; } fn process_letters() void { - const letter_type = akiba.io.read_letter(&letter_buffer) catch return; + const letter_type = io.readLetter(&letter_buffer) catch return; - if (letter_type == akiba.io.Letter.NAVIGATE) { + if (letter_type == io.Letter.NAVIGATE) { var len: usize = 0; while (len < letter_buffer.len and letter_buffer[len] != 0) : (len += 1) {} if (len > 0) { - akiba.io.setlocation(letter_buffer[0..len]) catch {}; + io.setlocation(letter_buffer[0..len]) catch {}; } } } - -fn find_null(buf: []const u8) usize { - var len: usize = 0; - while (len < buf.len and buf[len] != 0) : (len += 1) {} - return len; -} - -fn build_path(buf: []u8, prefix: []const u8, name: []const u8, suffix: []const u8) []const u8 { - var pos: usize = 0; - for (prefix) |c| { - if (pos >= buf.len) break; - buf[pos] = c; - pos += 1; - } - for (name) |c| { - if (pos >= buf.len) break; - buf[pos] = c; - pos += 1; - } - for (suffix) |c| { - if (pos >= buf.len) break; - buf[pos] = c; - pos += 1; - } - return buf[0..pos]; -} - -fn get_stack_name(location: []const u8) []const u8 { - // Root case - if (location.len == 0 or (location.len == 1 and location[0] == '/')) { - return "/"; - } - - // Find last '/' and return everything after it - var last_slash: usize = 0; - for (location, 0..) |c, i| { - if (c == '/') { - last_slash = i; - } - } - - // If path ends with '/', look for second-to-last slash - if (last_slash == location.len - 1 and location.len > 1) { - var i: usize = location.len - 2; - while (i > 0) : (i -= 1) { - if (location[i] == '/') { - return location[i + 1 .. location.len - 1]; - } - } - return location[1 .. location.len - 1]; - } - - // Return part after last slash - if (last_slash + 1 < location.len) { - return location[last_slash + 1 ..]; - } - - return location; -} diff --git a/system/ash/ash.zon b/system/ash/ash.zon index 0c72775..e96488a 100644 --- a/system/ash/ash.zon +++ b/system/ash/ash.zon @@ -1,8 +1,13 @@ .{ .name = "ash", .version = "0.1.0", - .paths = .{""}, .dependencies = .{ - .akiba = .{ .path = "../libraries/akiba" }, + .sys, + .io, + .kata, + .colors, + .string, + .format, }, + .entry = "ash.zig", } diff --git a/system/libraries/akiba/akiba.zig b/system/libraries/akiba/akiba.zig deleted file mode 100644 index 77911e1..0000000 --- a/system/libraries/akiba/akiba.zig +++ /dev/null @@ -1,10 +0,0 @@ -//! Akiba Runtime - Core system library - -pub const kata = @import("kata.zig"); -pub const io = @import("io.zig"); -pub const sys = @import("sys.zig"); -pub const start = @import("start.zig"); - -comptime { - _ = start; -} diff --git a/system/libraries/akiba/akiba.zon b/system/libraries/akiba/akiba.zon deleted file mode 100644 index aad4a03..0000000 --- a/system/libraries/akiba/akiba.zon +++ /dev/null @@ -1,6 +0,0 @@ -.{ - .name = "akiba", - .version = "1.0.0", - .type = .library, - .entry = "akiba.zig", -} diff --git a/system/libraries/akiba/io.zig b/system/libraries/akiba/io.zig deleted file mode 100644 index 155ac70..0000000 --- a/system/libraries/akiba/io.zig +++ /dev/null @@ -1,168 +0,0 @@ -//! File I/O operations - -const sys = @import("sys.zig"); -const kata = @import("kata.zig"); - -pub const Error = error{ - NotFound, - PermissionDenied, - InvalidDescriptor, - ReadFailed, - WriteFailed, -}; - -pub const FileDescriptor = u32; - -// Standard file descriptors -pub const source: FileDescriptor = 0; // Input stream -pub const stream: FileDescriptor = 1; // Output stream -pub const trace: FileDescriptor = 2; // Error/trace stream - -// Open modes -pub const VIEW_ONLY: u32 = 0x01; -pub const MARK_ONLY: u32 = 0x02; -pub const BOTH: u32 = 0x03; -pub const CREATE: u32 = 0x0100; - -pub const StackEntry = extern struct { - identity: [64]u8, - identity_len: u8, - is_stack: bool, - owner_name_len: u8, - permission_type: u8, - size: u32, - modified_time: u64, - owner_name: [64]u8, -}; - -// Letter types -pub const Letter = struct { - pub const NONE: u8 = 0; - pub const NAVIGATE: u8 = 1; -}; - -pub fn attach(path: []const u8, flags: u32) Error!FileDescriptor { - const result = sys.syscall(.attach, .{ @intFromPtr(path.ptr), flags }); - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return Error.NotFound; - } - return @truncate(result); -} - -pub fn seal(fd: FileDescriptor) void { - _ = sys.syscall(.seal, .{fd}); -} - -pub fn view(fd: FileDescriptor, buffer: []u8) Error!usize { - const result = sys.syscall(.view, .{ fd, @intFromPtr(buffer.ptr), buffer.len }); - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return Error.ReadFailed; - } - return result; -} - -pub fn viewstack(path: []const u8, entries: []StackEntry) !usize { - const result = sys.syscall(.viewstack, .{ - @intFromPtr(path.ptr), - path.len, - @intFromPtr(entries.ptr), - entries.len, - }); - - // Check for error (-1) - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.InvalidPath; - } - - return @intCast(result); -} - -pub fn mark(fd: FileDescriptor, data: []const u8, color: u32) Error!usize { - const result = sys.syscall(.mark, .{ fd, @intFromPtr(data.ptr), data.len, color }); - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return Error.WriteFailed; - } - return result; -} - -pub fn getchar() !u8 { - // Loop until character is available - while (true) { - const result = sys.syscall(.getkeychar, .{}); - if (result != @as(u64, @bitCast(@as(i64, -2)))) { - if (result != @as(u64, @bitCast(@as(i64, -1)))) { - return @truncate(result); - } - return error.ReadFailed; - } - // No input yet (-2 = EAGAIN), yield to kernel - kata.yield(); - } -} - -pub fn getlocation(buffer: []u8) ![]u8 { - const result = sys.syscall(.getlocation, .{ - @intFromPtr(buffer.ptr), - buffer.len, - }); - - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.GetLocationFailed; - } - - return buffer[0..@intCast(result)]; -} - -pub fn setlocation(path: []const u8) !void { - const result = sys.syscall(.setlocation, .{ - @intFromPtr(path.ptr), - path.len, - }); - - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.InvalidPath; - } -} - -/// Send a letter to parent Kata -pub fn send_letter(letter_type: u8, data: []const u8) !void { - const result = sys.syscall(.postman, .{ - @as(u64, 0), // MODE_SEND - @as(u64, letter_type), - @intFromPtr(data.ptr), - data.len, - }); - - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.SendFailed; - } -} - -/// Read letter from inbox -/// Returns letter type (0 = no letter), copies data to buffer -pub fn read_letter(buffer: []u8) !u8 { - const result = sys.syscall(.postman, .{ - @as(u64, 1), // MODE_READ - @intFromPtr(buffer.ptr), - buffer.len, - }); - - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.ReadFailed; - } - - return @intCast(result); -} - -pub fn wipe() void { - _ = sys.syscall(.wipe, .{}); -} - -pub fn print(text: []const u8) Error!void { - _ = try mark(stream, text, 0x00FFFFFF); -} - -pub fn println(text: []const u8) Error!void { - _ = try mark(stream, text, 0x00FFFFFF); - _ = try mark(stream, "\n", 0x00FFFFFF); -} diff --git a/system/libraries/akiba/kata.zig b/system/libraries/akiba/kata.zig deleted file mode 100644 index be3189b..0000000 --- a/system/libraries/akiba/kata.zig +++ /dev/null @@ -1,38 +0,0 @@ -//! Kata (process) control functions - -const sys = @import("sys.zig"); - -pub fn yield() void { - _ = sys.syscall(.yield, .{}); -} - -pub fn exit(code: u64) noreturn { - _ = sys.syscall(.exit, .{code}); - unreachable; -} - -pub fn spawn(path: []const u8) !u32 { - const result = sys.syscall(.spawn, .{ @intFromPtr(path.ptr), path.len, @as(u64, 0), @as(u64, 0) }); - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.SpawnFailed; - } - return @truncate(result); -} - -pub fn spawn_with_args(path: []const u8, argv: [][*:0]const u8) !u32 { - const result = sys.syscall(.spawn, .{ @intFromPtr(path.ptr), path.len, @intFromPtr(argv.ptr), argv.len }); - if (result == @as(u64, @bitCast(@as(i64, -1)))) { - return error.SpawnFailed; - } - return @truncate(result); -} - -pub fn wait(pid: u32) !u64 { - while (true) { - const result = sys.syscall(.wait, .{pid}); - if (result != @as(u64, @bitCast(@as(i64, -1)))) { - return result; - } - yield(); - } -} diff --git a/system/libraries/akiba/start.zig b/system/libraries/akiba/start.zig deleted file mode 100644 index fbe11e2..0000000 --- a/system/libraries/akiba/start.zig +++ /dev/null @@ -1,31 +0,0 @@ -//! Akiba Runtime Entry Point -//! Provides _start that calls user's main(pc, pv) and handles exit - -// User must provide this -extern fn main(pc: u32, pv: [*]const [*:0]const u8) u8; - -export fn _start() callconv(.naked) noreturn { - // At entry, stack layout is: - // [RSP + 0] = pc (parameter count, 64-bit but only low 32 used) - // [RSP + 8] = pv (pointer to parameter vector) - // - // x86-64 calling convention: - // First arg (u32) -> EDI - // Second arg (ptr) -> RSI - - asm volatile ( - // Load arguments for main(pc, pv) - \\mov (%%rsp), %%edi - \\mov 8(%%rsp), %%rsi - // Align stack to 16 bytes before call (required by ABI) - \\and $-16, %%rsp - \\call main - // main returned exit code in AL, zero-extend to RDI for exit syscall - \\movzbl %%al, %%edi - // exit syscall (0x01) - \\mov $0x01, %%eax - \\syscall - // Should never reach here - \\ud2 - ); -} diff --git a/system/libraries/akiba/sys.zig b/system/libraries/akiba/sys.zig deleted file mode 100644 index b2da4f1..0000000 --- a/system/libraries/akiba/sys.zig +++ /dev/null @@ -1,40 +0,0 @@ -//! Low-level invocation interface - -pub const Invocation = enum(u64) { exit = 0x01, attach = 0x02, seal = 0x03, view = 0x04, mark = 0x05, spawn = 0x06, wait = 0x07, yield = 0x08, getkeychar = 0x09, viewstack = 0x0A, getlocation = 0x0B, setlocation = 0x0C, postman = 0x0D, wipe = 0x0E }; - -/// Perform a system invocation with variable arguments -/// Uses comptime to handle different argument counts -pub inline fn syscall(invocation: Invocation, args: anytype) u64 { - const Args = @TypeOf(args); - const fields = @typeInfo(Args).@"struct".fields; - - // Always set all 6 argument registers, defaulting unused ones to 0 - const arg0: u64 = if (fields.len > 0) @as(u64, @bitCast(toU64(args[0]))) else 0; - const arg1: u64 = if (fields.len > 1) @as(u64, @bitCast(toU64(args[1]))) else 0; - const arg2: u64 = if (fields.len > 2) @as(u64, @bitCast(toU64(args[2]))) else 0; - const arg3: u64 = if (fields.len > 3) @as(u64, @bitCast(toU64(args[3]))) else 0; - const arg4: u64 = if (fields.len > 4) @as(u64, @bitCast(toU64(args[4]))) else 0; - const arg5: u64 = if (fields.len > 5) @as(u64, @bitCast(toU64(args[5]))) else 0; - - return asm volatile ("syscall" - : [ret] "={rax}" (-> u64), - : [number] "{rax}" (@intFromEnum(invocation)), - [arg0] "{rdi}" (arg0), - [arg1] "{rsi}" (arg1), - [arg2] "{rdx}" (arg2), - [arg3] "{r10}" (arg3), - [arg4] "{r8}" (arg4), - [arg5] "{r9}" (arg5), - : .{ .rcx = true, .r11 = true, .memory = true }); -} - -/// Convert various types to u64 for syscall arguments -inline fn toU64(value: anytype) u64 { - const T = @TypeOf(value); - return switch (@typeInfo(T)) { - .int, .comptime_int => @as(u64, @intCast(value)), - .pointer => @intFromPtr(value), - .@"enum" => @intFromEnum(value), - else => @as(u64, @bitCast(value)), - }; -} diff --git a/system/pulse/pulse.zig b/system/pulse/pulse.zig index d0f3dd2..3ef1091 100644 --- a/system/pulse/pulse.zig +++ b/system/pulse/pulse.zig @@ -1,29 +1,27 @@ //! Pulse - Akiba OS Init System -//! First Kata to run (PID 1), manages system lifecycle -const akiba = @import("akiba"); +const format = @import("format"); +const kata = @import("kata"); +const sys = @import("sys"); export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 { _ = pc; _ = pv; - // Init loop - respawn shell when it exits while (true) { - const shell_pid = akiba.kata.spawn("/system/ash/ash.akiba") catch { - akiba.io.println("Pulse: Failed to spawn shell") catch {}; - akiba.kata.yield(); + const shell_pid = kata.spawn("/system/ash/ash.akiba") catch { + format.println("Pulse: Failed to spawn shell"); + kata.yield(); continue; }; - // Wait for shell to exit - _ = akiba.kata.wait(shell_pid) catch { - akiba.io.println("Pulse: Shell wait failed") catch {}; - akiba.kata.yield(); + _ = kata.wait(shell_pid) catch { + format.println("Pulse: Shell wait failed"); + kata.yield(); continue; }; - // Shell exited, respawn - akiba.io.println("\nPulse: Shell exited, respawning...\n") catch {}; + format.println("\nPulse: Shell exited, respawning...\n"); } return 0; diff --git a/system/pulse/pulse.zon b/system/pulse/pulse.zon index d35e8c9..6a8da7f 100644 --- a/system/pulse/pulse.zon +++ b/system/pulse/pulse.zon @@ -1,8 +1,10 @@ .{ .name = "pulse", - .version = "1.0.0", - .type = .init, + .version = "0.1.0", .dependencies = .{ - "akiba", + .sys, + .kata, + .format, }, + .entry = "pulse.zig", } |
