blob: 60c3df4c67bae358115b472d230e9dfd71804c31 [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 LIB_SYSCONFIG_SYNC_CLIENT_H_
#define LIB_SYSCONFIG_SYNC_CLIENT_H_
#include <fuchsia/hardware/skipblock/llcpp/fidl.h>
#include <lib/fzl/owned-vmo-mapper.h>
#include <lib/zx/channel.h>
#include <zircon/types.h>
#include <optional>
#include <fbl/unique_fd.h>
#include "sysconfig-header.h"
namespace sysconfig {
// This class provides a synchronous read and write interface into sub-partitions of the sysconfig
// skip-block partition.
//
// The class takes into account differences that may appear in partition layout between various
// device's sysconfig partitions.
class __EXPORT SyncClient {
public:
// The sub partitions of the sysconfig partition.
enum class PartitionType {
kSysconfig,
// Used to determine which partition to boot into on boot.
kABRMetadata,
// The follow are used to store verified boot metadata.
kVerifiedBootMetadataA,
kVerifiedBootMetadataB,
kVerifiedBootMetadataR,
};
// Looks for a skip-block device of type sysconfig. If found, returns a client capable of reading
// and writing to sub-partitions of the sysconfig device.
static zx_status_t Create(std::optional<SyncClient>* out);
// Variation on `Create` with devfs (/dev) injected.
static zx_status_t Create(const fbl::unique_fd& devfs_root, std::optional<SyncClient>* out);
// Provides write access for the partition specified. Always writes full partition.
//
// |vmo| must have a size greater than or equal to the partitions size + |vmo_offset|.
zx_status_t WritePartition(PartitionType partition, const zx::vmo& vmo, zx_off_t vmo_offset);
// Provides read access for the partition specified. Always reads full partition.
//
// |vmo| must have a size greater than or equal to the partitions size + |vmo_offset|.
zx_status_t ReadPartition(PartitionType partition, const zx::vmo& vmo, zx_off_t vmo_offset);
// Returns the size of the partition specified.
zx_status_t GetPartitionSize(PartitionType partition, size_t* out);
zx_status_t GetPartitionOffset(PartitionType partition, size_t* out);
// Use caution when updating layout in multi-threaded context.
// It's dangerous to update layout and header while there are other instances of SyncClient
// in use.
// In particular, SyncClient caches header from storage after the first time it reads it. If
// layout is changed afterwards by some other instance of SyncClient, it will not be aware of it.
// Thus make sure that you only effectively update layout in a state where no other SyncClient is
// created and in use.
zx_status_t UpdateLayout(const sysconfig_header& target_header);
// No copy.
SyncClient(const SyncClient&) = delete;
SyncClient& operator=(const SyncClient&) = delete;
SyncClient(SyncClient&&) = default;
SyncClient& operator=(SyncClient&&) = default;
const sysconfig_header* GetHeader(zx_status_t* status_out = nullptr);
private:
SyncClient(::llcpp::fuchsia::hardware::skipblock::SkipBlock::SyncClient skip_block)
: skip_block_(std::move(skip_block)) {}
zx_status_t InitializeReadMapper();
zx_status_t Write(size_t offset, size_t len, const zx::vmo& vmo, zx_off_t vmo_offset);
zx_status_t Read(size_t offset, size_t len, const zx::vmo& vmo, zx_off_t vmo_offset);
zx_status_t LoadFromStorage();
::llcpp::fuchsia::hardware::skipblock::SkipBlock::SyncClient skip_block_;
// Lazily initialized on reads.
fzl::OwnedVmoMapper read_mapper_;
// Once loaded from storage, the header will be cached here
std::unique_ptr<sysconfig_header> header_;
};
} // namespace sysconfig
#endif // LIB_SYSCONFIG_SYNC_CLIENT_H_