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