sylveos

Toy Operating System
Log | Files | Refs

commit 4fb85d090f08846c57983eaf0e6c9e6d30458f43
parent 6a121abe685d378dd68813044283f763bdbc3107
Author: Sylvia Ivory <git@sivory.net>
Date:   Tue, 10 Feb 2026 20:12:11 -0800

Functional SWI

Diffstat:
Mpi/devices/gpio.zig | 3++-
Mpi/devices/mini-uart.zig | 9++++++++-
Mpi/interrupts.zig | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mpi/root.zig | 11+++++++----
Aprograms/syscall.zig | 50++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 129 insertions(+), 25 deletions(-)

diff --git a/pi/devices/gpio.zig b/pi/devices/gpio.zig @@ -227,8 +227,9 @@ pub fn enable_interrupts() !void { mem.barrier(.Write); } -noinline fn gpio_handler(pc: usize) void { +noinline fn gpio_handler(pc: usize, registers: *interrupts.Registers) void { _ = pc; + _ = registers; mem.barrier(.Write); defer mem.barrier(.Write); diff --git a/pi/devices/mini-uart.zig b/pi/devices/mini-uart.zig @@ -135,6 +135,11 @@ pub fn enable_interrupts() Error!void { interrupts_enabled = true; } +// Temporarily disables TX interrupting +pub fn toggle_tx_interrupts() void { + interrupts_enabled = !interrupts_enabled; +} + fn enable_tx_interrupt() void { mem.put_u32_barrier(@ptrFromInt(AUX_MU_IER_REG), 0b1111); } @@ -173,8 +178,10 @@ pub fn get_rx_written() usize { return rx_writer_written; } -noinline fn uart_handler(pc: usize) void { +noinline fn uart_handler(pc: usize, registers: *interrupts.Registers) void { _ = pc; + _ = registers; + mem.barrier(.Write); defer mem.barrier(.Write); diff --git a/pi/interrupts.zig b/pi/interrupts.zig @@ -1,4 +1,5 @@ const mem = @import("./mem.zig"); +const pi = @import("./root.zig"); const BASE_ADDRESS: usize = mem.BASE_ADDRESS + 0xB200; @@ -93,17 +94,39 @@ pub inline fn pending_peripheral_interrupt(i: PeripheralsInterrupt) bool { } } -fn empty(lr: u32) void { - _ = lr; +fn empty(pc: u32, registers: *Registers) void { + _ = pc; + _ = registers; } -var reset_handler: *const fn (u32) void = empty; -var undefined_instruction_handler: *const fn (u32) void = empty; -var software_interrupt_handler: *const fn (u32) void = empty; -var prefetch_abort_handler: *const fn (u32) void = empty; -var data_abort_handler: *const fn (u32) void = empty; -var interrupt_handler: *const fn (u32) void = empty; -var fast_interrupt_handler: *const fn (u32) void = empty; +var reset_handler: *const fn (u32, *Registers) void = empty; +var undefined_instruction_handler: *const fn (u32, *Registers) void = empty; +var software_interrupt_handler: *const fn (u32, *Registers) void = empty; +var prefetch_abort_handler: *const fn (u32, *Registers) void = empty; +var data_abort_handler: *const fn (u32, *Registers) void = empty; +var interrupt_handler: *const fn (u32, *Registers) void = empty; +var fast_interrupt_handler: *const fn (u32, *Registers) void = empty; + +pub const Registers = struct { + gp: [13]usize, + lr: usize, + + inline fn get_svc() *@This() { + return @ptrFromInt(@intFromPtr(&pi.svc_stack) + (pi.svc_stack.len * @sizeOf(usize))); + } + + inline fn get_abort() *@This() { + return @ptrCast(&pi.abort_stack); + } + + inline fn get_irq() *@This() { + return @ptrCast(&pi.irq_stack); + } + + inline fn get_fiq() *@This() { + return @ptrCast(&pi.fiq_stack); + } +}; inline fn get_lr() u32 { return asm volatile ("mov %[result], lr" @@ -132,31 +155,51 @@ inline fn clobber_all() void { export fn reset() callconv(.{ .arm_interrupt = .{ .type = .generic } }) void { clobber_all(); - reset_handler(get_lr() - 4); + reset_handler(get_lr() - 4, Registers.get_abort()); } export fn undefined_instruction() callconv(.{ .arm_interrupt = .{ .type = .undef } }) void { clobber_all(); - undefined_instruction_handler(get_lr() - 4); + undefined_instruction_handler(get_lr() - 4, Registers.get_abort()); } -export fn software_interrupt() callconv(.{ .arm_interrupt = .{ .type = .swi } }) void { - clobber_all(); - software_interrupt_handler(get_lr() - 4); +// export fn software_interrupt() callconv(.{ .arm_interrupt = .{ .type = .swi } }) void { +// clobber_all(); +// software_interrupt_handler(get_lr() - 4, Registers.get_svc()); +// } +export fn software_interrupt_handler_v(pc: u32, reg: *Registers) void { + software_interrupt_handler(pc, reg); } + +comptime { + asm ( + \\ .global software_interrupt + \\ .type software_interrupt, %function + \\ software_interrupt: + \\ push {r0-r12, lr} + \\ sub lr, lr, #4 + \\ mov r0, lr + \\ mov r1, sp + \\ blx software_interrupt_handler + \\ pop {r0-r12, lr} + \\ movs pc, lr + ); +} +extern fn software_interrupt() void; + export fn prefetch_abort() callconv(.{ .arm_interrupt = .{ .type = .abort } }) void { clobber_all(); - prefetch_abort_handler(get_lr() - 8); + prefetch_abort_handler(get_lr() - 8, Registers.get_abort()); } export fn data_abort() callconv(.{ .arm_interrupt = .{ .type = .abort } }) void { clobber_all(); - data_abort_handler(get_lr() - 4); + data_abort_handler(get_lr() - 4, Registers.get_abort()); } export fn interrupt() callconv(.{ .arm_interrupt = .{ .type = .irq } }) void { clobber_all(); - interrupt_handler(get_lr() - 4); + interrupt_handler(get_lr() - 4, Registers.get_irq()); } export fn fast_interrupt() callconv(.{ .arm_interrupt = .{ .type = .fiq } }) void { clobber_all(); - fast_interrupt_handler(get_lr() - 4); + fast_interrupt_handler(get_lr() - 4, Registers.get_fiq()); } // https://leiradel.github.io/2019/02/09/Initialization.html @@ -204,7 +247,7 @@ const ExceptionVector = enum { FIQ, }; -pub fn set_exception_handler(vector: ExceptionVector, handler: *const fn (u32) void) void { +pub fn set_exception_handler(vector: ExceptionVector, handler: *const fn (u32, *Registers) void) void { switch (vector) { .Reset => reset_handler = handler, .UndefinedInstruction => undefined_instruction_handler = handler, diff --git a/pi/root.zig b/pi/root.zig @@ -51,14 +51,17 @@ pub inline fn get_sp() usize { // TODO; should do something better const stack_size = 256; // 1kb stacks -export var svc_stack: [stack_size]usize align(8) = undefined; -export var abort_stack: [stack_size]usize align(8) = undefined; -export var irq_stack: [stack_size]usize align(8) = undefined; -export var fiq_stack: [stack_size]usize align(8) = undefined; +pub export var svc_stack: [stack_size]usize align(8) = undefined; +pub export var abort_stack: [stack_size]usize align(8) = undefined; +pub export var irq_stack: [stack_size]usize align(8) = undefined; +pub export var fiq_stack: [stack_size]usize align(8) = undefined; pub fn setup_stacks() void { const original_cpsr = PSR.get_c(); + _ = PSR.switch_current_mode(.Supervisor); + set_sp(@ptrFromInt(@intFromPtr(&svc_stack) + (svc_stack.len * @sizeOf(usize)))); + _ = PSR.switch_current_mode(.Undefined); set_sp(@ptrFromInt(@intFromPtr(&abort_stack) + (abort_stack.len * @sizeOf(usize)))); diff --git a/programs/syscall.zig b/programs/syscall.zig @@ -0,0 +1,50 @@ +const std = @import("std"); +const pi = @import("pi"); + +const uart = pi.devices.mini_uart; +const interrupts = pi.interrupts; + +comptime { + asm ( + \\ .global syscall_test; + \\ .type syscall_test, %function; + \\ syscall_test: + \\ mov r0, 0 + \\ mov r1, 1 + \\ mov r2, 2 + \\ mov r3, 3 + \\ mov r4, 4 + \\ mov r5, 5 + \\ mov r6, 6 + \\ mov r7, 7 + \\ mov r8, 8 + \\ mov r9, 9 + \\ mov r10, 10 + \\ mov r11, 11 + \\ mov r12, 12 + \\ swi 1 + \\ bx lr + ); +} +extern fn syscall_test() void; + +noinline fn software_interrupt_handler(pc: u32, registers: *interrupts.Registers) void { + uart.toggle_tx_interrupts(); + const dup = registers.*; + + uart.writer.print("instruction=0x{X}\n", .{pc}) catch {}; + for (dup.gp, 0..dup.gp.len) |r, i| { + uart.writer.print("r{d} = {d}\n", .{ i, r }) catch {}; + } + uart.writer.print("lr = 0x{X}\n", .{dup.lr}) catch {}; + uart.toggle_tx_interrupts(); +} + +pub fn main() !void { + interrupts.set_exception_handler(.SoftwareInterrupt, software_interrupt_handler); + + try uart.writer.print("testing syscall\n", .{}); + uart.flush(); + + syscall_test(); +}