blob: 3bfebd1b1035e2260a00ec232368ff289853608a [file] [log] [blame]
// Copyright 2026 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 "include/lib/mexec_boot/mexec_boot.h"
#include <fidl/fuchsia.boot/cpp/wire.h>
#include <fidl/fuchsia.system.state/cpp/wire.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/zbi-format/zbi.h>
#include <lib/zbitl/error-string.h>
#include <lib/zbitl/image.h>
#include <lib/zbitl/item.h>
#include <lib/zbitl/vmo.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <zircon/status.h>
#include <src/bringup/lib/mexec/mexec.h>
#include <src/lib/fsl/vmo/sized_vmo.h>
#include <src/lib/fsl/vmo/vector.h>
namespace {
struct MexecVmos {
zx::vmo kernel_zbi;
zx::vmo data_zbi;
};
zx::result<MexecVmos> GetMexecZbis(zx::unowned_resource mexec_resource) {
zx::result client_end = component::Connect<fuchsia_system_state::SystemStateTransition>();
if (client_end.is_error()) {
return client_end.take_error();
}
fidl::WireSyncClient client(std::move(*client_end));
fidl::WireResult result = client->GetMexecZbis();
if (!result.ok()) {
return zx::error(result.status());
}
if (result.value().is_error()) {
return result.value().take_error();
}
zx::vmo kernel_zbi = std::move(result.value().value()->kernel_zbi);
zx::vmo data_zbi = std::move(result.value().value()->data_zbi);
if (zx_status_t status = mexec::PrepareDataZbi(mexec_resource->borrow(), data_zbi.borrow());
status != ZX_OK) {
return zx::error(status);
}
zx::result connect_result = component::Connect<fuchsia_boot::Items>();
if (connect_result.is_error()) {
return connect_result.take_error();
}
fidl::WireSyncClient<fuchsia_boot::Items> items(std::move(connect_result).value());
// Driver metadata that the driver framework generally expects to be present.
constexpr std::array kItemsToAppend{ZBI_TYPE_DRV_MAC_ADDRESS, ZBI_TYPE_DRV_PARTITION_MAP,
ZBI_TYPE_DRV_BOARD_PRIVATE, ZBI_TYPE_DRV_BOARD_INFO};
zbitl::Image data_image{data_zbi.borrow()};
for (uint32_t type : kItemsToAppend) {
// TODO(https://fxbug.dev/42053781): Use a method that returns all matching items of
// a given type instead of guessing possible `extra` values.
for (uint32_t extra : std::array{0, 1, 2}) {
fidl::WireResult result = items->Get(type, extra);
if (!result.ok()) {
return zx::error(result.status());
}
if (!result.value().payload.is_valid()) {
// Absence is signified with an empty result value.
continue;
}
fsl::SizedVmo payload(std::move(result.value().payload), result.value().length);
std::vector<char> contents;
if (!fsl::VectorFromVmo(payload, &contents)) {
return zx::error(ZX_ERR_INTERNAL);
}
if (fit::result result = data_image.Append(zbi_header_t{.type = type, .extra = extra},
zbitl::AsBytes(contents));
result.is_error()) {
return zx::error(ZX_ERR_INTERNAL);
}
}
}
return zx::ok(MexecVmos{
.kernel_zbi = std::move(kernel_zbi),
.data_zbi = std::move(data_zbi),
});
}
} // namespace
extern "C" zx_status_t mexec_boot(zx_handle_t mexec_resource_handle) {
zx::unowned_resource mexec_resource(mexec_resource_handle);
zx::result<MexecVmos> mexec_vmos = GetMexecZbis(mexec_resource->borrow());
if (mexec_vmos.is_error()) {
return mexec_vmos.status_value();
}
zx_status_t status = mexec::BootZbi(std::move(mexec_resource), std::move(mexec_vmos->kernel_zbi),
std::move(mexec_vmos->data_zbi));
return status;
}