137 lines
3.5 KiB
Zig
137 lines
3.5 KiB
Zig
const std = @import("std");
|
|
|
|
// --- 1. IO PRIMITIVES ---
|
|
|
|
// We import 'write' and 'exit' from libc.nim / clib.c (found in libnexus.a)
|
|
extern fn write(fd: i32, buf: [*]const u8, count: usize) isize;
|
|
extern fn exit(status: i32) noreturn;
|
|
|
|
export fn fputc(c: i32, stream: ?*anyopaque) i32 {
|
|
_ = stream;
|
|
const char = @as(u8, @intCast(c));
|
|
const buf = [1]u8{char};
|
|
_ = write(1, &buf, 1);
|
|
return c;
|
|
}
|
|
|
|
export fn fputs(s: [*]const u8, stream: ?*anyopaque) i32 {
|
|
_ = stream;
|
|
var len: usize = 0;
|
|
while (s[len] != 0) : (len += 1) {}
|
|
_ = write(1, s, len);
|
|
return 1;
|
|
}
|
|
|
|
// --- 2. THE MISSING SYMBOLS (STUBS) ---
|
|
|
|
// Nim checks for errors on streams. We say "No error".
|
|
export fn ferror(stream: ?*anyopaque) i32 {
|
|
_ = stream;
|
|
return 0;
|
|
}
|
|
|
|
export fn clearerr(stream: ?*anyopaque) void {
|
|
_ = stream;
|
|
}
|
|
|
|
// Nim looks for chars in memory (optimized scans).
|
|
export fn memchr(s: ?*const anyopaque, c: i32, n: usize) ?*anyopaque {
|
|
if (s) |src_ptr| {
|
|
const src: [*]const u8 = @ptrCast(src_ptr);
|
|
const target = @as(u8, @intCast(c));
|
|
var i: usize = 0;
|
|
while (i < n) : (i += 1) {
|
|
if (src[i] == target) return @ptrCast(@constCast(src + i));
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
extern fn ion_user_free(pkt: ion.IonPacket) void;
|
|
|
|
export fn read(fd: i32, buf: [*]u8, count: usize) isize {
|
|
if (fd != 0) return -1;
|
|
|
|
var pkt: ion.IonPacket = undefined;
|
|
while (!ion.sys_input_pop(&pkt)) {
|
|
nexus_yield();
|
|
}
|
|
|
|
const to_copy = @min(count, pkt.len);
|
|
const src = @as([*]const u8, @ptrFromInt(pkt.data));
|
|
@memcpy(buf[0..to_copy], src[0..to_copy]);
|
|
|
|
ion_user_free(pkt);
|
|
return @intCast(to_copy);
|
|
}
|
|
|
|
// Nim tries to read lines.
|
|
export fn fgets(s: [*]u8, size: i32, stream: ?*anyopaque) ?[*]u8 {
|
|
_ = stream;
|
|
if (size <= 0) return null;
|
|
|
|
var pkt: ion.IonPacket = undefined;
|
|
while (!ion.sys_input_pop(&pkt)) {
|
|
nexus_yield();
|
|
}
|
|
|
|
const to_copy = @min(@as(usize, @intCast(size - 1)), pkt.len);
|
|
const src = @as([*]const u8, @ptrFromInt(pkt.data));
|
|
@memcpy(s[0..to_copy], src[0..to_copy]);
|
|
s[to_copy] = 0;
|
|
|
|
ion_user_free(pkt);
|
|
return s;
|
|
}
|
|
|
|
export fn fgetc(stream: ?*anyopaque) i32 {
|
|
_ = stream;
|
|
var c: u8 = undefined;
|
|
const n = read(0, @ptrCast(&c), 1);
|
|
if (n <= 0) return -1;
|
|
return @intCast(c);
|
|
}
|
|
|
|
// Math stubs (sometimes needed)
|
|
export fn dlopen() void {}
|
|
export fn dlsym() void {}
|
|
|
|
export fn strerror(errnum: i32) [*]const u8 {
|
|
_ = errnum;
|
|
return "Unknown Error";
|
|
}
|
|
|
|
extern fn main(argc: i32, argv: [*]const [*]const u8) i32;
|
|
|
|
// _start relocated to subject_entry.S
|
|
|
|
const ion = @import("ion.zig");
|
|
|
|
// Sovereign Syscall: Push to CMD Ring
|
|
export fn nexus_syscall(cmd_id: u32, arg: u32) c_int {
|
|
// Construct Packet
|
|
var pkt = ion.CmdPacket{ .kind = cmd_id, .arg = arg, .id = [_]u8{0} ** 16 };
|
|
|
|
// Compute Provenance (SipHash)
|
|
const key = "\xde\xad\xbe\xef\xca\xfe\xba\xbe\x00\x01\x02\x03\x04\x05\x06\x07";
|
|
|
|
var hasher = std.crypto.auth.siphash.SipHash128(1, 3).init(key);
|
|
hasher.update(std.mem.asBytes(&pkt.kind));
|
|
hasher.update(std.mem.asBytes(&pkt.arg));
|
|
const hash_int = hasher.finalInt();
|
|
|
|
pkt.id = std.mem.toBytes(hash_int);
|
|
|
|
// Push to High-Priority CMD Ring
|
|
if (!ion.sys_cmd_push(pkt)) {
|
|
return -1; // Error: Ring full/backpressure
|
|
}
|
|
return 0; // Success
|
|
}
|
|
|
|
// Sovereign Yield: Return control to Kernel Scheduler
|
|
export fn nexus_yield() void {
|
|
const yield_ptr = @as(*const *const fn () void, @ptrFromInt(0x83000FF0));
|
|
yield_ptr.*();
|
|
}
|