blob: d6ce18c951f3978ae536c40dfe3a32e1c37a1a9a [file] [log] [blame]
// Copyright 2020 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 "zbi-test-entry.h"
#include <lib/standalone-test/standalone.h>
#include <lib/zbitl/error-stdio.h>
#include <lib/zbitl/items/bootfs.h>
#include <lib/zbitl/view.h>
#include <lib/zbitl/vmo.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <stdio.h>
#include <zircon/status.h>
#include <zircon/syscalls/resource.h>
#include <cstddef>
#include <string_view>
#include <src/bringup/lib/mexec/mexec.h>
constexpr const char* kMexecZbi = "testdata/mexec-child.zbi";
namespace {
// The bootfs VFS (rooted under '/boot') is hosted by component manager. These tests can be started
// directly from userboot without starting component manager, so the bootfs VFS will not be
// available. Instead, we can just read any files needed directly from the uncompressed bootfs VMO.
zx_status_t GetFileFromBootfs(std::string_view path, zbitl::MapUnownedVmo bootfs, zx::vmo* vmo) {
using Bootfs = zbitl::Bootfs<zbitl::MapUnownedVmo>;
Bootfs reader;
if (auto result = Bootfs::Create(std::move(bootfs)); result.is_error()) {
zbitl::PrintBootfsError(result.error_value());
return ZX_ERR_INTERNAL;
} else {
reader = std::move(result).value();
}
auto view = reader.root();
auto file = view.find(path);
if (auto result = view.take_error(); result.is_error()) {
zbitl::PrintBootfsError(result.error_value());
return ZX_ERR_INTERNAL;
}
if (file == view.end()) {
return ZX_ERR_NOT_FOUND;
}
return reader.storage().vmo().create_child(ZX_VMO_CHILD_SNAPSHOT | ZX_VMO_CHILD_NO_WRITE,
file->offset, file->size, vmo);
}
} // namespace
zx::result<> ZbiTestEntry::Init(int argc, char** argv) {
ZX_ASSERT(argc > 0);
const char* program_name = argv[0];
zx::unowned_vmo bootfs(standalone::GetVmo("uncompressed-bootfs"));
if (!bootfs->is_valid()) {
printf("%s: received an invalid bootfs VMO handle\n", program_name);
return zx::error(ZX_ERR_INTERNAL);
}
{
zx::vmo vmo;
zbitl::MapUnownedVmo unowned_bootfs(bootfs->borrow());
if (zx_status_t status = GetFileFromBootfs(kMexecZbi, unowned_bootfs, &vmo); status != ZX_OK) {
printf("%s: failed to get child ZBI's VMO: %s\n", program_name, zx_status_get_string(status));
return zx::error(status);
}
zbitl::View view(std::move(vmo));
if (view.begin() == view.end()) {
if (auto result = view.take_error(); result.is_error()) {
printf("%s: invalid child ZBI: ", program_name);
zbitl::PrintViewError(result.error_value());
} else {
printf("%s: empty child ZBI\n", program_name);
}
return zx::error(ZX_ERR_INTERNAL);
}
auto first = view.begin();
auto second = std::next(first);
if (auto result = view.Copy(first, second); result.is_error()) {
printf("%s: failed to copy out kernel payload: ", program_name);
zbitl::PrintViewCopyError(result.error_value());
view.ignore_error();
return zx::error(ZX_ERR_INTERNAL);
} else {
kernel_zbi_ = std::move(result).value();
}
// Ensure that the data ZBI is resizable, as it wil be extended in
// `mexec::PrepareDataZbi()` below.
if (zx_status_t status = zx::vmo::create(0u, ZX_VMO_RESIZABLE, &data_zbi_); status != ZX_OK) {
return zx::error{status};
}
if (auto result = view.Copy(data_zbi_, second, view.end()); result.is_error()) {
printf("%s: failed to copy out data ZBI: ", program_name);
zbitl::PrintViewCopyError(result.error_value());
view.ignore_error();
return zx::error(ZX_ERR_INTERNAL);
}
if (auto result = view.take_error(); result.is_error()) {
printf("%s: ZBI iteration failure: ", program_name);
zbitl::PrintViewError(result.error_value());
return zx::error(ZX_ERR_INTERNAL);
}
}
zx_status_t status =
zx::resource::create(*standalone::GetSystemResource(), ZX_RSRC_KIND_SYSTEM,
ZX_RSRC_SYSTEM_MEXEC_BASE, 1, nullptr, 0, &mexec_resource_);
if (status != ZX_OK || !mexec_resource_.is_valid()) {
printf("%s: unable to get ahold of the mexec resource\n", program_name);
return zx::error(ZX_ERR_INTERNAL);
}
status = mexec::PrepareDataZbi(mexec_resource_.borrow(), data_zbi_.borrow());
if (status != ZX_OK) {
printf("%s: failed to prepare data ZBI: %s\n", program_name, zx_status_get_string(status));
return zx::error(status);
}
return zx::ok();
}