sylveos

Toy Operating System
Log | Files | Refs

commit 1cbdb8f727f0ad0b19d0b4a7f013b95a6f871e67
parent f328e76f70d63511c1c6f5150cbf2cdee341144d
Author: Sylvia Ivory <git@sivory.net>
Date:   Fri, 13 Mar 2026 16:42:53 -0700

Reorganize

Diffstat:
MJustfile | 9++-------
Mbuild.zig | 11++++++-----
Csylveos/root.zig -> sylveos/boot.zig | 0
Dsylveos/main.zig | 40----------------------------------------
Msylveos/root.zig | 220+++++++++++--------------------------------------------------------------------
5 files changed, 37 insertions(+), 243 deletions(-)

diff --git a/Justfile b/Justfile @@ -2,8 +2,7 @@ build program mode="Bootable": if [ "{{ program }}" = "bootloader" ]; then \ zig build -Dmode=Bootloader -Dprogram=bootloader; \ elif [ "{{ program }}" = "sylveos" ]; then \ - zig build -Dmode={{ mode }} -Dprogram={{ program }} || exit 1; \ - arm-none-eabi-objdump -m armv6 -D zig-out/bin/{{ program }}-vm.elf > zig-out/bin/{{ program }}-vm.s; \ + zig build -Dprogram={{ program }}; \ else \ zig build -Dmode={{ mode }} -Dprogram={{ program }}; \ fi @@ -30,11 +29,7 @@ tools *args: run program *args: just build {{ program }} Bootable - if [ "{{ program }}" = "sylveos" ]; then \ - just tools zig-out/bin/{{ program }}-vm.bin --arm-base 0x21100000; \ - else \ - just tools zig-out/bin/{{ program }}.bin {{ args }}; \ - fi + just tools zig-out/bin/{{ program }}.bin {{ args }}; clean: rm -rfv .zig-cache zig-out tools/target diff --git a/build.zig b/build.zig @@ -118,12 +118,12 @@ fn build_sylveos_vm( pi.addCSourceFile(.{ .file = b.path("include/emmc.c") }); pi.addCSourceFile(.{ .file = b.path("include/pi-sd.c") }); - const root = b.createModule(pi_module_opts(target, optimize, b.path("sylveos/main.zig"))); + const root = b.createModule(pi_module_opts(target, optimize, b.path("sylveos/root.zig"))); root.addImport("shared", shared); root.addImport("pi", pi); const exe = b.addExecutable(.{ - .name = "sylveos-vm.elf", + .name = "sylveos.elf", .linkage = .static, .root_module = root, .use_lld = true, @@ -142,7 +142,7 @@ fn build_sylveos_vm( }); obj_copy.step.dependOn(&exe.step); - const install_bin = b.addInstallBinFile(obj_copy.getOutput(), "sylveos-vm.bin"); + const install_bin = b.addInstallBinFile(obj_copy.getOutput(), "sylveos.bin"); b.getInstallStep().dependOn(&install_bin.step); return obj_copy; @@ -183,9 +183,10 @@ pub fn build(b: *std.Build) !void { return; }; - if (std.mem.eql(u8, program, "sylveos")) { + if (std.mem.eql(u8, program, "sylveos-boot")) { + _ = try build_pi(b, pi_target, optimize, "sylveos-boot", b.path("sylveos/boot.zig"), null); + } else if (std.mem.eql(u8, program, "sylveos")) { _ = try build_sylveos_vm(b, pi_target, optimize); - _ = 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/sylveos/root.zig b/sylveos/boot.zig diff --git a/sylveos/main.zig b/sylveos/main.zig @@ -1,40 +0,0 @@ -const pi = @import("pi"); - -const memory = @import("./memory.zig"); - -pub export fn _start() linksection(".kmain") callconv(.naked) noreturn { - asm volatile ( - \\ // Clear BSS - \\ mov r0, #0 - \\ ldr r1, =__bss_start__ - \\ ldr r2, =__bss_end__ - \\ subs r2, r2, r1 - \\ beq L3 - \\ L2: - \\ strb r0, [r1], #1 - \\ subs r2, r2, #1 - \\ bne L2 - \\ L3: - \\ // Boot - \\ bl %[kmain_fn:P] - \\ bl %[abort_fn:P] - : - : [kmain_fn] "X" (kmain), - [abort_fn] "X" (abort), - ); -} - -// Kinda just a repeat of boot... -export fn kmain() void { - pi.devices.mini_uart.initialize(921600, .Gpio14, .Gpio15) catch {}; - pi.devices.mini_uart.print("Hello, World in VM land!\n", .{}); - - memory.print_regions_physical(); - - pi.reboot(); -} - -export fn abort() noreturn { - @branchHint(.cold); - pi.reboot(); -} diff --git a/sylveos/root.zig b/sylveos/root.zig @@ -1,202 +1,40 @@ -const std = @import("std"); const pi = @import("pi"); const memory = @import("./memory.zig"); -const uart = pi.devices.mini_uart; -const interrupts = pi.interrupts; -const clock = pi.devices.clock; -const procmap = pi.procmap; -const page_table = pi.pt; -const mmu = pi.mmu; - -const Region = memory.Region; - -// figure out MMU issues -fn data_abort_handler(regs: interrupts.Registers) void { - const far = pi.faults.FAR.get(); - - uart.print("got fault on 0x{X:0>8} from 0x{X:0>8}\n", .{ far, regs.pc }); - pi.reboot(); +pub export fn _start() linksection(".kmain") callconv(.naked) noreturn { + asm volatile ( + \\ // Clear BSS + \\ mov r0, #0 + \\ ldr r1, =__bss_start__ + \\ ldr r2, =__bss_end__ + \\ subs r2, r2, r1 + \\ beq L3 + \\ L2: + \\ strb r0, [r1], #1 + \\ subs r2, r2, #1 + \\ bne L2 + \\ L3: + \\ // Boot + \\ bl %[kmain_fn:P] + \\ bl %[abort_fn:P] + : + : [kmain_fn] "X" (kmain), + [abort_fn] "X" (abort), + ); } -// The whole point of this code is to relocate the kernel into the high addresses -pub fn main() !void { - interrupts.set_exception_handler(.DataAbort, data_abort_handler); - memory.print_regions_physical(); - - // Now it's time for the fun - // We want to copy the kernel's code to high address space - // But we need to copy it somewhere in physical memory - // So we pick memory_end - kernel_size - const mem_region = Region.memory(); - const program_region = Region.program(); - const io_region = Region.io(); - - const kernel_relocation = mem_region.end - program_region.size; - const kernel_dest: [*]u8 = @ptrFromInt(kernel_relocation); - - try uart.set_rx_interrupts(true); - try get_bootload(kernel_dest); - - // Need it to be 1mb aligned, we'll just let stack eventually merge into it and deal with that bug - var page_table_raw: [*]mmu.FirstLevelDescriptor = @ptrFromInt(kernel_relocation - memory.MB); - const pt = page_table_raw[0..4096]; - @memset(pt, page_table.fault_page); - - // Setup ASID - const READ_WRITE_ATTR = procmap.READ_WRITE_ATTR.dupe_asid_domain(0, 1); - // const READ_ONLY_ATTR = procmap.READ_ONLY_ATTR.dupe_asid_domain(1, 1); - const DEVICE_ATTR = procmap.DEVICE_ATTR.dupe_asid_domain(0, 1); - - // We want to preserve program code and stack so we can continue running - try program_region.map_identity(pt, READ_WRITE_ATTR); - try Region.stack().map_identity(pt, READ_WRITE_ATTR); - try Region.interrupt_stack().map_identity(pt, READ_WRITE_ATTR); - try Region.stack_boot().map_identity(pt, READ_WRITE_ATTR); - - // And also the new program code and stack - const relocation: Region = .init(@intFromPtr(page_table_raw), mem_region.end); - // Right on top of IO - const mapped_kernel = io_region.end; +// Kinda just a repeat of boot... +export fn kmain() void { + pi.devices.mini_uart.initialize(921600, .Gpio14, .Gpio15) catch {}; + pi.devices.mini_uart.print("Hello, World in VM land!\n", .{}); - try relocation.map_identity(pt, READ_WRITE_ATTR); - try relocation.map_to(pt, mapped_kernel, READ_WRITE_ATTR); - - try io_region.map_identity(pt, DEVICE_ATTR); - - // We need to be careful with the page table - // So we squeeze a space just under the kernel for it - // Then we have the "root" page table - // It'll live in the same page as the main stack - // I doubt the main stack would need 1MB of ram - - for (pt, 0..) |page, idx| { - if (page.ty == .Fault) continue; - const va = idx << 20; - uart.print("Section 0x{X:0>8} -> 0x{X:0>8}\n", .{ va, @as(u32, page.descriptor.section.section_base_address) << 20 }); - } - - // Now do MMU things - mmu.init(); - mmu.DomainAccessControlRegister.set_all(.Manager); - - try page_table.pt_switch(pt, 0x140E, 1); - - mmu.sync_pte(); - mmu.enable(); - - const base_address = mapped_kernel + memory.MB; - - pi.interrupts.disable_interrupts(); + memory.print_regions_physical(); - pi.switching.jump(base_address, base_address - (memory.MB / 2)); + pi.reboot(); } -const net = @import("shared").bootloader_protocol; -const Message = net.Message; -const Error = net.Error; -fn get_bootload(dst: [*]u8) !void { - const w = &uart.writer; - const r = &uart.reader; - - while (true) { - // UART cannot fail - try net.put_message(w, .GET_PROG_INFO); - - if (uart.read_queue_length() >= 4) { - const response = try net.get_u32(r); - - if (response == @intFromEnum(Message.PUT_PROG_INFO)) break; - } - - clock.delay_ms(300); - } - - const header = net.receive_header(r, std.math.maxInt(u32)) catch |e| switch (e) { - Error.BadAddress => { - try net.put_message(w, .BAD_CODE_ADDR); - - return pi.reboot(); - }, - else => unreachable, - }; - - try net.request_code(w, header.checksum); - - while (true) { - if (uart.read_queue_length() >= 4) { - const response = try net.get_u32(r); - - if (response == @intFromEnum(Message.PUT_CODE)) break; - } - } - - net.receive_code(r, dst[0..(header.n_bytes)], header) catch |e| switch (e) { - Error.BadChecksum => { - try net.put_message(w, .BAD_CODE_CKSUM); - - return pi.reboot(); - }, - else => unreachable, - }; - - try net.put_message(w, .BOOT_SUCCESS); - uart.flush(); +export fn abort() noreturn { + @branchHint(.cold); + pi.reboot(); } - -// fn new_main() noreturn { -// const base_address = Region.io().end + memory.MB; -// // Keep interrupt stack on top of normal stack -// const stack = base_address - (memory.MB / 2); -// const interrupt_stack = base_address; - -// var page_table_raw: [*]mmu.FirstLevelDescriptor = @ptrFromInt(base_address - memory.MB); -// const pt = page_table_raw[0..4096]; - -// // 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("base address: 0x{X}!\n", .{base_address}); - -// const mem_region = Region.memory(); -// const program = Region.program(); - -// const relocation: Region = .init(mem_region.end - memory.MB * 2, mem_region.end); - -// Region.interrupt_stack().unmap(pt) catch {}; -// Region.stack_boot().unmap(pt) catch {}; -// Region.stack().unmap(pt) catch {}; -// relocation.unmap(pt) catch {}; -// program.unmap(pt) catch {}; - -// uart.write_slice("owo?\n"); -// uart.print("Program: 0x{X} - 0x{X}\n", .{ program.start, program.end }); -// uart.print("Remapping regions\n\n", .{}); - -// pi.update_stack_address(stack); -// pi.update_interrupt_stack_address(interrupt_stack); -// Region.update_program_address(base_address, base_address + memory.MB); -// Region.update_heap_address(0, Region.memory().end - memory.MB * 2); - -// memory.print_regions_virtual(); - -// for (pt, 0..) |page, idx| { -// if (page.ty == .Fault) continue; -// const va = idx << 20; -// uart.print("Section 0x{X:0>8} -> 0x{X:0>8}\n", .{ va, @as(u32, page.descriptor.section.section_base_address) << 20 }); -// } - -// pi.reboot(); -// }