sylveos

Toy Operating System
Log | Files | Refs

commit 6d2fe46133dbd3d4b2ffbac18a8fac5c4ad03314
parent 519bb1f2f4b188235b976c68c8576d4402d77bd6
Author: Sylvia Ivory <git@sivory.net>
Date:   Fri, 13 Mar 2026 12:21:22 -0700

Relocate interrupts

Diffstat:
MJustfile | 9+++++++--
Mboot/root.zig | 7+++----
Mbuild.zig | 49++++++++++++++++++++++++++-----------------------
Mpi/interrupts.zig | 46+++++++++++++++++++++++++++++++++++++---------
Mpi/system.zig | 10++++++++++
Msylveos/memory.zig | 1+
Msylveos/root.zig | 38+++++++++++++++++++++++++++++++++-----
7 files changed, 117 insertions(+), 43 deletions(-)

diff --git a/Justfile b/Justfile @@ -1,14 +1,19 @@ build program mode="Bootable": if [ "{{ program }}" = "bootloader" ]; then \ zig build -Dmode=Bootloader -Dprogram=bootloader; \ - elif [ "{{ program }}" = "sylveos" ]; then \ - zig build; \ else \ zig build -Dmode={{ mode }} -Dprogram={{ program }}; \ fi arm-none-eabi-objdump -m armv6 -D zig-out/bin/{{ program }}.elf > zig-out/bin/{{ program }}.s du -h zig-out/bin/{{ program }}.elf +check program="all": + if [ "{{ program }}" = "all" ]; then \ + zig build -Drelease=false; \ + else \ + zig build -Dmode=Bootable -Drelease=false -Dprogram={{ program }}; \ + fi \ + install program sd-card="/dev/mmcblk0p1": just build {{ program }} Standalone udisksctl mount -b {{ sd-card }} diff --git a/boot/root.zig b/boot/root.zig @@ -14,9 +14,8 @@ fn initialize_interrupts() void { pi.interrupts.clear_interrupt_flags(); pi.mem.barrier(.Write); - // uart.write_slice(" Setting exception vector\n"); - // pi.interrupts.setup_exception_vector(); - // pi.mem.barrier(.Write); + uart.write_slice(" Setting exception vector\n"); + pi.interrupts.setup_exception_vector(0); } export const _start = make(kmain, abort)._start; @@ -45,7 +44,7 @@ export fn kmain() void { // uart.write_slice("Enabling Interrupts\n"); // uart.set_tx_interrupts(true); // uart.set_rx_interrupts(true) catch {}; - // pi.interrupts.enable_interrupts(); + pi.interrupts.enable_interrupts(); uart.write_slice("Entering program\n"); uart.flush(); diff --git a/build.zig b/build.zig @@ -26,6 +26,7 @@ fn pi_module_opts(target: std.Build.ResolvedTarget, optimize: std.builtin.Optimi .omit_frame_pointer = true, .single_threaded = true, .no_builtin = true, + .pic = true, }; } @@ -104,42 +105,44 @@ fn build_pi( b.getInstallStep().dependOn(&install_bin.step); } -fn build_program_inner(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, program: []const u8, mode: ?BinaryMode) !void { +fn build_program(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode, program: []const u8, mode: ?BinaryMode) !void { const program_name = try std.fmt.allocPrint(b.allocator, "programs/{s}.zig", .{program}); defer b.allocator.free(program_name); try build_pi(b, target, optimize, program, b.path(program_name), mode); } -fn build_program(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !void { - const program = b.option([]const u8, "program", "specify pi program") orelse { - // Build all programs - - const path = try b.path("programs").getPath3(b, null).toString(b.allocator); - defer b.allocator.free(path); - - var dir = try std.fs.openDirAbsolute(path, .{ .access_sub_paths = false, .iterate = true }); - defer dir.close(); +fn build_all_programs(b: *std.Build, target: std.Build.ResolvedTarget, optimize: std.builtin.OptimizeMode) !void { + const path = try b.path("programs").getPath3(b, null).toString(b.allocator); + defer b.allocator.free(path); - var iter = dir.iterate(); - while (try iter.next()) |entry| { - if (entry.kind != .file) continue; - if (!std.mem.endsWith(u8, entry.name, ".zig")) continue; - const name = entry.name[0..(entry.name.len - 4)]; + var dir = try std.fs.openDirAbsolute(path, .{ .access_sub_paths = false, .iterate = true }); + defer dir.close(); - try build_program_inner(b, target, .Debug, name, .Bootable); - } - - return; - }; + var iter = dir.iterate(); + while (try iter.next()) |entry| { + if (entry.kind != .file) continue; + if (!std.mem.endsWith(u8, entry.name, ".zig")) continue; + const name = entry.name[0..(entry.name.len - 4)]; - try build_program_inner(b, target, optimize, program, null); + try build_program(b, target, optimize, name, .Bootable); + } } pub fn build(b: *std.Build) !void { const pi_target = pi_zero_target(b); const optimize = b.standardOptimizeOption(.{ .preferred_optimize_mode = .ReleaseFast }); - try build_program(b, pi_target, optimize); - try build_pi(b, pi_target, optimize, "sylveos", b.path("sylveos/root.zig"), .Bootable); + const program = b.option([]const u8, "program", "specify pi program") orelse { + try build_all_programs(b, pi_target, optimize); + try build_pi(b, pi_target, optimize, "sylveos", b.path("sylveos/root.zig"), .Bootable); + + return; + }; + + if (std.mem.eql(u8, program, "sylveos")) { + try build_pi(b, pi_target, optimize, "sylveos", b.path("sylveos/root.zig"), null); + } else { + try build_program(b, pi_target, optimize, program, null); + } } diff --git a/pi/interrupts.zig b/pi/interrupts.zig @@ -1,6 +1,8 @@ -const mem = @import("./mem.zig"); -const PSR = @import("./psr.zig").PSR; +const uart = @import("devices/mini-uart.zig"); const switching = @import("./switching.zig"); +const system = @import("./system.zig"); +const PSR = @import("./psr.zig").PSR; +const mem = @import("./mem.zig"); const BASE_ADDRESS: usize = mem.BASE_ADDRESS + 0xB200; @@ -96,8 +98,6 @@ pub inline fn pending_peripheral_interrupt(i: PeripheralsInterrupt) bool { } fn empty(regs: Registers) void { - const uart = @import("./devices/mini-uart.zig"); - uart.print("unexpected interrupt\n", .{}); dump_registers(&regs); } @@ -120,7 +120,6 @@ pub const Registers = struct { // TODO; remove pub fn dump_registers(regs: *const Registers) void { - const uart = @import("devices/mini-uart.zig"); uart.print("Registers\n", .{}); for (regs.gp, 0..) |r, i| { uart.print(" r{d} = 0x{X}\n", .{ i, r }); @@ -209,7 +208,10 @@ fn create_trampoline(name: []const u8, offset: []const u8, ret: []const u8) []co ".global " ++ name ++ "\n" ++ ".type " ++ name ++ ", %function\n" ++ name ++ ":\n" ++ - " mov sp, 0x9000000\n" ++ + " ldr sp, " ++ name ++ "_data\n" ++ + " b " ++ name ++ "_skip\n" ++ + " " ++ name ++ "_data: .word 0x09000000\n" ++ + " " ++ name ++ "_skip:\n" ++ " push {r0-r12, lr}\n" ++ " sub lr, lr, #" ++ offset ++ "\n" ++ " mov r0, lr\n" ++ @@ -236,14 +238,15 @@ extern fn interrupt() void; extern fn fast_interrupt() void; // https://leiradel.github.io/2019/02/09/Initialization.html -pub fn setup_exception_vector() void { - var exception_vector: usize = 0; +pub fn setup_exception_vector(base_address: u32) void { + var exception_vector = base_address; for (0..8) |_| { mem.put_u32(@ptrFromInt(exception_vector), 0xE59FF018); // ldr pc, [pc, #24] exception_vector += @sizeOf(u32); } + // These need to be absolute addresses mem.put_u32(@ptrFromInt(exception_vector), @intFromPtr(&reset)); exception_vector += @sizeOf(u32); @@ -267,7 +270,32 @@ pub fn setup_exception_vector() void { mem.put_u32(@ptrFromInt(exception_vector), @intFromPtr(&fast_interrupt)); - mem.barrier(.Write); + // We've just inserted _new_ code + system.flush_self_modifying_code(); +} + +pub inline fn relocate_exception_vector(location: u32) void { + asm volatile ("MCR p15, 0, %[value], c12, c0, 0" + : + : [value] "r" (location), + ); +} + +pub inline fn rewrite_stacks(stack: u32) void { + // <exception>_data is at an 8 byte offset + const offset = 8; + + // The first instruction of each function is the mov + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&reset)), stack); + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&undefined_instruction)), stack); + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&software_interrupt)), stack); + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&prefetch_abort)), stack); + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&data_abort)), stack); + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&interrupt)), stack); + mem.put_u32(@ptrFromInt(offset + @intFromPtr(&fast_interrupt)), stack); + + // We've just _modified_ existing code + system.flush_self_modifying_code(); } const ExceptionVector = enum { diff --git a/pi/system.zig b/pi/system.zig @@ -150,3 +150,13 @@ pub inline fn flush_btb() void { : [value] "r" (0), ); } + +// 2.7.2 (B2-22) +pub inline fn flush_self_modifying_code() void { + clear_entire_data_cache(); + mem.barrier(.Write); + invalidate_icache(); + flush_btb(); + mem.barrier(.Write); + mem.barrier(.Instruction); +} diff --git a/sylveos/memory.zig b/sylveos/memory.zig @@ -111,6 +111,7 @@ pub fn print_regions() void { \\ HEAP: 0x{X:0>8} - 0x{X:0>8} ({Bi}) \\ BCM2835 IO: 0x{X:0>8} - 0x{X:0>8} ({Bi}) \\ + \\ , .{ memory.start, memory.end, memory.size, program.start, program.end, program.size, diff --git a/sylveos/root.zig b/sylveos/root.zig @@ -4,6 +4,7 @@ const pi = @import("pi"); const memory = @import("./memory.zig"); const uart = pi.devices.mini_uart; +const interrupts = pi.interrupts; const procmap = pi.procmap; const page_table = pi.pt; const mmu = pi.mmu; @@ -67,14 +68,41 @@ pub fn main() !void { mmu.sync_pte(); mmu.enable(); - pi.switching.jump(mapped_kernel + memory.MB + new_main_offset, kernel_relocation); + pi.interrupts.disable_interrupts(); + pi.switching.jump(kernel_relocation + new_main_offset, kernel_relocation); } fn new_main() noreturn { - uart.print("Relocated successfully!\n", .{}); - - const foo: u32 = 3; - uart.print("foo lives at 0x{X}\n", .{@intFromPtr(&foo)}); + const base_address = Region.io().end + memory.MB; + const stack = base_address; + const interrupt_stack = base_address - (memory.MB / 2); + + uart.print( + \\new_main: 0x{X:8>0} + \\ stack: 0x{X:8>0} + \\ + \\ + , .{ @intFromPtr(&new_main), stack }); + + // Now we need to: + // 1. Load the new exception handler + // We use p15/c12 to relocate it + // 2. Unload previous sections + // Old stack, old code, old interrupt stack + // 3. Reenable exceptions + // We do waste 2mb for kernel overhead which is unfortunate + // 1mb for code + // 1mb for stacks + root page table + interrupts.setup_exception_vector(base_address); + interrupts.relocate_exception_vector(base_address); + interrupts.rewrite_stacks(interrupt_stack); + interrupts.enable_interrupts(); + + uart.print( + \\interrupts: 0x{X:8>0} + \\ stack: 0x{X:8>0} + \\ + , .{ base_address, interrupt_stack }); pi.reboot(); }