blob: 8a31549480a539da52e69b617236c4a39d033b49 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/boot-shim-utils/devicetree-bootloader-files-item.h>
void DevicetreeBootloaderFilesItem::SetScratchBuffer(std::span<std::byte> buffer) {
if (reinterpret_cast<size_t>(buffer.data()) % ZBI_ALIGNMENT) {
fprintf(stdout,
"Bootloader file buffer is not aligned to ZBI_ALIGNMENT. Files will not append.\n");
return;
}
files_ = zbitl::Image<std::span<std::byte>>(buffer);
if (auto result = files_.clear(); result.is_error()) {
fprintf(stdout, "Failed to initialize ZBI files container: %s\n",
result.error_value().zbi_error.data());
}
}
devicetree::ScanState DevicetreeBootloaderFilesItem::OnNode(
const devicetree::NodePath& path, const devicetree::PropertyDecoder& decoder) {
const char kRootPath[] = "/chosen/google/bootloader-files/";
switch (path.CompareWith(kRootPath)) {
// If this is in a parent node, continues searching the sub tree.
case devicetree::NodePath::Comparison::kParent:
case devicetree::NodePath::Comparison::kIndirectAncestor:
case devicetree::NodePath::Comparison::kEqual:
return devicetree::ScanState::kActive;
// If this is in a different sub tree, don't visit it any further.
case devicetree::NodePath::Comparison::kMismatch:
case devicetree::NodePath::Comparison::kIndirectDescendent:
return devicetree::ScanState::kDoneWithSubtree;
// If this is a direct child, collects the ZBI bootloader file.
case devicetree::NodePath::Comparison::kChild:
break;
};
// Extracts file name.
auto name = decoder.FindAndDecodeProperty<&devicetree::PropertyValue::AsString>("id");
if (!name) {
fprintf(stdout, "File has no `id` property. Skips.\n");
return devicetree::ScanState::kActive;
} else if (name->size() > std::numeric_limits<uint8_t>::max()) {
fprintf(stdout, "Name length oveflows uint8_t max\n");
return devicetree::ScanState::kActive;
}
// Extracts file payload.
auto data = decoder.FindProperty("data");
if (!data) {
fprintf(stdout, "File has no `data` property. Skips.\n");
return devicetree::ScanState::kActive;
}
auto payload = data->AsBytes();
size_t total = 1 + name->size() + payload.size();
if (total < payload.size()) {
fprintf(stdout, "Payload size overflows. Skips.\n");
return devicetree::ScanState::kActive;
}
// Collects the ZBI bootloader file.
auto result = files_.Append({
.type = ZBI_TYPE_BOOTLOADER_FILE,
.length = static_cast<uint32_t>(total),
.extra = 0,
.flags = 0,
.magic = ZBI_ITEM_MAGIC,
});
if (result.is_error()) {
fprintf(stdout, "Failed to append ZBI bootloader file %s: %s\n", name->data(),
result.error_value().zbi_error.data());
return devicetree::ScanState::kActive;
}
// name->size() already checked to fit within uint8_t above.
result->payload[0] = static_cast<std::byte>(name->size());
memcpy(result->payload.data() + 1, name->data(), name->size());
memcpy(result->payload.data() + 1 + name->size(), payload.data(), payload.size());
return devicetree::ScanState::kActive;
}
fit::result<DevicetreeBootloaderFilesItem::DataZbi::Error>
DevicetreeBootloaderFilesItem::AppendItems(DataZbi& zbi) const {
if (files_.storage().empty()) {
return fit::ok();
}
auto zbi_view = zbitl::View(files_.storage());
for (auto [header, payload] : zbi_view) {
if (auto result = zbi.Append(*header, payload); result.is_error()) {
fprintf(stdout, "Failed to append: %s\n", result.error_value().zbi_error.data());
return result.take_error();
}
}
return zbi_view.take_error();
}