-
Notifications
You must be signed in to change notification settings - Fork 7.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
storage: Storage area #79665
base: main
Are you sure you want to change the base?
storage: Storage area #79665
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,229 @@ | ||
/* | ||
* Copyright (c) 2024 Laczen | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/** | ||
* @brief A storage area is a region on flash, eeprom, disk, ram, ... with | ||
* fixed write-size and fixed erase-size. | ||
* | ||
* The storage area API is a subsystem that creates a unified method to work | ||
* with flash, eeprom, ram, disks, files, ... for storage. | ||
* | ||
* A storage area is an area that has a number of constant sized erase blocks, | ||
* and has constant write block size. The storage area does not necessarily | ||
* inherit the limitations of the underlying storage device but rather defines | ||
* a method of how the underlying storage device will be used (however it does | ||
* not remove any limitations of the underlying storage device). | ||
* | ||
* A storage area can be defined with wrong properties (e.g. an erase-size | ||
* smaller than the erase-block-size of the underlying storage device). | ||
* Optionally the definition is checked by defining the Kconfig option | ||
* `CONFIG_STORAGE_AREA_VERIFY` (default enabled for `DEBUG` builds). | ||
* | ||
* The subsystem is easy extendable to create custom (virtual) storage areas | ||
* that consist of e.g. a combination of flash and ram, an encrypted storage | ||
* area, ... | ||
* | ||
* There following methods are exposed: | ||
* - storage_area_read(): read data, | ||
* - storage_area_readv(): read data vector, | ||
* - storage_area_write(): write data, | ||
* - storage_area_writev(): write data vector, | ||
* - storage_area_erase(): erase (in erase block addressing), | ||
* - storage_area_ioctl(): used for e.g. getting xip addresses, | ||
* | ||
* A storage area is defined e.g. for a read-write area on flash: | ||
* @code{.c} | ||
* STORAGE_AREA_FLASH_RW_DEFINE(name, ...); | ||
* struct storage_area *area = GET_STORAGE_AREA(name); | ||
* @endcode | ||
* | ||
* For other storage devices (eeprom, ram, disk, ...) similar macros are | ||
* defines, but they might differ slightly. | ||
* | ||
* The write_size, erase_size, ... are declarations of how the storage_area | ||
* will be used The write_size is limited to a power of 2, erase_size should | ||
* be a multiple of write_size and size should be a multiple of erase_size. | ||
* The macro definitions STORAGE_AREA_XXX_DEFINE(...) checks these conditions. | ||
* | ||
* @defgroup storage_area Storage area | ||
* @ingroup storage_apis | ||
* @{ | ||
*/ | ||
|
||
#ifndef ZEPHYR_INCLUDE_STORAGE_STORAGE_AREA_H_ | ||
#define ZEPHYR_INCLUDE_STORAGE_STORAGE_AREA_H_ | ||
|
||
#include <stdint.h> | ||
#include <stddef.h> | ||
#include <zephyr/sys/util.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/* Allow the sa_off_t type to be redefined if needed */ | ||
#ifdef CONFIG_STORAGE_AREA_OFFSET_64BIT | ||
typedef uint64_t sa_off_t; | ||
#else | ||
typedef uint32_t sa_off_t; | ||
#endif | ||
|
||
struct storage_area; | ||
|
||
/** storage area input-output vector */ | ||
struct storage_area_iovec { | ||
void *data; /**< pointer to data */ | ||
size_t len; /**< data length */ | ||
}; | ||
|
||
/** storage area properties masks */ | ||
enum storage_area_properties_mask { | ||
/** full overwrite (e.g. ram, rram, ...) */ | ||
STORAGE_AREA_PROP_FOVRWRITE = BIT(0), | ||
/** limited overwrite (e.g. nor flash without crc */ | ||
STORAGE_AREA_PROP_LOVRWRITE = BIT(1), | ||
/** erase value is 0x00 */ | ||
STORAGE_AREA_PROP_ZEROERASE = BIT(2), | ||
/** erase while writing on flash devices */ | ||
STORAGE_AREA_PROP_AUTOERASE = BIT(3), | ||
}; | ||
|
||
/** storage area ioctl commands */ | ||
enum storage_area_ioctl_cmd { | ||
STORAGE_AREA_IOCTL_NONE, | ||
/** retrieve the storage area xip address */ | ||
STORAGE_AREA_IOCTL_XIPADDRESS, | ||
}; | ||
|
||
/** storage area api */ | ||
struct storage_area_api { | ||
int (*readv)(const struct storage_area *area, sa_off_t offset, | ||
const struct storage_area_iovec *iovec, size_t iovcnt); | ||
int (*writev)(const struct storage_area *area, sa_off_t offset, | ||
const struct storage_area_iovec *iovec, size_t iovcnt); | ||
int (*erase)(const struct storage_area *area, size_t sblk, size_t bcnt); | ||
int (*ioctl)(const struct storage_area *area, | ||
enum storage_area_ioctl_cmd cmd, void *data); | ||
}; | ||
|
||
/** storage area */ | ||
struct storage_area { | ||
const struct storage_area_api *api; | ||
size_t write_size; | ||
size_t erase_size; | ||
size_t erase_blocks; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be rather overall device size here, which is even indicated by initialization of disk_storage_area, flash_storage_area, and eeprom_storage area which all have to populate this by division of size by erase_size. Note also that #71270 is in path of making erase optional for drivers, i.e. returning -ENOTSUP, some drivers will no longer return pages layout nor hold information on device erase page. That benefits devices like MRAM in Ambiq or RRAM in Nordic, and many other devices where code not needed for these drivers to work and be removed and benefit users by reduction of code flash usage taken by vendor code to support these devices. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whether this should be |
||
/** bitfield of properties */ | ||
uint32_t props; | ||
}; | ||
|
||
#define STORAGE_AREA_HAS_PROPERTY(area, prop) ((area->props & prop) == prop) | ||
#define STORAGE_AREA_WRITESIZE(area) area->write_size | ||
#define STORAGE_AREA_ERASESIZE(area) area->erase_size | ||
#define STORAGE_AREA_SIZE(area) \ | ||
(area->erase_size * area->erase_blocks) | ||
#define STORAGE_AREA_FOVRWRITE(area) \ | ||
STORAGE_AREA_HAS_PROPERTY(area, STORAGE_AREA_PROP_FOVRWRITE) | ||
#define STORAGE_AREA_LOVRWRITE(area) \ | ||
STORAGE_AREA_HAS_PROPERTY(area, STORAGE_AREA_PROP_LOVRWRITE) | ||
#define STORAGE_AREA_ERASEVALUE(area) \ | ||
STORAGE_AREA_HAS_PROPERTY(area, STORAGE_AREA_PROP_ZEROERASE) ? 0x00 \ | ||
: 0xff | ||
#define STORAGE_AREA_AUTOERASE(area) \ | ||
STORAGE_AREA_HAS_PROPERTY(area, STORAGE_AREA_PROP_AUTOERASE) | ||
|
||
/** | ||
* @brief retrieve a pointer to a storage area | ||
* | ||
* @param _name the name of the storage area | ||
*/ | ||
#define GET_STORAGE_AREA(_name) \ | ||
(struct storage_area *)&_storage_area_##_name.area | ||
|
||
/** | ||
* @brief Read iovec from storage area. | ||
* | ||
* @param area storage area. | ||
* @param offset offset in storage area (byte). | ||
* @param iovec io vector for read. | ||
* @param iovcnt iovec element count. | ||
* | ||
* @retval 0 on success else negative errno code. | ||
*/ | ||
int storage_area_readv(const struct storage_area *area, sa_off_t offset, | ||
const struct storage_area_iovec *iovec, size_t iovcnt); | ||
|
||
/** | ||
* @brief Read from storage area. | ||
* | ||
* @param area storage area. | ||
* @param offset offset in storage area (byte). | ||
* @param data data. | ||
* @param len read size. | ||
* | ||
* @retval 0 on success else negative errno code. | ||
*/ | ||
int storage_area_read(const struct storage_area *area, sa_off_t offset, | ||
void *data, size_t len); | ||
|
||
/** | ||
* @brief Write iovec to storage area. | ||
* | ||
* @param area storage area. | ||
* @param offset offset in storage area (byte). | ||
* @param iovec io vector to write. | ||
* @param iovcnt iovec element count. | ||
* | ||
* @retval 0 on success else negative errno code. | ||
*/ | ||
int storage_area_writev(const struct storage_area *area, sa_off_t offset, | ||
const struct storage_area_iovec *iovec, size_t iovcnt); | ||
|
||
/** | ||
* @brief Write data to storage area. | ||
* | ||
* @param area storage area. | ||
* @param offset offset in storage area (byte). | ||
* @param data data to program. | ||
* @param len program size. | ||
* | ||
* @retval 0 on success else negative errno code. | ||
*/ | ||
int storage_area_write(const struct storage_area *area, sa_off_t offset, | ||
const void *data, size_t len); | ||
|
||
/** | ||
* @brief Erase storage area. | ||
* | ||
* @param area storage area. | ||
* @param sblk start block | ||
* @param bcnt number of blocks to erase. | ||
* | ||
* @retval 0 on success else negative errno code. | ||
*/ | ||
int storage_area_erase(const struct storage_area *area, size_t sblk, | ||
size_t bcnt); | ||
|
||
/** | ||
* @brief Storage area ioctl. | ||
* | ||
* @param area storage area. | ||
* @param cmd ioctl command. | ||
* @param data in/out data pointer. | ||
* | ||
* @retval 0 on success else negative errno code. | ||
*/ | ||
int storage_area_ioctl(const struct storage_area *area, | ||
enum storage_area_ioctl_cmd cmd, void *data); | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* ZEPHYR_INCLUDE_STORAGE_STORAGE_AREA_H_ */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* Copyright (c) 2024 Laczen | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/** | ||
* @brief A storage area on disk | ||
* @defgroup storage_area_disk Storage area on disk | ||
* @ingroup storage_area | ||
* @{ | ||
*/ | ||
|
||
#ifndef ZEPHYR_INCLUDE_STORAGE_STORAGE_AREA_DISK_H_ | ||
#define ZEPHYR_INCLUDE_STORAGE_STORAGE_AREA_DISK_H_ | ||
|
||
#include <zephyr/storage/disk_access.h> | ||
#include <zephyr/storage/storage_area/storage_area.h> | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
struct storage_area_disk { | ||
const struct storage_area area; | ||
const uint32_t start; | ||
const size_t ssize; | ||
const char *name; | ||
}; | ||
|
||
extern const struct storage_area_api storage_area_disk_rw_api; | ||
extern const struct storage_area_api storage_area_disk_ro_api; | ||
|
||
/** | ||
* @brief Helper macro to create a storage area on top of a disk | ||
*/ | ||
#define STORAGE_AREA_DISK(_dname, _start, _ssize, _ws, _es, _size, _props, \ | ||
_api) \ | ||
{ \ | ||
.area = \ | ||
{ \ | ||
.api = ((_ws == 0) || \ | ||
((_ws & (_ws - 1)) != 0) || \ | ||
((_es % _ws) != 0) || \ | ||
((_size % _es) != 0)) \ | ||
? NULL \ | ||
: _api, \ | ||
.write_size = _ws, \ | ||
.erase_size = _es, \ | ||
.erase_blocks = _size / _es, \ | ||
.props = _props | STORAGE_AREA_PROP_FOVRWRITE, \ | ||
}, \ | ||
.name = _dname, .start = _start, .ssize = _ssize, \ | ||
} | ||
|
||
/** | ||
* @brief Define a read-write storage area on top of a disk | ||
* | ||
* @param _name storage area name: used by GET_STORAGE_AREA(_name) | ||
* @param _dname disk name | ||
* @param _start start sector on disk | ||
* @param _ws write-size (equal or multiple of disk sector size) | ||
* @param _es erase-size (equal or multiple of disk sector size) | ||
* @param _size storage area size | ||
* @param _props storage area properties (see storage_area.h) | ||
*/ | ||
#define STORAGE_AREA_DISK_RW_DEFINE(_name, _dname, _start, _ssize, _ws, _es, \ | ||
_size, _props) \ | ||
BUILD_ASSERT(_ws != 0, "Invalid write size"); \ | ||
BUILD_ASSERT((_ws & (_ws - 1)) == 0, "Invalid write size"); \ | ||
BUILD_ASSERT((_es % _ws) == 0, "Invalid erase size"); \ | ||
BUILD_ASSERT((_size % _ws) == 0, "Invalid size"); \ | ||
BUILD_ASSERT((_ssize % _ws) == 0, "Invalid sector size"); \ | ||
const struct storage_area_disk _storage_area_##_name = \ | ||
STORAGE_AREA_DISK(_dname, _start, _ssize, _ws, _es, _size, \ | ||
_props, &storage_area_disk_rw_api) | ||
|
||
/** | ||
* @brief Define a read-only storage area on top of a disk | ||
* | ||
* see @ref STORAGE_AREA_DISK_RW_DEFINE for parameters | ||
* | ||
* remark: the write-size and erase-size are not used in read-only, however | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make these remarks stand out in the generated documentation consider using |
||
* to have a correct interpretation of the data that is used in | ||
* read-only mode it is advised to keep them equal to the sizes that | ||
* were used when creating the area. | ||
*/ | ||
#define STORAGE_AREA_DISK_RO_DEFINE(_name, _dname, _start, _ssize, _ws, _es, \ | ||
_size, _props) \ | ||
BUILD_ASSERT(_ws != 0, "Invalid write size"); \ | ||
BUILD_ASSERT((_ws & (_ws - 1)) == 0, "Invalid write size"); \ | ||
BUILD_ASSERT((_es % _ws) == 0, "Invalid erase size"); \ | ||
BUILD_ASSERT((_size % _ws) == 0, "Invalid size"); \ | ||
BUILD_ASSERT((_ssize % _ws) == 0, "Invalid sector size"); \ | ||
const struct storage_area_disk _storage_area_##_name = \ | ||
STORAGE_AREA_DISK(_dname, _start, _ssize, _ws, _es, _size, \ | ||
_props, &storage_area_disk_ro_api) | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* ZEPHYR_INCLUDE_STORAGE_STORAGE_AREA_DISK_H_ */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.