// SPDX-FileCopyrightText: 2024 Himbeer // // 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 = 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, stream: std.io.FixedBufferStream([]const u8), big_endian: bool, pub fn init(kind: DevKind, stream: std.io.FixedBufferStream([]const u8)) !ByKind { var fbs = stream; const endian = try fbs.reader().readByte(); return .{ .kind = kind, .stream = fbs, .big_endian = endian != 0 }; } pub fn next(it: *ByKind) !?Dev { const endian: std.builtin.Endian = if (it.big_endian) .big else .little; const reader = it.stream.reader(); while (reader.readStructEndian(Dev, endian)) |device| { if (device.kind == it.kind) return device; } else |err| return err; return null; } pub fn reset(it: *ByKind) !void { try it.stream.seekTo(1); } }; pub fn byKind(kind: DevKind) !ByKind { return ByKind.init(kind, devices); }