Embedded SDK
Embedded SDK
Loading...
Searching...
No Matches
app_storage.c
Go to the documentation of this file.
1/*****************************************************************************
2 * (c) 2024 Ledger SAS.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *****************************************************************************/
16
17#ifdef HAVE_APP_STORAGE
18#include <string.h>
19#include "app_storage.h"
21#include "lcx_crc.h"
22#include "os_nvm.h"
23#include "os_pic.h"
24
25#define APP_STORAGE_ERASE_BLOCK_SIZE 256
26
27CONST app_storage_t app_storage_real __attribute__((section(".storage_section")));
28#define app_storage (*(volatile app_storage_t *) PIC(&app_storage_real))
29
33STATIC int32_t app_storage_is_initalized(void)
34{
35 int32_t status = APP_STORAGE_ERR_INVALID_ARGUMENT;
36 if (memcmp((const void *) &app_storage.header.tag, APP_STORAGE_TAG, APP_STORAGE_TAG_LEN) == 0) {
37 status = APP_STORAGE_SUCCESS;
38 }
39 else {
40 status = APP_STORAGE_ERR_INVALID_HEADER;
41 goto error;
42 }
43
44 uint32_t crc = cx_crc32((void *) &app_storage.header,
45 sizeof(app_storage.header) + app_storage.header.size);
46 if (crc != app_storage.crc) {
47 // Invalid CRC, force reset
48 status = APP_STORAGE_ERR_CORRUPTED;
49 }
50 else {
51 status = APP_STORAGE_SUCCESS;
52 }
53
54error:
55 return status;
56}
57
58static inline void update_crc(void)
59{
60 uint32_t crc = cx_crc32((void *) &app_storage.header,
61 sizeof(app_storage.header) + app_storage.header.size);
62 nvm_write((void *) &app_storage.crc, &crc, sizeof(app_storage.crc));
63}
64
68static inline void system_header_reset(void)
69{
70 /* Starting with zero application data size */
71 app_storage_header_t header = {0};
72
73 memcpy(&header.tag, (void *) APP_STORAGE_TAG, APP_STORAGE_TAG_LEN);
74 /* Setting up current system structure version */
75 header.struct_version = APP_STORAGE_HEADER_STRUCT_VERSION;
76 /* Setting up initial application datat version */
77 header.data_version = APP_STORAGE_INITIAL_APP_DATA_VERSION;
78 /* Setting up properties fields from the app makefile */
79 header.properties = ((HAVE_APP_STORAGE_PROP_SETTINGS << 0) | (HAVE_APP_STORAGE_PROP_DATA << 1));
80 nvm_write((void *) &app_storage.header, &header, sizeof(header));
81 update_crc();
82}
83
97int32_t app_storage_init(void)
98{
99 int32_t status = app_storage_is_initalized();
100 switch (status) {
101 case APP_STORAGE_ERR_INVALID_HEADER:
102 // Invalid tag or uninitialized storage, reset the HEADER
103 system_header_reset();
104 status = APP_STORAGE_SUCCESS;
105 break;
106 case APP_STORAGE_ERR_CORRUPTED:
107 system_header_reset();
108 break;
109 case APP_STORAGE_SUCCESS:
110 default:
111 // Return status as-is
112 break;
113 }
114
115 return status;
116}
117
121void app_storage_reset(void)
122{
123 system_header_reset();
124
125 uint8_t erase_buf[APP_STORAGE_ERASE_BLOCK_SIZE] = {0};
126 uint32_t offset = 0;
127 bool need_update = false;
128
129 if (APP_STORAGE_SIZE > APP_STORAGE_ERASE_BLOCK_SIZE) {
130 for (; offset < APP_STORAGE_SIZE - APP_STORAGE_ERASE_BLOCK_SIZE;
131 offset += APP_STORAGE_ERASE_BLOCK_SIZE) {
132 nvm_write((void *) &app_storage.data[offset],
133 (void *) erase_buf,
134 APP_STORAGE_ERASE_BLOCK_SIZE);
135 }
136 need_update = true;
137 }
138 if (APP_STORAGE_SIZE > offset) {
139 nvm_write(
140 (void *) &app_storage.data[offset], (void *) erase_buf, APP_STORAGE_SIZE - offset);
141 need_update = true;
142 }
143 if (need_update) {
144 update_crc();
145 }
146}
147
151uint32_t app_storage_get_size(void)
152{
153 return app_storage.header.size;
154}
155
159uint32_t app_storage_get_data_version(void)
160{
161 return app_storage.header.data_version;
162}
163
167uint16_t app_storage_get_properties(void)
168{
169 return app_storage.header.properties;
170}
171
175void app_storage_increment_data_version(void)
176{
177 uint32_t data_version = app_storage.header.data_version;
178 data_version++;
179 if (data_version == 0) {
180 /* wraparound - we consider we'll never achieve this number,
181 knowing that the the maximum number of Flash write cycles
182 may be around 100 000.
183 */
184 data_version = APP_STORAGE_INITIAL_APP_DATA_VERSION;
185 }
186 nvm_write(
187 (void *) &app_storage.header.data_version, (void *) &data_version, sizeof(data_version));
188 update_crc();
189}
190
194void app_storage_set_data_version(uint32_t data_version)
195{
196 nvm_write(
197 (void *) &app_storage.header.data_version, (void *) &data_version, sizeof(data_version));
198 update_crc();
199}
200
204int32_t app_storage_write(const void *buf, uint32_t nbyte, uint32_t offset)
205{
206 /* Input parameters verification */
207 if (buf == NULL) {
208 return APP_STORAGE_ERR_INVALID_ARGUMENT;
209 }
210 if (nbyte == 0) {
211 return APP_STORAGE_ERR_INVALID_ARGUMENT;
212 }
213 uint32_t max_offset = 0;
214 if (__builtin_add_overflow(offset, nbyte, &max_offset)) {
215 return APP_STORAGE_ERR_INVALID_ARGUMENT;
216 }
217
218 /* Checking the app storage boundaries */
219 if (max_offset > APP_STORAGE_SIZE) {
220 return APP_STORAGE_ERR_OVERFLOW;
221 }
222
223 /* Updating data */
224 nvm_write((void *) &app_storage.data[offset], (void *) buf, nbyte);
225
226 /* Updating size if it increased */
227 if (app_storage.header.size < max_offset) {
228 nvm_write((void *) &app_storage.header.size, (void *) &max_offset, sizeof(max_offset));
229 }
230 update_crc();
231
232 return nbyte;
233}
234
238int32_t app_storage_read(void *buf, uint32_t nbyte, uint32_t offset)
239{
240 /* Input parameters verification */
241 if (buf == NULL) {
242 return APP_STORAGE_ERR_INVALID_ARGUMENT;
243 }
244 if (nbyte == 0) {
245 return APP_STORAGE_ERR_INVALID_ARGUMENT;
246 }
247 uint32_t max_offset = 0;
248 if (__builtin_add_overflow(offset, nbyte, &max_offset)) {
249 return APP_STORAGE_ERR_INVALID_ARGUMENT;
250 }
251
252 /* Checking if the data has been already written */
253 if (max_offset > app_storage.header.size) {
254 return APP_STORAGE_ERR_NO_DATA_AVAILABLE;
255 }
256
257 /* Reading data */
258 memcpy((void *) buf, (void *) &app_storage.data[offset], nbyte);
259
260 return nbyte;
261}
262
263#endif // HAVE_APP_STORAGE
CRC (Cyclic Redundancy Check).
__attribute__((section("._nbgl_fonts_"))) const
return the non-unicode font corresponding to the given font ID
Definition nbgl_fonts.c:71