sylveos

Toy Operating System
Log | Files | Refs

commit cc2c284a52816cafdc8ee58e774643faa4c1d028
parent 997b21c4f4c97481bc190ce3108c9ea7acd02886
Author: Sylvia Ivory <git@sivory.net>
Date:   Thu, 12 Mar 2026 18:14:50 -0700

Allow switching between procmaps

Diffstat:
Mpi/procmap.zig | 89+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mpi/pt.zig | 11++++++++++-
Mprograms/pinned-lookup.zig | 4++--
Aprograms/pt-asid.zig | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 133 insertions(+), 37 deletions(-)

diff --git a/pi/procmap.zig b/pi/procmap.zig @@ -1,10 +1,11 @@ +// TODO; handle different page sizes const std = @import("std"); +const uart = @import("./devices/mini-uart.zig"); const pinned = @import("./pinned.zig"); const mmu = @import("./mmu.zig"); const mem = @import("./mem.zig"); const pt = @import("./pt.zig"); -const uart = @import("./devices/mini-uart.zig"); const pi = @import("./root.zig"); @@ -35,6 +36,12 @@ const READ_ONLY_ATTR: pinned.PinnedAttribute = .{ .mem_attributes = .OuterInnerNoncacheable, }; +const MB = 1024 * 1024; + +pub const Error = error{ + FailedTranslation, +}; + pub const ProcEntry = struct { pub const ProcEntryType = enum { Device, @@ -42,11 +49,22 @@ pub const ProcEntry = struct { ReadOnly, }; - addr: u32, - // TODO; handle other byte sizes + virt_addr: u32, + phys_addr: u32, n_bytes: u32, type: ProcEntryType, - domain: u4, + domain: u4 = 1, + asid: u8 = 0, + + pub fn identity(addr: u32, n_bytes: u32, ty: ProcEntryType, dom: u4) ProcEntry { + return .{ + .virt_addr = addr, + .phys_addr = addr, + .n_bytes = n_bytes, + .domain = dom, + .type = ty, + }; + } }; pub const ProcMap = struct { @@ -63,23 +81,19 @@ pub const ProcMap = struct { .alloc = alloc, }; - const MB = 1024 * 1024; - // BCM2835 - try map.push(.{ .addr = 0x20000000, .n_bytes = MB, .type = .Device, .domain = dom }); - try map.push(.{ .addr = 0x20100000, .n_bytes = MB, .type = .Device, .domain = dom }); - try map.push(.{ .addr = 0x20200000, .n_bytes = MB, .type = .Device, .domain = dom }); + try map.push(ProcEntry.identity(0x20000000, MB * 3, .Device, dom)); // Program Code - try map.push(.{ .addr = 0x00000000, .n_bytes = MB, .type = .ReadWrite, .domain = dom }); + try map.push(ProcEntry.identity(0x00000000, MB, .ReadWrite, dom)); // Page table - try map.push(.{ .addr = 0x7E00000, .n_bytes = MB, .type = .ReadWrite, .domain = dom }); - try map.push(.{ .addr = @intFromPtr(map.pt.ptr), .n_bytes = MB, .type = .ReadWrite, .domain = dom }); + try map.push(ProcEntry.identity(@intFromPtr(map.pt.ptr), MB, .ReadWrite, dom)); + try map.push(ProcEntry.identity(0x7E00000, MB, .ReadWrite, dom)); // Stacks - try map.push(.{ .addr = pi.STACK_ADDRESS - MB, .n_bytes = MB, .type = .ReadWrite, .domain = dom }); - try map.push(.{ .addr = pi.STACK_INTERRUPT_ADDRESS - MB, .n_bytes = MB, .type = .ReadWrite, .domain = dom }); + 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)); return map; } @@ -96,40 +110,47 @@ pub const ProcMap = struct { .ReadOnly => READ_ONLY_ATTR, }; attr.domain = entry.domain; + attr.asid = entry.asid; - uart.print("pinning 0x{X} -> 0x{X}\n", .{ entry.addr, entry.addr }); - _ = try pt.set(self.pt, entry.addr, entry.addr, attr); - uart.print(" check 0x{X} -> 0x{X}\n", .{ entry.addr, pt.translate(self.pt, entry.addr) orelse 0 }); + for (0..(entry.n_bytes / MB)) |offset| { + const va = entry.virt_addr + offset * MB; + const pa = entry.phys_addr + offset * MB; + _ = try pt.set(self.pt, va, pa, attr); + } } } - pub fn enable(self: *const Self) !void { + pub fn enable(self: *const Self, asid: u8) !void { mmu.init(); mmu.DomainAccessControlRegister.set_all(.Manager); try self.pin(); - try pt.pt_switch(self.pt, 0x140E, 1); - - const ttbc = mmu.TranslationTableBaseControl.get(); - uart.print("N={}\n", .{@intFromEnum(ttbc.boundary_size)}); + try pt.pt_switch(self.pt, 0x140E, asid); + mmu.sync_pte(); + mmu.enable(); for (self.entries.items) |entry| { - pt.check_entry(entry.addr); - } - - const ctx = mmu.ContextId.get(); - uart.print("asid={} pid={X}\n", .{ ctx.asid, ctx.pid }); + const res = mmu.va_translation_cw(entry.virt_addr, .PrivilegedRead); + if (res.aborted) return Error.FailedTranslation; - mmu.sync_pte(); + const physical_base = @as(u32, res.inner.success.address) << 10; + const offset = entry.virt_addr & 0xFFF; - uart.print(" check 0x{X} -> 0x{X}\n", .{ 0x7EFFE24, pt.translate(self.pt, 0x7EFFE24) orelse 0 }); + if ((physical_base | offset) != entry.phys_addr) return Error.FailedTranslation; + } + } - mmu.enable(); + pub fn disable(self: *const Self) !void { + _ = self; + mmu.disable(); + } - uart.print("checking entries\n", .{}); - for (self.entries.items) |entry| { - if (!try pinned.is_pinned(entry.addr)) return pinned.Error.ExpectedPinned; - } + pub fn dupe(self: *const Self) !Self { + return .{ + .alloc = self.alloc, + .entries = try self.entries.clone(self.alloc), + .pt = try pt.dupe(self.alloc, self.pt), + }; } }; diff --git a/pi/pt.zig b/pi/pt.zig @@ -29,7 +29,16 @@ pub fn init(alloc: std.mem.Allocator, count: u16) Error![]mmu.FirstLevelDescript } pub fn dupe(alloc: std.mem.Allocator, pt: []mmu.FirstLevelDescriptor) Error![]mmu.FirstLevelDescriptor { - return try alloc.dupe(mmu.FirstLevelDescriptor, pt); + const page_table = try alloc.alignedAlloc( + mmu.FirstLevelDescriptor, + std.mem.Alignment.fromByteUnits(1 << 14), + pt.len, + ); + + @memcpy(page_table, pt); + mmu.sync_pte(); + + return page_table; } pub fn pt_switch(pt: []mmu.FirstLevelDescriptor, pid: u24, asid: u8) Error!void { diff --git a/programs/pinned-lookup.zig b/programs/pinned-lookup.zig @@ -20,10 +20,10 @@ pub fn main() !void { interrupts.set_exception_handler(.DataAbort, data_abort_handler); const map: pi.procmap.ProcMap = try .init(alloc, 1); - try map.enable(); + try map.enable(1); for (map.entries.items, 0..) |entry, n| { - const va = entry.addr; + const va = entry.virt_addr; uart.print("checking entry n={d} addr=0x{X}\n", .{ n, va }); uart.print(" translation result=0x{X}\n", .{try pi.pinned.get(va)}); diff --git a/programs/pt-asid.zig b/programs/pt-asid.zig @@ -0,0 +1,66 @@ +const std = @import("std"); +const pi = @import("pi"); + +const interrupts = pi.interrupts; +const faults = pi.faults; +const uart = pi.devices.mini_uart; +const mem = pi.mem; + +fn data_abort_handler(regs: interrupts.Registers) void { + pi.mmu.disable(); + const far = faults.FAR.get(); + + uart.print("got fault on 0x{X} from 0x{X}\n", .{ far, regs.pc }); + pi.reboot(); +} + +fn mb(n: u32) u32 { + return n * 1024 * 1024; +} + +pub fn main() !void { + var buffer: [1024 * 1024]u8 = undefined; + var fba: std.heap.FixedBufferAllocator = .init(&buffer); + const alloc = fba.allocator(); + + interrupts.set_exception_handler(.DataAbort, data_abort_handler); + + const user_addr: *u32 = @ptrFromInt(mb(16)); + const phys_1: *u32 = @ptrFromInt(@intFromPtr(user_addr) + mb(1)); + const phys_2: *u32 = @ptrFromInt(@intFromPtr(user_addr) + mb(2)); + + var map_1: pi.procmap.ProcMap = try .init(alloc, 1); + var map_2 = try map_1.dupe(); + + try map_1.push(.{ + .asid = 1, + .n_bytes = mb(1), + .type = .ReadWrite, + .phys_addr = @intFromPtr(phys_1), + .virt_addr = @intFromPtr(user_addr), + }); + try map_2.push(.{ + .asid = 2, + .n_bytes = mb(1), + .type = .ReadWrite, + .phys_addr = @intFromPtr(phys_2), + .virt_addr = @intFromPtr(user_addr), + }); + + mem.put_u32(phys_1, 0x1111_1111); + mem.put_u32(phys_2, 0x2222_2222); + + uart.print("enabling with ASID=1\n", .{}); + try map_1.enable(1); + uart.print("ASID 1 got 0x{X}\n", .{mem.get_u32(user_addr)}); + mem.put_u32(user_addr, 1); + try map_1.disable(); + uart.print("checking write: 0x{X}\n", .{mem.get_u32(phys_1)}); + + uart.print("enabling with ASID=2\n", .{}); + try map_2.enable(2); + uart.print("ASID 2 got 0x{X}\n", .{mem.get_u32(user_addr)}); + mem.put_u32(user_addr, 2); + try map_2.disable(); + uart.print("checking write: 0x{X}\n", .{mem.get_u32(phys_2)}); +}