diff options
-rw-r--r-- | build.zig | 11 | ||||
-rw-r--r-- | src/fdt.zig | 438 | ||||
-rw-r--r-- | src/hwi.zig | 21 | ||||
-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.hwi | bin | 0 -> 64 bytes | |||
-rw-r--r-- | src/lib/cfg/platform/lpi4a.txt | 2 | ||||
-rw-r--r-- | src/lib/hwinfo.zig | 96 | ||||
-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.zig | 39 | ||||
-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.zig | 49 | ||||
-rw-r--r-- | src/slice.zig | 47 |
24 files changed, 225 insertions, 670 deletions
@@ -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 Binary files differnew file mode 100644 index 0000000..cf57fc0 --- /dev/null +++ b/src/lib/cfg/platform/lpi4a.hwi 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; - } - }; -} |