1 /*
2  * Copyright (c) 2019 Laczen
3  * Copyright (c) 2019 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <errno.h>
9 #include <string.h>
10 
11 #include "settings/settings.h"
12 #include "settings/settings_nvs.h"
13 #include "settings_priv.h"
14 #include <storage/flash_map.h>
15 
16 #include <logging/log.h>
17 LOG_MODULE_DECLARE(settings, CONFIG_SETTINGS_LOG_LEVEL);
18 
19 struct settings_nvs_read_fn_arg {
20 	struct nvs_fs *fs;
21 	uint16_t id;
22 };
23 
24 static int settings_nvs_load(struct settings_store *cs,
25 			     const struct settings_load_arg *arg);
26 static int settings_nvs_save(struct settings_store *cs, const char *name,
27 			     const char *value, size_t val_len);
28 
29 static struct settings_store_itf settings_nvs_itf = {
30 	.csi_load = settings_nvs_load,
31 	.csi_save = settings_nvs_save,
32 };
33 
settings_nvs_read_fn(void * back_end,void * data,size_t len)34 static ssize_t settings_nvs_read_fn(void *back_end, void *data, size_t len)
35 {
36 	struct settings_nvs_read_fn_arg *rd_fn_arg;
37 	ssize_t rc;
38 
39 	rd_fn_arg = (struct settings_nvs_read_fn_arg *)back_end;
40 
41 	rc = nvs_read(rd_fn_arg->fs, rd_fn_arg->id, data, len);
42 	if (rc > (ssize_t)len) {
43 		/* nvs_read signals that not all bytes were read
44 		 * align read len to what was requested
45 		 */
46 		rc = len;
47 	}
48 	return rc;
49 }
50 
settings_nvs_src(struct settings_nvs * cf)51 int settings_nvs_src(struct settings_nvs *cf)
52 {
53 	cf->cf_store.cs_itf = &settings_nvs_itf;
54 	settings_src_register(&cf->cf_store);
55 
56 	return 0;
57 }
58 
settings_nvs_dst(struct settings_nvs * cf)59 int settings_nvs_dst(struct settings_nvs *cf)
60 {
61 	cf->cf_store.cs_itf = &settings_nvs_itf;
62 	settings_dst_register(&cf->cf_store);
63 
64 	return 0;
65 }
66 
settings_nvs_load(struct settings_store * cs,const struct settings_load_arg * arg)67 static int settings_nvs_load(struct settings_store *cs,
68 			     const struct settings_load_arg *arg)
69 {
70 	int ret = 0;
71 	struct settings_nvs *cf = (struct settings_nvs *)cs;
72 	struct settings_nvs_read_fn_arg read_fn_arg;
73 	char name[SETTINGS_MAX_NAME_LEN + SETTINGS_EXTRA_LEN + 1];
74 	char buf;
75 	ssize_t rc1, rc2;
76 	uint16_t name_id = NVS_NAMECNT_ID;
77 
78 	name_id = cf->last_name_id + 1;
79 
80 	while (1) {
81 
82 		name_id--;
83 		if (name_id == NVS_NAMECNT_ID) {
84 			break;
85 		}
86 
87 		/* In the NVS backend, each setting item is stored in two NVS
88 		 * entries one for the setting's name and one with the
89 		 * setting's value.
90 		 */
91 		rc1 = nvs_read(&cf->cf_nvs, name_id, &name, sizeof(name));
92 		rc2 = nvs_read(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET,
93 			       &buf, sizeof(buf));
94 
95 		if ((rc1 <= 0) && (rc2 <= 0)) {
96 			continue;
97 		}
98 
99 		if ((rc1 <= 0) || (rc2 <= 0)) {
100 			/* Settings item is not stored correctly in the NVS.
101 			 * NVS entry for its name or value is either missing
102 			 * or deleted. Clean dirty entries to make space for
103 			 * future settings item.
104 			 */
105 			if (name_id == cf->last_name_id) {
106 				cf->last_name_id--;
107 				nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID,
108 					  &cf->last_name_id, sizeof(uint16_t));
109 			}
110 			nvs_delete(&cf->cf_nvs, name_id);
111 			nvs_delete(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET);
112 			continue;
113 		}
114 
115 		/* Found a name, this might not include a trailing \0 */
116 		name[rc1] = '\0';
117 		read_fn_arg.fs = &cf->cf_nvs;
118 		read_fn_arg.id = name_id + NVS_NAME_ID_OFFSET;
119 
120 		ret = settings_call_set_handler(
121 			name, rc2,
122 			settings_nvs_read_fn, &read_fn_arg,
123 			(void *)arg);
124 		if (ret) {
125 			break;
126 		}
127 	}
128 	return ret;
129 }
130 
settings_nvs_save(struct settings_store * cs,const char * name,const char * value,size_t val_len)131 static int settings_nvs_save(struct settings_store *cs, const char *name,
132 			     const char *value, size_t val_len)
133 {
134 	struct settings_nvs *cf = (struct settings_nvs *)cs;
135 	char rdname[SETTINGS_MAX_NAME_LEN + SETTINGS_EXTRA_LEN + 1];
136 	uint16_t name_id, write_name_id;
137 	bool delete, write_name;
138 	int rc = 0;
139 
140 	if (!name) {
141 		return -EINVAL;
142 	}
143 
144 	/* Find out if we are doing a delete */
145 	delete = ((value == NULL) || (val_len == 0));
146 
147 	name_id = cf->last_name_id + 1;
148 	write_name_id = cf->last_name_id + 1;
149 	write_name = true;
150 
151 	while (1) {
152 		name_id--;
153 		if (name_id == NVS_NAMECNT_ID) {
154 			break;
155 		}
156 
157 		rc = nvs_read(&cf->cf_nvs, name_id, &rdname, sizeof(rdname));
158 
159 		if (rc < 0) {
160 			/* Error or entry not found */
161 			if (rc == -ENOENT) {
162 				write_name_id = name_id;
163 			}
164 			continue;
165 		}
166 
167 		rdname[rc] = '\0';
168 
169 		if (strcmp(name, rdname)) {
170 			continue;
171 		}
172 
173 		if ((delete) && (name_id == cf->last_name_id)) {
174 			cf->last_name_id--;
175 			rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID,
176 				       &cf->last_name_id, sizeof(uint16_t));
177 			if (rc < 0) {
178 				/* Error: can't to store
179 				 * the largest name ID in use.
180 				 */
181 				return rc;
182 			}
183 		}
184 
185 		if (delete) {
186 			rc = nvs_delete(&cf->cf_nvs, name_id);
187 
188 			if (rc >= 0) {
189 				rc = nvs_delete(&cf->cf_nvs, name_id +
190 					NVS_NAME_ID_OFFSET);
191 			}
192 
193 			if (rc < 0) {
194 				return rc;
195 			}
196 
197 			return 0;
198 		}
199 		write_name_id = name_id;
200 		write_name = false;
201 		break;
202 	}
203 
204 	if (delete) {
205 		return 0;
206 	}
207 
208 	/* No free IDs left. */
209 	if (write_name_id == NVS_NAMECNT_ID + NVS_NAME_ID_OFFSET) {
210 		return -ENOMEM;
211 	}
212 
213 	/* write the value */
214 	rc = nvs_write(&cf->cf_nvs, write_name_id + NVS_NAME_ID_OFFSET,
215 		       value, val_len);
216 	if (rc < 0) {
217 		return rc;
218 	}
219 
220 	/* write the name if required */
221 	if (write_name) {
222 		rc = nvs_write(&cf->cf_nvs, write_name_id, name, strlen(name));
223 		if (rc < 0) {
224 			return rc;
225 		}
226 	}
227 
228 	/* update the last_name_id and write to flash if required*/
229 	if (write_name_id > cf->last_name_id) {
230 		cf->last_name_id = write_name_id;
231 		rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id,
232 			       sizeof(uint16_t));
233 	}
234 
235 	if (rc < 0) {
236 		return rc;
237 	}
238 
239 	return 0;
240 }
241 
242 /* Initialize the nvs backend. */
settings_nvs_backend_init(struct settings_nvs * cf)243 int settings_nvs_backend_init(struct settings_nvs *cf)
244 {
245 	int rc;
246 	uint16_t last_name_id;
247 
248 	rc = nvs_init(&cf->cf_nvs, cf->flash_dev_name);
249 	if (rc) {
250 		return rc;
251 	}
252 
253 	rc = nvs_read(&cf->cf_nvs, NVS_NAMECNT_ID, &last_name_id,
254 		      sizeof(last_name_id));
255 	if (rc < 0) {
256 		cf->last_name_id = NVS_NAMECNT_ID;
257 	} else {
258 		cf->last_name_id = last_name_id;
259 	}
260 
261 	LOG_DBG("Initialized");
262 	return 0;
263 }
264 
settings_backend_init(void)265 int settings_backend_init(void)
266 {
267 	static struct settings_nvs default_settings_nvs;
268 	int rc;
269 	uint16_t cnt = 0;
270 	size_t nvs_sector_size, nvs_size = 0;
271 	const struct flash_area *fa;
272 	struct flash_sector hw_flash_sector;
273 	uint32_t sector_cnt = 1;
274 
275 	rc = flash_area_open(FLASH_AREA_ID(storage), &fa);
276 	if (rc) {
277 		return rc;
278 	}
279 
280 	rc = flash_area_get_sectors(FLASH_AREA_ID(storage), &sector_cnt,
281 				    &hw_flash_sector);
282 	if (rc == -ENODEV) {
283 		return rc;
284 	} else if (rc != 0 && rc != -ENOMEM) {
285 		k_panic();
286 	}
287 
288 	nvs_sector_size = CONFIG_SETTINGS_NVS_SECTOR_SIZE_MULT *
289 			  hw_flash_sector.fs_size;
290 
291 	if (nvs_sector_size > UINT16_MAX) {
292 		return -EDOM;
293 	}
294 
295 	while (cnt < CONFIG_SETTINGS_NVS_SECTOR_COUNT) {
296 		nvs_size += nvs_sector_size;
297 		if (nvs_size > fa->fa_size) {
298 			break;
299 		}
300 		cnt++;
301 	}
302 
303 	/* define the nvs file system using the page_info */
304 	default_settings_nvs.cf_nvs.sector_size = nvs_sector_size;
305 	default_settings_nvs.cf_nvs.sector_count = cnt;
306 	default_settings_nvs.cf_nvs.offset = fa->fa_off;
307 	default_settings_nvs.flash_dev_name = fa->fa_dev_name;
308 
309 	rc = settings_nvs_backend_init(&default_settings_nvs);
310 	if (rc) {
311 		return rc;
312 	}
313 
314 	rc = settings_nvs_src(&default_settings_nvs);
315 
316 	if (rc) {
317 		return rc;
318 	}
319 
320 	rc = settings_nvs_dst(&default_settings_nvs);
321 
322 	return rc;
323 }
324