procmap.zig (4288B)
1 // TODO; handle different page sizes 2 const std = @import("std"); 3 4 const uart = @import("./devices/mini-uart.zig"); 5 const pinned = @import("./pinned.zig"); 6 const mmu = @import("./mmu.zig"); 7 const mem = @import("./mem.zig"); 8 const pt = @import("./pt.zig"); 9 10 const pi = @import("./root.zig"); 11 12 pub const DEVICE_ATTR: pinned.PinnedAttribute = .{ 13 .asid = 0, 14 .domain = 1, 15 .scope = .Global, 16 .permission = .UserNoAccess, 17 .permission_x = .SupervisorRW, 18 .mem_attributes = .StronglyOrdered, 19 }; 20 21 pub const READ_WRITE_ATTR: pinned.PinnedAttribute = .{ 22 .asid = 0, 23 .domain = 1, 24 .scope = .Global, 25 .permission = .UserNoAccess, 26 .permission_x = .SupervisorRW, 27 .mem_attributes = .OuterInnerNoncacheable, 28 }; 29 30 pub const READ_ONLY_ATTR: pinned.PinnedAttribute = .{ 31 .asid = 0, 32 .domain = 1, 33 .scope = .Global, 34 .permission = .UserNoAccess, 35 .permission_x = .SupervisorRO, 36 .mem_attributes = .OuterInnerNoncacheable, 37 }; 38 39 const MB = 1024 * 1024; 40 41 pub const Error = error{ 42 FailedTranslation, 43 }; 44 45 pub const ProcEntry = struct { 46 pub const ProcEntryType = enum { 47 Device, 48 ReadWrite, 49 ReadOnly, 50 }; 51 52 virt_addr: u32, 53 phys_addr: u32, 54 n_bytes: u32, 55 type: ProcEntryType, 56 domain: u4 = 1, 57 asid: u8 = 0, 58 59 pub fn identity(addr: u32, n_bytes: u32, ty: ProcEntryType, dom: u4) ProcEntry { 60 return .{ 61 .virt_addr = addr, 62 .phys_addr = addr, 63 .n_bytes = n_bytes, 64 .domain = dom, 65 .type = ty, 66 }; 67 } 68 }; 69 70 pub const ProcMap = struct { 71 pt: []mmu.FirstLevelDescriptor, 72 entries: std.ArrayList(ProcEntry), 73 alloc: std.mem.Allocator, 74 75 const Self = @This(); 76 77 pub fn init(alloc: std.mem.Allocator, dom: u4) !Self { 78 var map: ProcMap = .{ 79 .pt = try pt.init(alloc, 4096), 80 .entries = try .initCapacity(alloc, 8), 81 .alloc = alloc, 82 }; 83 84 // BCM2835 85 try map.push(ProcEntry.identity(0x20000000, MB * 3, .Device, dom)); 86 87 // Program Code 88 try map.push(ProcEntry.identity(0x00000000, MB, .ReadWrite, dom)); 89 90 // Page table 91 try map.push(ProcEntry.identity(@intFromPtr(map.pt.ptr), MB, .ReadWrite, dom)); 92 try map.push(ProcEntry.identity(0x7E00000, MB, .ReadWrite, dom)); 93 94 // Stacks 95 try map.push(ProcEntry.identity(pi.get_stack_address() - MB, MB, .ReadWrite, dom)); 96 try map.push(ProcEntry.identity(pi.get_interrupt_stack_address() - MB, MB, .ReadWrite, dom)); 97 98 return map; 99 } 100 101 pub fn push(self: *Self, entry: ProcEntry) !void { 102 try self.entries.append(self.alloc, entry); 103 } 104 105 fn pin(self: *const Self) !void { 106 for (self.entries.items) |entry| { 107 var attr = switch (entry.type) { 108 .Device => DEVICE_ATTR, 109 .ReadWrite => READ_WRITE_ATTR, 110 .ReadOnly => READ_ONLY_ATTR, 111 }; 112 attr.domain = entry.domain; 113 attr.asid = entry.asid; 114 115 for (0..(entry.n_bytes / MB)) |offset| { 116 const va = entry.virt_addr + offset * MB; 117 const pa = entry.phys_addr + offset * MB; 118 _ = try pt.set(self.pt, va, pa, attr); 119 } 120 } 121 } 122 123 pub fn enable(self: *const Self, asid: u8) !void { 124 mmu.init(); 125 mmu.DomainAccessControlRegister.set_all(.Manager); 126 127 try self.pin(); 128 129 try pt.pt_switch(self.pt, 0x140E, asid); 130 mmu.sync_pte(); 131 mmu.enable(); 132 133 for (self.entries.items) |entry| { 134 const res = mmu.va_translation_cw(entry.virt_addr, .PrivilegedRead); 135 if (res.aborted) return Error.FailedTranslation; 136 137 const physical_base = @as(u32, res.inner.success.address) << 10; 138 const offset = entry.virt_addr & 0xFFF; 139 140 if ((physical_base | offset) != entry.phys_addr) return Error.FailedTranslation; 141 } 142 } 143 144 pub fn disable(self: *const Self) !void { 145 _ = self; 146 mmu.disable(); 147 } 148 149 pub fn dupe(self: *const Self) !Self { 150 return .{ 151 .alloc = self.alloc, 152 .entries = try self.entries.clone(self.alloc), 153 .pt = try pt.dupe(self.alloc, self.pt), 154 }; 155 } 156 };