commit 0fffffe53076e11126f574b594a71db62d144b2a
parent f0032e962f4cd48af67f1d78ca7f37c7c82f740e
Author: Sylvia Ivory <git@sivory.net>
Date: Sun, 15 Mar 2026 18:04:41 -0700
Hello World from Lua
Diffstat:
5 files changed, 534 insertions(+), 29 deletions(-)
diff --git a/pi/faults.zig b/pi/faults.zig
@@ -1,4 +1,5 @@
pub const FaultKindZero = enum(u4) {
+ _NoFunction0 = 0b0000,
AlignmentFault = 0b0001,
InstructionDebugEventFault = 0b0010,
AccessBitFaultOnSection = 0b0011,
@@ -8,6 +9,7 @@ pub const FaultKindZero = enum(u4) {
TranslationPageFault = 0b0111,
PreciseExternalAbort = 0b1000,
DomainSectionFault = 0b1001,
+ _NoFunction10 = 0b1010,
DomainPageFault = 0b1011,
ExternalAbortOnTranslationFirstLevel = 0b1100,
PermissionSectionFault = 0b1101,
@@ -56,7 +58,7 @@ pub const DFSR = packed struct(u32) {
pub const IFSR = packed struct(u32) {
status: FaultKindZero,
- _reserved_4_9: u8,
+ _reserved_4_9: u6,
status_kind: u1,
_reserved_11: u1,
axi_source: AxiSource,
diff --git a/sylveos/kuser.zig b/sylveos/kuser.zig
@@ -0,0 +1,140 @@
+// https://docs.kernel.org/6.2/arm/kernel_user_helpers.html
+
+fn mk_fn(name: []const u8, body: []const u8) []const u8 {
+ return "" ++
+ ".global " ++ name ++ "\n" ++
+ ".type " ++ name ++ ", %function\n" ++
+ name ++ ":\n" ++ body ++ "\n" ++
+ name ++ "_end:";
+}
+
+fn get_range(start_p: *const u32, end_p: *const u32) []const u8 {
+ const start = @intFromPtr(start_p);
+ const end = @intFromPtr(end_p);
+ const ptr: [*]const u8 = @ptrCast(start_p);
+
+ return ptr[0..(end - start)];
+}
+
+comptime {
+ asm (mk_fn("__kuser_get_tls",
+ \\ mcr p15, 0, r0, c13, c0, 3
+ \\ bx lr
+ ));
+
+ asm (mk_fn("__kuser_cmpxchg",
+ \\ ldr pc, .Lcmpxchg_impl
+ \\ .Lcmpxchg_impl: .word __kuser_cmpxchg_impl
+ ));
+
+ asm (mk_fn("__kuser_cmpxchg_impl",
+ \\ stmfd sp!, {r4, lr}
+ \\ .Lcmpxchg_retry:
+ \\ ldr r4, [r2]
+ \\ cmp r4, r0
+ \\ bne .Lcmpxchg_fail
+ \\ swp r3, r1, [r2]
+ \\ cmp r3, r0
+ \\ bne .Lcmpxchg_retry
+ \\ mov r0, #0
+ \\ ldmfd sp!, {r4, pc}
+ \\ .Lcmpxchg_fail:
+ \\ mov r0, #-1
+ \\ ldmfd sp!, {r4, pc}
+ ));
+
+ asm (mk_fn("__kuser_memory_barrier",
+ \\ mcr p15, 0, r0, c7, c10, 4
+ \\ mcr p15, 0, r0, c7, c5, 4
+ \\ bx lr
+ ));
+
+ asm (mk_fn("__kuser_cmpxchg64",
+ \\ ldr pc, .Lcmpxchg64_impl
+ \\ .Lcmpxchg64_impl: .word __kuser_cmpxchg64_impl
+ ));
+
+ asm (mk_fn("__kuser_cmpxchg64_impl",
+ \\ stmfd sp!, {r4, r5, r6, r7, lr}
+ \\ mov r7, r0
+ \\ ldmia r1, {r4, r5}
+ \\ mov r6, r2
+ \\ .Lcmpxchg64_retry:
+ \\ ldrexd r0, r1, [r6]
+ \\ ldmia r7, {r2, r3}
+ \\ teq r0, r2
+ \\ teqeq r1, r3
+ \\ bne .Lcmpxchg64_fail
+ \\ strexd r0, r4, r5, [r6]
+ \\ cmp r0, #0
+ \\ bne .Lcmpxchg64_retry
+ \\ mov r0, #0
+ \\ ldmfd sp!, {r4, r5, r6, r7, pc}
+ \\ .Lcmpxchg64_fail:
+ \\ mov r0, #-1
+ \\ ldmfd sp!, {r4, r5, r6, r7, pc}
+ ));
+}
+
+// 0xFFFF_0FFC
+pub const helper_version_offset = 0x0FFC;
+pub const helper_version: i32 = 2;
+
+// 0xFFFF_0FE0
+pub const get_tls_offset = 0x0FE0;
+extern const __kuser_get_tls: u32;
+extern const __kuser_get_tls_end: u32;
+pub fn get_tls() []const u8 {
+ const slice = get_range(&__kuser_get_tls, &__kuser_get_tls_end);
+ if (slice.len > 28) @panic("too large get_tls");
+ return slice;
+}
+
+// 0xFFFF_0FC0
+pub const cmpxchg_offset = 0x0FC0;
+pub extern const __kuser_cmpxchg: u32;
+pub extern const __kuser_cmpxchg_end: u32;
+pub fn cmpxchg() []const u8 {
+ const slice = get_range(&__kuser_cmpxchg, &__kuser_cmpxchg_end);
+ if (slice.len > 32) @panic("too large cmpxchg");
+ return slice;
+}
+
+// 0xFFFF_0FA0
+pub const memory_barrier_offset = 0x0FA0;
+pub extern const __kuser_memory_barrier: u32;
+pub extern const __kuser_memory_barrier_end: u32;
+pub fn memory_barrier() []const u8 {
+ const slice = get_range(&__kuser_memory_barrier, &__kuser_memory_barrier_end);
+ if (slice.len > 32) @panic("too large memory_barrier");
+ return slice;
+}
+
+// 0xFFFF_0F60
+pub const cmpxchg64_offset = 0x0F60;
+pub extern const __kuser_cmpxchg64: u32;
+pub extern const __kuser_cmpxchg64_end: u32;
+pub fn cmpxchg64() []const u8 {
+ const slice = get_range(&__kuser_cmpxchg64, &__kuser_cmpxchg64_end);
+ if (slice.len > 64) @panic("too large cmpxchg64");
+ return slice;
+}
+
+pub fn load(page: []u8) void {
+ @memset(page, 0);
+
+ const version_ptr: *i32 = @ptrCast(@alignCast(page.ptr + helper_version_offset));
+ version_ptr.* = helper_version;
+
+ const tls_slice = get_tls();
+ @memcpy(page[get_tls_offset..][0..tls_slice.len], tls_slice);
+
+ const cmpxchg_slice = cmpxchg();
+ @memcpy(page[cmpxchg_offset..][0..cmpxchg_slice.len], cmpxchg_slice);
+
+ const membar_slice = memory_barrier();
+ @memcpy(page[memory_barrier_offset..][0..membar_slice.len], membar_slice);
+
+ const cmpxchg64_slice = cmpxchg64();
+ @memcpy(page[cmpxchg64_offset..][0..cmpxchg64_slice.len], cmpxchg64_slice);
+}
diff --git a/sylveos/loader.zig b/sylveos/loader.zig
@@ -3,6 +3,7 @@ const pi = @import("pi");
const process = @import("./process.zig");
const memory = @import("./memory.zig");
+const kuser = @import("./kuser.zig");
const Pages = @import("./pages.zig");
const Page = process.Page;
@@ -19,6 +20,8 @@ pub const Program = struct {
stack_pointer: u32,
elf_header: std.elf.Header,
header_location: u32,
+ heap_start: u32,
+ heap_current: u32,
};
pub fn init(pt_alloc: std.mem.Allocator, heap_alloc: std.mem.Allocator, root: []mmu.FirstLevelDescriptor, elf: []const u8) !Program {
@@ -40,17 +43,22 @@ pub fn init(pt_alloc: std.mem.Allocator, heap_alloc: std.mem.Allocator, root: []
};
var header_location: ?u32 = null;
+ var heap_start: u32 = 0;
while (try it.next()) |program_header| {
if (program_header.p_type != std.elf.PT_LOAD) continue;
- var va = std.mem.alignBackward(u32, @intCast(program_header.p_vaddr), memory.KB4);
+ const alignment = @max(@as(u32, @truncate(program_header.p_align)), memory.KB4);
+
+ var va = std.mem.alignBackward(u32, @intCast(program_header.p_vaddr), alignment);
const end = std.mem.alignForward(u32, @intCast(program_header.p_vaddr + program_header.p_memsz), memory.KB4);
+ heap_start = @max(heap_start, end);
+
while (va < end) : (va += memory.KB4) {
const pa = try memory.request_4kb(heap_alloc);
- try pages.map_4kb(va, pa, .{});
+ try pages.map_4kb(va, pa, .{ .encoding = .{ .preset = .OuterInnerWriteBackAllocOnWrite } });
// Zero page
const dst: [*]u8 = @ptrFromInt(va);
@@ -87,6 +95,7 @@ pub fn init(pt_alloc: std.mem.Allocator, heap_alloc: std.mem.Allocator, root: []
if (header_location == null) {
// TODO; store header in VM
+ return error.NoHeader;
}
// Configure stack
@@ -98,21 +107,26 @@ pub fn init(pt_alloc: std.mem.Allocator, heap_alloc: std.mem.Allocator, root: []
const sp = stack_top - stack_size;
const pa = try memory.request_64kb(heap_alloc);
- try pages.map_64kb(sp, pa, .{});
+ try pages.map_64kb(sp, pa, .{ .encoding = .{ .preset = .OuterInnerWriteBackAllocOnWrite } });
const dst: [*]u8 = @ptrFromInt(sp);
@memset(dst[0..memory.KB4], 0);
}
// kuser
+
{
+ const va = 0xFFFF_0000;
const pa = try memory.request_4kb(heap_alloc);
// TODO; read only
- try pages.map_4kb(0xFFFF_0000, pa, .{});
- pi.mem.put_u32(@ptrFromInt(0xFFFF_0FFC), 2);
+ try pages.map_4kb(va, pa, .{ .encoding = .{ .preset = .OuterInnerWriteBackAllocOnWrite } });
+
+ kuser.load(@as([*]u8, @ptrFromInt(va))[0..memory.KB4]);
}
+ heap_start = std.mem.alignForward(u32, heap_start, memory.KB4);
+
return .{
.heap_alloc = heap_alloc,
.pt_alloc = pt_alloc,
@@ -121,9 +135,14 @@ pub fn init(pt_alloc: std.mem.Allocator, heap_alloc: std.mem.Allocator, root: []
.stack_pointer = stack_top,
.elf_header = header,
.header_location = header_location orelse unreachable,
+ .heap_start = heap_start,
+ .heap_current = heap_start,
};
}
+// TODO; proper process handling
+pub var current_program: *Program = undefined;
+
pub fn execute(self: *Program, pid: u24, args: []const []const u8, env: []const []const u8) !noreturn {
// TODO; args, env
self.pages.switch_into(pid);
@@ -242,12 +261,17 @@ pub fn execute(self: *Program, pid: u24, args: []const []const u8, env: []const
psr.i = false;
const registers: pi.interrupts.Registers = .{
.gp = .{0} ** 13,
- .lr = self.entrypoint,
+ .lr = 0,
.pc = self.entrypoint,
.sp = sp,
.psr = psr,
};
+ current_program = self;
+
+ // pi.debug.enable_monitor_mode();
+ // pi.debug.set_breakpoint(0, 0, .IMVAMismatch);
+
pi.switching.restore_state_privileged(®isters);
}
diff --git a/sylveos/root.zig b/sylveos/root.zig
@@ -4,7 +4,7 @@ const pi = @import("pi");
const memory = @import("./memory.zig");
const loader = @import("./loader.zig");
const syscall = @import("./syscall.zig");
-const hello_binary = @embedFile("./hello");
+const lua_binary = @embedFile("./lua");
const uart = pi.devices.mini_uart;
const interrupts = pi.interrupts;
@@ -49,11 +49,62 @@ fn panic_handler(msg: []const u8, trace_addr: ?usize) noreturn {
pub const panic = std.debug.FullPanic(panic_handler);
// figure out MMU issues
-fn abort_handler(regs: interrupts.Registers, _: interrupts.ExceptionVector) void {
+fn abort_handler(regs: interrupts.Registers, ev: interrupts.ExceptionVector) void {
const far = pi.faults.FAR.get();
+ const ifsr = pi.faults.IFSR.get();
+ const dfsr = pi.faults.DFSR.get();
+
+ // pi.debug.set_breakpoint(0, regs.pc, .IMVAMismatch);
+
+ if (ev == .PrefetchAbort and ifsr.status == .InstructionDebugEventFault) {
+ uart.print("[breakpoint] PC=0x{X:0>8}\n", .{regs.pc});
+ } else if (ev == .PrefetchAbort) {
+ uart.print("[{s}] [{s}] got fault on 0x{X:0>8} from 0x{X:0>8}\n", .{
+ @tagName(ev),
+ @tagName(ifsr.status),
+ far,
+ regs.pc,
+ });
+ interrupts.dump_registers(®s);
+ pi.reboot();
+ } else if (ev == .DataAbort) {
+ const status = if (dfsr.status_kind == 0) @tagName(dfsr.status.@"0") else @tagName(dfsr.status.@"1");
+
+ uart.print("[{s}] [{s}] got fault on 0x{X:0>8} from 0x{X:0>8} (source: {s})\n", .{
+ @tagName(ev),
+ status,
+ far,
+ regs.pc,
+ @tagName(dfsr.abort_source),
+ });
+ interrupts.dump_registers(®s);
+ pi.reboot();
+ }
- uart.print("got fault on 0x{X:0>8} from 0x{X:0>8}\n", .{ far, regs.pc });
- pi.reboot();
+ if (regs.pc == 0x0006E674) {
+ uart.print("0x86034: {X}\n", .{pi.mem.get_u32(@ptrFromInt(0x86034))});
+ interrupts.dump_registers(®s);
+ }
+}
+
+fn undef(regs: interrupts.Registers, _: interrupts.ExceptionVector) void {
+ if (regs.pc == 0x629c8) {
+ uart.print("\n=== DEBUGGING UDF ===\n", .{});
+ uart.print("lr = 0x{X}\n", .{regs.lr});
+
+ const mem_88028: *const u32 = @ptrFromInt(0x88028);
+ uart.print("Memory at [0x88028] = 0x{X:0>8}\n", .{mem_88028.*});
+
+ const mem_88010: *const [8]u32 = @ptrFromInt(0x88010);
+ uart.print("Memory at [0x88010]:\n", .{});
+ for (mem_88010.*, 0..) |val, i| {
+ uart.print(" [+0x{X}] = 0x{X:0>8}\n", .{ i * 4, val });
+ }
+
+ // Check if 0x88028 is executable
+ const translated = memory.translate(0x88028) catch 0;
+ uart.print("0x88028 translates to PA: 0x{X}\n", .{translated});
+ }
}
// Kinda just a repeat of boot...
@@ -100,6 +151,7 @@ export fn abort() noreturn {
fn main() !void {
interrupts.set_exception_handler(.SoftwareInterrupt, syscall.syscall_handler);
+ interrupts.set_exception_handler(.UndefinedInstruction, undef);
var heap_fba = memory.get_allocator();
const heap_alloc = heap_fba.allocator();
@@ -109,11 +161,11 @@ fn main() !void {
const pt = memory.get_page_table();
- var empty = try loader.init(pt_alloc, heap_alloc, pt, hello_binary);
+ var empty = try loader.init(pt_alloc, heap_alloc, pt, lua_binary);
uart.print(
\\Stack Pointer: {X:0>8}
\\ Entrypoint: {X:0>8}
\\
, .{ empty.stack_pointer, empty.entrypoint });
- try loader.execute(&empty, 0, &[_][]const u8{"hello"}, &[_][]u8{});
+ try loader.execute(&empty, 0, &[_][]const u8{ "lua", "hello.lua" }, &[_][]u8{});
}
diff --git a/sylveos/syscall.zig b/sylveos/syscall.zig
@@ -1,50 +1,337 @@
+const std = @import("std");
const pi = @import("pi");
+const loader = @import("./loader.zig");
+const memory = @import("./memory.zig");
+
+const switching = pi.switching;
const interrupts = pi.interrupts;
const uart = pi.devices.mini_uart;
+var last_registers: interrupts.Registers = undefined;
+
+const Timespec = extern struct {
+ tv_sec: i64,
+ tv_nsec: u32,
+};
+
+const IoVec = extern struct {
+ iov_base: [*]u8,
+ iov_len: u32,
+};
+
+fn sbrk(addr: u32) u32 {
+ const current = loader.current_program.heap_current;
+
+ if (addr == 0) {
+ return current;
+ }
+
+ if (addr <= current) {
+ return current; // Already have enough
+ }
+
+ // Align to page boundary
+ const old_end = std.mem.alignForward(u32, current, memory.KB4);
+ const new_end = std.mem.alignForward(u32, addr, memory.KB4);
+
+ var va = old_end;
+ while (va < new_end) : (va += memory.KB4) {
+ const pa = memory.request_4kb(loader.current_program.heap_alloc) catch {
+ // Partial allocation - update to what we got
+ if (va > old_end) {
+ loader.current_program.heap_current = va;
+ }
+ return loader.current_program.heap_current;
+ };
+
+ loader.current_program.pages.map_4kb(va, pa, .{
+ .encoding = .{ .preset = .OuterInnerWriteBackAllocOnWrite },
+ }) catch {
+ if (va > old_end) {
+ loader.current_program.heap_current = va;
+ }
+ return loader.current_program.heap_current;
+ };
+
+ // Zero the new page
+ const page_ptr: [*]u8 = @ptrFromInt(va);
+ @memset(page_ptr[0..memory.KB4], 0);
+ }
+
+ // Success - update heap end
+ loader.current_program.heap_current = new_end;
+ return new_end;
+}
+
pub fn syscall_handler(registers: interrupts.Registers, _: interrupts.ExceptionVector) void {
- const n = registers.gp[7];
+ var regs = registers;
+ const n = regs.gp[7];
switch (n) {
// restart_syscall
- 0 => {},
+ // 0 => {},
// exit
- 1 => {
- const error_code = registers.gp[0];
+ 1, 248 => {
+ const error_code = regs.gp[0];
uart.print("[syscall] exit({d})\n", .{error_code});
pi.reboot();
},
// fork
- 2 => {},
+ // 2 => {},
// read
- 3 => {},
+ 3 => {
+ const fd = regs.gp[0];
+ const buffer: [*]u8 = @ptrFromInt(regs.gp[1]);
+ const count = regs.gp[2];
+
+ uart.print("[syscall] read({d}, 0x{X}, {d})", .{ fd, @intFromPtr(buffer), count });
+
+ if (fd == 0) {
+ // stdin
+ for (0..count) |i| {
+ const byte = uart.read_byte_sync();
+ buffer[i] = byte;
+ }
+ regs.gp[0] = @bitCast(@as(i32, @bitCast(count)));
+ } else if (fd == 3) {
+ // temporary buffer
+ const code = "print('hello world')";
+
+ @memcpy(buffer, code);
+
+ regs.gp[0] = @bitCast(@as(i32, @bitCast(code.len)));
+ }
+ },
// write
4 => {
- const fd = registers.gp[0];
- const buffer: [*]u8 = @ptrFromInt(registers.gp[1]);
- const count = registers.gp[2];
+ const fd = regs.gp[0];
+ const buffer: [*]u8 = @ptrFromInt(regs.gp[1]);
+ const count = regs.gp[2];
- uart.print("[syscall] write({d}, 0x{X}, {d})\n", .{ fd, @intFromPtr(buffer), count });
+ uart.print("[syscall] write({d}, 0x{X}, {d})", .{ fd, @intFromPtr(buffer), count });
// stdout
if (fd == 1) {
uart.print("{s}", .{buffer[0..count]});
+ regs.gp[0] = @bitCast(@as(i32, @bitCast(count)));
+ } else {
+ regs.gp[0] = @bitCast(@as(i32, -9));
}
},
// open
- 5 => {},
+ 5 => {
+ const path: [*:0]u8 = @ptrFromInt(regs.gp[0]);
+ const flags = regs.gp[1];
+
+ uart.print("[syscall] open({s}, 0x{X})", .{ path, flags });
+
+ regs.gp[0] = @bitCast(@as(i32, 3));
+ },
// close
- 6 => {},
+ 6 => {
+ const fd = regs.gp[0];
+
+ uart.print("[syscall] close({d})", .{fd});
+
+ regs.gp[0] = 0;
+ },
+ // brk
+ 45 => {
+ uart.print("[syscall] brk(0x{X})", .{regs.gp[0]});
+ regs.gp[0] = sbrk(regs.gp[0]);
+ },
+ // clone
+ 120 => {
+ uart.print("[syscall] clone()", .{});
+ regs.gp[0] = @bitCast(@as(i32, -38));
+ },
+ // mprotect
+ 125 => {
+ // Trust me, totally protected
+ uart.print("[syscall] mprotect(0x{X})", .{regs.gp[0]});
+ regs.gp[0] = 0;
+ },
+ // readv
+ 145 => {
+ const fd = regs.gp[0];
+ const iov_ptr: [*]IoVec = @ptrFromInt(regs.gp[1]);
+ const count = regs.gp[2];
+
+ uart.print("[syscall] readv({d}, 0x{X}, {d})", .{ fd, @intFromPtr(iov_ptr), count });
+
+ const iov = iov_ptr[0..count];
+
+ if (fd == 0) {
+ var total: u32 = 0;
+ for (iov) |vec| {
+ if (vec.iov_len == 0) continue;
+
+ uart.print("{s}", .{vec.iov_base[0..vec.iov_len]});
+ total += vec.iov_len;
+ }
+ regs.gp[0] = total;
+ } else if (fd == 3) {
+ // done by first read
+ regs.gp[0] = 0;
+ } else {
+ regs.gp[0] = @bitCast(@as(i32, -1));
+ }
+ },
+ // writev
+ 146 => {
+ const fd = regs.gp[0];
+ const iov_ptr: [*]const IoVec = @ptrFromInt(regs.gp[1]);
+ const count = regs.gp[2];
+
+ uart.print("[syscall] writev({d}, 0x{X}, {d})", .{ fd, @intFromPtr(iov_ptr), count });
+
+ const iov = iov_ptr[0..count];
+
+ if (fd == 1 or fd == 2) {
+ var total: u32 = 0;
+ for (iov) |vec| {
+ if (vec.iov_len == 0) continue;
+
+ uart.print("{s}", .{vec.iov_base[0..vec.iov_len]});
+ total += vec.iov_len;
+ }
+ regs.gp[0] = total;
+ } else {
+ regs.gp[0] = @bitCast(@as(i32, -1));
+ }
+ },
+ // mmap2
+ 192 => {
+ const addr = regs.gp[0];
+ const length = regs.gp[1];
+ const prot = regs.gp[2];
+ const flags = regs.gp[3];
+ const fd = regs.gp[4];
+ const offset = regs.gp[5];
+
+ uart.print("[syscall] mmap2(0x{X}, {d}, 0x{X}, 0x{X}, {d}, {d})", .{
+ addr,
+ length,
+ prot,
+ flags,
+ fd,
+ offset,
+ });
+
+ var translated: u32 = 0;
+
+ if ((flags & 0x20) == 0) {
+ regs.gp[0] = @bitCast(@as(i32, -38));
+ } else {
+ const aligned_length = std.mem.alignForward(u32, length, memory.KB4);
+ var map_addr: usize = undefined;
+
+ if ((flags & 0x10) != 0) {
+ if (addr == 0 or !std.mem.isAligned(addr, memory.KB4)) {
+ regs.gp[0] = @bitCast(@as(i32, -22));
+ } else {
+ translated = memory.translate(addr) catch 0;
+
+ if (translated == 0) {
+ map_addr = addr;
+ } else {
+ // change permissions
+ // but we don't :3
+ regs.gp[0] = addr;
+ }
+ }
+ } else {
+ map_addr = loader.current_program.heap_current;
+ }
+
+ if (regs.gp[0] >= 0x80000000) {} else if (translated != 0 and (flags & 0x10) != 0) {} else {
+ var va = map_addr;
+ const end = map_addr + aligned_length;
+
+ while (va < end) : (va += memory.KB4) {
+ const pa = memory.request_4kb(loader.current_program.heap_alloc) catch {
+ regs.gp[0] = @bitCast(@as(i32, -12));
+ break;
+ };
+
+ loader.current_program.pages.map_4kb(va, pa, .{ .encoding = .{ .preset = .OuterInnerWriteBackAllocOnWrite } }) catch {
+ regs.gp[0] = @bitCast(@as(i32, -12));
+ break;
+ };
+
+ if (prot != 0) {
+ const page_ptr: [*]u8 = @ptrFromInt(va);
+ @memset(page_ptr[0..memory.KB4], 0);
+ }
+ }
+
+ if (va == end) {
+ if ((flags & 0x10) == 0) {
+ loader.current_program.heap_current = end;
+ }
+ regs.gp[0] = map_addr;
+ }
+ }
+ }
+ },
// exit_group
- 248 => {},
+ // 248 => {},
// set_tid_address
- 256 => {},
+ 256 => {
+ uart.print("[syscall] set_tid_address(0x{X})", .{regs.gp[0]});
+
+ const addr: ?*i32 = @ptrFromInt(regs.gp[0]);
+ if (addr) |ptr| {
+ ptr.* = 1;
+ }
+ regs.gp[0] = 1;
+ },
+ // clock_gettime64
+ 403 => {
+ uart.print("[syscall] clock_gettime64(0x{X})", .{regs.gp[0]});
+
+ const time = pi.devices.clock.current_count();
+ const seconds = time / std.time.us_per_s;
+ const ns = (time % 1000) * 1000;
+
+ const addr: ?*Timespec = @ptrFromInt(regs.gp[0]);
+ if (addr) |ptr| {
+ ptr.* = .{ .tv_nsec = @truncate(ns), .tv_sec = @intCast(seconds) };
+ }
+ regs.gp[0] = 0;
+ },
// ARM_set_tls
- 983045 => {},
+ 983045 => {
+ const addr = regs.gp[0];
+
+ uart.print("[syscall] ARM_set_tls(0x{X})", .{addr});
+
+ asm volatile ("mcr p15, 0, %[value], c13, c0, 3"
+ :
+ : [value] "r" (addr),
+ );
+
+ regs.gp[0] = 0;
+ },
+ // ARM_get_tls
+ 983046 => {
+ uart.print("[syscall] ARM_get_tls()", .{});
+
+ const result = asm volatile ("mrc p15, 0, %[result], c13, c0, 3"
+ : [result] "=r" (-> usize),
+ );
+ regs.gp[0] = result;
+ },
else => {
- uart.print("Unhandled syscall: {d}\n", .{n});
+ uart.print("[syscall]: UNHANDLED({d})", .{n});
+ regs.gp[0] = @bitCast(@as(i32, -1));
},
}
+
+ uart.print(" = 0x{X}\n", .{regs.gp[0]});
+ regs.pc += 4;
+ last_registers = regs;
+ switching.restore_state(&last_registers);
}