blob: aad9e7b9995030ddef7e47c1059710a0b60a026d [file] [log] [blame]
// Copyright 2016 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 "bootfs.h"
#include <lib/zbitl/error-stdio.h>
#include <lib/zircon-internal/align.h>
#include <lib/zx/vmo.h>
#include <stdarg.h>
#include <zircon/rights.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/log.h>
#include <zircon/types.h>
#include "util.h"
zx::vmo Bootfs::Open(std::string_view root, std::string_view filename, std::string_view purpose) {
printl(log_, "searching BOOTFS for '%.*s%s%.*s' (%.*s)", //
static_cast<int>(root.size()), root.data(), //
root.empty() ? "" : "/", //
static_cast<int>(filename.size()), filename.data(), //
static_cast<int>(purpose.size()), purpose.data());
BootfsView bootfs = bootfs_reader_.root();
auto it = root.empty() ? bootfs.find(filename) : bootfs.find({root, filename});
if (auto result = bootfs.take_error(); result.is_error()) {
Fail(result.error_value());
}
if (it == bootfs.end()) {
printl(log_, "failed to find '%.*s%s%.*s'", //
static_cast<int>(root.size()), root.data(), //
root.empty() ? "" : "/", //
static_cast<int>(filename.size()), filename.data());
return {};
}
zx::vmo file_vmo;
zx_status_t status;
// When booting multiple programs, for example, in test cases or cuckoo testing, we need to check
// if we have already generated a VMO for a given blob. If so, we can just duplicate the handle
// and hand it over.
if (booting_multiple_programs_) {
for (const auto& entry : entries()) {
if (entry.offset == it->offset) {
status = entry.contents.duplicate(ZX_RIGHT_SAME_RIGHTS, &file_vmo);
check(log_, status, "zx_handle_duplicate failed");
return file_vmo;
}
}
}
size_t page_aligned_size = ZX_PAGE_ALIGN(it->size);
status = zx::vmo::create(page_aligned_size, 0, &file_vmo);
check(log_, status, "zx_vmo_create failed");
status = zx_vmo_transfer_data(file_vmo.get(), 0, 0, page_aligned_size,
bootfs_reader_.storage().vmo().get(), it->offset);
check(log_, status, "zx_vmo_transfer_data failed");
status = file_vmo.set_property(ZX_PROP_NAME, filename.data(), filename.size());
check(log_, status, "failed to set ZX_PROP_NAME");
uint64_t size = it->size;
status = file_vmo.set_property(ZX_PROP_VMO_CONTENT_SIZE, &size, sizeof(size));
check(log_, status, "failed to set ZX_PROP_VMO_CONTENT_SIZE");
status = file_vmo.replace_as_executable(vmex_resource_, &file_vmo);
check(log_, status, "zx_vmo_replace_as_executable failed");
// Duplicate `file_vmo` handle to be provided.
zx::vmo extra;
status = file_vmo.duplicate(ZX_RIGHT_SAME_RIGHTS, &extra);
check(log_, status, "zx_handle_duplicate failed.");
ZX_ASSERT_MSG(entry_count_ < entries_.size(),
"entry_count_=%zu be smaller than entries.size()=%zu for insertion", entry_count_,
entries_.size());
entries_[entry_count_++] = {.offset = it->offset, .contents = std::move(file_vmo)};
return extra;
}
void Bootfs::Fail(const BootfsView::Error& error) {
zbitl::PrintBootfsError(error, [this](const char* fmt, ...) {
va_list args;
va_start(args, fmt);
printl(log_, fmt, args);
va_end(args);
});
zx_process_exit(-1);
}