commit 1cbdb8f727f0ad0b19d0b4a7f013b95a6f871e67
parent f328e76f70d63511c1c6f5150cbf2cdee341144d
Author: Sylvia Ivory <git@sivory.net>
Date: Fri, 13 Mar 2026 16:42:53 -0700
Reorganize
Diffstat:
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();
-// }