1 /*
2  * Copyright (c) 2017-2020 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Runtime Inc
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <limits.h>
9 #include <stdlib.h>
10 
11 #include <zephyr/fs/fcb.h>
12 #include "fcb_priv.h"
13 #include "string.h"
14 #include <errno.h>
15 #include <zephyr/device.h>
16 #include <zephyr/drivers/flash.h>
17 
18 uint8_t
fcb_get_align(const struct fcb * fcb)19 fcb_get_align(const struct fcb *fcb)
20 {
21 	uint8_t align;
22 
23 	if (fcb->fap == NULL) {
24 		return 0;
25 	}
26 
27 	align = flash_area_align(fcb->fap);
28 
29 	return align;
30 }
31 
fcb_flash_read(const struct fcb * fcb,const struct flash_sector * sector,off_t off,void * dst,size_t len)32 int fcb_flash_read(const struct fcb *fcb, const struct flash_sector *sector,
33 		   off_t off, void *dst, size_t len)
34 {
35 	int rc;
36 
37 	if (off + len > sector->fs_size) {
38 		return -EINVAL;
39 	}
40 
41 	if (fcb->fap == NULL) {
42 		return -EIO;
43 	}
44 
45 	rc = flash_area_read(fcb->fap, sector->fs_off + off, dst, len);
46 
47 	if (rc != 0) {
48 		return -EIO;
49 	}
50 
51 	return 0;
52 }
53 
fcb_flash_write(const struct fcb * fcb,const struct flash_sector * sector,off_t off,const void * src,size_t len)54 int fcb_flash_write(const struct fcb *fcb, const struct flash_sector *sector,
55 		    off_t off, const void *src, size_t len)
56 {
57 	int rc;
58 
59 	if (off + len > sector->fs_size) {
60 		return -EINVAL;
61 	}
62 
63 	if (fcb->fap == NULL) {
64 		return -EIO;
65 	}
66 
67 	rc = flash_area_write(fcb->fap, sector->fs_off + off, src, len);
68 
69 	if (rc != 0) {
70 		return -EIO;
71 	}
72 
73 	return 0;
74 }
75 
76 int
fcb_erase_sector(const struct fcb * fcb,const struct flash_sector * sector)77 fcb_erase_sector(const struct fcb *fcb, const struct flash_sector *sector)
78 {
79 	int rc;
80 
81 	if (fcb->fap == NULL) {
82 		return -EIO;
83 	}
84 
85 	rc = flash_area_erase(fcb->fap, sector->fs_off, sector->fs_size);
86 
87 	if (rc != 0) {
88 		return -EIO;
89 	}
90 
91 	return 0;
92 }
93 
94 int
fcb_init(int f_area_id,struct fcb * fcb)95 fcb_init(int f_area_id, struct fcb *fcb)
96 {
97 	struct flash_sector *sector;
98 	int rc;
99 	int i;
100 	uint8_t align;
101 	int oldest = -1, newest = -1;
102 	struct flash_sector *oldest_sector = NULL, *newest_sector = NULL;
103 	struct fcb_disk_area fda;
104 	const struct flash_parameters *fparam;
105 
106 	if (!fcb->f_sectors || fcb->f_sector_cnt - fcb->f_scratch_cnt < 1) {
107 		return -EINVAL;
108 	}
109 
110 	rc = flash_area_open(f_area_id, &fcb->fap);
111 	if (rc != 0) {
112 		return -EINVAL;
113 	}
114 
115 	fparam = flash_get_parameters(fcb->fap->fa_dev);
116 	fcb->f_erase_value = fparam->erase_value;
117 
118 	align = fcb_get_align(fcb);
119 	if (align == 0U) {
120 		return -EINVAL;
121 	}
122 
123 	/* Fill last used, first used */
124 	for (i = 0; i < fcb->f_sector_cnt; i++) {
125 		sector = &fcb->f_sectors[i];
126 		rc = fcb_sector_hdr_read(fcb, sector, &fda);
127 		if (rc < 0) {
128 			return rc;
129 		}
130 		if (rc == 0) {
131 			continue;
132 		}
133 		if (oldest < 0) {
134 			oldest = newest = fda.fd_id;
135 			oldest_sector = newest_sector = sector;
136 			continue;
137 		}
138 		if (FCB_ID_GT(fda.fd_id, newest)) {
139 			newest = fda.fd_id;
140 			newest_sector = sector;
141 		} else if (FCB_ID_GT(oldest, fda.fd_id)) {
142 			oldest = fda.fd_id;
143 			oldest_sector = sector;
144 		}
145 	}
146 	if (oldest < 0) {
147 		/*
148 		 * No initialized areas.
149 		 */
150 		oldest_sector = newest_sector = &fcb->f_sectors[0];
151 		rc = fcb_sector_hdr_init(fcb, oldest_sector, 0);
152 		if (rc) {
153 			return rc;
154 		}
155 		newest = oldest = 0;
156 	}
157 	fcb->f_align = align;
158 	fcb->f_oldest = oldest_sector;
159 	fcb->f_active.fe_sector = newest_sector;
160 	fcb->f_active.fe_elem_off = fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area));
161 	fcb->f_active_id = newest;
162 
163 	while (1) {
164 		rc = fcb_getnext_in_sector(fcb, &fcb->f_active);
165 		if (rc == -ENOTSUP) {
166 			rc = 0;
167 			break;
168 		}
169 		if (rc != 0) {
170 			break;
171 		}
172 	}
173 	k_mutex_init(&fcb->f_mtx);
174 	return rc;
175 }
176 
177 int
fcb_free_sector_cnt(struct fcb * fcb)178 fcb_free_sector_cnt(struct fcb *fcb)
179 {
180 	int i;
181 	struct flash_sector *fa;
182 
183 	fa = fcb->f_active.fe_sector;
184 	for (i = 0; i < fcb->f_sector_cnt; i++) {
185 		fa = fcb_getnext_sector(fcb, fa);
186 		if (fa == fcb->f_oldest) {
187 			break;
188 		}
189 	}
190 	return i;
191 }
192 
193 int
fcb_is_empty(struct fcb * fcb)194 fcb_is_empty(struct fcb *fcb)
195 {
196 	return (fcb->f_active.fe_sector == fcb->f_oldest &&
197 	  fcb->f_active.fe_elem_off == fcb_len_in_flash(fcb, sizeof(struct fcb_disk_area)));
198 }
199 
200 /**
201  * Length of an element is encoded in 1 or 2 bytes.
202  * 1 byte for lengths < 128 bytes, 2 bytes for < 16384.
203  *
204  * The storage of length has been originally designed to work with 0xff erasable
205  * flash devices and gives length 0xffff special meaning: that there is no value
206  * written; this is smart way to utilize value in non-written flash to figure
207  * out where data ends. Additionally it sets highest bit of first byte of
208  * the length to 1, to mark that there is second byte to be read.
209  * Above poses some problems when non-0xff erasable flash is used. To solve
210  * the problem all length values are xored with not of erase value for given
211  * flash:
212  *	len' = len ^ ~erase_value;
213  * To obtain original value, the logic is reversed:
214  *	len = len' ^ ~erase_value;
215  *
216  * In case of 0xff erased flash this does not modify data that is written to
217  * flash; in case of other flash devices, e.g. that erase to 0x00, it allows
218  * to correctly use the first bit of byte to figure out how many bytes are there
219  * and if there is any data at all or both bytes are equal to erase value.
220  */
221 int
fcb_put_len(const struct fcb * fcb,uint8_t * buf,uint16_t len)222 fcb_put_len(const struct fcb *fcb, uint8_t *buf, uint16_t len)
223 {
224 	if (len < 0x80) {
225 		buf[0] = len ^ ~fcb->f_erase_value;
226 		return 1;
227 	} else if (len < FCB_MAX_LEN) {
228 		buf[0] = (len | 0x80) ^ ~fcb->f_erase_value;
229 		buf[1] = (len >> 7) ^ ~fcb->f_erase_value;
230 		return 2;
231 	} else {
232 		return -EINVAL;
233 	}
234 }
235 
236 int
fcb_get_len(const struct fcb * fcb,uint8_t * buf,uint16_t * len)237 fcb_get_len(const struct fcb *fcb, uint8_t *buf, uint16_t *len)
238 {
239 	int rc;
240 	if ((buf[0] ^ ~fcb->f_erase_value) & 0x80) {
241 		if ((buf[0] == fcb->f_erase_value) &&
242 		    (buf[1] == fcb->f_erase_value)) {
243 			return -ENOTSUP;
244 		}
245 		*len = ((buf[0] ^ ~fcb->f_erase_value) & 0x7f) |
246 			((uint8_t)(buf[1] ^ ~fcb->f_erase_value) << 7);
247 		rc = 2;
248 	} else {
249 		*len = (uint8_t)(buf[0] ^ ~fcb->f_erase_value);
250 		rc = 1;
251 	}
252 	return rc;
253 }
254 
255 /**
256  * Initialize erased sector for use.
257  */
258 int
fcb_sector_hdr_init(struct fcb * fcb,struct flash_sector * sector,uint16_t id)259 fcb_sector_hdr_init(struct fcb *fcb, struct flash_sector *sector, uint16_t id)
260 {
261 	struct fcb_disk_area fda;
262 	int rc;
263 
264 	fda.fd_magic = fcb_flash_magic(fcb);
265 	fda.fd_ver = fcb->f_version;
266 	fda._pad = fcb->f_erase_value;
267 	fda.fd_id = id;
268 
269 	rc = fcb_flash_write(fcb, sector, 0, &fda, sizeof(fda));
270 	if (rc != 0) {
271 		return -EIO;
272 	}
273 	return 0;
274 }
275 
276 /**
277  * Checks whether FCB sector contains data or not.
278  * Returns <0 in error.
279  * Returns 0 if sector is unused;
280  * Returns 1 if sector has data.
281  */
fcb_sector_hdr_read(struct fcb * fcb,struct flash_sector * sector,struct fcb_disk_area * fdap)282 int fcb_sector_hdr_read(struct fcb *fcb, struct flash_sector *sector,
283 			struct fcb_disk_area *fdap)
284 {
285 	struct fcb_disk_area fda;
286 	int rc;
287 
288 	if (!fdap) {
289 		fdap = &fda;
290 	}
291 	rc = fcb_flash_read(fcb, sector, 0, fdap, sizeof(*fdap));
292 	if (rc) {
293 		return -EIO;
294 	}
295 	if (fdap->fd_magic == MK32(fcb->f_erase_value)) {
296 		return 0;
297 	}
298 	if (fdap->fd_magic != fcb_flash_magic(fcb)) {
299 		return -ENOMSG;
300 	}
301 	return 1;
302 }
303 
304 /**
305  * Finds the fcb entry that gives back upto n entries at the end.
306  * @param0 ptr to fcb
307  * @param1 n number of fcb entries the user wants to get
308  * @param2 ptr to the fcb_entry to be returned
309  * @return 0 on there are any fcbs aviable; -ENOENT otherwise
310  */
311 int
fcb_offset_last_n(struct fcb * fcb,uint8_t entries,struct fcb_entry * last_n_entry)312 fcb_offset_last_n(struct fcb *fcb, uint8_t entries,
313 		struct fcb_entry *last_n_entry)
314 {
315 	struct fcb_entry loc;
316 	int i;
317 	int rc;
318 
319 	/* assure a minimum amount of entries */
320 	if (!entries) {
321 		entries = 1U;
322 	}
323 
324 	i = 0;
325 	(void)memset(&loc, 0, sizeof(loc));
326 	while (!fcb_getnext(fcb, &loc)) {
327 		if (i == 0) {
328 			/* Start from the beginning of fcb entries */
329 			*last_n_entry = loc;
330 		}
331 		/* Update last_n_entry after n entries and keep updating */
332 		else if (i > (entries - 1)) {
333 			rc = fcb_getnext(fcb, last_n_entry);
334 
335 			if (rc) {
336 				/* A fcb history must have been erased,
337 				 * wanted entry doesn't exist anymore.
338 				 */
339 				return -ENOENT;
340 			}
341 		}
342 		i++;
343 	}
344 
345 	return (i == 0) ? -ENOENT : 0;
346 }
347 
348 /**
349  * Clear fcb
350  * @param fcb
351  * @return 0 on success; non-zero on failure
352  */
353 int
fcb_clear(struct fcb * fcb)354 fcb_clear(struct fcb *fcb)
355 {
356 	int rc;
357 
358 	rc = 0;
359 	while (!fcb_is_empty(fcb)) {
360 		rc = fcb_rotate(fcb);
361 		if (rc) {
362 			break;
363 		}
364 	}
365 	return rc;
366 }
367