1 /*  NVS: non volatile storage in flash
2  *
3  * Copyright (c) 2018 Laczen
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <drivers/flash.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <inttypes.h>
12 #include <fs/nvs.h>
13 #include <sys/crc.h>
14 #include "nvs_priv.h"
15 
16 #include <logging/log.h>
17 LOG_MODULE_REGISTER(fs_nvs, CONFIG_NVS_LOG_LEVEL);
18 
19 /* basic routines */
20 /* nvs_al_size returns size aligned to fs->write_block_size */
nvs_al_size(struct nvs_fs * fs,size_t len)21 static inline size_t nvs_al_size(struct nvs_fs *fs, size_t len)
22 {
23 	uint8_t write_block_size = fs->flash_parameters->write_block_size;
24 
25 	if (write_block_size <= 1U) {
26 		return len;
27 	}
28 	return (len + (write_block_size - 1U)) & ~(write_block_size - 1U);
29 }
30 /* end basic routines */
31 
32 /* flash routines */
33 /* basic aligned flash write to nvs address */
nvs_flash_al_wrt(struct nvs_fs * fs,uint32_t addr,const void * data,size_t len)34 static int nvs_flash_al_wrt(struct nvs_fs *fs, uint32_t addr, const void *data,
35 			     size_t len)
36 {
37 	const uint8_t *data8 = (const uint8_t *)data;
38 	int rc = 0;
39 	off_t offset;
40 	size_t blen;
41 	uint8_t buf[NVS_BLOCK_SIZE];
42 
43 	if (!len) {
44 		/* Nothing to write, avoid changing the flash protection */
45 		return 0;
46 	}
47 
48 	offset = fs->offset;
49 	offset += fs->sector_size * (addr >> ADDR_SECT_SHIFT);
50 	offset += addr & ADDR_OFFS_MASK;
51 
52 	blen = len & ~(fs->flash_parameters->write_block_size - 1U);
53 	if (blen > 0) {
54 		rc = flash_write(fs->flash_device, offset, data8, blen);
55 		if (rc) {
56 			/* flash write error */
57 			goto end;
58 		}
59 		len -= blen;
60 		offset += blen;
61 		data8 += blen;
62 	}
63 	if (len) {
64 		memcpy(buf, data8, len);
65 		(void)memset(buf + len, fs->flash_parameters->erase_value,
66 			fs->flash_parameters->write_block_size - len);
67 
68 		rc = flash_write(fs->flash_device, offset, buf,
69 				 fs->flash_parameters->write_block_size);
70 	}
71 
72 end:
73 	return rc;
74 }
75 
76 /* basic flash read from nvs address */
nvs_flash_rd(struct nvs_fs * fs,uint32_t addr,void * data,size_t len)77 static int nvs_flash_rd(struct nvs_fs *fs, uint32_t addr, void *data,
78 			 size_t len)
79 {
80 	int rc;
81 	off_t offset;
82 
83 	offset = fs->offset;
84 	offset += fs->sector_size * (addr >> ADDR_SECT_SHIFT);
85 	offset += addr & ADDR_OFFS_MASK;
86 
87 	rc = flash_read(fs->flash_device, offset, data, len);
88 	return rc;
89 
90 }
91 
92 /* allocation entry write */
nvs_flash_ate_wrt(struct nvs_fs * fs,const struct nvs_ate * entry)93 static int nvs_flash_ate_wrt(struct nvs_fs *fs, const struct nvs_ate *entry)
94 {
95 	int rc;
96 
97 	rc = nvs_flash_al_wrt(fs, fs->ate_wra, entry,
98 			       sizeof(struct nvs_ate));
99 	fs->ate_wra -= nvs_al_size(fs, sizeof(struct nvs_ate));
100 
101 	return rc;
102 }
103 
104 /* data write */
nvs_flash_data_wrt(struct nvs_fs * fs,const void * data,size_t len)105 static int nvs_flash_data_wrt(struct nvs_fs *fs, const void *data, size_t len)
106 {
107 	int rc;
108 
109 	rc = nvs_flash_al_wrt(fs, fs->data_wra, data, len);
110 	fs->data_wra += nvs_al_size(fs, len);
111 
112 	return rc;
113 }
114 
115 /* flash ate read */
nvs_flash_ate_rd(struct nvs_fs * fs,uint32_t addr,struct nvs_ate * entry)116 static int nvs_flash_ate_rd(struct nvs_fs *fs, uint32_t addr,
117 			     struct nvs_ate *entry)
118 {
119 	return nvs_flash_rd(fs, addr, entry, sizeof(struct nvs_ate));
120 }
121 
122 /* end of basic flash routines */
123 
124 /* advanced flash routines */
125 
126 /* nvs_flash_block_cmp compares the data in flash at addr to data
127  * in blocks of size NVS_BLOCK_SIZE aligned to fs->write_block_size
128  * returns 0 if equal, 1 if not equal, errcode if error
129  */
nvs_flash_block_cmp(struct nvs_fs * fs,uint32_t addr,const void * data,size_t len)130 static int nvs_flash_block_cmp(struct nvs_fs *fs, uint32_t addr, const void *data,
131 				size_t len)
132 {
133 	const uint8_t *data8 = (const uint8_t *)data;
134 	int rc;
135 	size_t bytes_to_cmp, block_size;
136 	uint8_t buf[NVS_BLOCK_SIZE];
137 
138 	block_size =
139 		NVS_BLOCK_SIZE & ~(fs->flash_parameters->write_block_size - 1U);
140 
141 	while (len) {
142 		bytes_to_cmp = MIN(block_size, len);
143 		rc = nvs_flash_rd(fs, addr, buf, bytes_to_cmp);
144 		if (rc) {
145 			return rc;
146 		}
147 		rc = memcmp(data8, buf, bytes_to_cmp);
148 		if (rc) {
149 			return 1;
150 		}
151 		len -= bytes_to_cmp;
152 		addr += bytes_to_cmp;
153 		data8 += bytes_to_cmp;
154 	}
155 	return 0;
156 }
157 
158 /* nvs_flash_cmp_const compares the data in flash at addr to a constant
159  * value. returns 0 if all data in flash is equal to value, 1 if not equal,
160  * errcode if error
161  */
nvs_flash_cmp_const(struct nvs_fs * fs,uint32_t addr,uint8_t value,size_t len)162 static int nvs_flash_cmp_const(struct nvs_fs *fs, uint32_t addr, uint8_t value,
163 				size_t len)
164 {
165 	int rc;
166 	size_t bytes_to_cmp, block_size;
167 	uint8_t cmp[NVS_BLOCK_SIZE];
168 
169 	block_size =
170 		NVS_BLOCK_SIZE & ~(fs->flash_parameters->write_block_size - 1U);
171 
172 	(void)memset(cmp, value, block_size);
173 	while (len) {
174 		bytes_to_cmp = MIN(block_size, len);
175 		rc = nvs_flash_block_cmp(fs, addr, cmp, bytes_to_cmp);
176 		if (rc) {
177 			return rc;
178 		}
179 		len -= bytes_to_cmp;
180 		addr += bytes_to_cmp;
181 	}
182 	return 0;
183 }
184 
185 /* flash block move: move a block at addr to the current data write location
186  * and updates the data write location.
187  */
nvs_flash_block_move(struct nvs_fs * fs,uint32_t addr,size_t len)188 static int nvs_flash_block_move(struct nvs_fs *fs, uint32_t addr, size_t len)
189 {
190 	int rc;
191 	size_t bytes_to_copy, block_size;
192 	uint8_t buf[NVS_BLOCK_SIZE];
193 
194 	block_size =
195 		NVS_BLOCK_SIZE & ~(fs->flash_parameters->write_block_size - 1U);
196 
197 	while (len) {
198 		bytes_to_copy = MIN(block_size, len);
199 		rc = nvs_flash_rd(fs, addr, buf, bytes_to_copy);
200 		if (rc) {
201 			return rc;
202 		}
203 		rc = nvs_flash_data_wrt(fs, buf, bytes_to_copy);
204 		if (rc) {
205 			return rc;
206 		}
207 		len -= bytes_to_copy;
208 		addr += bytes_to_copy;
209 	}
210 	return 0;
211 }
212 
213 /* erase a sector and verify erase was OK.
214  * return 0 if OK, errorcode on error.
215  */
nvs_flash_erase_sector(struct nvs_fs * fs,uint32_t addr)216 static int nvs_flash_erase_sector(struct nvs_fs *fs, uint32_t addr)
217 {
218 	int rc;
219 	off_t offset;
220 
221 	addr &= ADDR_SECT_MASK;
222 
223 	offset = fs->offset;
224 	offset += fs->sector_size * (addr >> ADDR_SECT_SHIFT);
225 
226 	LOG_DBG("Erasing flash at %lx, len %d", (long int) offset,
227 		fs->sector_size);
228 	rc = flash_erase(fs->flash_device, offset, fs->sector_size);
229 
230 	if (rc) {
231 		return rc;
232 	}
233 
234 	if (nvs_flash_cmp_const(fs, addr, fs->flash_parameters->erase_value,
235 			fs->sector_size)) {
236 		rc = -ENXIO;
237 	}
238 
239 	return rc;
240 }
241 
242 /* crc update on allocation entry */
nvs_ate_crc8_update(struct nvs_ate * entry)243 static void nvs_ate_crc8_update(struct nvs_ate *entry)
244 {
245 	uint8_t crc8;
246 
247 	crc8 = crc8_ccitt(0xff, entry, offsetof(struct nvs_ate, crc8));
248 	entry->crc8 = crc8;
249 }
250 
251 /* crc check on allocation entry
252  * returns 0 if OK, 1 on crc fail
253  */
nvs_ate_crc8_check(const struct nvs_ate * entry)254 static int nvs_ate_crc8_check(const struct nvs_ate *entry)
255 {
256 	uint8_t crc8;
257 
258 	crc8 = crc8_ccitt(0xff, entry, offsetof(struct nvs_ate, crc8));
259 	if (crc8 == entry->crc8) {
260 		return 0;
261 	}
262 	return 1;
263 }
264 
265 /* nvs_ate_cmp_const compares an ATE to a constant value. returns 0 if
266  * the whole ATE is equal to value, 1 if not equal.
267  */
268 
nvs_ate_cmp_const(const struct nvs_ate * entry,uint8_t value)269 static int nvs_ate_cmp_const(const struct nvs_ate *entry, uint8_t value)
270 {
271 	const uint8_t *data8 = (const uint8_t *)entry;
272 	int i;
273 
274 	for (i = 0; i < sizeof(struct nvs_ate); i++) {
275 		if (data8[i] != value) {
276 			return 1;
277 		}
278 	}
279 
280 	return 0;
281 }
282 
283 /* nvs_ate_valid validates an ate:
284  *     return 1 if crc8 and offset valid,
285  *            0 otherwise
286  */
nvs_ate_valid(struct nvs_fs * fs,const struct nvs_ate * entry)287 static int nvs_ate_valid(struct nvs_fs *fs, const struct nvs_ate *entry)
288 {
289 	size_t ate_size;
290 
291 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
292 
293 	if ((nvs_ate_crc8_check(entry)) ||
294 	    (entry->offset >= (fs->sector_size - ate_size))) {
295 		return 0;
296 	}
297 
298 	return 1;
299 
300 }
301 
302 /* nvs_close_ate_valid validates an sector close ate: a valid sector close ate:
303  * - valid ate
304  * - len = 0 and id = 0xFFFF
305  * - offset points to location at ate multiple from sector size
306  * return 1 if valid, 0 otherwise
307  */
nvs_close_ate_valid(struct nvs_fs * fs,const struct nvs_ate * entry)308 static int nvs_close_ate_valid(struct nvs_fs *fs, const struct nvs_ate *entry)
309 {
310 	size_t ate_size;
311 
312 	if ((!nvs_ate_valid(fs, entry)) || (entry->len != 0U) ||
313 	    (entry->id != 0xFFFF)) {
314 		return 0;
315 	}
316 
317 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
318 	if ((fs->sector_size - entry->offset) % ate_size) {
319 		return 0;
320 	}
321 
322 	return 1;
323 }
324 
325 /* store an entry in flash */
nvs_flash_wrt_entry(struct nvs_fs * fs,uint16_t id,const void * data,size_t len)326 static int nvs_flash_wrt_entry(struct nvs_fs *fs, uint16_t id, const void *data,
327 				size_t len)
328 {
329 	int rc;
330 	struct nvs_ate entry;
331 	size_t ate_size;
332 
333 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
334 
335 	entry.id = id;
336 	entry.offset = (uint16_t)(fs->data_wra & ADDR_OFFS_MASK);
337 	entry.len = (uint16_t)len;
338 	entry.part = 0xff;
339 
340 	nvs_ate_crc8_update(&entry);
341 
342 	rc = nvs_flash_data_wrt(fs, data, len);
343 	if (rc) {
344 		return rc;
345 	}
346 	rc = nvs_flash_ate_wrt(fs, &entry);
347 	if (rc) {
348 		return rc;
349 	}
350 
351 	return 0;
352 }
353 /* end of flash routines */
354 
355 /* If the closing ate is invalid, its offset cannot be trusted and
356  * the last valod ate of the sector should instead try to be recovered by going
357  * through all ate's.
358  *
359  * addr should point to the faulty closing ate and will be updated to the last
360  * valid ate. If no valid ate is found it will be left untouched.
361  */
nvs_recover_last_ate(struct nvs_fs * fs,uint32_t * addr)362 static int nvs_recover_last_ate(struct nvs_fs *fs, uint32_t *addr)
363 {
364 	uint32_t data_end_addr, ate_end_addr;
365 	struct nvs_ate end_ate;
366 	size_t ate_size;
367 	int rc;
368 
369 	LOG_DBG("Recovering last ate from sector %d",
370 		(*addr >> ADDR_SECT_SHIFT));
371 
372 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
373 
374 	*addr -= ate_size;
375 	ate_end_addr = *addr;
376 	data_end_addr = *addr & ADDR_SECT_MASK;
377 	while (ate_end_addr > data_end_addr) {
378 		rc = nvs_flash_ate_rd(fs, ate_end_addr, &end_ate);
379 		if (rc) {
380 			return rc;
381 		}
382 		if (nvs_ate_valid(fs, &end_ate)) {
383 			/* found a valid ate, update data_end_addr and *addr */
384 			data_end_addr &= ADDR_SECT_MASK;
385 			data_end_addr += end_ate.offset + end_ate.len;
386 			*addr = ate_end_addr;
387 		}
388 		ate_end_addr -= ate_size;
389 	}
390 
391 	return 0;
392 }
393 
394 /* walking through allocation entry list, from newest to oldest entries
395  * read ate from addr, modify addr to the previous ate
396  */
nvs_prev_ate(struct nvs_fs * fs,uint32_t * addr,struct nvs_ate * ate)397 static int nvs_prev_ate(struct nvs_fs *fs, uint32_t *addr, struct nvs_ate *ate)
398 {
399 	int rc;
400 	struct nvs_ate close_ate;
401 	size_t ate_size;
402 
403 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
404 
405 	rc = nvs_flash_ate_rd(fs, *addr, ate);
406 	if (rc) {
407 		return rc;
408 	}
409 
410 	*addr += ate_size;
411 	if (((*addr) & ADDR_OFFS_MASK) != (fs->sector_size - ate_size)) {
412 		return 0;
413 	}
414 
415 	/* last ate in sector, do jump to previous sector */
416 	if (((*addr) >> ADDR_SECT_SHIFT) == 0U) {
417 		*addr += ((fs->sector_count - 1) << ADDR_SECT_SHIFT);
418 	} else {
419 		*addr -= (1 << ADDR_SECT_SHIFT);
420 	}
421 
422 	rc = nvs_flash_ate_rd(fs, *addr, &close_ate);
423 	if (rc) {
424 		return rc;
425 	}
426 
427 	rc = nvs_ate_cmp_const(&close_ate, fs->flash_parameters->erase_value);
428 	/* at the end of filesystem */
429 	if (!rc) {
430 		*addr = fs->ate_wra;
431 		return 0;
432 	}
433 
434 	/* Update the address if the close ate is valid.
435 	 */
436 	if (nvs_close_ate_valid(fs, &close_ate)) {
437 		(*addr) &= ADDR_SECT_MASK;
438 		(*addr) += close_ate.offset;
439 		return 0;
440 	}
441 
442 	/* The close_ate was invalid, `lets find out the last valid ate
443 	 * and point the address to this found ate.
444 	 *
445 	 * remark: if there was absolutely no valid data in the sector *addr
446 	 * is kept at sector_end - 2*ate_size, the next read will contain
447 	 * invalid data and continue with a sector jump
448 	 */
449 	return nvs_recover_last_ate(fs, addr);
450 }
451 
nvs_sector_advance(struct nvs_fs * fs,uint32_t * addr)452 static void nvs_sector_advance(struct nvs_fs *fs, uint32_t *addr)
453 {
454 	*addr += (1 << ADDR_SECT_SHIFT);
455 	if ((*addr >> ADDR_SECT_SHIFT) == fs->sector_count) {
456 		*addr -= (fs->sector_count << ADDR_SECT_SHIFT);
457 	}
458 }
459 
460 /* allocation entry close (this closes the current sector) by writing offset
461  * of last ate to the sector end.
462  */
nvs_sector_close(struct nvs_fs * fs)463 static int nvs_sector_close(struct nvs_fs *fs)
464 {
465 	int rc;
466 	struct nvs_ate close_ate;
467 	size_t ate_size;
468 
469 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
470 
471 	close_ate.id = 0xFFFF;
472 	close_ate.len = 0U;
473 	close_ate.offset = (uint16_t)((fs->ate_wra + ate_size) & ADDR_OFFS_MASK);
474 
475 	fs->ate_wra &= ADDR_SECT_MASK;
476 	fs->ate_wra += (fs->sector_size - ate_size);
477 
478 	nvs_ate_crc8_update(&close_ate);
479 
480 	rc = nvs_flash_ate_wrt(fs, &close_ate);
481 
482 	nvs_sector_advance(fs, &fs->ate_wra);
483 
484 	fs->data_wra = fs->ate_wra & ADDR_SECT_MASK;
485 
486 	return 0;
487 }
488 
nvs_add_gc_done_ate(struct nvs_fs * fs)489 static int nvs_add_gc_done_ate(struct nvs_fs *fs)
490 {
491 	struct nvs_ate gc_done_ate;
492 
493 	LOG_DBG("Adding gc done ate at %x", fs->ate_wra & ADDR_OFFS_MASK);
494 	gc_done_ate.id = 0xffff;
495 	gc_done_ate.len = 0U;
496 	gc_done_ate.offset = (uint16_t)(fs->data_wra & ADDR_OFFS_MASK);
497 	nvs_ate_crc8_update(&gc_done_ate);
498 
499 	return nvs_flash_ate_wrt(fs, &gc_done_ate);
500 }
501 /* garbage collection: the address ate_wra has been updated to the new sector
502  * that has just been started. The data to gc is in the sector after this new
503  * sector.
504  */
nvs_gc(struct nvs_fs * fs)505 static int nvs_gc(struct nvs_fs *fs)
506 {
507 	int rc;
508 	struct nvs_ate close_ate, gc_ate, wlk_ate;
509 	uint32_t sec_addr, gc_addr, gc_prev_addr, wlk_addr, wlk_prev_addr,
510 	      data_addr, stop_addr;
511 	size_t ate_size;
512 
513 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
514 
515 	sec_addr = (fs->ate_wra & ADDR_SECT_MASK);
516 	nvs_sector_advance(fs, &sec_addr);
517 	gc_addr = sec_addr + fs->sector_size - ate_size;
518 
519 	/* if the sector is not closed don't do gc */
520 	rc = nvs_flash_ate_rd(fs, gc_addr, &close_ate);
521 	if (rc < 0) {
522 		/* flash error */
523 		return rc;
524 	}
525 
526 	rc = nvs_ate_cmp_const(&close_ate, fs->flash_parameters->erase_value);
527 	if (!rc) {
528 		goto gc_done;
529 	}
530 
531 	stop_addr = gc_addr - ate_size;
532 
533 	if (nvs_close_ate_valid(fs, &close_ate)) {
534 		gc_addr &= ADDR_SECT_MASK;
535 		gc_addr += close_ate.offset;
536 	} else {
537 		rc = nvs_recover_last_ate(fs, &gc_addr);
538 		if (rc) {
539 			return rc;
540 		}
541 	}
542 
543 	do {
544 		gc_prev_addr = gc_addr;
545 		rc = nvs_prev_ate(fs, &gc_addr, &gc_ate);
546 		if (rc) {
547 			return rc;
548 		}
549 
550 		if (!nvs_ate_valid(fs, &gc_ate)) {
551 			continue;
552 		}
553 
554 		wlk_addr = fs->ate_wra;
555 		do {
556 			wlk_prev_addr = wlk_addr;
557 			rc = nvs_prev_ate(fs, &wlk_addr, &wlk_ate);
558 			if (rc) {
559 				return rc;
560 			}
561 			/* if ate with same id is reached we might need to copy.
562 			 * only consider valid wlk_ate's. Something wrong might
563 			 * have been written that has the same ate but is
564 			 * invalid, don't consider these as a match.
565 			 */
566 			if ((wlk_ate.id == gc_ate.id) &&
567 			    (nvs_ate_valid(fs, &wlk_ate))) {
568 				break;
569 			}
570 		} while (wlk_addr != fs->ate_wra);
571 
572 		/* if walk has reached the same address as gc_addr copy is
573 		 * needed unless it is a deleted item.
574 		 */
575 		if ((wlk_prev_addr == gc_prev_addr) && gc_ate.len) {
576 			/* copy needed */
577 			LOG_DBG("Moving %d, len %d", gc_ate.id, gc_ate.len);
578 
579 			data_addr = (gc_prev_addr & ADDR_SECT_MASK);
580 			data_addr += gc_ate.offset;
581 
582 			gc_ate.offset = (uint16_t)(fs->data_wra & ADDR_OFFS_MASK);
583 			nvs_ate_crc8_update(&gc_ate);
584 
585 			rc = nvs_flash_block_move(fs, data_addr, gc_ate.len);
586 			if (rc) {
587 				return rc;
588 			}
589 
590 			rc = nvs_flash_ate_wrt(fs, &gc_ate);
591 			if (rc) {
592 				return rc;
593 			}
594 		}
595 	} while (gc_prev_addr != stop_addr);
596 
597 gc_done:
598 
599 	/* Make it possible to detect that gc has finished by writing a
600 	 * gc done ate to the sector. In the field we might have nvs systems
601 	 * that do not have sufficient space to add this ate, so for these
602 	 * situations avoid adding the gc done ate.
603 	 */
604 
605 	if (fs->ate_wra >= (fs->data_wra + ate_size)) {
606 		rc = nvs_add_gc_done_ate(fs);
607 		if (rc) {
608 			return rc;
609 		}
610 	}
611 
612 	/* Erase the gc'ed sector */
613 	rc = nvs_flash_erase_sector(fs, sec_addr);
614 	if (rc) {
615 		return rc;
616 	}
617 	return 0;
618 }
619 
nvs_startup(struct nvs_fs * fs)620 static int nvs_startup(struct nvs_fs *fs)
621 {
622 	int rc;
623 	struct nvs_ate last_ate;
624 	size_t ate_size, empty_len;
625 	/* Initialize addr to 0 for the case fs->sector_count == 0. This
626 	 * should never happen as this is verified in nvs_init() but both
627 	 * Coverity and GCC believe the contrary.
628 	 */
629 	uint32_t addr = 0U;
630 	uint16_t i, closed_sectors = 0;
631 	uint8_t erase_value = fs->flash_parameters->erase_value;
632 
633 	k_mutex_lock(&fs->nvs_lock, K_FOREVER);
634 
635 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
636 	/* step through the sectors to find a open sector following
637 	 * a closed sector, this is where NVS can to write.
638 	 */
639 	for (i = 0; i < fs->sector_count; i++) {
640 		addr = (i << ADDR_SECT_SHIFT) +
641 		       (uint16_t)(fs->sector_size - ate_size);
642 		rc = nvs_flash_cmp_const(fs, addr, erase_value,
643 					 sizeof(struct nvs_ate));
644 		if (rc) {
645 			/* closed sector */
646 			closed_sectors++;
647 			nvs_sector_advance(fs, &addr);
648 			rc = nvs_flash_cmp_const(fs, addr, erase_value,
649 						 sizeof(struct nvs_ate));
650 			if (!rc) {
651 				/* open sector */
652 				break;
653 			}
654 		}
655 	}
656 	/* all sectors are closed, this is not a nvs fs */
657 	if (closed_sectors == fs->sector_count) {
658 		rc = -EDEADLK;
659 		goto end;
660 	}
661 
662 	if (i == fs->sector_count) {
663 		/* none of the sectors where closed, in most cases we can set
664 		 * the address to the first sector, except when there are only
665 		 * two sectors. Then we can only set it to the first sector if
666 		 * the last sector contains no ate's. So we check this first
667 		 */
668 		rc = nvs_flash_cmp_const(fs, addr - ate_size, erase_value,
669 				sizeof(struct nvs_ate));
670 		if (!rc) {
671 			/* empty ate */
672 			nvs_sector_advance(fs, &addr);
673 		}
674 	}
675 
676 	/* addr contains address of closing ate in the most recent sector,
677 	 * search for the last valid ate using the recover_last_ate routine
678 	 */
679 
680 	rc = nvs_recover_last_ate(fs, &addr);
681 	if (rc) {
682 		goto end;
683 	}
684 
685 
686 	/* addr contains address of the last valid ate in the most recent sector
687 	 * search for the first ate containing all cells erased, in the process
688 	 * also update fs->data_wra.
689 	 */
690 	fs->ate_wra = addr;
691 	fs->data_wra = addr & ADDR_SECT_MASK;
692 
693 	while (fs->ate_wra >= fs->data_wra) {
694 		rc = nvs_flash_ate_rd(fs, fs->ate_wra, &last_ate);
695 		if (rc) {
696 			goto end;
697 		}
698 
699 		rc = nvs_ate_cmp_const(&last_ate, erase_value);
700 
701 		if (!rc) {
702 			/* found ff empty location */
703 			break;
704 		}
705 
706 		if (nvs_ate_valid(fs, &last_ate)) {
707 			/* complete write of ate was performed */
708 			fs->data_wra = addr & ADDR_SECT_MASK;
709 			/* Align the data write address to the current
710 			 * write block size so that it is possible to write to
711 			 * the sector even if the block size has changed after
712 			 * a software upgrade (unless the physical ATE size
713 			 * will change)."
714 			 */
715 			fs->data_wra += nvs_al_size(fs, last_ate.offset + last_ate.len);
716 
717 			/* ate on the last possition within the sector is
718 			 * reserved for deletion an entry
719 			 */
720 			if (fs->ate_wra == fs->data_wra && last_ate.len) {
721 				/* not a delete ate */
722 				rc = -ESPIPE;
723 				goto end;
724 			}
725 		}
726 
727 		fs->ate_wra -= ate_size;
728 	}
729 
730 	/* if the sector after the write sector is not empty gc was interrupted
731 	 * we might need to restart gc if it has not yet finished. Otherwise
732 	 * just erase the sector.
733 	 * When gc needs to be restarted, first erase the sector otherwise the
734 	 * data might not fit into the sector.
735 	 */
736 	addr = fs->ate_wra & ADDR_SECT_MASK;
737 	nvs_sector_advance(fs, &addr);
738 	rc = nvs_flash_cmp_const(fs, addr, erase_value, fs->sector_size);
739 	if (rc < 0) {
740 		goto end;
741 	}
742 	if (rc) {
743 		/* the sector after fs->ate_wrt is not empty, look for a marker
744 		 * (gc_done_ate) that indicates that gc was finished.
745 		 */
746 		bool gc_done_marker = false;
747 		struct nvs_ate gc_done_ate;
748 
749 		addr = fs->ate_wra + ate_size;
750 		while ((addr & ADDR_OFFS_MASK) < (fs->sector_size - ate_size)) {
751 			rc = nvs_flash_ate_rd(fs, addr, &gc_done_ate);
752 			if (rc) {
753 				goto end;
754 			}
755 			if (nvs_ate_valid(fs, &gc_done_ate) &&
756 			    (gc_done_ate.id == 0xffff) &&
757 			    (gc_done_ate.len == 0U)) {
758 				gc_done_marker = true;
759 				break;
760 			}
761 			addr += ate_size;
762 		}
763 
764 		if (gc_done_marker) {
765 			/* erase the next sector */
766 			LOG_INF("GC Done marker found");
767 			addr = fs->ate_wra & ADDR_SECT_MASK;
768 			nvs_sector_advance(fs, &addr);
769 			rc = nvs_flash_erase_sector(fs, addr);
770 			goto end;
771 		}
772 		LOG_INF("No GC Done marker found: restarting gc");
773 		rc = nvs_flash_erase_sector(fs, fs->ate_wra);
774 		if (rc) {
775 			goto end;
776 		}
777 		fs->ate_wra &= ADDR_SECT_MASK;
778 		fs->ate_wra += (fs->sector_size - 2 * ate_size);
779 		fs->data_wra = (fs->ate_wra & ADDR_SECT_MASK);
780 		rc = nvs_gc(fs);
781 		goto end;
782 	}
783 
784 	/* possible data write after last ate write, update data_wra */
785 	while (fs->ate_wra > fs->data_wra) {
786 		empty_len = fs->ate_wra - fs->data_wra;
787 
788 		rc = nvs_flash_cmp_const(fs, fs->data_wra, erase_value,
789 				empty_len);
790 		if (rc < 0) {
791 			goto end;
792 		}
793 		if (!rc) {
794 			break;
795 		}
796 
797 		fs->data_wra += fs->flash_parameters->write_block_size;
798 	}
799 
800 	/* If the ate_wra is pointing to the first ate write location in a
801 	 * sector and data_wra is not 0, erase the sector as it contains no
802 	 * valid data (this also avoids closing a sector without any data).
803 	 */
804 	if (((fs->ate_wra + 2 * ate_size) == fs->sector_size) &&
805 	    (fs->data_wra != (fs->ate_wra & ADDR_SECT_MASK))) {
806 		rc = nvs_flash_erase_sector(fs, fs->ate_wra);
807 		if (rc) {
808 			goto end;
809 		}
810 		fs->data_wra = fs->ate_wra & ADDR_SECT_MASK;
811 	}
812 
813 end:
814 	/* If the sector is empty add a gc done ate to avoid having insufficient
815 	 * space when doing gc.
816 	 */
817 	if ((!rc) && ((fs->ate_wra & ADDR_OFFS_MASK) ==
818 		      (fs->sector_size - 2 * ate_size))) {
819 
820 		rc = nvs_add_gc_done_ate(fs);
821 	}
822 	k_mutex_unlock(&fs->nvs_lock);
823 	return rc;
824 }
825 
nvs_clear(struct nvs_fs * fs)826 int nvs_clear(struct nvs_fs *fs)
827 {
828 	int rc;
829 	uint32_t addr;
830 
831 	if (!fs->ready) {
832 		LOG_ERR("NVS not initialized");
833 		return -EACCES;
834 	}
835 
836 	for (uint16_t i = 0; i < fs->sector_count; i++) {
837 		addr = i << ADDR_SECT_SHIFT;
838 		rc = nvs_flash_erase_sector(fs, addr);
839 		if (rc) {
840 			return rc;
841 		}
842 	}
843 
844 	/* nvs needs to be reinitialized after clearing */
845 	fs->ready = false;
846 
847 	return 0;
848 }
849 
nvs_init(struct nvs_fs * fs,const char * dev_name)850 int nvs_init(struct nvs_fs *fs, const char *dev_name)
851 {
852 
853 	int rc;
854 	struct flash_pages_info info;
855 	size_t write_block_size;
856 
857 	k_mutex_init(&fs->nvs_lock);
858 
859 	fs->flash_device = device_get_binding(dev_name);
860 	if (!fs->flash_device) {
861 		LOG_ERR("No valid flash device found");
862 		return -ENXIO;
863 	}
864 
865 	fs->flash_parameters = flash_get_parameters(fs->flash_device);
866 	if (fs->flash_parameters == NULL) {
867 		LOG_ERR("Could not obtain flash parameters");
868 		return -EINVAL;
869 	}
870 
871 	write_block_size = flash_get_write_block_size(fs->flash_device);
872 
873 	/* check that the write block size is supported */
874 	if (write_block_size > NVS_BLOCK_SIZE || write_block_size == 0) {
875 		LOG_ERR("Unsupported write block size");
876 		return -EINVAL;
877 	}
878 
879 	/* check that sector size is a multiple of pagesize */
880 	rc = flash_get_page_info_by_offs(fs->flash_device, fs->offset, &info);
881 	if (rc) {
882 		LOG_ERR("Unable to get page info");
883 		return -EINVAL;
884 	}
885 	if (!fs->sector_size || fs->sector_size % info.size) {
886 		LOG_ERR("Invalid sector size");
887 		return -EINVAL;
888 	}
889 
890 	/* check the number of sectors, it should be at least 2 */
891 	if (fs->sector_count < 2) {
892 		LOG_ERR("Configuration error - sector count");
893 		return -EINVAL;
894 	}
895 
896 	rc = nvs_startup(fs);
897 	if (rc) {
898 		return rc;
899 	}
900 
901 	/* nvs is ready for use */
902 	fs->ready = true;
903 
904 	LOG_INF("%d Sectors of %d bytes", fs->sector_count, fs->sector_size);
905 	LOG_INF("alloc wra: %d, %x",
906 		(fs->ate_wra >> ADDR_SECT_SHIFT),
907 		(fs->ate_wra & ADDR_OFFS_MASK));
908 	LOG_INF("data wra: %d, %x",
909 		(fs->data_wra >> ADDR_SECT_SHIFT),
910 		(fs->data_wra & ADDR_OFFS_MASK));
911 
912 	return 0;
913 }
914 
nvs_write(struct nvs_fs * fs,uint16_t id,const void * data,size_t len)915 ssize_t nvs_write(struct nvs_fs *fs, uint16_t id, const void *data, size_t len)
916 {
917 	int rc, gc_count;
918 	size_t ate_size, data_size;
919 	struct nvs_ate wlk_ate;
920 	uint32_t wlk_addr, rd_addr;
921 	uint16_t required_space = 0U; /* no space, appropriate for delete ate */
922 	bool prev_found = false;
923 
924 	if (!fs->ready) {
925 		LOG_ERR("NVS not initialized");
926 		return -EACCES;
927 	}
928 
929 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
930 	data_size = nvs_al_size(fs, len);
931 
932 	/* The maximum data size is sector size - 4 ate
933 	 * where: 1 ate for data, 1 ate for sector close, 1 ate for gc done,
934 	 * and 1 ate to always allow a delete.
935 	 */
936 	if ((len > (fs->sector_size - 4 * ate_size)) ||
937 	    ((len > 0) && (data == NULL))) {
938 		return -EINVAL;
939 	}
940 
941 	/* find latest entry with same id */
942 	wlk_addr = fs->ate_wra;
943 	rd_addr = wlk_addr;
944 
945 	while (1) {
946 		rd_addr = wlk_addr;
947 		rc = nvs_prev_ate(fs, &wlk_addr, &wlk_ate);
948 		if (rc) {
949 			return rc;
950 		}
951 		if ((wlk_ate.id == id) && (nvs_ate_valid(fs, &wlk_ate))) {
952 			prev_found = true;
953 			break;
954 		}
955 		if (wlk_addr == fs->ate_wra) {
956 			break;
957 		}
958 	}
959 
960 	if (prev_found) {
961 		/* previous entry found */
962 		rd_addr &= ADDR_SECT_MASK;
963 		rd_addr += wlk_ate.offset;
964 
965 		if (len == 0) {
966 			/* do not try to compare with empty data */
967 			if (wlk_ate.len == 0U) {
968 				/* skip delete entry as it is already the
969 				 * last one
970 				 */
971 				return 0;
972 			}
973 		} else if (len == wlk_ate.len) {
974 			/* do not try to compare if lengths are not equal */
975 			/* compare the data and if equal return 0 */
976 			rc = nvs_flash_block_cmp(fs, rd_addr, data, len);
977 			if (rc <= 0) {
978 				return rc;
979 			}
980 		}
981 	} else {
982 		/* skip delete entry for non-existing entry */
983 		if (len == 0) {
984 			return 0;
985 		}
986 	}
987 
988 	/* calculate required space if the entry contains data */
989 	if (data_size) {
990 		/* Leave space for delete ate */
991 		required_space = data_size + ate_size;
992 	}
993 
994 	k_mutex_lock(&fs->nvs_lock, K_FOREVER);
995 
996 	gc_count = 0;
997 	while (1) {
998 		if (gc_count == fs->sector_count) {
999 			/* gc'ed all sectors, no extra space will be created
1000 			 * by extra gc.
1001 			 */
1002 			rc = -ENOSPC;
1003 			goto end;
1004 		}
1005 
1006 		if (fs->ate_wra >= (fs->data_wra + required_space)) {
1007 
1008 			rc = nvs_flash_wrt_entry(fs, id, data, len);
1009 			if (rc) {
1010 				goto end;
1011 			}
1012 			break;
1013 		}
1014 
1015 
1016 		rc = nvs_sector_close(fs);
1017 		if (rc) {
1018 			goto end;
1019 		}
1020 
1021 		rc = nvs_gc(fs);
1022 		if (rc) {
1023 			goto end;
1024 		}
1025 		gc_count++;
1026 	}
1027 	rc = len;
1028 end:
1029 	k_mutex_unlock(&fs->nvs_lock);
1030 	return rc;
1031 }
1032 
nvs_delete(struct nvs_fs * fs,uint16_t id)1033 int nvs_delete(struct nvs_fs *fs, uint16_t id)
1034 {
1035 	return nvs_write(fs, id, NULL, 0);
1036 }
1037 
nvs_read_hist(struct nvs_fs * fs,uint16_t id,void * data,size_t len,uint16_t cnt)1038 ssize_t nvs_read_hist(struct nvs_fs *fs, uint16_t id, void *data, size_t len,
1039 		      uint16_t cnt)
1040 {
1041 	int rc;
1042 	uint32_t wlk_addr, rd_addr;
1043 	uint16_t cnt_his;
1044 	struct nvs_ate wlk_ate;
1045 	size_t ate_size;
1046 
1047 	if (!fs->ready) {
1048 		LOG_ERR("NVS not initialized");
1049 		return -EACCES;
1050 	}
1051 
1052 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
1053 
1054 	if (len > (fs->sector_size - 2 * ate_size)) {
1055 		return -EINVAL;
1056 	}
1057 
1058 	cnt_his = 0U;
1059 
1060 	wlk_addr = fs->ate_wra;
1061 	rd_addr = wlk_addr;
1062 
1063 	while (cnt_his <= cnt) {
1064 		rd_addr = wlk_addr;
1065 		rc = nvs_prev_ate(fs, &wlk_addr, &wlk_ate);
1066 		if (rc) {
1067 			goto err;
1068 		}
1069 		if ((wlk_ate.id == id) &&  (nvs_ate_valid(fs, &wlk_ate))) {
1070 			cnt_his++;
1071 		}
1072 		if (wlk_addr == fs->ate_wra) {
1073 			break;
1074 		}
1075 	}
1076 
1077 	if (((wlk_addr == fs->ate_wra) && (wlk_ate.id != id)) ||
1078 	    (wlk_ate.len == 0U) || (cnt_his < cnt)) {
1079 		return -ENOENT;
1080 	}
1081 
1082 	rd_addr &= ADDR_SECT_MASK;
1083 	rd_addr += wlk_ate.offset;
1084 	rc = nvs_flash_rd(fs, rd_addr, data, MIN(len, wlk_ate.len));
1085 	if (rc) {
1086 		goto err;
1087 	}
1088 
1089 	return wlk_ate.len;
1090 
1091 err:
1092 	return rc;
1093 }
1094 
nvs_read(struct nvs_fs * fs,uint16_t id,void * data,size_t len)1095 ssize_t nvs_read(struct nvs_fs *fs, uint16_t id, void *data, size_t len)
1096 {
1097 	int rc;
1098 
1099 	rc = nvs_read_hist(fs, id, data, len, 0);
1100 	return rc;
1101 }
1102 
nvs_calc_free_space(struct nvs_fs * fs)1103 ssize_t nvs_calc_free_space(struct nvs_fs *fs)
1104 {
1105 
1106 	int rc;
1107 	struct nvs_ate step_ate, wlk_ate;
1108 	uint32_t step_addr, wlk_addr;
1109 	size_t ate_size, free_space;
1110 
1111 	if (!fs->ready) {
1112 		LOG_ERR("NVS not initialized");
1113 		return -EACCES;
1114 	}
1115 
1116 	ate_size = nvs_al_size(fs, sizeof(struct nvs_ate));
1117 
1118 	free_space = 0;
1119 	for (uint16_t i = 1; i < fs->sector_count; i++) {
1120 		free_space += (fs->sector_size - ate_size);
1121 	}
1122 
1123 	step_addr = fs->ate_wra;
1124 
1125 	while (1) {
1126 		rc = nvs_prev_ate(fs, &step_addr, &step_ate);
1127 		if (rc) {
1128 			return rc;
1129 		}
1130 
1131 		wlk_addr = fs->ate_wra;
1132 
1133 		while (1) {
1134 			rc = nvs_prev_ate(fs, &wlk_addr, &wlk_ate);
1135 			if (rc) {
1136 				return rc;
1137 			}
1138 			if ((wlk_ate.id == step_ate.id) ||
1139 			    (wlk_addr == fs->ate_wra)) {
1140 				break;
1141 			}
1142 		}
1143 
1144 		if ((wlk_addr == step_addr) && step_ate.len &&
1145 		    (nvs_ate_valid(fs, &step_ate))) {
1146 			/* count needed */
1147 			free_space -= nvs_al_size(fs, step_ate.len);
1148 			free_space -= ate_size;
1149 		}
1150 
1151 		if (step_addr == fs->ate_wra) {
1152 			break;
1153 		}
1154 
1155 	}
1156 	return free_space;
1157 }
1158