blob: 7e86275d4e24688684cc72acebac6d5e63af9c79 [file] [log] [blame]
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/ddk/platform-defs.h>
#include <lib/driver_test_realm/src/boot_items.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zbi-format/board.h>
#include <lib/zbi-format/zbi.h>
#include <zircon/rights.h>
#include <ddk/metadata/test.h>
namespace driver_test_realm {
namespace {
// This board driver knows how to interpret the metadata for which devices to
// spawn.
const zbi_platform_id_t kPlatformId = []() {
zbi_platform_id_t plat_id = {};
plat_id.vid = PDEV_VID_TEST;
plat_id.pid = PDEV_PID_PBUS_TEST;
strcpy(plat_id.board_name, "driver-integration-test");
return plat_id;
}();
#define BOARD_REVISION_TEST 42
const zbi_board_info_t kBoardInfo = []() {
zbi_board_info_t board_info = {};
board_info.revision = BOARD_REVISION_TEST;
return board_info;
}();
// This function is responsible for serializing driver data. It must be kept
// updated with the function that deserialized the data. This function
// is TestBoard::FetchAndDeserialize.
zx_status_t GetBootItem(const std::vector<board_test::DeviceEntry>& entries, uint32_t type,
const std::string& board_name, const std::optional<uint32_t>& vid,
const std::optional<uint32_t>& pid, const zx::vmo& devicetree,
uint32_t extra, zx::vmo* out, uint32_t* length) {
zx::vmo vmo;
switch (type) {
case ZBI_TYPE_PLATFORM_ID: {
zbi_platform_id_t platform_id = kPlatformId;
if (!board_name.empty()) {
strncpy(platform_id.board_name, board_name.c_str(), ZBI_BOARD_NAME_LEN - 1);
}
if (vid.has_value()) {
platform_id.vid = vid.value();
}
if (pid.has_value()) {
platform_id.pid = pid.value();
}
zx_status_t status = zx::vmo::create(sizeof(kPlatformId), 0, &vmo);
if (status != ZX_OK) {
return status;
}
status = vmo.write(&platform_id, 0, sizeof(kPlatformId));
if (status != ZX_OK) {
return status;
}
*length = sizeof(kPlatformId);
break;
}
case ZBI_TYPE_DRV_BOARD_INFO: {
zx_status_t status = zx::vmo::create(sizeof(kBoardInfo), 0, &vmo);
if (status != ZX_OK) {
return status;
}
status = vmo.write(&kBoardInfo, 0, sizeof(kBoardInfo));
if (status != ZX_OK) {
return status;
}
*length = sizeof(kBoardInfo);
break;
}
case ZBI_TYPE_DRV_BOARD_PRIVATE: {
size_t list_size = sizeof(board_test::DeviceList);
size_t entry_size = entries.size() * sizeof(board_test::DeviceEntry);
size_t metadata_size = 0;
for (const board_test::DeviceEntry& entry : entries) {
metadata_size += entry.metadata_size;
}
zx_status_t status = zx::vmo::create(list_size + entry_size + metadata_size, 0, &vmo);
if (status != ZX_OK) {
return status;
}
// Write DeviceList to vmo.
board_test::DeviceList list{.count = entries.size()};
status = vmo.write(&list, 0, sizeof(list));
if (status != ZX_OK) {
return status;
}
// Write DeviceEntries to vmo.
status = vmo.write(entries.data(), list_size, entry_size);
if (status != ZX_OK) {
return status;
}
// Write Metadata to vmo.
size_t write_offset = list_size + entry_size;
for (const board_test::DeviceEntry& entry : entries) {
status = vmo.write(entry.metadata, write_offset, entry.metadata_size);
if (status != ZX_OK) {
return status;
}
write_offset += entry.metadata_size;
}
*length = static_cast<uint32_t>(list_size + entry_size + metadata_size);
break;
}
case ZBI_TYPE_DEVICETREE: {
zx_status_t status = devicetree.duplicate(ZX_RIGHT_SAME_RIGHTS, &vmo);
if (status != ZX_OK) {
return status;
}
uint64_t length64;
status = devicetree.get_size(&length64);
if (status != ZX_OK) {
return status;
}
*length = static_cast<uint32_t>(length64);
break;
}
default:
return ZX_ERR_NOT_FOUND;
}
*out = std::move(vmo);
return ZX_OK;
}
} // namespace
void BootItems::SetBoardName(std::string_view board_name) { board_name_ = std::string(board_name); }
void BootItems::SetDeviceTree(zx::vmo devicetree) { devicetree_ = std::move(devicetree); }
void BootItems::SetVid(uint32_t vid) { vid_ = vid; }
void BootItems::SetPid(uint32_t pid) { pid_ = pid; }
zx::result<> BootItems::Serve(async_dispatcher_t* dispatcher,
fidl::ServerEnd<fuchsia_boot::Items> server_end,
bool tunnel_to_incoming) {
if (tunnel_to_incoming) {
return component::Connect<fuchsia_boot::Items>(std::move(server_end));
}
bindings_.AddBinding(dispatcher, std::move(server_end), this, fidl::kIgnoreBindingClosure);
return zx::ok();
}
void BootItems::Get(GetRequestView request, GetCompleter::Sync& completer) {
zx::vmo vmo;
uint32_t length = 0;
std::vector<board_test::DeviceEntry> entries = {};
zx_status_t status = GetBootItem(entries, request->type, board_name_, vid_, pid_, devicetree_,
request->extra, &vmo, &length);
if (status != ZX_OK) {
FX_LOG_KV(WARNING, "Failed to get boot items", FX_KV("status", status));
}
completer.Reply(std::move(vmo), length);
}
void BootItems::Get2(Get2RequestView request, Get2Completer::Sync& completer) {
std::vector<board_test::DeviceEntry> entries = {};
zx::vmo vmo;
uint32_t length = 0;
uint32_t extra = 0;
zx_status_t status = GetBootItem(entries, request->type, board_name_, vid_, pid_, devicetree_,
extra, &vmo, &length);
if (status != ZX_OK) {
FX_LOG_KV(WARNING, "Failed to get boot items", FX_KV("status", status));
completer.Reply(zx::error(status));
return;
}
std::vector<fuchsia_boot::wire::RetrievedItems> result;
fuchsia_boot::wire::RetrievedItems items = {
.payload = std::move(vmo), .length = length, .extra = extra};
result.emplace_back(std::move(items));
completer.ReplySuccess(
fidl::VectorView<fuchsia_boot::wire::RetrievedItems>::FromExternal(result));
}
void BootItems::GetBootloaderFile(GetBootloaderFileRequestView request,
GetBootloaderFileCompleter::Sync& completer) {
completer.Reply(zx::vmo());
}
} // namespace driver_test_realm