aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHimbeer <himbeer@disroot.org>2024-05-23 13:48:01 +0200
committerHimbeer <himbeer@disroot.org>2024-05-23 13:48:01 +0200
commit3274a700daff545437f919041cbdce6938eede06 (patch)
tree60a4ec5ebb1406af20733027a2bb4a5d54e54908
parent0f61d3bed969fecb35e438bfac2fe34f588834c6 (diff)
Drop FDT support in favor of custom HWI format
Fixes numerous parsing bugs and increases efficiency. The kernel now runs successfully on the Lichee Pi 4A.
-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;
- }
- };
-}