• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * Description: KV Storage Library store access module implementation
15  */
16 
17 #include "nv_store.h"
18 #include "nv_key.h"
19 #include "nv_page.h"
20 #include "nv_nvregion.h"
21 #include "securec.h"
22 #include "nv_porting.h"
23 #include "common_def.h"
24 #include "nv.h"
25 
26 #define kv_page_base(a)               ((uint8_t *)(((uint32_t)(a)) & ~(KV_PAGE_SIZE - 1)))
27 #define kv_is_pointer_in_page(x, p)   ((((uint32_t)(x)) >= ((uint32_t) (p))) && \
28                                        (((uint32_t)(x)) < (((uint32_t) (p)) + KV_PAGE_SIZE)))
29 #define kv_is_pointer_word_aligned(x) (((uint32_t)(x) & 0x3) == 0)
30 #define kv_bytes_to_words(x)          (((x)+3) >> 2) /* minimal number of words needed to store that many bytes */
31 #define kv_is_mem_in_page(x, y, p)    ((kv_is_pointer_in_page((x), (p))) && \
32                                        (kv_is_pointer_in_page(((uint32_t)(x) + ((uint32_t)(y) - 1)), (p))))
33 
34 /**
35  * Array holding the id for each KV store
36  */
37 static const uint16_t g_kv_store_ids[KV_STORE_MAX_NUM] = {
38     KV_STORE_ID_ACPU,
39 };
40 
41 /**
42  *  Array holding the number of pages used by each KV store
43  */
44 /* Consider using NV region contents to determine actual number of pages and stores */
45 static const uint8_t g_kv_store_num_pages[KV_STORE_MAX_NUM] = {
46     KV_STORE_PAGES_ACPU,
47 };
48 
kv_store_get_id(kv_store_t store)49 uint16_t kv_store_get_id(kv_store_t store)
50 {
51     if (store < KV_STORE_MAX_NUM) {
52         return g_kv_store_ids[store];
53     }
54     return 0;
55 }
56 
kv_store_get_page_count(kv_store_t store)57 uint8_t kv_store_get_page_count(kv_store_t store)
58 {
59     if (store < KV_STORE_MAX_NUM) {
60         return g_kv_store_num_pages[store];
61     }
62     return 0;
63 }
64 
kv_store_get_page_handle(kv_store_t store,uint32_t page_index,kv_page_handle_t * page)65 errcode_t kv_store_get_page_handle(kv_store_t store, uint32_t page_index, kv_page_handle_t *page)
66 {
67     errcode_t res;
68     uint16_t store_id;
69     kv_page_location page_location;
70 
71     (void)memset_s(page, sizeof(kv_page_handle_t), 0, sizeof(*page));
72 
73     store_id = kv_store_get_id(store);
74     res = kv_nvregion_find_page(store_id, (uint8_t)page_index, &page_location, &page->page_header);
75     if (res != ERRCODE_SUCC) {
76         return res;
77     }
78     page->page_location = page_location;
79     return ERRCODE_SUCC;
80 }
81 
kv_store_find_valid_key(kv_store_t store,kv_key_id key_id,kv_key_handle_t * key)82 errcode_t kv_store_find_valid_key(kv_store_t store, kv_key_id key_id, kv_key_handle_t *key)
83 {
84     uint32_t page_index;
85     uint32_t pages_in_store;
86     kv_key_filter_t search_filter;
87 
88     /* We are looking for the first (and only) valid key in a store */
89     search_filter.location = 0;
90     search_filter.mask = 0xFFFF;
91     search_filter.pattern = key_id;
92     search_filter.state = KV_KEY_FILTER_STATE_VALID;
93     search_filter.type = KV_KEY_FILTER_TYPE_ANY;
94     pages_in_store = kv_store_get_page_count(store);
95     for (page_index = 0; page_index < pages_in_store; page_index++) {
96         kv_page_handle_t page;
97         if ((kv_store_get_page_handle(store, page_index, &page) == ERRCODE_SUCC) &&
98             (kv_page_find_first_key(&page, &search_filter, key) ==  ERRCODE_SUCC)) {
99             return ERRCODE_SUCC;
100         }
101     }
102     return ERRCODE_NV_KEY_NOT_FOUND;
103 }
104 
kv_store_find_backup_key(kv_key_id key_id,kv_key_handle_t * key,kv_page_location page_location)105 static errcode_t kv_store_find_backup_key(kv_key_id key_id, kv_key_handle_t *key, kv_page_location page_location)
106 {
107     kv_page_handle_t page;
108     kv_key_filter_t search_filter;
109     page.page_location = page_location;
110     /* We are looking for the first (and only) valid key in a store */
111     search_filter.location = 0;
112     search_filter.mask = 0xFFFF;
113     search_filter.pattern = key_id;
114     search_filter.state = KV_KEY_FILTER_STATE_VALID;
115     search_filter.type = KV_KEY_FILTER_TYPE_ANY;
116 
117     if (kv_page_find_first_key(&page, &search_filter, key) ==  ERRCODE_SUCC) {
118         return ERRCODE_SUCC;
119     }
120     return ERRCODE_NV_KEY_NOT_FOUND;
121 }
122 
kv_store_get_key_attr(kv_store_t store,kv_key_id key_id,uint16_t * len,kv_attributes_t * attributes)123 errcode_t kv_store_get_key_attr(kv_store_t store, kv_key_id key_id, uint16_t *len, kv_attributes_t *attributes)
124 {
125     errcode_t res = ERRCODE_FAIL;
126     kv_key_handle_t key;
127 
128     res = kv_store_find_valid_key(store, key_id, &key);
129     if (res != ERRCODE_SUCC) {
130         return res;
131     }
132 
133     /* Extract stored attributes from the key */
134     *attributes = kv_key_attributes(&key);
135     *len = key.header.length;
136     return res;
137 }
138 
kv_store_get_backup_key_attr(kv_key_id key_id,uint16_t * len,kv_attributes_t * attributes,kv_key_handle_t * backup_key)139 errcode_t kv_store_get_backup_key_attr(kv_key_id key_id, uint16_t *len, kv_attributes_t *attributes,
140     kv_key_handle_t *backup_key)
141 {
142 #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
143     errcode_t res = ERRCODE_FAIL;
144     kv_page_location page_location;
145     kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
146     if (nvregion_area == NULL) {
147         return ERRCODE_FAIL;
148     }
149 
150     for (uint32_t page_num = 0; page_num < KV_BACKUP_PAGE_NUM; page_num++) {
151         page_location = (kv_page_location)(uintptr_t)(nvregion_area->nv_backup_addr + page_num * KV_PAGE_SIZE);
152         res = kv_store_find_backup_key(key_id, backup_key, page_location);
153         if (res != ERRCODE_SUCC && page_num == KV_BACKUP_PAGE_NUM - 1) {
154             return res;
155         } else if (res == ERRCODE_SUCC) {
156             break;
157         }
158     }
159 
160     if (attributes != NULL && len != NULL) {
161         /* Extract stored attributes from the backup_key */
162         *attributes = kv_key_attributes(backup_key);
163         *len = backup_key->header.length;
164     }
165     return res;
166 #else
167     unused(key_id);
168     unused(len);
169     unused(attributes);
170     unused(backup_key);
171     return ERRCODE_SUCC;
172 #endif
173 }
174 
kv_store_read_backup_key(kv_key_id key_id,kv_store_key_data_t * key_data,kv_attributes_t * attributes)175 errcode_t kv_store_read_backup_key(kv_key_id key_id, kv_store_key_data_t *key_data,
176     kv_attributes_t *attributes)
177 {
178 #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
179     errcode_t res;
180     kv_page_location page_location;
181     kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
182     if (nvregion_area == NULL) {
183         return ERRCODE_FAIL;
184     }
185 
186     for (uint32_t page_num = 0; page_num < KV_BACKUP_PAGE_NUM; page_num++) {
187         page_location = (kv_page_location)(uintptr_t)(nvregion_area->nv_backup_addr + page_num * KV_PAGE_SIZE);
188         res = kv_store_get_backup_key(key_id, key_data, attributes, page_location);
189         if (res == ERRCODE_SUCC) {
190             return res;
191         }
192     }
193     return ERRCODE_NV_KEY_NOT_FOUND;
194 #else
195     unused(key_id);
196     unused(key_data);
197     unused(attributes);
198     return ERRCODE_NV_KEY_NOT_FOUND;
199 #endif
200 }
201 
202 
kv_store_get_key(kv_store_t store,kv_key_id key_id,kv_store_key_data_t * key_data,kv_attributes_t * attributes)203 errcode_t kv_store_get_key(kv_store_t store, kv_key_id key_id, kv_store_key_data_t *key_data,
204                            kv_attributes_t *attributes)
205 {
206     errcode_t res;
207     kv_key_handle_t key;
208 
209     res = kv_store_find_valid_key(store, key_id, &key);
210     if (res != ERRCODE_SUCC) {
211         return res;
212     }
213 
214     if (attributes != NULL) {
215         *attributes = kv_key_attributes(&key);
216     }
217 
218     /* Attempt to obtain key data from store */
219     key_data->kvalue_actual_length = key.header.length;
220     if (key_data->kvalue_max_length < key_data->kvalue_actual_length) {
221         return ERRCODE_NV_GET_BUFFER_TOO_SMALL;
222     }
223 
224     res = kv_key_read_data(&key, key_data->kvalue);
225     return res;
226 }
227 
kv_store_get_backup_key(kv_key_id key_id,kv_store_key_data_t * key_data,kv_attributes_t * attributes,kv_page_location page_location)228 errcode_t kv_store_get_backup_key(kv_key_id key_id, kv_store_key_data_t *key_data, kv_attributes_t *attributes,
229     kv_page_location page_location)
230 {
231     errcode_t res_b;
232     kv_key_handle_t key;
233 
234     res_b = kv_store_find_backup_key(key_id, &key, page_location);
235     if (res_b != ERRCODE_SUCC) {
236         return res_b;
237     }
238 
239     if (attributes != NULL) {
240         *attributes = kv_key_attributes(&key);
241     }
242 
243     /* Attempt to obtain key data from store */
244     key_data->kvalue_actual_length = key.header.length;
245     if (key_data->kvalue_max_length < key_data->kvalue_actual_length) {
246         return ERRCODE_NV_GET_BUFFER_TOO_SMALL;
247     }
248 
249     res_b = kv_key_read_data(&key, key_data->kvalue);
250     return res_b;
251 }
252 
kv_store_get_status(kv_store_t store,nv_store_status_t * store_status)253 errcode_t kv_store_get_status(kv_store_t store, nv_store_status_t *store_status)
254 {
255     uint32_t pages_in_store;
256     uint32_t page_index;
257 
258     if ((store >= KV_STORE_MAX_NUM) || (store_status == NULL)) {
259         return ERRCODE_NV_INVALID_PARAMS;
260     }
261 
262     (void)memset_s(store_status, sizeof(nv_store_status_t), 0, sizeof(nv_store_status_t));
263 
264     pages_in_store = kv_store_get_page_count(store);
265     for (page_index = 0; page_index < pages_in_store; page_index++) {
266         kv_page_handle_t page;
267         kv_page_status_t page_status;
268         if (kv_store_get_page_handle(store, page_index, &page) == ERRCODE_SUCC) {
269             kv_page_get_status(&page, &page_status);
270             store_status->total_space += page_status.total_space;
271             store_status->used_space += page_status.used_space;
272             store_status->reclaimable_space += page_status.reclaimable_space;
273             store_status->corrupted_space += page_status.corrupted_space;
274             if (page_status.max_key_space > store_status->max_key_space) {
275                 store_status->max_key_space = page_status.max_key_space;
276             }
277         }
278     }
279     return ERRCODE_SUCC;
280 }
281 
kv_store_find_write_page(kv_store_t store,uint32_t required_space,kv_page_handle_t * page,kv_page_status_t * page_status)282 errcode_t kv_store_find_write_page(kv_store_t store, uint32_t required_space, kv_page_handle_t *page,
283                                    kv_page_status_t *page_status)
284 {
285     uint32_t pages_in_store;
286     uint32_t page_index;
287     kv_page_handle_t page_tmp;
288     kv_page_status_t page_status_tmp;
289     uint32_t mininal_used_times = 0;
290     uint32_t need_defrag_page = (uint32_t)-1;
291 
292     pages_in_store = kv_store_get_page_count(store);
293 
294     for (page_index = 0; page_index < pages_in_store; page_index++) {
295         errcode_t res = kv_store_get_page_handle(store, page_index, page);
296         if (res != ERRCODE_SUCC) {
297             return res;
298         }
299         kv_page_get_status_from_map(page, page_status);
300 
301         /* 如果有未使用的空间,直接返回该页,空间计算使用加法判断更保险 */
302         if (page_status->total_space >= (page_status->used_space + required_space)) {
303             return ERRCODE_SUCC;
304         }
305 
306         /* 如果未找到有未使用空间够用的页,考虑到flash擦写平衡,在可换页的页中找到一个擦写次数最少的 */
307         if (page_status->max_key_space >= required_space) {
308             uint32_t used_times = kv_nvregion_get_use_times(page->page_location);
309             if ((need_defrag_page == (uint32_t)-1) || (used_times < mininal_used_times)) {
310                 need_defrag_page = page_index;
311                 page_tmp = *page;
312                 page_status_tmp = *page_status;
313                 mininal_used_times = used_times;
314             }
315         }
316     }
317 
318     if (need_defrag_page != (uint32_t)-1) {
319         *page = page_tmp;
320         *page_status = page_status_tmp;
321         return ERRCODE_NV_DEFRAGMENTATION_NEEDED;
322     }
323 
324     return ERRCODE_NV_NO_ENOUGH_SPACE;
325 }
326