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