diff options
author | Himbeer <himbeer@disroot.org> | 2024-08-02 18:07:28 +0200 |
---|---|---|
committer | Himbeer <himbeer@disroot.org> | 2024-08-02 18:16:53 +0200 |
commit | 6cef76913e0c3e1db80d754665590495b093aeb8 (patch) | |
tree | def874781b1d2260ede137cb120a22d93407b400 | |
parent | e994ebad9977ff3ed60a5c2217d5a3e077462125 (diff) |
syscall: Implement hardware access by adding lock() and unlock()
Closes #73.
-rw-r--r-- | src/hwinfo.zig | 62 | ||||
-rw-r--r-- | src/kernel.zig | 5 | ||||
-rw-r--r-- | src/paging.zig | 24 | ||||
-rw-r--r-- | src/process.zig | 2 | ||||
-rw-r--r-- | src/sbi/time.zig | 2 | ||||
-rw-r--r-- | src/syscall.zig | 67 |
6 files changed, 126 insertions, 36 deletions
diff --git a/src/hwinfo.zig b/src/hwinfo.zig index 81fc4cc..98e767a 100644 --- a/src/hwinfo.zig +++ b/src/hwinfo.zig @@ -77,33 +77,61 @@ pub const Reg = extern struct { } }; -pub const ByKind = struct { - kind: DevKind, +pub const Iterator = struct { stream: std.io.FixedBufferStream([]const u8), - big_endian: bool, + endian: std.builtin.Endian, - pub fn init(kind: DevKind, stream: std.io.FixedBufferStream([]const u8)) !ByKind { + pub fn init(stream: std.io.FixedBufferStream([]const u8)) !Iterator { var fbs = stream; - const endian = try fbs.reader().readByte(); - return .{ .kind = kind, .stream = fbs, .big_endian = endian != 0 }; + const big_endian = try fbs.reader().readByte(); + return .{ + .stream = fbs, + .endian = if (big_endian != 0) .big else .little, + }; } - pub fn next(it: *ByKind) !?Dev { - const endian: std.builtin.Endian = if (it.big_endian) .big else .little; - + pub fn next(it: *Iterator) ?Dev { const reader = it.stream.reader(); - while (reader.readStructEndian(Dev, endian)) |device| { - if (device.kind == it.kind) return device; - } else |err| return err; - - return null; + return reader.readStructEndian(Dev, it.endian) catch null; } - pub fn reset(it: *ByKind) !void { + pub fn reset(it: *Iterator) void { try it.stream.seekTo(1); } + + pub fn byKind(it: Iterator, kind: DevKind) ByKind { + return .{ .iterator = it, .kind = kind }; + } +}; + +pub fn iterator() !Iterator { + return Iterator.init(devices); +} + +pub const ByKind = struct { + iterator: Iterator, + kind: DevKind, + + pub fn next(it: *ByKind) ?Dev { + while (it.iterator.next()) |device| { + if (device.kind == it.kind) return device; + } else return null; + } + + pub fn reset(it: *ByKind) void { + it.iterator.reset(); + } }; -pub fn byKind(kind: DevKind) !ByKind { - return ByKind.init(kind, devices); +pub inline fn byKind(kind: DevKind) !ByKind { + const it = try iterator(); + return it.byKind(kind); +} + +pub fn byAddress(reg_addr: usize, only_user_manageable: bool) !?Dev { + var it = try iterator(); + while (it.next()) |device| { + const authorized = !only_user_manageable or device.kind.isUserManagable(); + if (device.reg.addr == reg_addr and authorized) return device; + } else return null; } diff --git a/src/kernel.zig b/src/kernel.zig index 2395fa1..737cd28 100644 --- a/src/kernel.zig +++ b/src/kernel.zig @@ -157,9 +157,8 @@ fn pagedRun() !noreturn { try w.print("Timer : {d} Hz\r\n", .{1 / (@as(f64, process.schedule_interval_millis) / 1000)}); - var plic_dev = try hwinfo.byKind(.plic); - if (try plic_dev.next()) |plic_handle| { - _ = &plic_handle; + var plics = try hwinfo.byKind(.plic); + if (plics.next() != null) { try w.print("PLIC : Disabled\r\n", .{}); } else { try w.print("PLIC : Not present\r\n", .{}); diff --git a/src/paging.zig b/src/paging.zig index d1d309c..33e32f0 100644 --- a/src/paging.zig +++ b/src/paging.zig @@ -32,7 +32,6 @@ inline fn heapSize() usize { pub const page_size: usize = 0x1000; // 4096 bytes var num_pages: usize = undefined; -var next_mmio_vaddr: usize = 0xff000000; pub var alloc_start: usize = undefined; pub var kmem: *Table = undefined; @@ -147,6 +146,17 @@ pub const EntryFlags = packed struct(u8) { accessed: u1, dirty: u1, + pub const invalid = EntryFlags{ + .valid = 0, + .read = 0, + .write = 0, + .exec = 0, + .user = 0, + .global = 0, + .accessed = 0, + .dirty = 0, + }; + pub const branch = EntryFlags{ .valid = 1, .read = 0, @@ -444,16 +454,14 @@ pub const Table = struct { try root.identityMapRange(@intFromPtr(heap_start), @intFromPtr(heap_end), EntryFlags.readWrite); } - pub fn mapDevice(root: *Table, reg: *hwinfo.Reg) !void { - const physical_start = reg.addr & ~(page_size - 1); - const physical_end = (reg.addr + reg.len - 1) & ~(page_size - 1); - - reg.addr = next_mmio_vaddr | (reg.addr & (page_size - 1)); + pub fn mapDevice(root: *Table, reg: hwinfo.Reg, vaddr: *usize, flags: EntryFlags) !void { + const physical_start = std.mem.alignBackward(usize, reg.addr, page_size); + const physical_end = std.mem.alignBackward(usize, reg.addr + reg.len - 1, page_size); var paddr = physical_start; while (paddr <= physical_end) : (paddr += page_size) { - try root.map(next_mmio_vaddr, paddr, EntryFlags.readWrite, 0); - next_mmio_vaddr += page_size; + try root.map(vaddr.*, paddr, flags, 0); + vaddr.* += page_size; } } }; diff --git a/src/process.zig b/src/process.zig index 9970f2e..59e4429 100644 --- a/src/process.zig +++ b/src/process.zig @@ -13,6 +13,7 @@ const Allocator = std.mem.Allocator; const elf = std.elf; pub const schedule_interval_millis = 1; +pub const mmio_start_vaddr = 0x7f00000000; pub var list = std.mem.zeroInit(std.DoublyLinkedList(Info), .{}); var next_pid: u16 = 1; @@ -52,6 +53,7 @@ pub const Info = struct { stack: []align(paging.page_size) u8, pc: usize, page_table: *paging.Table, + next_mmio_vaddr: usize = mmio_start_vaddr, state: State, pub fn satp(self: *const Info) paging.Satp { diff --git a/src/sbi/time.zig b/src/sbi/time.zig index eed5324..ffd7028 100644 --- a/src/sbi/time.zig +++ b/src/sbi/time.zig @@ -26,7 +26,7 @@ pub fn setTimer(stime_absolute: u64) !void { pub fn interruptInMillis(millis: u64) !void { var cpus = try hwinfo.byKind(.cpus); - const frequency = try cpus.next() orelse return error.NoCpusHwInfo; + const frequency = cpus.next() orelse return error.NoCpusHwInfo; const cycles = frequency.value / 1000 * millis; const time = riscv.time.read(); diff --git a/src/syscall.zig b/src/syscall.zig index e3b54c9..3a346ab 100644 --- a/src/syscall.zig +++ b/src/syscall.zig @@ -25,10 +25,12 @@ pub fn handler(proc: *process.Info, trap_frame: *TrapFrame) !void { 100005 => trap_frame.setReturnValue(processId(proc)), 100006 => trap_frame.setReturnValue(threadId(proc)), 100007 => trap_frame.setReturnValue(devicesByKind(trap_frame)), - 100008 => trap_frame.setReturnValue(join(proc, trap_frame)), - 100009 => trap_frame.setReturnValue(leave(proc, trap_frame)), - 100010 => trap_frame.setReturnValue(pass(proc, trap_frame)), - 100011 => trap_frame.setReturnValue(receive(proc, trap_frame)), + 100008 => trap_frame.setReturnValue(unlock(proc, trap_frame)), + 100009 => trap_frame.setReturnValue(lock(proc, trap_frame)), + 100010 => trap_frame.setReturnValue(join(proc, trap_frame)), + 100011 => trap_frame.setReturnValue(leave(proc, trap_frame)), + 100012 => trap_frame.setReturnValue(pass(proc, trap_frame)), + 100013 => trap_frame.setReturnValue(receive(proc, trap_frame)), else => return HandleError.UnknownSyscall, } } @@ -135,7 +137,11 @@ fn threadId(proc: *const process.Info) usize { return proc.thread_id; } -pub const DeviceError = error{KindNotUserManagable}; +pub const DeviceError = error{ + KindNotUserManagable, + DeviceNotFound, + VirtualAddressOutOfRange, +}; // devicesByKind(kind: hwinfo.DevKind, devices: [*]hwinfo.Dev, len: usize) !usize fn devicesByKind(trap_frame: *const TrapFrame) !usize { @@ -147,16 +153,63 @@ fn devicesByKind(trap_frame: *const TrapFrame) !usize { var i: usize = 0; var devs = try hwinfo.byKind(kind); - while (try devs.next()) |dev| { + while (devs.next()) |device| { if (i >= len) break; - devices[i] = dev; + devices[i] = device; i += 1; } return i; } +// unlock(reg_addr: usize, writable: bool) !usize +fn unlock(proc: *process.Info, trap_frame: *const TrapFrame) !usize { + const reg_addr = trap_frame.general_purpose_registers[10]; + const writable = trap_frame.general_purpose_registers[11] != 0; + + const flags = if (writable) blk: { + break :blk paging.EntryFlags.userReadWrite; + } else blk: { + break :blk paging.EntryFlags.userReadOnly; + }; + + const vaddr = proc.next_mmio_vaddr; + + const device = try hwinfo.byAddress(reg_addr, true) orelse return DeviceError.DeviceNotFound; + try proc.page_table.mapDevice(device.reg, &proc.next_mmio_vaddr, flags); + asm volatile ( + \\ sfence.vma %[addr], %[asid] + : + : [addr] "r" (device.reg.addr), + [asid] "r" (proc.id), + ); + + return vaddr; +} + +// lock(vaddr: usize) !void +fn lock(proc: *const process.Info, trap_frame: *const TrapFrame) !void { + var vaddr = trap_frame.general_purpose_registers[10]; + + if (vaddr < process.mmio_start_vaddr) return DeviceError.VirtualAddressOutOfRange; + + const reg_addr = proc.page_table.translate(vaddr, paging.EntryFlags.invalid) orelse { + const faulter: *volatile u8 = @ptrFromInt(vaddr); + _ = faulter.*; + unreachable; + }; + + const device = try hwinfo.byAddress(reg_addr, true) orelse return DeviceError.DeviceNotFound; + try proc.page_table.mapDevice(device.reg, &vaddr, paging.EntryFlags.invalid); + asm volatile ( + \\ sfence.vma %[addr], %[asid] + : + : [addr] "r" (device.reg.addr), + [asid] "r" (proc.id), + ); +} + // join(channel: usize) !void fn join(proc: *const process.Info, trap_frame: *const TrapFrame) !void { const id = trap_frame.general_purpose_registers[10]; |