Skip to content

Commit

Permalink
use dtb Traverser
Browse files Browse the repository at this point in the history
  • Loading branch information
kivikakk committed Feb 12, 2021
1 parent ce94c12 commit e33551d
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 24 deletions.
28 changes: 5 additions & 23 deletions dainboot/src/dainboot.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const uefi = std.os.uefi;
const build_options = @import("build_options");
const elf = @import("elf.zig");
const dtblib = @import("dtb");
const searchDtbForUartBase = @import("dtb.zig").searchDtbForUartBase;

usingnamespace @import("util.zig");

Expand Down Expand Up @@ -331,29 +332,10 @@ fn exitBootServices(dainkrnl: []const u8, dtb: []const u8) noreturn {

printf("framebuffer is at {*}\r\n", .{fb});
printf("looking up serial base in DTB ... ", .{});
var uart_base: u64 = 0;
dtb: {
var fba = std.heap.FixedBufferAllocator.init(dtb_scratch);
var root = dtblib.parse(&fba.allocator, dtb) catch |err| {
printf("failed to parse dtb: {}", .{err});
break :dtb;
};

// try pl011, or a serial that doesn't have a 'bluetooth' node.
for (root.children) |child| {
if (std.mem.startsWith(u8, child.name, "pl011@")) {
// YOU'LL DO
uart_base = @truncate(u64, child.prop(.Reg).?[0][0]);
break :dtb;
} else if (std.mem.startsWith(u8, child.name, "serial@")) {
if (child.child("bluetooth") == null and child.prop(.Status).? == .Okay) {
uart_base = @truncate(u64, child.prop(.Reg).?[0][0]);
break :dtb;
}
}
}
}

var uart_base: u64 = searchDtbForUartBase(dtb) catch |err| dtb: {
printf("failed to parse dtb: {}", .{err});
break :dtb 0;
};
printf("0x{x:0>8}\r\n", .{uart_base});

printf("exiting boot services\r\n", .{});
Expand Down
103 changes: 103 additions & 0 deletions dainboot/src/dtb.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const std = @import("std");
const dtblib = @import("dtb");

const Error = dtblib.Error || error{UartNotFound};

pub fn searchDtbForUartBase(dtb: []const u8) Error!u64 {
var traverser: dtblib.Traverser = undefined;
try traverser.init(dtb);

var state: union(enum) { Root, Irrelevant: u8, Pl011, Serial } = .Root;
var address_cells: ?u32 = null;
var size_cells: ?u32 = null;
var serial_value: ?u64 = null;

// try pl011, or a serial that doesn't have a 'bluetooth' node.

// skip root node
var ev = try traverser.next();
while (ev != .End) : (ev = try traverser.next()) {
switch (state) {
.Root => switch (ev) {
.BeginNode => |name| {
if (std.mem.startsWith(u8, name, "pl011@")) {
state = .Pl011;
} else if (std.mem.startsWith(u8, name, "serial@")) {
serial_value = null;
state = .Serial;
} else {
state = .{ .Irrelevant = 0 };
}
},
.Prop => |prop| {
if (std.mem.eql(u8, prop.name, "#address-cells")) {
address_cells = std.mem.bigToNative(u32, @ptrCast(*const u32, @alignCast(@alignOf(u32), prop.value.ptr)).*);
} else if (std.mem.eql(u8, prop.name, "#size-cells")) {
size_cells = std.mem.bigToNative(u32, @ptrCast(*const u32, @alignCast(@alignOf(u32), prop.value.ptr)).*);
}
},
else => {},
},
.Irrelevant => |*depth| switch (ev) {
.BeginNode => {
depth.* += 1;
},
.EndNode => {
if (depth.* == 0) {
state = .Root;
} else {
depth.* -= 1;
}
},
else => {},
},
.Pl011 => switch (ev) {
.Prop => |prop| {
if (std.mem.eql(u8, prop.name, "reg") and address_cells != null and size_cells != null) {
return try firstReg(address_cells.?, prop.value);
}
},
.BeginNode => state = .{ .Irrelevant = 1 },
.EndNode => state = .Root,
else => {},
},
.Serial => switch (ev) {
.Prop => |prop| {
if (std.mem.eql(u8, prop.name, "reg") and address_cells != null and size_cells != null) {
serial_value = try firstReg(address_cells.?, prop.value);
} else if (std.mem.eql(u8, prop.name, "status")) {
if (!std.mem.eql(u8, "okay\x00", prop.value)) {
state = .{ .Irrelevant = 0 };
}
}
},
.BeginNode => {
// Don't want any serial with a subnode.
state = .{ .Irrelevant = 1 };
},
.EndNode => {
if (serial_value) |made_it| {
return made_it;
}
state = .Root;
},
else => {},
},
}
}

return error.UartNotFound;
}

fn firstReg(address_cells: u32, value: []const u8) !u64 {
if (value.len % @sizeOf(u32) != 0) {
return error.BadStructure;
}
var big_endian_cells: []const u32 = @ptrCast([*]const u32, @alignCast(@alignOf(u32), value.ptr))[0 .. value.len / @sizeOf(u32)];
if (address_cells == 1) {
return std.mem.bigToNative(u32, big_endian_cells[0]);
} else if (address_cells == 2) {
return @as(u64, std.mem.bigToNative(u32, big_endian_cells[0])) << 32 | std.mem.bigToNative(u32, big_endian_cells[1]);
}
return error.UnsupportedCells;
}
2 changes: 1 addition & 1 deletion dtb
Submodule dtb updated 6 files
+31 −0 README.md
+29 −0 src/dtb.zig
+30 −0 src/fdt.zig
+77 −181 src/parser.zig
+183 −0 src/traverser.zig
+9 −0 src/util.zig

0 comments on commit e33551d

Please sign in to comment.