sylveos

Toy Operating System
Log | Files | Refs

commit 9bcb202f74089cceae8aef091d85d71405b8a0f4
parent fbd39d3228b71f6c2bb61b7234ee5bb7eb447e1a
Author: Sylvia Ivory <git@sivory.net>
Date:   Thu, 12 Mar 2026 21:56:36 -0700

Shuffle memory around

Diffstat:
MJustfile | 2++
Mboot/root.zig | 3+++
Mpi/interrupts.zig | 2+-
Mpi/linker.ld | 30+++++++++++++++++++++++-------
Mpi/mmu.zig | 4++--
Mpi/procmap.zig | 4++--
Mpi/root.zig | 14++++++++++++--
Mprograms/pinned-basic.zig | 170+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msylveos/loader.zig | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msylveos/root.zig | 5++++-
10 files changed, 196 insertions(+), 103 deletions(-)

diff --git a/Justfile b/Justfile @@ -1,6 +1,8 @@ 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 diff --git a/boot/root.zig b/boot/root.zig @@ -22,6 +22,9 @@ fn initialize_interrupts() void { export const _start = make(kmain, abort)._start; export fn kmain() void { + // We don't return so we can modify SP + pi.set_sp(@ptrFromInt(pi.get_stack_address())); + uart.initialize(921600, .Gpio14, .Gpio15) catch {}; uart.write_slice("Initializing interrupts\n"); diff --git a/pi/interrupts.zig b/pi/interrupts.zig @@ -209,7 +209,7 @@ 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, =__int_stack_end__\n" ++ " push {r0-r12, lr}\n" ++ " sub lr, lr, #" ++ offset ++ "\n" ++ " mov r0, lr\n" ++ diff --git a/pi/linker.ld b/pi/linker.ld @@ -1,8 +1,13 @@ OUTPUT_ARCH(arm) ENTRY(_start) +STACK_SIZE = 0x100000; +MB = 1024 * 1024; + SECTIONS { + __program_start__ = .; + /* link the code first at 0x8000. */ .text 0x8000 : { __code_start__ = .; @@ -13,21 +18,19 @@ SECTIONS } /* read-only data */ - .rodata : { - . = ALIGN(4); + .rodata ALIGN(8) : { *(.rodata*) + . = ALIGN(8); } /* rw data */ - .data : { - __data_start__ = .; + .data ALIGN(8) : { *(.data*) . = ALIGN(8); - __data_end__ = .; } /* 0 data */ .bss : { - . = ALIGN(4); + . = ALIGN(8); __bss_start__ = .; *(.bss*) *(COMMON) @@ -35,7 +38,20 @@ SECTIONS __bss_end__ = .; } - . = ALIGN(16); + . = ALIGN(8); + __program_end__ = .; + . = ALIGN(MB); + __stack_start__ = .; + . = . + STACK_SIZE; + . = ALIGN(MB); + __stack_end__ = .; + . = ALIGN(MB); + __int_stack_start__ = .; + . = . + STACK_SIZE; + . = ALIGN(MB); + __int_stack_end__ = .; + + . = ALIGN(32); __heap_start__ = .; /DISCARD/ : { *(.debug*) } diff --git a/pi/mmu.zig b/pi/mmu.zig @@ -1,5 +1,5 @@ -pub const system = @import("./system.zig"); -pub const mem = @import("./mem.zig"); +const system = @import("./system.zig"); +const mem = @import("./mem.zig"); pub const LockdownIndex = struct { pub inline fn get() u3 { diff --git a/pi/procmap.zig b/pi/procmap.zig @@ -92,8 +92,8 @@ pub const ProcMap = struct { try map.push(ProcEntry.identity(0x7E00000, MB, .ReadWrite, dom)); // Stacks - try map.push(ProcEntry.identity(pi.STACK_ADDRESS - MB, MB, .ReadWrite, dom)); - try map.push(ProcEntry.identity(pi.STACK_INTERRUPT_ADDRESS - MB, MB, .ReadWrite, dom)); + try map.push(ProcEntry.identity(pi.get_stack_address() - MB, MB, .ReadWrite, dom)); + try map.push(ProcEntry.identity(pi.get_interrupt_stack_address() - MB, MB, .ReadWrite, dom)); return map; } diff --git a/pi/root.zig b/pi/root.zig @@ -15,6 +15,7 @@ pub const system = @import("./system.zig"); pub const debug = @import("./debug.zig"); pub const mem = @import("./mem.zig"); pub const mmu = @import("./mmu.zig"); +pub const pt = @import("./pt.zig"); pub const devices = struct { pub const clock = @import("./devices/clock.zig"); @@ -36,8 +37,17 @@ pub const fs = struct { pub const FatVFS = @import("./fs/fatvfs.zig"); }; -pub export const STACK_ADDRESS: usize = 0x8000000; -pub export const STACK_INTERRUPT_ADDRESS: usize = 0x9000000; +extern const __stack_start__: u32; +extern const __stack_end__: u32; +extern const __int_stack_start__: u32; +extern const __int_stack_end__: u32; + +pub inline fn get_stack_address() u32 { + return std.mem.alignForward(u32, @intFromPtr(&__stack_end__), 1024 * 1024); +} +pub inline fn get_interrupt_stack_address() u32 { + return std.mem.alignForward(u32, @intFromPtr(&__int_stack_end__), 1024 * 1024); +} pub inline fn cycle_counter_init() void { asm volatile ("MCR p15, 0, %[in], c15, c12, 0" diff --git a/programs/pinned-basic.zig b/programs/pinned-basic.zig @@ -17,8 +17,6 @@ inline fn mb(n: usize) usize { const Segments = struct { const Code = mb(0); const Heap = mb(1); - const Stack = pi.STACK_ADDRESS - mb(1); - const StackInterrupts = pi.STACK_INTERRUPT_ADDRESS - mb(1); const BCM0 = mem.BASE_ADDRESS; const BCM1 = mem.BASE_ADDRESS + mb(1); const BCM2 = mem.BASE_ADDRESS + mb(2); @@ -36,88 +34,88 @@ fn data_abort_handler(regs: interrupts.Registers) void { } pub fn main() !void { - interrupts.set_exception_handler(.DataAbort, data_abort_handler); - uart.print("Set data abort!\n", .{}); - - const dev: pinned.PinnedAttribute = .{ - .asid = 0, - .domain = 1, - .scope = .Global, - .permission = .UserNoAccess, - .permission_x = .SupervisorRW, - .mem_attributes = .StronglyOrdered, - }; - const kern: pinned.PinnedAttribute = .{ - .asid = 0, - .domain = 1, - .scope = .Global, - .permission = .UserNoAccess, - .permission_x = .SupervisorRW, - .mem_attributes = .OuterInnerNoncacheable, - }; - - mmu.init(); - uart.print("Initialized MMU!\n", .{}); - - try pinned.set(0, @bitCast(Segments.Code), @bitCast(Segments.Code), kern); - try pinned.set(1, @bitCast(Segments.Heap), @bitCast(Segments.Heap), kern); - try pinned.set(2, @bitCast(Segments.Stack), @bitCast(Segments.Stack), kern); - try pinned.set(3, @bitCast(Segments.StackInterrupts), @bitCast(Segments.StackInterrupts), kern); - try pinned.set(4, @bitCast(Segments.BCM0), @bitCast(Segments.BCM0), dev); - try pinned.set(5, @bitCast(Segments.BCM1), @bitCast(Segments.BCM1), dev); - try pinned.set(6, @bitCast(Segments.BCM2), @bitCast(Segments.BCM2), dev); - - uart.print("Setup TLB!\n", .{}); - - const dacr: mmu.DomainAccessControlRegister = .{ - .d1 = .Client, - }; - dacr.set(); - - // mmu.set_context(.{ - // .asid = 1, - // .pid = 128, - // }); - var null_ptr: [4096 * 4]u8 align(1 << 14) = .{0} ** (4096 * 4); - mmu.set_context_ttbr0(.{ - .asid = 1, - .pid = 128 << 8, - }, @bitCast(@intFromPtr(&null_ptr))); - - uart.print("Set context!\n", .{}); - - pinned.lockdown_print_entries(); - - for (0..10) |i| { - mmu.enable(); - - if (mmu.is_enabled()) { - uart.print("MMU ON: hello from virtual memory! count = {}\n", .{i}); - } else { - uart.print("MMU is off?\n", .{}); - } - - mmu.disable(); - - if (!mmu.is_enabled()) { - uart.print("MMU is off!\n", .{}); - } else { - uart.print("MMU is on?\n", .{}); - } - } - - const illegal: *u32 = @ptrFromInt(Segments.Illegal); - - mem.put_u32(illegal, 0xdeadbeef); - - uart.print("wrote without vm: got 0x{X}\n", .{mem.get_u32(illegal)}); - - mmu.enable(); - - uart.print("mmu.is_enabled() = {any}\n", .{mmu.is_enabled()}); - uart.print("about to write to 0x{X} (illegal)\n", .{Segments.Illegal}); - - mem.put_u32(illegal, 0xdeadbeef); - - uart.print("should be unreachable\n", .{}); + // interrupts.set_exception_handler(.DataAbort, data_abort_handler); + // uart.print("Set data abort!\n", .{}); + + // const dev: pinned.PinnedAttribute = .{ + // .asid = 0, + // .domain = 1, + // .scope = .Global, + // .permission = .UserNoAccess, + // .permission_x = .SupervisorRW, + // .mem_attributes = .StronglyOrdered, + // }; + // const kern: pinned.PinnedAttribute = .{ + // .asid = 0, + // .domain = 1, + // .scope = .Global, + // .permission = .UserNoAccess, + // .permission_x = .SupervisorRW, + // .mem_attributes = .OuterInnerNoncacheable, + // }; + + // mmu.init(); + // uart.print("Initialized MMU!\n", .{}); + + // try pinned.set(0, @bitCast(Segments.Code), @bitCast(Segments.Code), kern); + // try pinned.set(1, @bitCast(Segments.Heap), @bitCast(Segments.Heap), kern); + // try pinned.set(2, @bitCast(Segments.Stack), @bitCast(Segments.Stack), kern); + // try pinned.set(3, @bitCast(Segments.StackInterrupts), @bitCast(Segments.StackInterrupts), kern); + // try pinned.set(4, @bitCast(Segments.BCM0), @bitCast(Segments.BCM0), dev); + // try pinned.set(5, @bitCast(Segments.BCM1), @bitCast(Segments.BCM1), dev); + // try pinned.set(6, @bitCast(Segments.BCM2), @bitCast(Segments.BCM2), dev); + + // uart.print("Setup TLB!\n", .{}); + + // const dacr: mmu.DomainAccessControlRegister = .{ + // .d1 = .Client, + // }; + // dacr.set(); + + // // mmu.set_context(.{ + // // .asid = 1, + // // .pid = 128, + // // }); + // var null_ptr: [4096 * 4]u8 align(1 << 14) = .{0} ** (4096 * 4); + // mmu.set_context_ttbr0(.{ + // .asid = 1, + // .pid = 128 << 8, + // }, @bitCast(@intFromPtr(&null_ptr))); + + // uart.print("Set context!\n", .{}); + + // pinned.lockdown_print_entries(); + + // for (0..10) |i| { + // mmu.enable(); + + // if (mmu.is_enabled()) { + // uart.print("MMU ON: hello from virtual memory! count = {}\n", .{i}); + // } else { + // uart.print("MMU is off?\n", .{}); + // } + + // mmu.disable(); + + // if (!mmu.is_enabled()) { + // uart.print("MMU is off!\n", .{}); + // } else { + // uart.print("MMU is on?\n", .{}); + // } + // } + + // const illegal: *u32 = @ptrFromInt(Segments.Illegal); + + // mem.put_u32(illegal, 0xdeadbeef); + + // uart.print("wrote without vm: got 0x{X}\n", .{mem.get_u32(illegal)}); + + // mmu.enable(); + + // uart.print("mmu.is_enabled() = {any}\n", .{mmu.is_enabled()}); + // uart.print("about to write to 0x{X} (illegal)\n", .{Segments.Illegal}); + + // mem.put_u32(illegal, 0xdeadbeef); + + // uart.print("should be unreachable\n", .{}); } diff --git a/sylveos/loader.zig b/sylveos/loader.zig @@ -3,12 +3,73 @@ const pi = @import("pi"); const process = @import("./process.zig"); -const ProcMap = pi.procmap.ProcMap; const Page = process.Page; +const mailbox = pi.devices.mailbox; +const uart = pi.devices.mini_uart; +const mmu = pi.mmu; +const pt = pi.pt; + +const MB: u32 = 1024 * 1024; + +// Kernel: 0x20FF_FFFF -> 0xFFFF_FFFF +// IO : 0x2000_0000 -> 0x20FF_FFFF +// User : 0x0000_0000 -> 0x2000_0000 (512mb, fine enough) // Program contains a static series of pages (unfortunately 1mb each) pub const Program = struct { pages: std.ArrayList(Page), - proc_map: ProcMap, + pt: []mmu.FirstLevelDescriptor, entrypoint: u32, }; + +// We map kernel into high addresses +extern const __program_start__: u32; +extern const __program_end__: u32; +extern const __heap_start__: u32; + +pub fn map_kernel() void { + const program_start = std.mem.alignBackward(u32, @intFromPtr(&__program_start__), MB); + const program_end = std.mem.alignForward(u32, @intFromPtr(&__program_end__), MB); + const program_size = program_end - program_start; + + const stack_end = pi.get_stack_address(); + const stack_start = stack_end - MB; + const stack_size = stack_end - stack_start; + + const int_stack_end = pi.get_interrupt_stack_address(); + const int_stack_start = int_stack_end - MB; + const int_stack_size = int_stack_end - int_stack_start; + + const io_start = std.mem.alignBackward(u32, 0x2000_0000, MB); + const io_end = std.mem.alignForward(u32, 0x20FF_FFFF, MB); + const io_size = io_end - io_start; + + const memory_info = mailbox.get_arm_memory_info() catch unreachable; + const memory_start = memory_info.base_address; + const memory_end = memory_info.base_address + memory_info.memory_size; + const memory_size = memory_end - memory_start; + + const heap_start = @max( + std.mem.alignBackward(u32, @intFromPtr(&__heap_start__), MB), + int_stack_end, + ); + const heap_end = std.mem.alignBackward(u32, memory_end, MB); + const heap_size = heap_end - heap_start; + + uart.print( + \\Physical Memory Layout: 0x{X:0>8} - 0x{X:0>8} ({Bi}) + \\ KERNEL: 0x{X:0>8} - 0x{X:0>8} ({Bi}) + \\ KERNEL STACK: 0x{X:0>8} - 0x{X:0>8} ({Bi}) + \\KERNEL INTERRUPT STACK: 0x{X:0>8} - 0x{X:0>8} ({Bi}) + \\ 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, + stack_start, stack_end, stack_size, + int_stack_start, int_stack_end, int_stack_size, + heap_start, heap_end, heap_size, + io_start, io_end, io_size, + }); +} diff --git a/sylveos/root.zig b/sylveos/root.zig @@ -1,3 +1,6 @@ const pi = @import("pi"); +const loader = @import("./loader.zig"); -pub fn main() !void {} +pub fn main() !void { + loader.map_kernel(); +}