blob: 3697c87863e52a725892e0448d254a8b294df9c2 [file] [log] [blame]
// Copyright 2022 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_FIRMWARE_LIB_STORAGE_STORAGE_H_
#define SRC_FIRMWARE_LIB_STORAGE_STORAGE_H_
#ifdef FIRMWARE_STORAGE_CUSTOM_SYSDEPS_HEADER
#include <firmware_storage_sysdeps.h>
#else
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// The macro specifies the buffer alignment requirement for reading/writing device storage. One
// example is DMA alignment. Users should define this according to the actual device. The default
// value is 64.
#ifndef FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT
#define FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT 64
#endif
typedef struct FuchsiaFirmwareStorage {
// The minimal size for read/write. On EMMC this should be the block size. On NAND this should be
// the erase block size.
size_t block_size;
// The total size of the storage in number of blocks.
size_t total_blocks;
// A scratch buffer for unaligned read/write. It must have a capacity at least `block_size` and
// must be buffer aligned according to FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT.
void* scratch_buffer;
// The size of the scratch buffer in bytes.
size_t scratch_buffer_size_bytes;
// A buffer used as an optimization for fill writes to storage.
// Its size must be a multiple of both `block_size` and FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT
// and must be buffer aligned according to FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT
void* fill_buffer;
// The size of the fill buffer in bytes.
// A buffer much larger than `block_size` can provide an optimization for writing fill data.
// Empirical testing shows good results with a buffer size of ~4MiB.
size_t fill_buffer_size_bytes;
// Context pointer for calling the `read` callback.
void* ctx;
// Callback for reading from the storage.
//
// Implementation can assume that`dst` is buffer aligned according to
// FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT. However `block_offset` and `blocks_count` must be
// treated as logical. It's up to the implementation to convert them into physical offset and size
// for accessing storage. For example, in the case of NAND device, implementation must take into
// consideration bad block and may want to compute the corresponding physical offset and size
// using skip block logic.
//
// @ctx: Context pointer. It will always be the `ctx` field above.
// @block_offset: Logical offset from the storage to read in terms of number of blocks.
// @blocks_count: Logical size to read in terms of number of blocks.
// @dst: Output pointer to read to.
//
// Return true if success, false otherwise.
bool (*read)(void* ctx, size_t block_offset, size_t blocks_count, void* dst);
// Callback for writing to the storage.
//
// Similar to read(), implementation can assume that `src` is buffer aligned according to
// FUCHSIA_FIRMWARE_STORAGE_BUFFER_ALIGNMENT. However `block_offset` and `blocks_count` must be
// treated as logical.
//
// @ctx: Context pointer. It will always be the `ctx` field above.
// @block_offset: Logical offset from the storage to write in terms of number of blocks.
// @blocks_count: Logical size to write in terms of number of blocks.
// @src: Pointer to buffer of data to write.
//
// Note: Some storage such as NAND requires data to be erased first before it can write new data.
// This should be handled in the implementation of this callback.
//
// Return true if success, false otherwise.
bool (*write)(void* ctx, size_t block_offset, size_t blocks_count, const void* src);
} FuchsiaFirmwareStorage;
// Read data from storage
//
// @ops: Pointer to FuchsiaFirmwareStorage
// @offset: offset in number of bytes to read from.
// @size: size in number of bytes to read.
// @dst: Pointer to buffer to read to.
//
// Return true if success, false otherwise.
bool FuchsiaFirmwareStorageRead(FuchsiaFirmwareStorage* ops, size_t offset, size_t size, void* dst);
// Write data to storage
//
// @ops: Pointer to FuchsiaFirmwareStorage
// @offset: offset in number of bytes to write.
// @size: size in number of bytes to write.
// @src: Pointer to buffer of data to write.
//
// Note: `src` needs to be non-const since it might need to be temporarily modified internally
// to optimize performance.
//
// Return true if success, false otherwise.
bool FuchsiaFirmwareStorageWrite(FuchsiaFirmwareStorage* ops, size_t offset, size_t size,
void* src);
// Functionally the same as FuchsiaFirmwareStorageWrite but accepts a const pointer for `src`.
// However there's less optimization that can be done and may be slow when writing large amount
// of data when offset, size or `src` is unaligned.
bool FuchsiaFirmwareStorageWriteConst(FuchsiaFirmwareStorage* ops, size_t offset, size_t size,
const void* src);
#ifdef ENABLE_FIRMWARE_STORAGE_LOG
#define firmware_storage_log printf
#else
#define firmware_storage_log(...)
#endif
#ifdef __cplusplus
}
#endif
#endif // SRC_FIRMWARE_LIB_STORAGE_STORAGE_H_