aboutsummaryrefslogtreecommitdiff
path: root/src/hwinfo.zig
blob: 81fc4cc621dd949f697f6ce57804fbf3a33de0c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 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 = 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 fn isUserManagable(self: DevKind) bool {
        return switch (self) {
            .pcie, .pci => true,
            else => false,
        };
    }
};

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);
}