1 /*
2 * Copyright (c) 2017-2023 Nordic Semiconductor ASA
3 * Copyright (c) 2015 Runtime Inc
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/sys/crc.h>
9
10 #include <zephyr/fs/fcb.h>
11 #include "fcb_priv.h"
12
13 #define FCB_FIXED_ENDMARKER 0xab
14
15 /*
16 * Given offset in flash sector, fill in rest of the fcb_entry, and crc8 over
17 * the data.
18 */
19 static int
fcb_elem_crc8(struct fcb * _fcb,struct fcb_entry * loc,uint8_t * c8p)20 fcb_elem_crc8(struct fcb *_fcb, struct fcb_entry *loc, uint8_t *c8p)
21 {
22 uint8_t tmp_str[FCB_TMP_BUF_SZ];
23 int cnt;
24 int blk_sz;
25 uint8_t crc8;
26 uint16_t len;
27 uint32_t off;
28 uint32_t end;
29 int rc;
30
31 if (loc->fe_elem_off + 2 > loc->fe_sector->fs_size) {
32 return -ENOTSUP;
33 }
34
35 rc = fcb_flash_read(_fcb, loc->fe_sector, loc->fe_elem_off, tmp_str, 2);
36 if (rc) {
37 return -EIO;
38 }
39
40 cnt = fcb_get_len(_fcb, tmp_str, &len);
41 if (cnt < 0) {
42 return cnt;
43 }
44 loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(_fcb, cnt);
45 loc->fe_data_len = len;
46
47 crc8 = CRC8_CCITT_INITIAL_VALUE;
48 crc8 = crc8_ccitt(crc8, tmp_str, cnt);
49
50 off = loc->fe_data_off;
51 end = loc->fe_data_off + len;
52 for (; off < end; off += blk_sz) {
53 blk_sz = end - off;
54 if (blk_sz > sizeof(tmp_str)) {
55 blk_sz = sizeof(tmp_str);
56 }
57
58 rc = fcb_flash_read(_fcb, loc->fe_sector, off, tmp_str, blk_sz);
59 if (rc) {
60 return -EIO;
61 }
62 crc8 = crc8_ccitt(crc8, tmp_str, blk_sz);
63 }
64 *c8p = crc8;
65
66 return 0;
67 }
68
69 #if IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER)
70 /* Given the offset in flash sector, calculate the FCB entry data offset and size, and set
71 * the fixed endmarker.
72 */
73 static int
fcb_elem_endmarker_fixed(struct fcb * _fcb,struct fcb_entry * loc,uint8_t * em)74 fcb_elem_endmarker_fixed(struct fcb *_fcb, struct fcb_entry *loc, uint8_t *em)
75 {
76 uint8_t tmp_str[2];
77 int cnt;
78 uint16_t len;
79 int rc;
80
81 if (loc->fe_elem_off + 2 > loc->fe_sector->fs_size) {
82 return -ENOTSUP;
83 }
84
85 rc = fcb_flash_read(_fcb, loc->fe_sector, loc->fe_elem_off, tmp_str, 2);
86 if (rc) {
87 return -EIO;
88 }
89
90 cnt = fcb_get_len(_fcb, tmp_str, &len);
91 if (cnt < 0) {
92 return cnt;
93 }
94 loc->fe_data_off = loc->fe_elem_off + fcb_len_in_flash(_fcb, cnt);
95 loc->fe_data_len = len;
96
97 *em = FCB_FIXED_ENDMARKER;
98 return 0;
99 }
100 #endif /* IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER) */
101
102 /* Given the offset in flash sector, calculate the FCB entry data offset and size, and calculate
103 * the expected endmarker.
104 */
105 int
fcb_elem_endmarker(struct fcb * _fcb,struct fcb_entry * loc,uint8_t * em)106 fcb_elem_endmarker(struct fcb *_fcb, struct fcb_entry *loc, uint8_t *em)
107 {
108 #if IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER)
109 if (_fcb->f_flags & FCB_FLAGS_CRC_DISABLED) {
110 return fcb_elem_endmarker_fixed(_fcb, loc, em);
111 }
112 #endif /* IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER) */
113
114 return fcb_elem_crc8(_fcb, loc, em);
115 }
116
117 /* Given the offset in flash sector, calculate the FCB entry data offset and size, and verify that
118 * the FCB entry endmarker is correct.
119 */
fcb_elem_info(struct fcb * _fcb,struct fcb_entry * loc)120 int fcb_elem_info(struct fcb *_fcb, struct fcb_entry *loc)
121 {
122 int rc;
123 uint8_t em;
124 uint8_t fl_em;
125 off_t off;
126
127 rc = fcb_elem_endmarker(_fcb, loc, &em);
128 if (rc) {
129 return rc;
130 }
131 off = loc->fe_data_off + fcb_len_in_flash(_fcb, loc->fe_data_len);
132
133 rc = fcb_flash_read(_fcb, loc->fe_sector, off, &fl_em, sizeof(fl_em));
134 if (rc) {
135 return -EIO;
136 }
137
138 if (IS_ENABLED(CONFIG_FCB_ALLOW_FIXED_ENDMARKER) && (fl_em != em)) {
139 rc = fcb_elem_crc8(_fcb, loc, &em);
140 if (rc) {
141 return rc;
142 }
143 }
144
145 if (fl_em != em) {
146 return -EBADMSG;
147 }
148 return 0;
149 }
150