aboutsummaryrefslogtreecommitdiff
path: root/system
diff options
context:
space:
mode:
Diffstat (limited to 'system')
-rw-r--r--system/ash/ash.zig110
-rw-r--r--system/ash/ash.zon9
-rw-r--r--system/libraries/akiba/akiba.zig10
-rw-r--r--system/libraries/akiba/akiba.zon6
-rw-r--r--system/libraries/akiba/io.zig168
-rw-r--r--system/libraries/akiba/kata.zig38
-rw-r--r--system/libraries/akiba/start.zig31
-rw-r--r--system/libraries/akiba/sys.zig40
-rw-r--r--system/pulse/pulse.zig22
-rw-r--r--system/pulse/pulse.zon8
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",
}