sylveos

Toy Operating System
Log | Files | Refs

commit 8e1e9d0353d992a7f7cb738e999e59c4d20585f0
parent 2be6a19907a081b3489323b6bc3cb6cee478f169
Author: Sylvia Ivory <git@sivory.net>
Date:   Tue, 10 Mar 2026 19:56:43 -0700

Add page table

Diffstat:
Mpi/mmu.zig | 84+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Api/pt.zig | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 160 insertions(+), 36 deletions(-)

diff --git a/pi/mmu.zig b/pi/mmu.zig @@ -250,42 +250,6 @@ pub const InnerCacheableAttr = enum(u3) { }; pub const TranslationTableBaseRegister0 = packed struct(u32) { - // // This is pain - // pub const TranslationTableBase = packed union { - // @"16KB": packed struct { - // translation_table_base: u15, - // _reserved_13_5: u9, - // }, - // @"8KB": packed struct { - // translation_table_base: u16, - // _reserved_12_5: u8, - // }, - // @"4KB": packed struct { - // translation_table_base: u17, - // _reserved_11_5: u7, - // }, - // @"2KB": packed struct { - // translation_table_base: u18, - // _reserved_10_5: u6, - // }, - // @"1KB": packed struct { - // translation_table_base: u19, - // _reserved_9_5: u5, - // }, - // @"512B": packed struct { - // translation_table_base: u20, - // _reserved_8_5: u4, - // }, - // @"256B": packed struct { - // translation_table_base: u21, - // _reserved_7_5: u3, - // }, - // @"128B": packed struct { - // translation_table_base: u22, - // _reserved_6_5: u2, - // }, - // }; - inner_cacheable: bool, shared: bool, ecc: bool, @@ -390,6 +354,54 @@ pub const ContextId = packed struct(u32) { } }; +pub const FirstLevelDescriptor = packed struct(u32) { + pub const Fault = packed struct(u30) { + _ignore_31_2: u30, + }; + pub const Section = packed struct(u30) { + b: u1, + c: u1, + never_execute: bool, + domain: u4, + _implementation_9: u1 = 0, + ap: AccessPermissions, + tex: u3, + apx: AccessPermissions, + shared: bool, + not_global: bool, + is_supersection: bool = false, + section_base_address: u22, + }; + pub const SuperSection = packed struct(u30) { + b: u1, + c: u1, + never_execute: bool, + base_address_39_36: u4, + _implementation_9: u1, + ap: AccessPermissions, + tex: u3, + apx: AccessPermissions, + shared: bool, + not_global: bool, + is_supersection: bool = true, + base_address_35_32: u4, + section_base_address: u18, + }; + + pub const Type = enum(u2) { + Fault = 0b00, + CoarsePageTable = 0b01, + Section = 0b10, + }; + + ty: Type, + descriptor: packed union { + fault: Fault, + section: Section, + supersection: SuperSection, + }, +}; + pub const TranslationMode = enum { PrivilegedRead, PrivilegedWrite, diff --git a/pi/pt.zig b/pi/pt.zig @@ -0,0 +1,112 @@ +const std = @import("std"); + +const procmap = @import("./procmap.zig"); +const pinned = @import("./pinned.zig"); +const mmu = @import("./mmu.zig"); +const mem = @import("./mem.zig"); + +pub const Error = error{ + InvalidPageCount, + MmuEnabled, + MmuDisabled, +} || std.mem.Allocator; + +pub fn init(alloc: std.mem.Allocator, count: u16) Error![]mmu.FirstLevelDescriptor { + if (count != 4096) return Error.InvalidPageCount; + + const invalid: mmu.FirstLevelDescriptor = .{ + .ty = .Fault, + .descriptor = .{ .fault = .{ ._ignore_31_2 = 0 } }, + }; + + var page_table = try alloc.allocWithOptions( + mmu.FirstLevelDescriptor, + count, + std.mem.Alignment.fromByteUnits(14), + null, + ); + + @memset(&page_table, invalid); + + return page_table; +} + +pub fn dupe(alloc: std.mem.Allocator, pt: []mmu.FirstLevelDescriptor) Error![]mmu.FirstLevelDescriptor { + return try alloc.dupe(mmu.FirstLevelDescriptor, pt); +} + +pub fn enable() Error!void { + if (mmu.is_enabled()) return Error.MmuEnabled; + mmu.enable(); + if (!mmu.is_enabled()) return Error.MmuDisabled; +} + +pub fn disable() Error!void { + if (!mmu.is_enabled()) return Error.MmuDisabled; + mmu.disable(); + if (mmu.is_enabled()) return Error.MmuEnabled; +} + +pub fn pt_switch(pt: []mmu.FirstLevelDescriptor, pid: u32, asid: u8) Error!void { + mmu.set_context_ttbr0(.{ .asid = asid, .pid = pid }, .{ + // just guess wcgw + .ecc = false, + .shared = true, + .inner_cacheable = false, + .outer_cacheable_attr = .OuterNoncacheable, + .translation_table_base = @truncate(@intFromPtr(pt) >> 5), + }); +} + +pub fn set(pt: []mmu.FirstLevelDescriptor, va: u32, pa: u32, attr: pinned.PinnedAttribute) Error!*mmu.FirstLevelDescriptor { + const cs = mem.enter_critical_section(); + defer cs.exit(); + + const index = va >> 20; + const page = pt[index]; + + const mem_attr: mmu.LockdownAttributesRegister.PageTableEncodingManual = @bitCast(attr.mem_attributes); + + page.ty = .Section; + page.descriptor = .{ .section = .{ + .not_global = if (attr.scope == .Global) false else true, + .ap = attr.permission, + .apx = attr.permission_x, + .domain = attr.domain, + .never_execute = false, + .b = mem_attr.b, + .c = mem_attr.c, + .tex = mem_attr.tex, + .shared = true, + .section_base_address = @truncate(pa >> 10), + } }; + + mmu.sync_pte(); + + return &page; +} + +pub fn get(pt: []mmu.FirstLevelDescriptor, va: u32) !?*mmu.FirstLevelDescriptor { + const index = va >> 20; + const page = pt[index]; + + if (page.ty == .Fault) return null; + + return page; +} + +pub fn translate(pt: []mmu.FirstLevelDescriptor, va: u32) ?u32 { + const index = va >> 20; + const page = pt[index]; + + // Not dealing with with coarse/fault + if (page.ty != .Section) return null; + const section = page.descriptor.section; + // Not dealing with super sections + if (section.is_supersection) return null; + + const base = @as(u32, section.section_base_address) << 10; + + // Probably correct + return base | (index << 22); +}