blob: 022d364c87b6ac49c5af4ca2a8d7c3566f2c0c9a [file] [log] [blame]
// Copyright 2018 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.
#ifndef SRC_STORAGE_LIB_PAVER_PAVER_H_
#define SRC_STORAGE_LIB_PAVER_PAVER_H_
#include <fidl/fuchsia.mem/cpp/wire.h>
#include <fidl/fuchsia.paver/cpp/wire.h>
#include <lib/async/dispatcher.h>
#include <lib/zx/channel.h>
#include <lib/zx/result.h>
#include <zircon/types.h>
#include <utility>
#include <variant>
#include <fbl/mutex.h>
#include <fbl/string.h>
#include <fbl/unique_fd.h>
#include <sdk/lib/syslog/cpp/macros.h>
#include "abr-client.h"
#include "device-partitioner.h"
#include "paver-context.h"
namespace paver {
class Paver : public fidl::WireServer<fuchsia_paver::Paver> {
public:
void FindDataSink(FindDataSinkRequestView request,
FindDataSinkCompleter::Sync& completer) override;
void UseBlockDevice(UseBlockDeviceRequestView request,
UseBlockDeviceCompleter::Sync& completer) override;
void UseBlockDevice(BlockAndController block_device,
fidl::ServerEnd<fuchsia_paver::DynamicDataSink> dynamic_data_sink);
void FindBootManager(FindBootManagerRequestView request,
FindBootManagerCompleter::Sync& completer) override;
void FindSysconfig(FindSysconfigRequestView request,
FindSysconfigCompleter::Sync& completer) override;
void FindSysconfig(fidl::ServerEnd<fuchsia_paver::Sysconfig> sysconfig);
void set_dispatcher(async_dispatcher_t* dispatcher) { dispatcher_ = dispatcher; }
void set_devfs_root(fbl::unique_fd devfs_root) { devfs_root_ = std::move(devfs_root); }
void set_svc_root(fidl::ClientEnd<fuchsia_io::Directory> svc_root) {
svc_root_ = std::move(svc_root);
}
Paver() : context_(std::make_shared<Context>()) {}
void LifecycleStopCallback(fit::callback<void(zx_status_t status)> cb);
private:
// Used for test injection.
fbl::unique_fd devfs_root_;
fidl::ClientEnd<fuchsia_io::Directory> svc_root_;
async_dispatcher_t* dispatcher_ = nullptr;
// Declared as shared_ptr to avoid life time issues (i.e. Paver exiting before the created device
// partitioners).
std::shared_ptr<Context> context_;
};
// Common shared implementation for DataSink and DynamicDataSink. Necessary to work around lack of
// "is-a" relationship in llcpp bindings.
class DataSinkImpl {
public:
DataSinkImpl(fbl::unique_fd devfs_root, std::unique_ptr<DevicePartitioner> partitioner)
: devfs_root_(std::move(devfs_root)), partitioner_(std::move(partitioner)) {}
zx::result<fuchsia_mem::wire::Buffer> ReadAsset(fuchsia_paver::wire::Configuration configuration,
fuchsia_paver::wire::Asset asset);
zx::result<> WriteAsset(fuchsia_paver::wire::Configuration configuration,
fuchsia_paver::wire::Asset asset, fuchsia_mem::wire::Buffer payload);
zx::result<> WriteOpaqueVolume(fuchsia_mem::wire::Buffer payload);
zx::result<> WriteSparseVolume(fuchsia_mem::wire::Buffer payload);
// FIDL llcpp unions don't currently support memory ownership so we need to
// return something that does own the underlying memory.
//
// Once unions do support owned memory we can just return
// WriteBootloaderResult directly here.
std::variant<zx_status_t, bool> WriteFirmware(fuchsia_paver::wire::Configuration configuration,
fidl::StringView type,
fuchsia_mem::wire::Buffer payload);
zx::result<fuchsia_mem::wire::Buffer> ReadFirmware(
fuchsia_paver::wire::Configuration configuration, fidl::StringView type);
zx::result<> WriteVolumes(fidl::ClientEnd<fuchsia_paver::PayloadStream> payload_stream);
DevicePartitioner* partitioner() { return partitioner_.get(); }
private:
// Used for test injection.
fbl::unique_fd devfs_root_;
std::unique_ptr<DevicePartitioner> partitioner_;
// A helper to get firmware partition spec.
std::optional<PartitionSpec> GetFirmwarePartitionSpec(
fuchsia_paver::wire::Configuration configuration, fidl::StringView type);
};
class DataSink : public fidl::WireServer<fuchsia_paver::DataSink> {
public:
DataSink(fbl::unique_fd devfs_root, std::unique_ptr<DevicePartitioner> partitioner)
: sink_(std::move(devfs_root), std::move(partitioner)) {}
// Automatically finds block device to use.
static void Bind(async_dispatcher_t* dispatcher, fbl::unique_fd devfs_root,
fidl::ClientEnd<fuchsia_io::Directory> svc_root,
fidl::ServerEnd<fuchsia_paver::DataSink> server,
std::shared_ptr<Context> context);
void ReadAsset(ReadAssetRequestView request, ReadAssetCompleter::Sync& completer) override;
void WriteAsset(WriteAssetRequestView request, WriteAssetCompleter::Sync& completer) override {
completer.Reply(
sink_.WriteAsset(request->configuration, request->asset, std::move(request->payload))
.status_value());
}
void WriteOpaqueVolume(WriteOpaqueVolumeRequestView request,
WriteOpaqueVolumeCompleter::Sync& completer) override {
zx::result<> res = sink_.WriteOpaqueVolume(std::move(request->payload));
if (res.is_ok()) {
completer.ReplySuccess();
} else {
completer.ReplyError(res.status_value());
}
}
void WriteSparseVolume(WriteSparseVolumeRequestView request,
WriteSparseVolumeCompleter::Sync& completer) override {
zx::result<> res = sink_.WriteSparseVolume(std::move(request->payload));
if (res.is_ok()) {
completer.ReplySuccess();
} else {
completer.ReplyError(res.status_value());
}
}
void WriteFirmware(WriteFirmwareRequestView request,
WriteFirmwareCompleter::Sync& completer) override;
void ReadFirmware(ReadFirmwareRequestView request,
ReadFirmwareCompleter::Sync& completer) override;
void WriteVolumes(WriteVolumesRequestView request,
WriteVolumesCompleter::Sync& completer) override {
completer.Reply(sink_.WriteVolumes(std::move(request->payload)).status_value());
}
void Flush(FlushCompleter::Sync& completer) override {
completer.Reply(sink_.partitioner()->Flush().status_value());
}
private:
DataSinkImpl sink_;
};
class DynamicDataSink : public fidl::WireServer<fuchsia_paver::DynamicDataSink> {
public:
DynamicDataSink(fbl::unique_fd devfs_root, std::unique_ptr<DevicePartitioner> partitioner)
: sink_(std::move(devfs_root), std::move(partitioner)) {}
static void Bind(async_dispatcher_t* dispatcher, fbl::unique_fd devfs_root,
fidl::ClientEnd<fuchsia_io::Directory> svc_root, BlockAndController block_device,
fidl::ServerEnd<fuchsia_paver::DynamicDataSink> server,
std::shared_ptr<Context> context);
void InitializePartitionTables(InitializePartitionTablesCompleter::Sync& completer) override;
void WipePartitionTables(WipePartitionTablesCompleter::Sync& completer) override;
void ReadAsset(ReadAssetRequestView request, ReadAssetCompleter::Sync& completer) override;
void WriteAsset(WriteAssetRequestView request, WriteAssetCompleter::Sync& completer) override {
completer.Reply(
sink_.WriteAsset(request->configuration, request->asset, std::move(request->payload))
.status_value());
}
void WriteOpaqueVolume(WriteOpaqueVolumeRequestView request,
WriteOpaqueVolumeCompleter::Sync& completer) override {
zx::result<> res = sink_.WriteOpaqueVolume(std::move(request->payload));
if (res.is_ok()) {
completer.ReplySuccess();
} else {
completer.ReplyError(res.status_value());
}
}
void WriteSparseVolume(WriteSparseVolumeRequestView request,
WriteSparseVolumeCompleter::Sync& completer) override {
zx::result<> res = sink_.WriteSparseVolume(std::move(request->payload));
if (res.is_ok()) {
completer.ReplySuccess();
} else {
completer.ReplyError(res.status_value());
}
}
void WriteFirmware(WriteFirmwareRequestView request,
WriteFirmwareCompleter::Sync& completer) override;
void ReadFirmware(ReadFirmwareRequestView request,
ReadFirmwareCompleter::Sync& completer) override;
void WriteVolumes(WriteVolumesRequestView request,
WriteVolumesCompleter::Sync& completer) override {
completer.Reply(sink_.WriteVolumes(std::move(request->payload)).status_value());
}
void Flush(FlushCompleter::Sync& completer) override {
completer.Reply(sink_.partitioner()->Flush().status_value());
}
private:
DataSinkImpl sink_;
};
class BootManager : public fidl::WireServer<fuchsia_paver::BootManager> {
public:
BootManager(std::unique_ptr<abr::Client> abr_client, fbl::unique_fd devfs_root,
fidl::ClientEnd<fuchsia_io::Directory> svc_root)
: abr_client_(std::move(abr_client)),
devfs_root_(std::move(devfs_root)),
svc_root_(std::move(svc_root)) {}
static void Bind(async_dispatcher_t* dispatcher, fbl::unique_fd devfs_root,
fidl::ClientEnd<fuchsia_io::Directory> svc_root,
std::shared_ptr<Context> context,
fidl::ServerEnd<fuchsia_paver::BootManager> server);
void QueryCurrentConfiguration(QueryCurrentConfigurationCompleter::Sync& completer) override;
void QueryActiveConfiguration(QueryActiveConfigurationCompleter::Sync& completer) override;
void QueryConfigurationLastSetActive(
QueryConfigurationLastSetActiveCompleter::Sync& completer) override;
void QueryConfigurationStatus(QueryConfigurationStatusRequestView request,
QueryConfigurationStatusCompleter::Sync& completer) override;
void SetConfigurationActive(SetConfigurationActiveRequestView request,
SetConfigurationActiveCompleter::Sync& completer) override;
void SetConfigurationUnbootable(SetConfigurationUnbootableRequestView request,
SetConfigurationUnbootableCompleter::Sync& completer) override;
void SetConfigurationHealthy(SetConfigurationHealthyRequestView request,
SetConfigurationHealthyCompleter::Sync& completer) override;
void SetOneShotRecovery(SetOneShotRecoveryCompleter::Sync& completer) override;
void Flush(FlushCompleter::Sync& completer) override {
completer.Reply(abr_client_->Flush().status_value());
}
private:
std::unique_ptr<abr::Client> abr_client_;
fbl::unique_fd devfs_root_;
fidl::ClientEnd<fuchsia_io::Directory> svc_root_;
};
} // namespace paver
#endif // SRC_STORAGE_LIB_PAVER_PAVER_H_