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 <zephyr/settings/settings.h>
12 #include "settings/settings_nvs.h"
13 #include <zephyr/sys/crc.h>
14 #include "settings_priv.h"
15 #include <zephyr/storage/flash_map.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_DECLARE(settings, CONFIG_SETTINGS_LOG_LEVEL);
19 
20 #if DT_HAS_CHOSEN(zephyr_settings_partition)
21 #define SETTINGS_PARTITION DT_FIXED_PARTITION_ID(DT_CHOSEN(zephyr_settings_partition))
22 #else
23 #define SETTINGS_PARTITION FIXED_PARTITION_ID(storage_partition)
24 #endif
25 
26 struct settings_nvs_read_fn_arg {
27 	struct nvs_fs *fs;
28 	uint16_t id;
29 };
30 
31 static int settings_nvs_load(struct settings_store *cs,
32 			     const struct settings_load_arg *arg);
33 static int settings_nvs_save(struct settings_store *cs, const char *name,
34 			     const char *value, size_t val_len);
35 static void *settings_nvs_storage_get(struct settings_store *cs);
36 
37 static struct settings_store_itf settings_nvs_itf = {
38 	.csi_load = settings_nvs_load,
39 	.csi_save = settings_nvs_save,
40 	.csi_storage_get = settings_nvs_storage_get
41 };
42 
settings_nvs_read_fn(void * back_end,void * data,size_t len)43 static ssize_t settings_nvs_read_fn(void *back_end, void *data, size_t len)
44 {
45 	struct settings_nvs_read_fn_arg *rd_fn_arg;
46 	ssize_t rc;
47 
48 	rd_fn_arg = (struct settings_nvs_read_fn_arg *)back_end;
49 
50 	rc = nvs_read(rd_fn_arg->fs, rd_fn_arg->id, data, len);
51 	if (rc > (ssize_t)len) {
52 		/* nvs_read signals that not all bytes were read
53 		 * align read len to what was requested
54 		 */
55 		rc = len;
56 	}
57 	return rc;
58 }
59 
settings_nvs_src(struct settings_nvs * cf)60 int settings_nvs_src(struct settings_nvs *cf)
61 {
62 	cf->cf_store.cs_itf = &settings_nvs_itf;
63 	settings_src_register(&cf->cf_store);
64 
65 	return 0;
66 }
67 
settings_nvs_dst(struct settings_nvs * cf)68 int settings_nvs_dst(struct settings_nvs *cf)
69 {
70 	cf->cf_store.cs_itf = &settings_nvs_itf;
71 	settings_dst_register(&cf->cf_store);
72 
73 	return 0;
74 }
75 
76 #if CONFIG_SETTINGS_NVS_NAME_CACHE
77 #define SETTINGS_NVS_CACHE_OVFL(cf) ((cf)->cache_total > ARRAY_SIZE((cf)->cache))
78 
settings_nvs_cache_add(struct settings_nvs * cf,const char * name,uint16_t name_id)79 static void settings_nvs_cache_add(struct settings_nvs *cf, const char *name,
80 				   uint16_t name_id)
81 {
82 	uint16_t name_hash = crc16_ccitt(0xffff, name, strlen(name));
83 
84 	cf->cache[cf->cache_next].name_hash = name_hash;
85 	cf->cache[cf->cache_next++].name_id = name_id;
86 
87 	cf->cache_next %= CONFIG_SETTINGS_NVS_NAME_CACHE_SIZE;
88 }
89 
settings_nvs_cache_match(struct settings_nvs * cf,const char * name,char * rdname,size_t len)90 static uint16_t settings_nvs_cache_match(struct settings_nvs *cf, const char *name,
91 					 char *rdname, size_t len)
92 {
93 	uint16_t name_hash = crc16_ccitt(0xffff, name, strlen(name));
94 	int rc;
95 
96 	for (int i = 0; i < CONFIG_SETTINGS_NVS_NAME_CACHE_SIZE; i++) {
97 		if (cf->cache[i].name_hash != name_hash) {
98 			continue;
99 		}
100 
101 		if (cf->cache[i].name_id <= NVS_NAMECNT_ID) {
102 			continue;
103 		}
104 
105 		rc = nvs_read(&cf->cf_nvs, cf->cache[i].name_id, rdname, len);
106 		if (rc < 0) {
107 			continue;
108 		}
109 
110 		rdname[rc] = '\0';
111 
112 		if (strcmp(name, rdname)) {
113 			continue;
114 		}
115 
116 		return cf->cache[i].name_id;
117 	}
118 
119 	return NVS_NAMECNT_ID;
120 }
121 #endif /* CONFIG_SETTINGS_NVS_NAME_CACHE */
122 
settings_nvs_load(struct settings_store * cs,const struct settings_load_arg * arg)123 static int settings_nvs_load(struct settings_store *cs,
124 			     const struct settings_load_arg *arg)
125 {
126 	int ret = 0;
127 	struct settings_nvs *cf = CONTAINER_OF(cs, struct settings_nvs, cf_store);
128 	struct settings_nvs_read_fn_arg read_fn_arg;
129 	char name[SETTINGS_MAX_NAME_LEN + SETTINGS_EXTRA_LEN + 1];
130 	char buf;
131 	ssize_t rc1, rc2;
132 	uint16_t name_id = NVS_NAMECNT_ID;
133 
134 #if CONFIG_SETTINGS_NVS_NAME_CACHE
135 	uint16_t cached = 0;
136 
137 	cf->loaded = false;
138 #endif
139 
140 	name_id = cf->last_name_id + 1;
141 
142 	while (1) {
143 
144 		name_id--;
145 		if (name_id == NVS_NAMECNT_ID) {
146 #if CONFIG_SETTINGS_NVS_NAME_CACHE
147 			cf->loaded = true;
148 			cf->cache_total = cached;
149 #endif
150 			break;
151 		}
152 
153 		/* In the NVS backend, each setting item is stored in two NVS
154 		 * entries one for the setting's name and one with the
155 		 * setting's value.
156 		 */
157 		rc1 = nvs_read(&cf->cf_nvs, name_id, &name, sizeof(name));
158 		rc2 = nvs_read(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET,
159 			       &buf, sizeof(buf));
160 
161 		if ((rc1 <= 0) && (rc2 <= 0)) {
162 			/* Settings largest ID in use is invalid due to
163 			 * reset, power failure or partition overflow.
164 			 * Decrement it and check the next ID in subsequent
165 			 * iteration.
166 			 */
167 			if (name_id == cf->last_name_id) {
168 				cf->last_name_id--;
169 				nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID,
170 					  &cf->last_name_id, sizeof(uint16_t));
171 			}
172 
173 			continue;
174 		}
175 
176 		if ((rc1 <= 0) || (rc2 <= 0)) {
177 			/* Settings item is not stored correctly in the NVS.
178 			 * NVS entry for its name or value is either missing
179 			 * or deleted. Clean dirty entries to make space for
180 			 * future settings item.
181 			 */
182 			nvs_delete(&cf->cf_nvs, name_id);
183 			nvs_delete(&cf->cf_nvs, name_id + NVS_NAME_ID_OFFSET);
184 
185 			if (name_id == cf->last_name_id) {
186 				cf->last_name_id--;
187 				nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID,
188 					  &cf->last_name_id, sizeof(uint16_t));
189 			}
190 
191 			continue;
192 		}
193 
194 		/* Found a name, this might not include a trailing \0 */
195 		name[rc1] = '\0';
196 		read_fn_arg.fs = &cf->cf_nvs;
197 		read_fn_arg.id = name_id + NVS_NAME_ID_OFFSET;
198 
199 #if CONFIG_SETTINGS_NVS_NAME_CACHE
200 		settings_nvs_cache_add(cf, name, name_id);
201 		cached++;
202 #endif
203 
204 		ret = settings_call_set_handler(
205 			name, rc2,
206 			settings_nvs_read_fn, &read_fn_arg,
207 			(void *)arg);
208 		if (ret) {
209 			break;
210 		}
211 	}
212 	return ret;
213 }
214 
settings_nvs_save(struct settings_store * cs,const char * name,const char * value,size_t val_len)215 static int settings_nvs_save(struct settings_store *cs, const char *name,
216 			     const char *value, size_t val_len)
217 {
218 	struct settings_nvs *cf = CONTAINER_OF(cs, struct settings_nvs, cf_store);
219 	char rdname[SETTINGS_MAX_NAME_LEN + SETTINGS_EXTRA_LEN + 1];
220 	uint16_t name_id, write_name_id;
221 	bool delete, write_name;
222 	int rc = 0;
223 
224 	if (!name) {
225 		return -EINVAL;
226 	}
227 
228 	/* Find out if we are doing a delete */
229 	delete = ((value == NULL) || (val_len == 0));
230 
231 #if CONFIG_SETTINGS_NVS_NAME_CACHE
232 	bool name_in_cache = false;
233 
234 	name_id = settings_nvs_cache_match(cf, name, rdname, sizeof(rdname));
235 	if (name_id != NVS_NAMECNT_ID) {
236 		write_name_id = name_id;
237 		write_name = false;
238 		name_in_cache = true;
239 		goto found;
240 	}
241 #endif
242 
243 	name_id = cf->last_name_id + 1;
244 	write_name_id = cf->last_name_id + 1;
245 	write_name = true;
246 
247 #if CONFIG_SETTINGS_NVS_NAME_CACHE
248 	/* We can skip reading NVS if we know that the cache wasn't overflowed. */
249 	if (cf->loaded && !SETTINGS_NVS_CACHE_OVFL(cf)) {
250 		goto found;
251 	}
252 #endif
253 
254 	while (1) {
255 		name_id--;
256 		if (name_id == NVS_NAMECNT_ID) {
257 			break;
258 		}
259 
260 		rc = nvs_read(&cf->cf_nvs, name_id, &rdname, sizeof(rdname));
261 
262 		if (rc < 0) {
263 			/* Error or entry not found */
264 			if (rc == -ENOENT) {
265 				write_name_id = name_id;
266 			}
267 			continue;
268 		}
269 
270 		rdname[rc] = '\0';
271 
272 		if (strcmp(name, rdname)) {
273 			continue;
274 		}
275 
276 		if (!delete) {
277 			write_name_id = name_id;
278 			write_name = false;
279 		}
280 
281 		goto found;
282 	}
283 
284 found:
285 	if (delete) {
286 		if (name_id == NVS_NAMECNT_ID) {
287 			return 0;
288 		}
289 
290 		rc = nvs_delete(&cf->cf_nvs, name_id);
291 		if (rc >= 0) {
292 			rc = nvs_delete(&cf->cf_nvs, name_id +
293 					NVS_NAME_ID_OFFSET);
294 		}
295 
296 		if (rc < 0) {
297 			return rc;
298 		}
299 
300 		if (name_id == cf->last_name_id) {
301 			cf->last_name_id--;
302 			rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID,
303 				       &cf->last_name_id, sizeof(uint16_t));
304 			if (rc < 0) {
305 				/* Error: can't to store
306 				 * the largest name ID in use.
307 				 */
308 				return rc;
309 			}
310 		}
311 
312 		return 0;
313 	}
314 
315 	/* No free IDs left. */
316 	if (write_name_id == NVS_NAMECNT_ID + NVS_NAME_ID_OFFSET) {
317 		return -ENOMEM;
318 	}
319 
320 	/* update the last_name_id and write to flash if required*/
321 	if (write_name_id > cf->last_name_id) {
322 		cf->last_name_id = write_name_id;
323 		rc = nvs_write(&cf->cf_nvs, NVS_NAMECNT_ID, &cf->last_name_id,
324 			       sizeof(uint16_t));
325 		if (rc < 0) {
326 			return rc;
327 		}
328 	}
329 
330 	/* write the value */
331 	rc = nvs_write(&cf->cf_nvs, write_name_id + NVS_NAME_ID_OFFSET,
332 		       value, val_len);
333 	if (rc < 0) {
334 		return rc;
335 	}
336 
337 	/* write the name if required */
338 	if (write_name) {
339 		rc = nvs_write(&cf->cf_nvs, write_name_id, name, strlen(name));
340 		if (rc < 0) {
341 			return rc;
342 		}
343 	}
344 
345 #if CONFIG_SETTINGS_NVS_NAME_CACHE
346 	if (!name_in_cache) {
347 		settings_nvs_cache_add(cf, name, write_name_id);
348 		if (cf->loaded && !SETTINGS_NVS_CACHE_OVFL(cf)) {
349 			cf->cache_total++;
350 		}
351 	}
352 #endif
353 
354 	return 0;
355 }
356 
357 /* Initialize the nvs backend. */
settings_nvs_backend_init(struct settings_nvs * cf)358 int settings_nvs_backend_init(struct settings_nvs *cf)
359 {
360 	int rc;
361 	uint16_t last_name_id;
362 
363 	cf->cf_nvs.flash_device = cf->flash_dev;
364 	if (cf->cf_nvs.flash_device == NULL) {
365 		return -ENODEV;
366 	}
367 
368 	rc = nvs_mount(&cf->cf_nvs);
369 	if (rc) {
370 		return rc;
371 	}
372 
373 	rc = nvs_read(&cf->cf_nvs, NVS_NAMECNT_ID, &last_name_id,
374 		      sizeof(last_name_id));
375 	if (rc < 0) {
376 		cf->last_name_id = NVS_NAMECNT_ID;
377 	} else {
378 		cf->last_name_id = last_name_id;
379 	}
380 
381 	LOG_DBG("Initialized");
382 	return 0;
383 }
384 
settings_backend_init(void)385 int settings_backend_init(void)
386 {
387 	static struct settings_nvs default_settings_nvs;
388 	int rc;
389 	uint16_t cnt = 0;
390 	size_t nvs_sector_size, nvs_size = 0;
391 	const struct flash_area *fa;
392 	struct flash_sector hw_flash_sector;
393 	uint32_t sector_cnt = 1;
394 
395 	rc = flash_area_open(SETTINGS_PARTITION, &fa);
396 	if (rc) {
397 		return rc;
398 	}
399 
400 	rc = flash_area_get_sectors(SETTINGS_PARTITION, &sector_cnt,
401 				    &hw_flash_sector);
402 	if (rc != 0 && rc != -ENOMEM) {
403 		return rc;
404 	}
405 
406 	nvs_sector_size = CONFIG_SETTINGS_NVS_SECTOR_SIZE_MULT *
407 			  hw_flash_sector.fs_size;
408 
409 	if (nvs_sector_size > UINT16_MAX) {
410 		return -EDOM;
411 	}
412 
413 	while (cnt < CONFIG_SETTINGS_NVS_SECTOR_COUNT) {
414 		nvs_size += nvs_sector_size;
415 		if (nvs_size > fa->fa_size) {
416 			break;
417 		}
418 		cnt++;
419 	}
420 
421 	/* define the nvs file system using the page_info */
422 	default_settings_nvs.cf_nvs.sector_size = nvs_sector_size;
423 	default_settings_nvs.cf_nvs.sector_count = cnt;
424 	default_settings_nvs.cf_nvs.offset = fa->fa_off;
425 	default_settings_nvs.flash_dev = fa->fa_dev;
426 
427 	rc = settings_nvs_backend_init(&default_settings_nvs);
428 	if (rc) {
429 		return rc;
430 	}
431 
432 	rc = settings_nvs_src(&default_settings_nvs);
433 
434 	if (rc) {
435 		return rc;
436 	}
437 
438 	rc = settings_nvs_dst(&default_settings_nvs);
439 
440 	return rc;
441 }
442 
settings_nvs_storage_get(struct settings_store * cs)443 static void *settings_nvs_storage_get(struct settings_store *cs)
444 {
445 	struct settings_nvs *cf = CONTAINER_OF(cs, struct settings_nvs, cf_store);
446 
447 	return &cf->cf_nvs;
448 }
449