1 /* Copyright (c) 2018 Laczen
2  * Copyright (c) 2024 BayLibre SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * ZMS: Zephyr Memory Storage
7  */
8 #ifndef ZEPHYR_INCLUDE_FS_ZMS_H_
9 #define ZEPHYR_INCLUDE_FS_ZMS_H_
10 
11 #include <sys/types.h>
12 #include <zephyr/drivers/flash.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/device.h>
15 #include <zephyr/toolchain.h>
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 /**
22  * @defgroup zms Zephyr Memory Storage (ZMS)
23  * @ingroup file_system_storage
24  * @{
25  * @}
26  */
27 
28 /**
29  * @defgroup zms_data_structures ZMS data structures
30  * @ingroup zms
31  * @{
32  */
33 
34 /** Zephyr Memory Storage file system structure */
35 struct zms_fs {
36 	/** File system offset in flash */
37 	off_t offset;
38 	/** Allocation Table Entry (ATE) write address.
39 	 * Addresses are stored as `uint64_t`:
40 	 * - high 4 bytes correspond to the sector
41 	 * - low 4 bytes are the offset in the sector
42 	 */
43 	uint64_t ate_wra;
44 	/** Data write address */
45 	uint64_t data_wra;
46 	/** Storage system is split into sectors. The sector size must be a multiple of
47 	 *  `erase-block-size` if the device has erase capabilities
48 	 */
49 	uint32_t sector_size;
50 	/** Number of sectors in the file system */
51 	uint32_t sector_count;
52 	/** Current cycle counter of the active sector (pointed to by `ate_wra`) */
53 	uint8_t sector_cycle;
54 	/** Flag indicating if the file system is initialized */
55 	bool ready;
56 	/** Mutex used to lock flash writes */
57 	struct k_mutex zms_lock;
58 	/** Flash device runtime structure */
59 	const struct device *flash_device;
60 	/** Flash memory parameters structure */
61 	const struct flash_parameters *flash_parameters;
62 	/** Size of an Allocation Table Entry */
63 	size_t ate_size;
64 #if CONFIG_ZMS_LOOKUP_CACHE
65 	/** Lookup table used to cache ATE addresses of written IDs */
66 	uint64_t lookup_cache[CONFIG_ZMS_LOOKUP_CACHE_SIZE];
67 #endif
68 };
69 
70 /**
71  * @}
72  */
73 
74 /**
75  * @defgroup zms_high_level_api ZMS API
76  * @ingroup zms
77  * @{
78  */
79 
80 /**
81  * @brief Mount a ZMS file system onto the device specified in `fs`.
82  *
83  * @param fs Pointer to the file system.
84  *
85  * @retval 0 on success.
86  * @retval -ENOTSUP if the detected file system is not ZMS.
87  * @retval -EPROTONOSUPPORT if the ZMS version is not supported.
88  * @retval -EINVAL if any of the flash parameters or the sector layout is invalid.
89  * @retval -ENXIO if there is a device error.
90  * @retval -EIO if there is a memory read/write error.
91  */
92 int zms_mount(struct zms_fs *fs);
93 
94 /**
95  * @brief Clear the ZMS file system from device.
96  *
97  * @param fs Pointer to the file system.
98  *
99  * @retval 0 on success.
100  * @retval -EACCES if `fs` is not mounted.
101  * @retval -ENXIO if there is a device error.
102  * @retval -EIO if there is a memory read/write error.
103  */
104 int zms_clear(struct zms_fs *fs);
105 
106 /**
107  * @brief Write an entry to the file system.
108  *
109  * @note  When the `len` parameter is equal to `0` the entry is effectively removed (it is
110  * equivalent to calling @ref zms_delete()). It is not possible to distinguish between a deleted
111  * entry and an entry with data of length 0.
112  *
113  * @param fs Pointer to the file system.
114  * @param id ID of the entry to be written.
115  * @param data Pointer to the data to be written.
116  * @param len Number of bytes to be written (maximum 64 KiB).
117  *
118  * @return Number of bytes written. On success, it will be equal to the number of bytes requested
119  * to be written or 0.
120  * When a rewrite of the same data already stored is attempted, nothing is written to flash,
121  * thus 0 is returned. On error, returns negative value of error codes defined in `errno.h`.
122  * @retval Number of bytes written (`len` or 0) on success.
123  * @retval -EACCES if ZMS is still not initialized.
124  * @retval -ENXIO if there is a device error.
125  * @retval -EIO if there is a memory read/write error.
126  * @retval -EINVAL if `len` is invalid.
127  * @retval -ENOSPC if no space is left on the device.
128  */
129 ssize_t zms_write(struct zms_fs *fs, uint32_t id, const void *data, size_t len);
130 
131 /**
132  * @brief Delete an entry from the file system
133  *
134  * @param fs Pointer to the file system.
135  * @param id ID of the entry to be deleted.
136  *
137  * @retval 0 on success.
138  * @retval -EACCES if ZMS is still not initialized.
139  * @retval -ENXIO if there is a device error.
140  * @retval -EIO if there is a memory read/write error.
141  */
142 int zms_delete(struct zms_fs *fs, uint32_t id);
143 
144 /**
145  * @brief Read an entry from the file system.
146  *
147  * @param fs Pointer to the file system.
148  * @param id ID of the entry to be read.
149  * @param data Pointer to data buffer.
150  * @param len Number of bytes to read at most.
151  *
152  * @return Number of bytes read. On success, it will be equal to the number of bytes requested
153  * to be read or less than that if the stored data has a smaller size than the requested one.
154  * On error, returns negative value of error codes defined in `errno.h`.
155  * @retval Number of bytes read (> 0) on success.
156  * @retval -EACCES if ZMS is still not initialized.
157  * @retval -EIO if there is a memory read/write error.
158  * @retval -ENOENT if there is no entry with the given `id`.
159  */
160 ssize_t zms_read(struct zms_fs *fs, uint32_t id, void *data, size_t len);
161 
162 /**
163  * @brief Read a history entry from the file system.
164  *
165  * @param fs Pointer to the file system.
166  * @param id ID of the entry to be read.
167  * @param data Pointer to data buffer.
168  * @param len Number of bytes to be read.
169  * @param cnt History counter: 0: latest entry, 1: one before latest ...
170  *
171  * @return Number of bytes read. On success, it will be equal to the number of bytes requested
172  * to be read. When the return value is larger than the number of bytes requested to read this
173  * indicates not all bytes were read, and more data is available. On error, returns negative
174  * value of error codes defined in `errno.h`.
175  * @retval Number of bytes read (> 0) on success.
176  * @retval -EACCES if ZMS is still not initialized.
177  * @retval -EIO if there is a memory read/write error.
178  * @retval -ENOENT if there is no entry with the given `id` and history counter.
179  */
180 ssize_t zms_read_hist(struct zms_fs *fs, uint32_t id, void *data, size_t len, uint32_t cnt);
181 
182 /**
183  * @brief Gets the length of the data that is stored in an entry with a given `id`
184  *
185  * @param fs Pointer to the file system.
186  * @param id ID of the entry whose data length to retrieve.
187  *
188  * @return Data length contained in the ATE. On success, it will be equal to the number of bytes
189  * in the ATE. On error, returns negative value of error codes defined in `errno.h`.
190  * @retval Length of the entry with the given `id` (> 0) on success.
191  * @retval -EACCES if ZMS is still not initialized.
192  * @retval -EIO if there is a memory read/write error.
193  * @retval -ENOENT if there is no entry with the given id and history counter.
194  */
195 ssize_t zms_get_data_length(struct zms_fs *fs, uint32_t id);
196 
197 /**
198  * @brief Calculate the available free space in the file system.
199  *
200  * @param fs Pointer to the file system.
201  *
202  * @return Number of free bytes. On success, it will be equal to the number of bytes that can
203  * still be written to the file system.
204  * Calculating the free space is a time-consuming operation, especially on SPI flash.
205  * On error, returns negative value of error codes defined in `errno.h`.
206  * @retval Number of free bytes (>= 0) on success.
207  * @retval -EACCES if ZMS is still not initialized.
208  * @retval -EIO if there is a memory read/write error.
209  */
210 ssize_t zms_calc_free_space(struct zms_fs *fs);
211 
212 /**
213  * @brief Tell how much contiguous free space remains in the currently active ZMS sector.
214  *
215  * @param fs Pointer to the file system.
216  *
217  * @retval >=0 Number of free bytes in the currently active sector
218  * @retval -EACCES if ZMS is still not initialized.
219  */
220 size_t zms_active_sector_free_space(struct zms_fs *fs);
221 
222 /**
223  * @brief Close the currently active sector and switch to the next one.
224  *
225  * @note The garbage collector is called on the new sector.
226  *
227  * @warning This routine is made available for specific use cases.
228  * It collides with ZMS's goal of avoiding any unnecessary flash erase operations.
229  * Using this routine extensively can result in premature failure of the flash device.
230  *
231  * @param fs Pointer to the file system.
232  *
233  * @retval 0 on success.
234  * @retval -EACCES if ZMS is still not initialized.
235  * @retval -EIO if there is a memory read/write error.
236  */
237 int zms_sector_use_next(struct zms_fs *fs);
238 
239 /**
240  * @}
241  */
242 
243 #ifdef __cplusplus
244 }
245 #endif
246 
247 #endif /* ZEPHYR_INCLUDE_FS_ZMS_H_ */
248