| // 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_ |