aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-08-02 18:07:28 +0200
committerHimbeer <himbeer@disroot.org>2024-08-02 18:16:53 +0200
commit6cef76913e0c3e1db80d754665590495b093aeb8 (patch)
treedef874781b1d2260ede137cb120a22d93407b400
parente994ebad9977ff3ed60a5c2217d5a3e077462125 (diff)
syscall: Implement hardware access by adding lock() and unlock()
Closes #73.
-rw-r--r--src/hwinfo.zig62
-rw-r--r--src/kernel.zig5
-rw-r--r--src/paging.zig24
-rw-r--r--src/process.zig2
-rw-r--r--src/sbi/time.zig2
-rw-r--r--src/syscall.zig67
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];