aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.zig11
-rw-r--r--src/fdt.zig438
-rw-r--r--src/hwi.zig21
-rw-r--r--src/kernel.zig (renamed from src/main.zig)81
-rw-r--r--src/lib/Console.zig (renamed from src/Console.zig)2
-rw-r--r--src/lib/cfg/platform/lpi4a.hwibin0 -> 64 bytes
-rw-r--r--src/lib/cfg/platform/lpi4a.txt2
-rw-r--r--src/lib/hwinfo.zig96
-rw-r--r--src/lib/instructions.zig (renamed from src/instructions.zig)0
-rw-r--r--src/lib/interrupts.zig (renamed from src/interrupts.zig)2
-rw-r--r--src/lib/mem.zig (renamed from src/mem.zig)0
-rw-r--r--src/lib/paging.zig (renamed from src/paging.zig)14
-rw-r--r--src/lib/pci.zig (renamed from src/pci.zig)60
-rw-r--r--src/lib/plic.zig (renamed from src/plic.zig)29
-rw-r--r--src/lib/process.zig (renamed from src/process.zig)4
-rw-r--r--src/lib/sbi.zig (renamed from src/sbi.zig)0
-rw-r--r--src/lib/sbi/debug_console.zig (renamed from src/sbi/debug_console.zig)0
-rw-r--r--src/lib/sbi/legacy.zig (renamed from src/sbi/legacy.zig)0
-rw-r--r--src/lib/sbi/sys_reset.zig (renamed from src/sbi/sys_reset.zig)0
-rw-r--r--src/lib/sbi/time.zig39
-rw-r--r--src/lib/syscall.zig (renamed from src/syscall.zig)0
-rw-r--r--src/lib/trap.zig (renamed from src/trap.zig)0
-rw-r--r--src/sbi/time.zig49
-rw-r--r--src/slice.zig47
24 files changed, 225 insertions, 670 deletions
diff --git a/build.zig b/build.zig
index fe82a1a..62a325e 100644
--- a/build.zig
+++ b/build.zig
@@ -31,11 +31,20 @@ pub fn build(b: *std.Build) void {
// In this case the main source file is merely a path, however, in more
// complicated build scripts, this could be a generated file.
.target = target,
- .root_source_file = b.path("src/main.zig"),
+ .root_source_file = b.path("src/kernel.zig"),
.optimize = optimize,
.code_model = .medium,
});
+ const platform = b.option([]const u8, "platform", "Set the target platform") orelse {
+ std.log.default.err("No target platform specified", .{});
+ return;
+ };
+
+ const options = b.addOptions();
+ options.addOption([]const u8, "platform", platform);
+
+ exe.root_module.addOptions("config", options);
exe.setLinkerScript(b.path("linker.ld"));
// This declares intent for the executable to be installed into the
diff --git a/src/fdt.zig b/src/fdt.zig
deleted file mode 100644
index 9ea85d0..0000000
--- a/src/fdt.zig
+++ /dev/null
@@ -1,438 +0,0 @@
-// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
-//
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-const std = @import("std");
-
-const slice = @import("slice.zig");
-
-pub var default: Tree = undefined;
-
-pub const ParseError = error{
- BadMagic,
- BadToken,
- ExpectedBeginNodeToken,
- ExpectedPropToken,
- DuplicateProperty,
-};
-
-pub const NodeError = error{
- NoParent,
- BadCellSize,
- PropertyNotFound,
-};
-
-pub const MemReservation = struct {
- const sentinel = .{
- .addr = 0,
- .size = 0,
- };
-
- addr: u64,
- size: u64,
-};
-
-pub const Reg = struct {
- start: usize,
- len: usize,
-
- pub fn slice(self: Reg, comptime T: type) []volatile T {
- const start_ptr: [*]volatile T = @ptrFromInt(self.start);
- return start_ptr[0 .. self.len / @sizeOf(T)];
- }
-};
-
-pub const Tree = struct {
- header: *const Header,
- nodes: std.ArrayList(Node),
-};
-
-pub const Node = struct {
- name: []const u8,
- props: std.StringHashMap([]const u8),
- parent: ?*Node,
- subnodes: std.ArrayList(Node),
-
- pub fn unitAddr(self: Node) !?usize {
- var nameSplit = std.mem.splitScalar(u8, self.name, '@');
- _ = nameSplit.next();
- const unitAddrStr = nameSplit.next() orelse return null;
-
- return try std.fmt.parseInt(usize, unitAddrStr, 16);
- }
-
- pub fn preferredDriver(self: Node, drivers: []const []const u8) ?[]const u8 {
- const compatible_prop = self.props.get("compatible") orelse return null;
-
- var compatibles = std.mem.tokenizeScalar(u8, compatible_prop, '\x00');
- while (compatibles.next()) |compatible| {
- for (drivers) |driver| {
- if (std.mem.eql(u8, driver, compatible)) return compatible;
- }
- }
-
- return null;
- }
-
- pub fn isCompatible(self: Node, with: []const u8) bool {
- return self.preferredDriver(&[_][]const u8{with}) != null;
- }
-
- pub fn reg(self: *const Node, allocator: std.mem.Allocator) !std.ArrayList(Reg) {
- if (self.parent == null) return NodeError.NoParent;
-
- const address_cells_bytes = self.parent.?.props.get("#address-cells");
- const size_cells_bytes = self.parent.?.props.get("#size-cells");
-
- const address_cells = if (address_cells_bytes) |bytes| std.mem.readInt(u32, bytes[0..4], .big) else 2;
- const size_cells = if (size_cells_bytes) |bytes| std.mem.readInt(u32, bytes[0..4], .big) else 1;
-
- if (address_cells == 0 or size_cells == 0) return NodeError.BadCellSize;
-
- const reg_prop = self.props.get("reg") orelse return NodeError.PropertyNotFound;
- const reg_elem_len = 4 * address_cells + 4 * size_cells;
-
- const n = reg_prop.len / reg_elem_len;
-
- var regs = std.ArrayList(Reg).init(allocator);
-
- for (0..n) |i| {
- const start_offset = i * reg_elem_len;
- const len_offset = start_offset + 4 * address_cells;
-
- try regs.append(.{
- .start = std.mem.readVarInt(usize, reg_prop[start_offset .. start_offset + 4 * address_cells], .big),
- .len = std.mem.readVarInt(usize, reg_prop[len_offset .. len_offset + 4 * size_cells], .big),
- });
- }
-
- return regs;
- }
-};
-
-pub const Property = struct {
- name: []const u8,
- value: []const u8,
-};
-
-pub const PropertyDesc = struct {
- len: u32,
- name_offset: u32,
-
- pub fn fromPtr(ptr: *align(1) PropertyDesc) PropertyDesc {
- return .{
- .len = std.mem.bigToNative(u32, ptr.len),
- .name_offset = std.mem.bigToNative(u32, ptr.name_offset),
- };
- }
-};
-
-fn ParseResult(comptime T: type) type {
- return struct {
- addr: usize,
- value: T,
- };
-}
-
-pub const RawHeader = struct {
- magic: u32,
- total_size: u32,
- offset_dt_struct: u32,
- offset_dt_strings: u32,
- offset_mem_reserve_map: u32,
- version: u32,
- last_compat_version: u32,
-
- // v2
- boot_cpuid_phys: u32,
-
- // v3
- size_dt_strings: u32,
-
- // v17
- size_dt_struct: u32,
-};
-
-pub const Header = struct {
- const magic = 0xd00dfeed;
-
- const token_begin_node = 0x00000001;
- const token_end_node = 0x00000002;
- const token_prop = 0x00000003;
- const token_nop = 0x00000004;
- const token_end = 0x00000009;
-
- raw_hdr: *align(1) RawHeader,
-
- magic: u32,
- total_size: u32,
- offset_dt_struct: u32,
- offset_dt_strings: u32,
- offset_mem_reserve_map: u32,
- version: u32,
- last_compat_version: u32,
-
- // v2
- boot_cpuid_phys: u32,
-
- // v3
- size_dt_strings: u32,
-
- // v17
- size_dt_struct: u32,
-
- pub fn parse(raw_hdr: *align(1) RawHeader) !Header {
- const hdr = .{
- .raw_hdr = raw_hdr,
-
- .magic = std.mem.bigToNative(u32, raw_hdr.magic),
- .total_size = std.mem.bigToNative(u32, raw_hdr.total_size),
- .offset_dt_struct = std.mem.bigToNative(u32, raw_hdr.offset_dt_struct),
- .offset_dt_strings = std.mem.bigToNative(u32, raw_hdr.offset_dt_strings),
- .offset_mem_reserve_map = std.mem.bigToNative(u32, raw_hdr.offset_mem_reserve_map),
- .version = std.mem.bigToNative(u32, raw_hdr.version),
- .last_compat_version = std.mem.bigToNative(u32, raw_hdr.last_compat_version),
-
- // v2
- .boot_cpuid_phys = std.mem.bigToNative(u32, raw_hdr.boot_cpuid_phys),
-
- // v3
- .size_dt_strings = std.mem.bigToNative(u32, raw_hdr.size_dt_strings),
-
- // v17
- .size_dt_struct = std.mem.bigToNative(u32, raw_hdr.size_dt_struct),
- };
-
- if (hdr.magic != magic) {
- return ParseError.BadMagic;
- }
-
- return hdr;
- }
-
- pub fn memoryReservations(self: *const Header) []MemReservation {
- const mem_reserve_map_addr = @intFromPtr(self.raw_hdr) + @as(usize, self.offset_mem_reserve_map);
- const mem_reservations: [*:MemReservation.sentinel]MemReservation = @ptrFromInt(mem_reserve_map_addr);
-
- var i: usize = 0;
- while (!std.meta.eql(mem_reservations[i], MemReservation.sentinel)) {
- i += 1;
- }
-
- return @ptrCast(mem_reservations[0..i]);
- }
-
- pub fn parseTree(self: *const Header, allocator: std.mem.Allocator) !Tree {
- var nodes = std.ArrayList(Node).init(allocator);
-
- var dt_struct_addr = @intFromPtr(self.raw_hdr) + @as(usize, self.offset_dt_struct);
-
- const dt_strings_addr = @intFromPtr(self.raw_hdr) + @as(usize, self.offset_dt_strings);
- const dt_strings: [*:0]const u8 = @ptrFromInt(dt_strings_addr);
-
- while (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(dt_struct_addr)).*) != token_end) {
- const parsed = try parseNode(allocator, dt_struct_addr, dt_strings);
- dt_struct_addr = parsed.addr;
- try nodes.append(parsed.value);
- }
-
- var tree = Tree{ .header = self, .nodes = nodes };
- initParentPtrs(&tree);
- return tree;
- }
-};
-
-pub fn findNode(nodes: []const Node, name: []const u8) slice.Filter(Node, []const u8) {
- return slice.Filter(Node, []const u8).new(nodes, nodeNameFilter, name);
-}
-
-pub fn findNodeExact(nodes: []const Node, name: []const u8) ?struct { usize, Node } {
- for (nodes, 0..) |node, i| {
- if (std.mem.eql(u8, node.name, name)) {
- return .{ i, node };
- }
- }
-
- return null;
-}
-
-pub fn findPath(dt: *const Tree, path: []const u8) ?Node {
- if (dt.nodes.items.len < 1) return null;
-
- const trimmed_path = std.mem.trim(u8, path, "/");
-
- var node = dt.nodes.items[0];
-
- var segments = std.mem.tokenizeScalar(u8, trimmed_path, '/');
- while (segments.next()) |segment| {
- var nodes = findNode(node.subnodes.items, segment);
- if (nodes.next()) |result| {
- node = result;
- } else return null;
- }
-
- return node;
-}
-
-pub fn findPathExact(dt: *const Tree, path: []const u8) ?Node {
- if (dt.nodes.items.len < 1) return null;
-
- const trimmed_path = std.mem.trim(u8, path, "/");
-
- var node = dt.nodes.items[0];
-
- var segments = std.mem.tokenizeScalar(u8, trimmed_path, '/');
- while (segments.next()) |segment| {
- if (findNodeExact(node.subnodes.items, segment)) |result| {
- node = result[1];
- } else return null;
- }
-
- return node;
-}
-
-pub fn findCompatible(node: *Node, compatible: []const []const u8, max: comptime_int) []Node {
- var results: [max]Node = undefined;
- var n: usize = 0;
-
- for (node.subnodes.items) |subnode| {
- var subnode_mut = subnode;
-
- const subresults = findCompatible(&subnode_mut, compatible, max);
- for (subresults) |subresult| {
- if (n >= max) break;
-
- results[n] = subresult;
- n += 1;
- }
-
- for (compatible) |driver| {
- if (n >= max) break;
-
- if (subnode.isCompatible(driver)) {
- results[n] = subnode;
- n += 1;
- }
- }
- }
-
- return results[0..n];
-}
-
-fn nodeNameFilter(node: Node, name: []const u8) bool {
- var it = std.mem.splitScalar(u8, node.name, '@');
- const trueName = it.first();
- return std.mem.eql(u8, trueName, name);
-}
-
-fn parseNode(allocator: std.mem.Allocator, dt_struct_addr: usize, dt_strings: [*:0]const u8) !ParseResult(Node) {
- var props = std.StringHashMap([]const u8).init(allocator);
- var subnodes = std.ArrayList(Node).init(allocator);
-
- var addr = dt_struct_addr;
-
- // Skip Nop tokens
- while (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(addr)).*) == Header.token_nop) {
- addr += @sizeOf(u32);
- }
-
- if (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(addr)).*) != Header.token_begin_node) {
- return ParseError.ExpectedBeginNodeToken;
- }
-
- addr += @sizeOf(u32);
-
- const name: [*:0]u8 = @ptrFromInt(addr);
-
- addr += std.mem.len(name) + 1;
-
- // Skip zeroed alignment padding
- addr += (4 - ((std.mem.len(name) + 1) % 4)) % 4;
-
- while (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(addr)).*) != Header.token_end_node) {
- switch (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(addr)).*)) {
- Header.token_prop => {
- const parsed = try parseProperty(addr, dt_strings);
- addr = parsed.addr;
-
- const result = try props.getOrPut(parsed.value.name);
- if (result.found_existing) {
- return ParseError.DuplicateProperty;
- }
-
- result.value_ptr.* = parsed.value.value;
- },
- // Skip Nop tokens
- Header.token_nop => addr += @sizeOf(u32),
- Header.token_begin_node => {
- const parsed = try parseNode(allocator, addr, dt_strings);
- addr = parsed.addr;
- try subnodes.append(parsed.value);
- },
- else => return ParseError.BadToken,
- }
- }
-
- addr += @sizeOf(u32);
-
- return .{
- .addr = addr,
- .value = .{
- .name = std.mem.span(name),
- .props = props,
- .parent = null,
- .subnodes = subnodes,
- },
- };
-}
-
-fn parseProperty(dt_struct_addr: usize, dt_strings: [*:0]const u8) !ParseResult(Property) {
- var addr = dt_struct_addr;
-
- // Skip Nop tokens
- while (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(addr)).*) == Header.token_nop) {
- addr += @sizeOf(u32);
- }
-
- if (std.mem.bigToNative(u32, @as(*align(1) u32, @ptrFromInt(addr)).*) != Header.token_prop) {
- return ParseError.ExpectedPropToken;
- }
-
- addr += @sizeOf(u32);
-
- const desc = PropertyDesc.fromPtr(@ptrFromInt(addr));
-
- addr += @sizeOf(PropertyDesc);
-
- const name = dt_strings + desc.name_offset;
- const value_bytes: [*]u8 = @ptrFromInt(addr);
- const value: []const u8 = @ptrCast(value_bytes[0..desc.len]);
-
- addr += desc.len;
-
- // Skip zeroed alignment padding
- addr += (4 - (desc.len % 4)) % 4;
-
- return .{
- .addr = addr,
- .value = .{
- .name = std.mem.span(name),
- .value = value,
- },
- };
-}
-
-fn initParentPtrs(dt: *Tree) void {
- for (dt.nodes.items, 0..) |_, i| {
- for (dt.nodes.items[i].subnodes.items, 0..) |_, j| {
- initParentPtrsRecursive(&dt.nodes.items[i].subnodes.items[j], &dt.nodes.items[i]);
- }
- }
-}
-
-fn initParentPtrsRecursive(node: *Node, parent: *Node) void {
- node.parent = parent;
- for (node.subnodes.items, 0..) |_, i| {
- initParentPtrsRecursive(&node.subnodes.items[i], node);
- }
-}
diff --git a/src/hwi.zig b/src/hwi.zig
new file mode 100644
index 0000000..d5311ed
--- /dev/null
+++ b/src/hwi.zig
@@ -0,0 +1,21 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+
+const hwinfo = @import("lib/hwinfo.zig");
+
+pub fn main() !void {
+ const stdin = std.io.getStdIn();
+ const stdout = std.io.getStdOut();
+
+ const reader = stdin.reader();
+ const writer = stdout.writer();
+
+ var buf = [_]u8{0} ** 256;
+ while (try reader.readUntilDelimiterOrEof(&buf, '\n')) |line| {
+ const dev = try hwinfo.Dev.parse(line);
+ try writer.writeStruct(dev);
+ }
+}
diff --git a/src/main.zig b/src/kernel.zig
index 544e3a6..3f71c01 100644
--- a/src/main.zig
+++ b/src/kernel.zig
@@ -4,25 +4,23 @@
const std = @import("std");
-const Console = @import("Console.zig");
-const fdt = @import("fdt.zig");
-const instructions = @import("instructions.zig");
-const interrupts = @import("interrupts.zig");
-const mem = @import("mem.zig");
-const paging = @import("paging.zig");
-const pci = @import("pci.zig");
-const plic = @import("plic.zig");
-const process = @import("process.zig");
+const Console = @import("lib/Console.zig");
+const hwinfo = @import("lib/hwinfo.zig");
+const instructions = @import("lib/instructions.zig");
+const interrupts = @import("lib/interrupts.zig");
+const mem = @import("lib/mem.zig");
+const paging = @import("lib/paging.zig");
+const pci = @import("lib/pci.zig");
+const plic = @import("lib/plic.zig");
+const process = @import("lib/process.zig");
const Error = error{
HartIdOutOfRange,
- SuspiciousFdtAddr,
};
const HartData = packed struct(usize) {
hart_id: u16,
- fdt_blob: u32,
- reserved: u16,
+ reserved: u48,
pub inline fn loadSScratch() HartData {
return asm volatile (
@@ -75,29 +73,24 @@ export fn _start() callconv(.Naked) noreturn {
);
}
-fn kmain(hart_id: usize, fdt_blob: *fdt.RawHeader) noreturn {
- run(hart_id, fdt_blob) catch |err| std.debug.panic("Hart {d}: {any}", .{ hart_id, err });
+fn kmain(hart_id: usize, _: usize) noreturn {
+ run(hart_id) catch |err| std.debug.panic("Hart {d}: {any}", .{ hart_id, err });
}
-fn run(hart_id: usize, fdt_blob: *fdt.RawHeader) !noreturn {
+fn run(hart_id: usize) !noreturn {
if (hart_id > ~@as(u16, 0)) return Error.HartIdOutOfRange;
- if (@intFromPtr(fdt_blob) > std.math.maxInt(u32)) return Error.SuspiciousFdtAddr;
const hart_data = HartData{
.hart_id = @intCast(hart_id),
- .fdt_blob = @intCast(@intFromPtr(fdt_blob)),
.reserved = 0,
};
hart_data.storeSScratch();
paging.init();
- const dt_header = try fdt.Header.parse(fdt_blob);
-
const kmem: *paging.Table = @alignCast(@ptrCast(try paging.zeroedAlloc(1)));
try kmem.mapKernel();
- try kmem.mapFdt(&dt_header);
instructions.setSatp(kmem.satp(0));
@@ -135,7 +128,6 @@ fn pagedRun() !noreturn {
const hart_data = HartData.loadSScratch();
try w.print("Hart : {d}\r\n", .{hart_data.hart_id});
- try w.print("FDT address : 0x{x:0>8}\r\n", .{hart_data.fdt_blob});
try w.print("Paging : Sv39\r\n", .{});
@@ -148,10 +140,6 @@ fn pagedRun() !noreturn {
var chunk_allocator = try mem.ChunkAllocator(.{ .auto_merge_free = true }).init(128);
const allocator = chunk_allocator.allocator();
- const dt_header = try fdt.Header.parse(@ptrFromInt(hart_data.fdt_blob));
-
- fdt.default = try dt_header.parseTree(allocator);
-
try w.print("\r\n", .{});
try w.print("===================== Kernel Page Table =====================\r\n", .{});
try w.print(".text: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (r-x)\r\n", .{ @intFromPtr(paging.text_start), @intFromPtr(paging.text_end) });
@@ -164,39 +152,42 @@ fn pagedRun() !noreturn {
try w.print("Trap Stack: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.stvec_stack_start), @intFromPtr(paging.stvec_stack_end) });
try w.print("\r\n", .{});
try w.print("Heap: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (rw-)\r\n", .{ @intFromPtr(paging.heap_start), @intFromPtr(paging.heap_end) });
- try w.print("\r\n", .{});
- try w.print("FDT: 0x{x:0>8} - 0x{x:0>8} -> identity mapped (r--)\r\n", .{ hart_data.fdt_blob, hart_data.fdt_blob + dt_header.total_size });
try w.print("=============================================================\r\n", .{});
try w.print("\r\n", .{});
try w.print("Timer : {d} Hz\r\n", .{1 / (@as(f64, process.schedule_interval_millis) / 1000)});
- try plic.init(&fdt.default, allocator);
- try w.print("PLIC : Disabled\r\n", .{});
+ var plic_dev = hwinfo.byKind(.plic);
+ if (try plic_dev.next()) |plic_handle| {
+ _ = &plic_handle;
+ try w.print("PLIC : Disabled\r\n", .{});
+ } else {
+ try w.print("PLIC : Not present\r\n", .{});
+ }
try w.print("\r\n", .{});
- try w.print("Locate PCI MMIO\r\n", .{});
+ if (pci.controllerFromHwInfo()) |pci_controller| {
+ try w.print("\r\n", .{});
- const pci_controller = try pci.controllerFromFdt(&fdt.default);
+ for (0..256) |bus| {
+ for (0..32) |device| {
+ const cfg_space = pci_controller.cfgSpace(@intCast(bus), @intCast(device), 0);
+ const vendor_id = cfg_space.getVendorId();
+ const device_id = cfg_space.getDeviceId();
+ const class = cfg_space.getClass();
+ const subclass = cfg_space.getSubclass();
- try w.print("\r\n", .{});
-
- for (0..256) |bus| {
- for (0..32) |device| {
- const cfg_space = pci_controller.cfgSpace(@intCast(bus), @intCast(device), 0);
- const vendor_id = cfg_space.getVendorId();
- const device_id = cfg_space.getDeviceId();
- const class = cfg_space.getClass();
- const subclass = cfg_space.getSubclass();
-
- if (vendor_id != 0xffff) {
- try w.print("PCI {:0>3}.{:0>3}: Vendor = 0x{x:0>4}, Device = 0x{x:0>4}, Class = 0x{x:0>4}, Subclass = 0x{x:0>4}\r\n", .{ bus, device, vendor_id, device_id, class, subclass });
+ if (vendor_id != 0xffff) {
+ try w.print("PCI {:0>3}.{:0>3}: Vendor = 0x{x:0>4}, Device = 0x{x:0>4}, Class = 0x{x:0>4}, Subclass = 0x{x:0>4}\r\n", .{ bus, device, vendor_id, device_id, class, subclass });
+ }
}
}
- }
- try w.print("\r\n", .{});
+ try w.print("\r\n", .{});
+ } else {
+ try w.print("PCI not present\r\n", .{});
+ }
try w.print("Enter process demo\r\n", .{});
try process.demo(allocator);
diff --git a/src/Console.zig b/src/lib/Console.zig
index ad2249e..1e2920d 100644
--- a/src/Console.zig
+++ b/src/lib/Console.zig
@@ -5,9 +5,7 @@
const std = @import("std");
const debug_console = @import("sbi/debug_console.zig");
-const fdt = @import("fdt.zig");
const legacy = @import("sbi/legacy.zig");
-const paging = @import("paging.zig");
provider: Provider,
diff --git a/src/lib/cfg/platform/lpi4a.hwi b/src/lib/cfg/platform/lpi4a.hwi
new file mode 100644
index 0000000..cf57fc0
--- /dev/null
+++ b/src/lib/cfg/platform/lpi4a.hwi
Binary files differ
diff --git a/src/lib/cfg/platform/lpi4a.txt b/src/lib/cfg/platform/lpi4a.txt
new file mode 100644
index 0000000..6213698
--- /dev/null
+++ b/src/lib/cfg/platform/lpi4a.txt
@@ -0,0 +1,2 @@
+cpus 0 0 0x2dc6c0
+plic 0xffd8000000 0x4000000
diff --git a/src/lib/hwinfo.zig b/src/lib/hwinfo.zig
new file mode 100644
index 0000000..a2d6a5e
--- /dev/null
+++ b/src/lib/hwinfo.zig
@@ -0,0 +1,96 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const config = @import("config");
+const std = @import("std");
+
+const hw_info = @embedFile("cfg/platform/" ++ config.platform ++ ".hwi");
+//const devices: *[hw_info.len / @sizeOf(Dev)]Dev = @ptrCast(hw_info);
+const devices = std.io.FixedBufferStream([]const u8){ .buffer = hw_info, .pos = 0 };
+
+pub const ParseError = error{
+ MissingKind,
+ MissingRegAddr,
+ MissingRegLen,
+
+ UnknownDevKind,
+};
+
+pub const DevKind = enum(u32) {
+ cpus,
+ plic,
+ pcie,
+ pci,
+
+ pub fn parse(buf: []const u8) !DevKind {
+ if (std.mem.eql(u8, buf, "cpus")) {
+ return .cpus;
+ } else if (std.mem.eql(u8, buf, "plic")) {
+ return .plic;
+ } else if (std.mem.eql(u8, buf, "pcie")) {
+ return .pcie;
+ } else if (std.mem.eql(u8, buf, "pci")) {
+ return .pci;
+ }
+
+ return ParseError.UnknownDevKind;
+ }
+};
+
+pub const Dev = extern struct {
+ kind: DevKind,
+ reg: Reg,
+ value: u64,
+
+ pub fn parse(buf: []const u8) !Dev {
+ var columns = std.mem.tokenizeScalar(u8, buf, ' ');
+ const kind_buf = columns.next() orelse return ParseError.MissingKind;
+ const reg_addr_buf = columns.next() orelse return ParseError.MissingRegAddr;
+ const reg_len_buf = columns.next() orelse return ParseError.MissingRegLen;
+ const value_buf = columns.next() orelse "0";
+
+ return .{
+ .kind = try DevKind.parse(kind_buf),
+ .reg = .{
+ .addr = try std.fmt.parseUnsigned(u64, reg_addr_buf, 0),
+ .len = try std.fmt.parseUnsigned(u64, reg_len_buf, 0),
+ },
+ .value = try std.fmt.parseUnsigned(u64, value_buf, 0),
+ };
+ }
+};
+
+pub const Reg = extern struct {
+ addr: u64,
+ len: u64,
+
+ pub fn slice(self: Reg, comptime T: type) []volatile T {
+ const ptr: [*]volatile T = @ptrFromInt(self.addr);
+ return ptr[0 .. self.len / @sizeOf(T)];
+ }
+};
+
+pub const ByKind = struct {
+ kind: DevKind,
+ fbs: std.io.FixedBufferStream([]const u8),
+
+ pub fn next(it: *ByKind) !?Dev {
+ const reader = it.fbs.reader();
+ while (reader.readStruct(Dev)) |device| {
+ if (device.kind == it.kind) {
+ return device;
+ }
+ } else |_| {}
+
+ return null;
+ }
+
+ pub fn reset(it: *ByKind) !void {
+ try it.fbs.seekTo(0);
+ }
+};
+
+pub fn byKind(kind: DevKind) ByKind {
+ return .{ .kind = kind, .fbs = devices };
+}
diff --git a/src/instructions.zig b/src/lib/instructions.zig
index 2ae53ec..2ae53ec 100644
--- a/src/instructions.zig
+++ b/src/lib/instructions.zig
diff --git a/src/interrupts.zig b/src/lib/interrupts.zig
index de762d3..35a20d4 100644
--- a/src/interrupts.zig
+++ b/src/lib/interrupts.zig
@@ -299,7 +299,7 @@ export fn supervisorTrapVector() align(4) callconv(.Naked) noreturn {
fn schedule() !noreturn {
if (process.next()) |next| {
- try time.interruptInMillis(null, process.schedule_interval_millis);
+ try time.interruptInMillis(process.schedule_interval_millis);
process.switchTo(next);
}
diff --git a/src/mem.zig b/src/lib/mem.zig
index 639ac39..639ac39 100644
--- a/src/mem.zig
+++ b/src/lib/mem.zig
diff --git a/src/paging.zig b/src/lib/paging.zig
index 7268882..1e785e7 100644
--- a/src/paging.zig
+++ b/src/lib/paging.zig
@@ -5,7 +5,7 @@
// This is an implementation of Sv39 paging, meaning that the virtual addresses
// are 39 bits wide. Sv32 and Sv48 are currently not implemented.
-const fdt = @import("fdt.zig");
+const hwinfo = @import("hwinfo.zig");
// Defined by linker script.
pub const text_start = @extern(*anyopaque, .{ .name = "_text_start" });
@@ -440,25 +440,17 @@ pub const Table = struct {
try root.identityMapRange(@intFromPtr(heap_start), @intFromPtr(heap_end), EntryFlags.readWrite);
}
- pub fn mapFdt(root: *Table, dt_header: *const fdt.Header) !void {
- const fdt_blob = @intFromPtr(dt_header.raw_hdr);
- try root.identityMapRange(fdt_blob, fdt_blob + dt_header.total_size, EntryFlags.readOnly);
- }
-
- pub fn mapDevice(root: *Table, reg: fdt.Reg) !fdt.Reg {
+ pub fn mapDevice(root: *Table, reg: *hwinfo.Reg) !void {
const physical_start = reg.start & ~(page_size - 1);
const physical_end = (reg.start + reg.len - 1) & ~(page_size - 1);
- const offset = reg.start & (page_size - 1);
- const vaddr = next_mmio_vaddr | offset;
+ reg.addr = next_mmio_vaddr | (reg.start & (page_size - 1));
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;
}
-
- return .{ .start = vaddr, .len = reg.len };
}
};
diff --git a/src/pci.zig b/src/lib/pci.zig
index 7ee8f7b..7b862ee 100644
--- a/src/pci.zig
+++ b/src/lib/pci.zig
@@ -4,7 +4,7 @@
const std = @import("std");
-const fdt = @import("fdt.zig");
+const hwinfo = @import("hwinfo.zig");
pub const Error = error{
NoRootNode,
@@ -36,30 +36,20 @@ pub const Controller = union(CamType) {
};
pub const CamController = struct {
- register: []u8,
-
- fn init(register: []u8) CamController {
- return .{ .register = register };
- }
+ reg: []volatile u8,
pub fn cfgSpace(self: CamController, bus: u8, device: u5, function: u3) *volatile CfgSpace {
- const mmio_base = @intFromPtr(self.register.ptr);
+ const mmio_base = @intFromPtr(self.reg.ptr);
const addr = mmio_base + ((@as(usize, bus) * 0x100) + (@as(usize, device) * 0x08) + function) * 0x1000;
return @ptrFromInt(addr);
}
};
pub const EcamController = struct {
- register: []u8,
-
- fn init(register: []u8) EcamController {
- return .{
- .register = register,
- };
- }
+ reg: []volatile u8,
pub fn cfgSpace(self: EcamController, bus: u8, device: u5, function: u3) *volatile CfgSpace {
- const mmio_base = @intFromPtr(self.register.ptr);
+ const mmio_base = @intFromPtr(self.reg.ptr);
const addr = mmio_base + ((@as(usize, bus) * 0x100) + (@as(usize, device) * 0x08) + function) * 0x1000;
return @ptrFromInt(addr);
}
@@ -757,39 +747,15 @@ pub const CfgSpace = packed struct(u576) {
}
};
-pub fn controllerFromFdt(dt: *const fdt.Tree) !Controller {
- if (dt.nodes.items.len < 1) return Error.NoRootNode;
- const root = dt.nodes.items[0];
-
- const soc = fdt.findNodeExact(root.subnodes.items, "soc") orelse return Error.NoSoCnode;
- const address_cells_bytes = soc[1].props.get("#address-cells") orelse return Error.NoAddrCells;
- const size_cells_bytes = soc[1].props.get("#size-cells") orelse return Error.NoSizeCells;
-
- const address_cells = 16 * std.mem.readInt(u32, address_cells_bytes[0..4], .big);
- const size_cells = 16 * std.mem.readInt(u32, size_cells_bytes[0..4], .big);
-
- var results = fdt.findNode(soc[1].subnodes.items, "pci");
- const node = results.next() orelse return Error.NoPcinode;
- const unitAddr = try node.unitAddr() orelse return Error.NoUnitAddr;
-
- const reg = node.props.get("reg") orelse return Error.NoReg;
-
- const regSize = ((address_cells / 8) + (size_cells / 8));
- const n = reg.len / regSize;
-
- if (n < 1) return Error.NoReg;
-
- const ptr: [*]u8 = @ptrFromInt(unitAddr + std.mem.readVarInt(usize, reg[0..(address_cells / 8)], .big));
- const len = std.mem.readVarInt(usize, reg[(address_cells / 8) .. (size_cells / 8) + (address_cells / 8)], .big);
- const slice = ptr[0..len];
-
- const compatible = node.props.get("compatible") orelse return Error.NoCompatInfo;
+pub fn controllerFromHwInfo() ?Controller {
+ var pcie = hwinfo.byKind(.pcie);
+ var pci = hwinfo.byKind(.pci);
- if (std.mem.eql(u8, compatible, "pci-host-cam-generic\x00")) {
- return Controller{ .conventional = CamController.init(slice) };
- } else if (std.mem.eql(u8, compatible, "pci-host-ecam-generic\x00")) {
- return Controller{ .enhanced = EcamController.init(slice) };
+ if (try pcie.next()) |ecam| {
+ return Controller{ .enhanced = .{ .reg = ecam.reg.slice(u8) } };
+ } else if (try pci.next()) |cam| {
+ return Controller{ .conventional = .{ .reg = cam.reg.slice(u8) } };
} else {
- return Error.Incompatible;
+ return null;
}
}
diff --git a/src/plic.zig b/src/lib/plic.zig
index 302e76e..227b8b8 100644
--- a/src/plic.zig
+++ b/src/lib/plic.zig
@@ -4,7 +4,7 @@
const std = @import("std");
-const fdt = @import("fdt.zig");
+const hwinfo = @import("hwinfo.zig");
pub var default: Plic = undefined;
@@ -22,7 +22,7 @@ pub const Context = packed struct {
};
pub const Plic = struct {
- mmio_register: fdt.Reg,
+ mmio_register: hwinfo.Reg,
const priority_offset = 0x0;
const enable_offset = 0x2000;
@@ -84,15 +84,10 @@ pub const Plic = struct {
context_ptr.claim_or_complete = interrupt;
}
- fn mmioSlice(self: Plic) []volatile u8 {
- const mmio_ptr: [*]volatile u8 = @ptrFromInt(self.mmio_register.start);
- return mmio_ptr[0..self.mmio_register.len];
- }
-
fn contextPtr(self: Plic, context: u14) !*volatile Context {
if (context >= num_contexts) return Error.ContextOutOfRange;
- const mmio_slice = self.mmioSlice();
+ const mmio_slice = self.mmio_register.slice(u8);
if (context == 0) {
return @alignCast(@ptrCast(&mmio_slice[context_offset_zero]));
@@ -104,21 +99,3 @@ pub const Plic = struct {
}
}
};
-
-pub fn init(dt: *const fdt.Tree, allocator: std.mem.Allocator) !void {
- default = try fromFdt(dt, allocator);
-}
-
-fn fromFdt(dt: *const fdt.Tree, allocator: std.mem.Allocator) !Plic {
- const plic_node = fdt.findPath(dt, "/soc/plic") orelse return Error.NoPlic;
- if (!plic_node.isCompatible("riscv,plic0")) return Error.PlicIncompatible;
-
- const regs = try plic_node.reg(allocator);
- defer regs.deinit();
-
- if (regs.items.len == 0) return Error.NoPlicReg;
-
- return .{
- .mmio_register = regs.items[0],
- };
-}
diff --git a/src/process.zig b/src/lib/process.zig
index ff6018e..7b3e696 100644
--- a/src/process.zig
+++ b/src/lib/process.zig
@@ -4,7 +4,6 @@
const std = @import("std");
-const fdt = @import("fdt.zig");
const instructions = @import("instructions.zig");
const paging = @import("paging.zig");
const time = @import("sbi/time.zig");
@@ -68,7 +67,6 @@ fn new(entry: usize) !Info {
proc.trap_frame.general_purpose_registers[2] = stack_top;
try procmem.mapKernel();
- try procmem.mapFdt(fdt.default.header);
try procmem.map(entry, entry, paging.EntryFlags.userReadExec, 0);
// Not using identityMapRange because this is going to be expanded for non-relocatable binaries.
@@ -168,7 +166,7 @@ pub fn demo(allocator: std.mem.Allocator) !void {
proc_node.data = proc;
list.prepend(proc_node);
- try time.interruptInMillis(null, schedule_interval_millis);
+ try time.interruptInMillis(schedule_interval_millis);
try switchTo(&proc_node.data);
while (true) asm volatile ("wfi");
diff --git a/src/sbi.zig b/src/lib/sbi.zig
index 2072b90..2072b90 100644
--- a/src/sbi.zig
+++ b/src/lib/sbi.zig
diff --git a/src/sbi/debug_console.zig b/src/lib/sbi/debug_console.zig
index afd249f..afd249f 100644
--- a/src/sbi/debug_console.zig
+++ b/src/lib/sbi/debug_console.zig
diff --git a/src/sbi/legacy.zig b/src/lib/sbi/legacy.zig
index e544367..e544367 100644
--- a/src/sbi/legacy.zig
+++ b/src/lib/sbi/legacy.zig
diff --git a/src/sbi/sys_reset.zig b/src/lib/sbi/sys_reset.zig
index 5651fba..5651fba 100644
--- a/src/sbi/sys_reset.zig
+++ b/src/lib/sbi/sys_reset.zig
diff --git a/src/lib/sbi/time.zig b/src/lib/sbi/time.zig
new file mode 100644
index 0000000..2fad3e8
--- /dev/null
+++ b/src/lib/sbi/time.zig
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+
+const std = @import("std");
+
+const hwinfo = @import("../hwinfo.zig");
+const instructions = @import("../instructions.zig");
+const sbi = @import("../sbi.zig");
+
+const ExtId: usize = 0x54494d45;
+
+const FnId = enum(usize) {
+ SetTimer = 0,
+};
+
+pub const Error = error{
+ NoCpusHwInfo,
+};
+
+pub fn setTimer(stime_absolute: u64) !void {
+ if (!try sbi.probeExt(ExtId)) return sbi.Error.NotSupported;
+
+ const ret = instructions.ecall(ExtId, @intFromEnum(FnId.SetTimer), stime_absolute, 0, 0);
+ if (ret.err != 0) return sbi.errorFromCode(ret.err);
+}
+
+pub fn interruptInMillis(millis: u64) !void {
+ const stime = asm volatile (
+ \\ csrr %[stime], time
+ : [stime] "=r" (-> u64),
+ );
+
+ var cpus = hwinfo.byKind(.cpus);
+ const frequency = try cpus.next() orelse return error.NoCpusHwInfo;
+ const cycles = frequency.value / 1000 * millis;
+
+ try setTimer(stime + cycles);
+}
diff --git a/src/syscall.zig b/src/lib/syscall.zig
index 692507e..692507e 100644
--- a/src/syscall.zig
+++ b/src/lib/syscall.zig
diff --git a/src/trap.zig b/src/lib/trap.zig
index 4460cfd..4460cfd 100644
--- a/src/trap.zig
+++ b/src/lib/trap.zig
diff --git a/src/sbi/time.zig b/src/sbi/time.zig
deleted file mode 100644
index 4700191..0000000
--- a/src/sbi/time.zig
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
-//
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-const std = @import("std");
-
-const fdt = @import("../fdt.zig");
-const instructions = @import("../instructions.zig");
-const sbi = @import("../sbi.zig");
-
-const ExtId: usize = 0x54494d45;
-
-const FnId = enum(usize) {
- SetTimer = 0,
-};
-
-pub const Error = error{
- NoCpusNode,
- NoTimebaseFrequencyProp,
- TimebaseFrequencyPropTooShort,
-};
-
-pub fn setTimer(stime_absolute: u64) !void {
- if (!try sbi.probeExt(ExtId)) return sbi.Error.NotSupported;
-
- const ret = instructions.ecall(ExtId, @intFromEnum(FnId.SetTimer), stime_absolute, 0, 0);
- if (ret.err != 0) return sbi.errorFromCode(ret.err);
-}
-
-pub fn interruptInMillis(dt: ?*const fdt.Tree, millis: u64) !void {
- const stime = asm volatile (
- \\ csrr %[stime], time
- : [stime] "=r" (-> u64),
- );
-
- const cpus = fdt.findPathExact(dt orelse &fdt.default, "/cpus") orelse return Error.NoCpusNode;
- const frequency_prop = cpus.props.get("timebase-frequency") orelse return Error.NoTimebaseFrequencyProp;
-
- var frequency: u64 = undefined;
- if (frequency_prop.len >= @sizeOf(u64)) {
- frequency = std.mem.readInt(u64, frequency_prop[0..@sizeOf(u64)], .big);
- } else if (frequency_prop.len >= @sizeOf(u32)) {
- frequency = std.mem.readInt(u32, frequency_prop[0..@sizeOf(u32)], .big);
- } else return Error.TimebaseFrequencyPropTooShort;
-
- const cycles = frequency / 1000 * millis;
-
- try setTimer(stime + cycles);
-}
diff --git a/src/slice.zig b/src/slice.zig
deleted file mode 100644
index 1e4a095..0000000
--- a/src/slice.zig
+++ /dev/null
@@ -1,47 +0,0 @@
-// SPDX-FileCopyrightText: 2024 Himbeer <himbeer@disroot.org>
-//
-// SPDX-License-Identifier: AGPL-3.0-or-later
-
-pub fn Filter(comptime T: type, comptime U: type) type {
- return struct {
- pub const Predicate = *const fn (T, U) bool;
-
- buffer: []const T,
- index: ?usize,
- predicate: Predicate,
- matcher: U,
-
- const Self = @This();
-
- pub fn new(buffer: []const T, predicate: Predicate, matcher: U) Self {
- return .{
- .buffer = buffer,
- .index = 0,
- .predicate = predicate,
- .matcher = matcher,
- };
- }
-
- pub fn next(self: *Self) ?T {
- const start = self.index orelse return null;
-
- const index = for (self.buffer[start..], 0..) |elem, skipped| {
- if (self.predicate(elem, self.matcher)) {
- break start + skipped;
- }
- } else null;
-
- if (index) |i| {
- self.index = if (1 + i < self.buffer.len) 1 + i else null;
- return self.buffer[i];
- }
-
- self.index = null;
- return null;
- }
-
- pub fn reset(self: *Self) void {
- self.index = 0;
- }
- };
-}