|
| 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 | +#define ZMS_HEADER_HASH 0x80000000 |
| 64 | + |
| 65 | +/* some useful macros */ |
| 66 | +#define ZMS_NAME_HASH_ID(x) (x & ZMS_HASH_TOTAL_MASK) |
| 67 | +#define ZMS_UPDATE_COLLISION_NUM(x, y) \ |
| 68 | + ((x & ~ZMS_COLLISIONS_MASK) | ((y << 1) & ZMS_COLLISIONS_MASK)) |
| 69 | +#define ZMS_COLLISION_NUM(x) ((x & ZMS_COLLISIONS_MASK) >> 1) |
| 70 | + |
| 71 | +struct settings_zms { |
| 72 | + struct settings_store cf_store; |
| 73 | + struct zms_fs cf_zms; |
| 74 | + const struct device *flash_dev; |
| 75 | + uint32_t last_hash_id; |
| 76 | + uint32_t second_to_last_hash_id; |
| 77 | + uint8_t hash_collision_num; |
| 78 | +}; |
| 79 | + |
| 80 | +struct settings_hash_linked_list { |
| 81 | + uint32_t previous_hash; |
| 82 | + uint32_t next_hash; |
| 83 | +}; |
| 84 | + |
| 85 | +#ifdef __cplusplus |
| 86 | +} |
| 87 | +#endif |
| 88 | + |
| 89 | +#endif /* __SETTINGS_ZMS_H_ */ |
0 commit comments