sylveos

Toy Operating System
Log | Files | Refs

commit 861ced844d7e2be03fc021af5376ac168563f583
parent b549d4b153c15eaeaa02cbc6f9f214728e69d073
Author: Sylvia Ivory <git@sivory.net>
Date:   Thu,  5 Mar 2026 13:42:14 -0800

Fix MMU code

Diffstat:
Mpi/mmu.zig | 114++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mpi/system.zig | 4+++-
2 files changed, 87 insertions(+), 31 deletions(-)

diff --git a/pi/mmu.zig b/pi/mmu.zig @@ -333,6 +333,8 @@ pub const TranslationTableBaseRegister1 = packed struct(u32) { } }; +// ARM ARM only defines boundary_size +// ARM1176JZF-S specifies more on top pub const TranslationTableBaseControl = packed struct(u32) { pub const BoundarySize = enum(u3) { @"16KB" = 0b000, @@ -345,11 +347,11 @@ pub const TranslationTableBaseControl = packed struct(u32) { @"128B" = 0b111, }; - boundary_size: BoundarySize, - _reserved_3: u1, - page_table_walk_0: u1, - page_table_walk_1: u1, - _reserved_31_6: u26, + boundary_size: BoundarySize = .@"16KB", + _reserved_3: u1 = 0, + page_table_walk_0: u1 = 0, + page_table_walk_1: u1 = 0, + _reserved_31_6: u26 = 0, pub inline fn get() @This() { return asm volatile ("MRC p15, 0, %[result], c2, c0, 2" @@ -417,6 +419,8 @@ pub const TranslationResult = packed struct(u32) { }, }; +// 3-82 +// Write to p15, c7, c4, 0 with VA and read to get PA + extra pub inline fn va_translation_cw(va: u32, comptime mode: TranslationMode) TranslationResult { const mode_asm = switch (mode) { .PrivilegedRead => "0", @@ -447,6 +451,7 @@ pub fn init() void { reg.set(); } +// We want to ensure the processor is in a known state, so: // 1. Invalidate all caches // 2. B2 (memory) ordering operations pub fn reset() void { @@ -459,16 +464,16 @@ pub fn reset() void { // Ensure maintenance completes mem.barrier(.Write); - // Flush BTB as part of reset - system.flush_btb(); + // // Flush BTB as part of reset + // system.flush_btb(); - // Ensure completion - mem.barrier(.Write); - // Required after BTB flush - mem.barrier(.Instruction); + // // Ensure completion + // mem.barrier(.Write); + // // Required after BTB flush + // mem.barrier(.Instruction); } -// 6.4.1 - Enabling the MMU +// 6-9: 6.4.1 - Enabling the MMU // 1. Program all relevant CP15 registers // 2. Program first-level and second-level page tables as required // 3. Disable and invalidate instruction cache @@ -479,7 +484,7 @@ pub noinline fn enable() void { // Should be done by reset/user // 2. Program first-level and second-level page tables - // Should be done by user + // Should be done by user (via set_context_ttbr0) // 3. Disable instruction cache var reg = system.SystemControlRegister.get(); @@ -497,7 +502,7 @@ pub noinline fn enable() void { reg.set(); // Ensure completion of enabling - mem.barrier(.Write); + mem.barrier(.Instruction); // Required after enabling MMU system.flush_btb(); @@ -505,7 +510,7 @@ pub noinline fn enable() void { mem.barrier(.Instruction); } -// 6.4.2 - Disabling the MMU +// 6-9: 6.4.2 - Disabling the MMU // 1. Clear bit 2 to 0 in System Control Register (level one data cache) // 2. Clear bit 0 to 0 in System Control Register (MMU Enabled) pub noinline fn disable() void { @@ -519,27 +524,26 @@ pub noinline fn disable() void { reg.level_one_data_cache = false; reg.set(); + mem.barrier(.Instruction); + // Invalidate instruction cache system.invalidate_icache(); + mem.barrier(.Write); // 2. Clear bit 0 to 0 reg.mmu_enabled = false; reg.set(); + mem.barrier(.Instruction); + // BTB is to be flushed after any change to MMU system.flush_btb(); - // Ensure sync of MMU maintenance operation (turning it off) - mem.barrier(.Write); // Prefetch flush is required after BTB flush mem.barrier(.Instruction); } -pub fn is_enabled() bool { - return system.SystemControlRegister.get().mmu_enabled; -} - +// 3-129 pub fn set_context(ctx: ContextId) void { - // 3-129 // "You must ensure that software performs a Data Synchronization // Barrier operation before changes to this register." mem.barrier(.Write); @@ -559,19 +563,24 @@ pub fn set_context(ctx: ContextId) void { // 4. Prefetch Flush // 5. Change ASID to new value pub fn set_context_ttbr0(ctx: ContextId, ttrb0: TranslationTableBaseRegister0) void { + mem.barrier(.Write); + // 1. Change ASID to 0 const cleared: ContextId = .{}; - set_context(cleared); - // 2. set_context already does a prefetch flush + cleared.set(); + mem.barrier(.Instruction); - // 3. Change TTRB0 + // 3. Set control N = 0 to use TTRB0 + const control: TranslationTableBaseControl = .{ + // Specifies TTRB0 (3-62), N = 0 + .boundary_size = .@"16KB", + }; + control.set(); + + // 3. Set TTRB0 ttrb0.set(); - // Zero out TTRB1 as we're not using it - TranslationTableBaseRegister1.clear(); - // Invalidate BTB after any change to TTRB0 - system.flush_btb(); - // 4. Prefetch flush required after BTB flush + // 4. Prefetch flush mem.barrier(.Instruction); // 5. Change ASID to new value @@ -581,3 +590,48 @@ pub fn set_context_ttbr0(ctx: ContextId, ttrb0: TranslationTableBaseRegister0) v system.flush_btb(); mem.barrier(.Instruction); } + +// B2.7.3 +// Synchronize PTE modifications +// +// 1. Store PTE +// 2. Clean PTE line +// 3. DSB +// 4. Invalidate TLB +// 5. Invalidate BTB +// 6. DSB +// 7. Prefetch +pub fn sync_pte() void { + // 1. Store page table + // Should be done by user + + // 2. Clean page table + // This ensures that the page table is fully committed to memory + system.clear_entire_data_cache(); + + // 3. DSB + mem.barrier(.Write); + + // 4. Invalidate TLB + system.invalidate_TLB(); + + // 5. Invalidate BTB + system.flush_btb(); + + // 6. DSB + mem.barrier(.Write); + + // 7. Prefetch + mem.barrier(.Instruction); +} + +pub fn set_domain(domain: DomainAccessControlRegister) void { + domain.set(); + mem.barrier(.Instruction); +} + +// Higher Level Abstractions + +pub fn is_enabled() bool { + return system.SystemControlRegister.get().mmu_enabled; +} diff --git a/pi/system.zig b/pi/system.zig @@ -133,6 +133,8 @@ pub inline fn invalidate_all_caches() void { invalidate_icache(); } +/// 2.7.5 +/// /// Call after: /// /// 1. Enabling/Disabling MMU @@ -141,7 +143,7 @@ pub inline fn invalidate_all_caches() void { /// 4. Changing TTBR0, TTBR1, TTBCR /// 5. Changing context ID /// -/// Always perform a prefetch buffer afterwards +/// Always perform a prefetch buffer afterwards (3-74) pub inline fn flush_btb() void { asm volatile ("mcr p15, 0, %[value], c7, c5, 6" :