blob: 765a5a54993c3dc60bbfd4c579852b113f4d18d1 [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 <fuchsia/device/manager/llcpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/io.h>
#include <lib/fidl/llcpp/server.h>
#include <lib/zbitl/error_stdio.h>
#include <lib/zbitl/image.h>
#include <lib/zbitl/view.h>
#include <lib/zbitl/vmo.h>
#include <lib/zx/vmo.h>
#include <stdio.h>
#include <zircon/processargs.h>
#include <zircon/status.h>
#include <cstddef>
#include <string_view>
#include <fbl/unique_fd.h>
#include "src/bringup/lib/mexec/mexec.h"
constexpr const char* kMexecZbi = "/boot/testdata/mexec-child.zbi";
namespace devmgr = fuchsia_device_manager;
namespace {
// No userspace drivers are actually running at the time that this program
// runs as we were launched instead of component_manager; accordingly, fake out
// device suspension, as mexec::Boot expects a service to do so.
struct FakeDeviceAdmin : public fidl::WireServer<devmgr::Administrator> {
void Suspend(SuspendRequestView request, SuspendCompleter::Sync& completer) override {
completer.Reply(request->flags == devmgr::wire::kSuspendFlagMexec ? ZX_OK
: ZX_ERR_INVALID_ARGS);
}
void UnregisterSystemStorageForShutdown(
UnregisterSystemStorageForShutdownRequestView request,
UnregisterSystemStorageForShutdownCompleter::Sync& completer) override {
completer.Reply(ZX_OK);
}
};
} // namespace
int main() {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
if (zx_status_t status = loop.StartThread(); status != ZX_OK) {
printf("failed to start message loop: %s\n", zx_status_get_string(status));
return ZX_ERR_INTERNAL;
}
zx::channel devmgr_channel, remote;
if (zx_status_t status = zx::channel::create(0, &devmgr_channel, &remote); status != ZX_OK) {
printf("failed to create a channel: %s\n", zx_status_get_string(status));
return ZX_ERR_INTERNAL;
}
FakeDeviceAdmin admin;
fidl::BindServer(loop.dispatcher(), std::move(remote), &admin);
fbl::unique_fd fd{open(kMexecZbi, O_RDONLY)};
if (!fd) {
printf("failed to open %s: %s\n", kMexecZbi, strerror(errno));
return ZX_ERR_INTERNAL;
}
zx::vmo kernel_zbi, data_zbi;
{
zx::vmo vmo;
if (zx_status_t status = fdio_get_vmo_exact(fd.get(), vmo.reset_and_get_address());
status != ZX_OK) {
printf("failed get child ZBI's VMO: %s\n", zx_status_get_string(status));
return status;
}
zbitl::View view(std::move(vmo));
if (auto result = view.Copy(view.begin(), ++view.begin()); result.is_error()) {
zbitl::PrintViewCopyError(result.error_value());
view.ignore_error();
return ZX_ERR_INTERNAL;
} else {
kernel_zbi = std::move(result).value();
}
if (auto result = view.Copy(++view.begin(), view.end()); result.is_error()) {
zbitl::PrintViewCopyError(result.error_value());
view.ignore_error();
return ZX_ERR_INTERNAL;
} else {
data_zbi = std::move(result).value();
}
if (auto result = view.take_error(); result.is_error()) {
zbitl::PrintViewError(result.error_value());
return ZX_ERR_INTERNAL;
}
}
zx::resource root_resource{zx_take_startup_handle(PA_HND(PA_RESOURCE, 0))};
if (!root_resource.is_valid()) {
printf("unable to get a hold of the root resource\n");
return ZX_ERR_INTERNAL;
}
if (zx_status_t status = mexec::Boot(std::move(root_resource), std::move(devmgr_channel),
std::move(kernel_zbi), std::move(data_zbi));
status != ZX_OK) {
printf("failed to mexec: %s\n", zx_status_get_string(status));
return status;
}
return ZX_OK;
}