blob: bdcbba5c002e9ff5949b895a30b873718aa80e60 [file] [log] [blame]
// Copyright 2019 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_ABR_CLIENT_H_
#define SRC_STORAGE_LIB_PAVER_ABR_CLIENT_H_
#include <fidl/fuchsia.io/cpp/wire.h>
#include <fidl/fuchsia.paver/cpp/wire.h>
#include <lib/abr/abr.h>
#include <lib/zx/channel.h>
#include <lib/zx/result.h>
#include <memory>
#include <vector>
#include <fbl/unique_fd.h>
#include "src/lib/uuid/uuid.h"
#include "src/storage/lib/paver/partition-client.h"
#include "src/storage/lib/paver/paver-context.h"
#include "zircon/errors.h"
namespace abr {
// For testing only.
zx::result<fuchsia_paver::wire::Configuration> PartitionUuidToConfiguration(
const fbl::unique_fd& devfs_root, uuid::Uuid uuid);
// For testing only.
zx::result<fuchsia_paver::wire::Configuration> CurrentSlotToConfiguration(std::string_view slot);
zx::result<fuchsia_paver::wire::Configuration> QueryBootConfig(
const fbl::unique_fd& devfs_root, fidl::UnownedClientEnd<fuchsia_io::Directory> svc_root);
// Interface for interacting with ABR data.
class Client {
public:
// Factory create method.
static zx::result<std::unique_ptr<abr::Client>> Create(
fbl::unique_fd devfs_root, fidl::UnownedClientEnd<fuchsia_io::Directory> svc_root,
std::shared_ptr<paver::Context> context);
virtual ~Client() = default;
AbrSlotIndex GetBootSlot(bool update_metadata, bool* is_slot_marked_successful) const {
return AbrGetBootSlot(&abr_ops_, update_metadata, is_slot_marked_successful);
}
zx::result<AbrSlotIndex> GetSlotLastMarkedActive() const {
AbrSlotIndex slot;
auto status = AbrResultToZxStatus(AbrGetSlotLastMarkedActive(&abr_ops_, &slot));
if (status.is_error()) {
return status.take_error();
}
return zx::ok(slot);
}
zx::result<> MarkSlotActive(AbrSlotIndex index) {
return AbrResultToZxStatus(AbrMarkSlotActive(&abr_ops_, index));
}
zx::result<> MarkSlotUnbootable(AbrSlotIndex index) {
return AbrResultToZxStatus(AbrMarkSlotUnbootable(&abr_ops_, index));
}
zx::result<> MarkSlotSuccessful(AbrSlotIndex index) {
return AbrResultToZxStatus(AbrMarkSlotSuccessful(&abr_ops_, index));
}
zx::result<AbrSlotInfo> GetSlotInfo(AbrSlotIndex index) const {
AbrSlotInfo info;
auto status = AbrResultToZxStatus(AbrGetSlotInfo(&abr_ops_, index, &info));
if (status.is_error()) {
return status.take_error();
}
return zx::ok(info);
}
zx::result<AbrDataOneShotFlags> GetAndClearOneShotFlags() {
AbrDataOneShotFlags flags;
auto status = AbrResultToZxStatus(AbrGetAndClearOneShotFlags(&abr_ops_, &flags));
if (status.is_error()) {
return status.take_error();
}
return zx::ok(flags);
}
zx::result<> SetOneShotRecovery() {
return AbrResultToZxStatus(AbrSetOneShotRecovery(&abr_ops_, true));
}
zx::result<> SetOneShotBootloader() {
return AbrResultToZxStatus(AbrSetOneShotBootloader(&abr_ops_, true));
}
static zx::result<> AbrResultToZxStatus(AbrResult status);
virtual zx::result<> Flush() const = 0;
void InitializeAbrOps();
explicit Client(bool custom = false) {
if (custom) {
abr_ops_ = {this, nullptr, nullptr, Client::ReadAbrMetadataCustom,
Client::WriteAbrMetadataCustom};
} else {
abr_ops_ = {this, Client::ReadAbrMetaData, Client::WriteAbrMetaData, nullptr, nullptr};
}
}
// No copy, move, assign.
// This is to ensure that |abr_ops_| is always valid. |abr_ops_.context| shall always be
// a |this| pointer to the Client instance that hosts |abr_ops_|. This may be
// violated if we allow Client to be copied/moved/assign.
Client(const Client&) = delete;
Client& operator=(const Client&) = delete;
Client(Client&&) = delete;
Client& operator=(Client&&) = delete;
private:
AbrOps abr_ops_;
// ReadAbrMetaData and WriteAbrMetaData will be assigned to fields in AbrOps
static bool ReadAbrMetaData(void* context, size_t size, uint8_t* buffer);
static bool WriteAbrMetaData(void* context, const uint8_t* buffer, size_t size);
static bool ReadAbrMetadataCustom(void* context, AbrSlotData* a, AbrSlotData* b,
uint8_t* one_shot_recovery);
static bool WriteAbrMetadataCustom(void* context, const AbrSlotData* a, const AbrSlotData* b,
uint8_t one_shot_recovery);
virtual zx::result<> Read(uint8_t* buffer, size_t size) = 0;
virtual zx::result<> Write(const uint8_t* buffer, size_t size) = 0;
virtual zx::result<> ReadCustom(AbrSlotData* a, AbrSlotData* b, uint8_t* one_shot_recovery) = 0;
virtual zx::result<> WriteCustom(const AbrSlotData* a, const AbrSlotData* b,
uint8_t one_shot_recovery) = 0;
};
class ClientFactory {
public:
// Factory create method.
static zx::result<std::unique_ptr<abr::Client>> Create(
fbl::unique_fd devfs_root, fidl::UnownedClientEnd<fuchsia_io::Directory> svc_root,
std::shared_ptr<paver::Context> context);
static void Register(std::unique_ptr<ClientFactory> factory);
virtual ~ClientFactory() = default;
private:
virtual zx::result<std::unique_ptr<abr::Client>> New(
fbl::unique_fd devfs_root, fidl::UnownedClientEnd<fuchsia_io::Directory> svc_root,
std::shared_ptr<paver::Context> context) = 0;
static std::vector<std::unique_ptr<ClientFactory>>* registered_factory_list();
};
// Implementation of abr::Client which works with a contiguous partition storing AbrData.
class AbrPartitionClient : public Client {
public:
// |partition| should contain AbrData with no offset.
static zx::result<std::unique_ptr<abr::Client>> Create(
std::unique_ptr<paver::PartitionClient> partition);
private:
AbrPartitionClient(std::unique_ptr<paver::PartitionClient> partition, zx::vmo vmo,
size_t block_size)
: partition_(std::move(partition)), vmo_(std::move(vmo)), block_size_(block_size) {}
zx::result<> Read(uint8_t* buffer, size_t size) override;
zx::result<> Write(const uint8_t* buffer, size_t size) override;
zx::result<> ReadCustom(AbrSlotData* a, AbrSlotData* b, uint8_t* one_shot_recovery) override {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
zx::result<> WriteCustom(const AbrSlotData* a, const AbrSlotData* b,
uint8_t one_shot_recovery) override {
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
zx::result<> Flush() const override { return partition_->Flush(); }
std::unique_ptr<paver::PartitionClient> partition_;
zx::vmo vmo_;
size_t block_size_;
};
} // namespace abr
#endif // SRC_STORAGE_LIB_PAVER_ABR_CLIENT_H_