commit 861ced844d7e2be03fc021af5376ac168563f583
parent b549d4b153c15eaeaa02cbc6f9f214728e69d073
Author: Sylvia Ivory <git@sivory.net>
Date: Thu, 5 Mar 2026 13:42:14 -0800
Fix MMU code
Diffstat:
| M | pi/mmu.zig | | | 114 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
| M | pi/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"
: