pinned.zig (4781B)
1 const system = @import("./system.zig"); 2 const mmu = @import("./mmu.zig"); 3 const mem = @import("./mem.zig"); 4 5 pub const Error = error{ 6 MMUEnabled, 7 MMUDisabled, 8 InvalidMVA, 9 TranslationAborted, 10 BadSetVA, 11 BadSetAttr, 12 BadSetPA, 13 ExpectedPinned, 14 }; 15 16 // Invalidate page table 17 const null_pages: [4096 * 4]u8 align(1 << 14) = .{0} ** (4096 * 4); 18 pub fn init() Error!void { 19 if (mmu.is_enabled()) return Error.MMUEnabled; 20 21 mmu.init(); 22 mmu.DomainAccessControlRegister.set_all(.Client); 23 } 24 25 // Map VA -> PA at IDX with attributes E 26 pub fn set(idx: u3, va: usize, pa: usize, attr: PinnedAttribute) Error!void { 27 const cs = mem.enter_critical_section(); 28 defer cs.exit(); 29 30 // Initialize lockdown values 31 const lockdown_attr: mmu.LockdownAttributesRegister = .{ 32 .shared = true, 33 .domain = attr.domain, 34 .page_table_encoding = .{ .preset = attr.mem_attributes }, 35 // 0 initialize everything else 36 .execute_never = false, 37 .ap1 = .TotalNoAccess, 38 .ap2 = .TotalNoAccess, 39 .ap3 = .TotalNoAccess, 40 .subpages_valid = false, 41 }; 42 43 // Make user pointers into real values 44 var lockdown_va: mmu.LockdownVA = @bitCast(va); 45 lockdown_va.asid = attr.asid; 46 lockdown_va.scope = attr.scope; 47 48 var lockdown_pa: mmu.LockdownPA = @bitCast(pa); 49 lockdown_pa.nsa = .Secure; 50 lockdown_pa.nstid = .Secure; 51 lockdown_pa.valid = true; 52 lockdown_pa.size = .@"1MB"; 53 lockdown_pa.ap0 = attr.permission; 54 lockdown_pa.apx = attr.permission_x; 55 56 mmu.LockdownIndex.set(idx); 57 58 lockdown_va.set(); 59 lockdown_attr.set(); 60 lockdown_pa.set(); 61 62 // Update to TLB, need prefetch flush 63 mem.barrier(.Instruction); 64 65 // Validate 66 if (mmu.LockdownVA.get() != lockdown_va) return Error.BadSetPA; 67 if (mmu.LockdownAttributesRegister.get() != lockdown_attr) return Error.BadSetAttr; 68 if (mmu.LockdownPA.get() != lockdown_pa) return Error.BadSetVA; 69 } 70 71 // Clear IDX 72 pub fn clear(idx: u3) Error!void { 73 mmu.LockdownIndex.set(idx); 74 75 // Zero out everything 76 mmu.LockdownVA.set(@bitCast(0)); 77 mmu.LockdownAttributesRegister.set(@bitCast(0)); 78 mmu.LockdownPA.set(@bitCast(0)); 79 80 // Update to TLB, need prefetch flush 81 mem.barrier(.Instruction); 82 83 // Validate 84 if (mmu.LockdownVA.get() != 0) return Error.BadSetPA; 85 if (mmu.LockdownAttributesRegister.get() != 0) return Error.BadSetAttr; 86 if (mmu.LockdownPA.get() != 0) return Error.BadSetVA; 87 } 88 89 // Get VA -> PA 90 pub fn get(va: u32) Error!u32 { 91 if (!mmu.is_enabled()) return Error.MMUDisabled; 92 // 3-79: MVA 0:2 SBZ 93 if (va & 0b11 != 0) return Error.InvalidMVA; 94 95 const pa = mmu.va_translation_cw(va, .PrivilegedRead); 96 if (pa.aborted) return Error.TranslationAborted; 97 98 const physical_base = @as(u32, pa.inner.success.address) << 10; 99 const offset = va & 0xFFF; 100 101 return physical_base | offset; 102 } 103 104 // Check if VA == PA 105 pub fn is_pinned(va: u32) Error!bool { 106 const pa = get(va) catch |err| { 107 // A translation abort explicitly means the VA is not pinned 108 if (err == Error.TranslationAborted) return false; 109 return err; 110 }; 111 112 return va == pa; 113 } 114 115 pub const PinnedAttribute = struct { 116 asid: u8, 117 domain: u4, 118 scope: mmu.LockdownVA.Scope, 119 permission: mmu.AccessPermissions, 120 permission_x: mmu.AccessPermissionsExtended, 121 mem_attributes: mmu.LockdownAttributesRegister.PageTableEncodingPreset, 122 123 pub fn dupe_asid_domain(self: *const PinnedAttribute, asid: u8, domain: u4) PinnedAttribute { 124 return .{ 125 .scope = self.scope, 126 .permission = self.permission, 127 .permission_x = self.permission_x, 128 .mem_attributes = self.mem_attributes, 129 .asid = asid, 130 .domain = domain, 131 }; 132 } 133 }; 134 135 const uart = @import("./devices/mini-uart.zig"); 136 pub fn lockdown_print_entry(idx: u3) void { 137 mmu.LockdownIndex.set(idx); 138 const pa = mmu.LockdownPA.get(); 139 const va = mmu.LockdownVA.get(); 140 const attr = mmu.LockdownAttributesRegister.get(); 141 142 uart.print(" PA = 0x{X} (valid={any} size={s} ap={s} apx={s})\n", .{ pa.physical_address, pa.valid, @tagName(pa.size), @tagName(pa.ap0), @tagName(pa.apx) }); 143 uart.print(" VA = 0x{X} (asid={d} scope={s})\n", .{ va.virtual_address, va.asid, @tagName(va.scope) }); 144 uart.print(" Attributes: domain={d} XN={any} shared={any} tex={d} c={d} b={d}\n", .{ attr.domain, attr.execute_never, attr.shared, attr.page_table_encoding.manual.tex, attr.page_table_encoding.manual.c, attr.page_table_encoding.manual.b }); 145 uart.flush(); 146 } 147 148 pub fn lockdown_print_entries() void { 149 for (0..8) |i| { 150 uart.print("Entry {d}:\n", .{i}); 151 lockdown_print_entry(@truncate(i)); 152 } 153 }