sylveos

Toy Operating System
Log | Files | Refs

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 }