1 /* Copyright (c) 2024 BayLibre SAS
2  *
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #ifndef __SETTINGS_ZMS_H_
7 #define __SETTINGS_ZMS_H_
8 
9 #include <zephyr/fs/zms.h>
10 #include <zephyr/settings/settings.h>
11 
12 #ifdef __cplusplus
13 extern "C" {
14 #endif
15 
16 /* In the ZMS backend, each setting is stored in two ZMS entries:
17  *	1. setting's name
18  *	2. setting's value
19  *
20  * The ZMS entry ID for the setting's value is determined implicitly based on
21  * the ID of the ZMS entry for the setting's name, once that is found. The
22  * difference between name and value ID is constant and equal to
23  * ZMS_NAME_ID_OFFSET.
24  *
25  * Setting's name is hashed into 29 bits minus hash_collisions_bits.
26  * The 2 MSB_bits have always the same value 10, the LL_bit for the name's hash is 0
27  * and the hash_collisions_bits is configurable through CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS.
28  * The resulted 32 bits is the ZMS_ID of the Setting's name.
29  * If we detect a collision between ZMS_IDs we increment the value within hash_collision_bits
30  * until we find a free ZMS_ID.
31  * Separately, we store a linked list using the Setting's name ZMS_ID but setting the lsb to 1.
32  *
33  * The linked list is used to maintain a relation between all ZMS_IDs. This is necessary to load
34  * all settings at initialization.
35  * The linked list contains at least a header followed by multiple linked list elements that
36  * we can refer to as LL_x (where x is the order of that element in that list).
37  * This is a representation of the Linked List that is stored in the storage.
38  * LL_header <--> LL_0 <--> LL_1 <--> LL_2.
39  * The "next_hash" pointer of each LL element refers to the next element in the linked list.
40  * The "previous_hash" pointer is referring the previous element in the linked list.
41  *
42  * The bit representation of the 32 bits ZMS_ID is the following:
43  * --------------------------------------------------------------
44  * | MSB_bits | hash (truncated) | hash_collision_bits | LL_bit |
45  * --------------------------------------------------------------
46  * Where:
47  * MSB_bits (2 bits width) : = 10 for Name IDs
48  *			     = 11 for Data IDs
49  * hash (29 bits - hash_collision_bits) : truncated hash obtained from sys_hash32
50  * hash_collision_bits (configurable width) : used to handle hash collisions
51  * LL_bit : = 0 when this is a name's ZMS_ID
52  *	    = 1 when this is the linked list ZMS_ID corresponding to the name
53  *
54  * if a settings element is deleted it won't be found.
55  */
56 
57 #define ZMS_LL_HEAD_HASH_ID 0x80000000
58 #define ZMS_DATA_ID_OFFSET  0x40000000
59 #define ZMS_HASH_MASK       GENMASK(29, CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS + 1)
60 #define ZMS_COLLISIONS_MASK GENMASK(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS, 1)
61 #define ZMS_HASH_TOTAL_MASK GENMASK(29, 1)
62 #define ZMS_MAX_COLLISIONS  (BIT(CONFIG_SETTINGS_ZMS_MAX_COLLISIONS_BITS) - 1)
63 
64 /* some useful macros */
65 #define ZMS_NAME_ID_FROM_LL_NODE(x) (x & ~BIT(0))
66 #define ZMS_UPDATE_COLLISION_NUM(x, y)                                                             \
67 	((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK))
68 #define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1)
69 
70 struct settings_zms {
71 	struct settings_store cf_store;
72 	struct zms_fs cf_zms;
73 	const struct device *flash_dev;
74 	uint32_t last_hash_id;
75 	uint32_t second_to_last_hash_id;
76 	uint8_t hash_collision_num;
77 };
78 
79 struct settings_hash_linked_list {
80 	uint32_t previous_hash;
81 	uint32_t next_hash;
82 };
83 
84 #ifdef __cplusplus
85 }
86 #endif
87 
88 #endif /* __SETTINGS_ZMS_H_ */
89