sylveos

Toy Operating System
Log | Files | Refs

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 };