commit 9bcb202f74089cceae8aef091d85d71405b8a0f4
parent fbd39d3228b71f6c2bb61b7234ee5bb7eb447e1a
Author: Sylvia Ivory <git@sivory.net>
Date: Thu, 12 Mar 2026 21:56:36 -0700
Shuffle memory around
Diffstat:
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();
+}