1 /*
2 * Copyright (c) 2017 Nordic Semiconductor ASA
3 * Copyright (c) 2015 Runtime Inc
4 * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
5 * Copyright 2024 NXP
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/ztest.h>
11 #include <zephyr/drivers/flash.h>
12 #include <zephyr/storage/flash_map.h>
13
14 #define SLOT1_PARTITION slot1_partition
15 #define SLOT1_PARTITION_ID FIXED_PARTITION_ID(SLOT1_PARTITION)
16 #define SLOT1_PARTITION_DEV FIXED_PARTITION_DEVICE(SLOT1_PARTITION)
17 #define SLOT1_PARTITION_NODE DT_NODELABEL(SLOT1_PARTITION)
18 #define SLOT1_PARTITION_OFFSET FIXED_PARTITION_OFFSET(SLOT1_PARTITION)
19 #define SLOT1_PARTITION_SIZE FIXED_PARTITION_SIZE(SLOT1_PARTITION)
20
21 #define FLASH_AREA_COPY_SIZE MIN((SLOT1_PARTITION_SIZE / 2), 128)
22
23 extern int flash_map_entries;
24 struct flash_sector fs_sectors[2048];
25
ZTEST(flash_map,test_flash_area_disabled_device)26 ZTEST(flash_map, test_flash_area_disabled_device)
27 {
28 /* The test checks if Flash Map will report partition
29 * non-existend if it is disabled, but it also assumes that
30 * disabled parition will have an ID generated.
31 * Custom partition maps may not be generating entries for
32 * disabled partitions nor identifiers, which makes the
33 * test fail with custom partition manager, for no real reason.
34 */
35 #if defined(CONFIG_TEST_FLASH_MAP_DISABLED_PARTITIONS)
36 const struct flash_area *fa;
37 int rc;
38
39 /* Test that attempting to open a disabled flash area fails */
40 rc = flash_area_open(FIXED_PARTITION_ID(disabled_a), &fa);
41 zassert_equal(rc, -ENOENT, "Open did not fail");
42 rc = flash_area_open(FIXED_PARTITION_ID(disabled_b), &fa);
43 zassert_equal(rc, -ENOENT, "Open did not fail");
44
45 /* Note lack of tests for FIXED_PARTITION(...) instantiation,
46 * because this macro will fail, at compile time, if node does not
47 * exist or is disabled.
48 */
49 #else
50 ztest_test_skip();
51 #endif
52 }
53
ZTEST(flash_map,test_flash_area_device_is_ready)54 ZTEST(flash_map, test_flash_area_device_is_ready)
55 {
56 const struct flash_area no_dev = {
57 .fa_dev = NULL,
58 };
59
60 zassert_false(flash_area_device_is_ready(NULL));
61 zassert_false(flash_area_device_is_ready(&no_dev));
62 /* The below just assumes that tests are executed so late that
63 * all devices are already initialized and ready.
64 */
65 zassert_true(flash_area_device_is_ready(
66 FIXED_PARTITION(SLOT1_PARTITION)));
67 }
68
layout_match(const struct device * flash_dev,uint32_t sec_cnt)69 static void layout_match(const struct device *flash_dev, uint32_t sec_cnt)
70 {
71 off_t off = 0;
72 int i;
73
74 /* For each reported sector, check if it corresponds to real page on device */
75 for (i = 0; i < sec_cnt; ++i) {
76 struct flash_pages_info fpi;
77
78 zassert_ok(
79 flash_get_page_info_by_offs(flash_dev, SLOT1_PARTITION_OFFSET + off, &fpi));
80 /* Offset of page taken directly from device corresponds to offset
81 * within flash area
82 */
83 zassert_equal(fpi.start_offset, fs_sectors[i].fs_off + SLOT1_PARTITION_OFFSET);
84 zassert_equal(fpi.size, fs_sectors[i].fs_size);
85 off += fs_sectors[i].fs_size;
86 }
87 }
88
89 /**
90 * @brief Test flash_area_get_sectors()
91 */
ZTEST(flash_map,test_flash_area_get_sectors)92 ZTEST(flash_map, test_flash_area_get_sectors)
93 {
94 const struct flash_area *fa;
95 const struct device *flash_dev_a = SLOT1_PARTITION_DEV;
96 uint32_t sec_cnt;
97 int rc;
98
99 fa = FIXED_PARTITION(SLOT1_PARTITION);
100
101 zassert_true(flash_area_device_is_ready(fa));
102
103 zassert_true(device_is_ready(flash_dev_a));
104
105 /* Device obtained by label should match the one from fa object */
106 zassert_equal(fa->fa_dev, flash_dev_a, "Device for slot1_partition do not match");
107
108 memset(&fs_sectors[0], 0, sizeof(fs_sectors));
109
110 sec_cnt = ARRAY_SIZE(fs_sectors);
111 rc = flash_area_get_sectors(SLOT1_PARTITION_ID, &sec_cnt, fs_sectors);
112 zassert_true(rc == 0, "flash_area_get_sectors failed");
113
114 layout_match(flash_dev_a, sec_cnt);
115 }
116
ZTEST(flash_map,test_flash_area_sectors)117 ZTEST(flash_map, test_flash_area_sectors)
118 {
119 const struct flash_area *fa;
120 uint32_t sec_cnt;
121 int rc;
122 const struct device *flash_dev_a = SLOT1_PARTITION_DEV;
123
124 fa = FIXED_PARTITION(SLOT1_PARTITION);
125
126 zassert_true(flash_area_device_is_ready(fa));
127
128 zassert_true(device_is_ready(flash_dev_a));
129
130 /* Device obtained by label should match the one from fa object */
131 zassert_equal(fa->fa_dev, flash_dev_a, "Device for slot1_partition do not match");
132
133 sec_cnt = ARRAY_SIZE(fs_sectors);
134 rc = flash_area_sectors(fa, &sec_cnt, fs_sectors);
135 zassert_true(rc == 0, "flash_area_get_sectors failed");
136
137 layout_match(flash_dev_a, sec_cnt);
138 }
139
ZTEST(flash_map,test_flash_area_erased_val)140 ZTEST(flash_map, test_flash_area_erased_val)
141 {
142 const struct flash_parameters *param;
143 const struct flash_area *fa;
144 uint8_t val;
145
146 fa = FIXED_PARTITION(SLOT1_PARTITION);
147
148 val = flash_area_erased_val(fa);
149
150 param = flash_get_parameters(fa->fa_dev);
151
152 zassert_equal(param->erase_value, val,
153 "value different than the flash erase value");
154 }
155
ZTEST(flash_map,test_fixed_partition_node_macros)156 ZTEST(flash_map, test_fixed_partition_node_macros)
157 {
158 /* DTS node macros, for accessing fixed partitions, are only available
159 * for DTS based partitions; custom flash map may define partition outside
160 * of DTS definition, making the NODE macros fail to evaluate.
161 */
162 #if defined(CONFIG_TEST_FLASH_MAP_NODE_MACROS)
163 /* Test against changes in API */
164 zassert_equal(FIXED_PARTITION_NODE_OFFSET(SLOT1_PARTITION_NODE),
165 DT_REG_ADDR(SLOT1_PARTITION_NODE));
166 zassert_equal(FIXED_PARTITION_NODE_SIZE(SLOT1_PARTITION_NODE),
167 DT_REG_SIZE(SLOT1_PARTITION_NODE));
168 zassert_equal(FIXED_PARTITION_NODE_DEVICE(SLOT1_PARTITION_NODE),
169 DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(SLOT1_PARTITION_NODE)));
170
171 /* Taking by node and taking by label should give same device */
172 zassert_equal(FIXED_PARTITION_BY_NODE(DT_NODELABEL(SLOT1_PARTITION)),
173 FIXED_PARTITION(SLOT1_PARTITION));
174 #else
175 ztest_test_skip();
176 #endif
177 }
178
ZTEST(flash_map,test_flash_area_erase_and_flatten)179 ZTEST(flash_map, test_flash_area_erase_and_flatten)
180 {
181 int i;
182 bool erased = true;
183 int rc;
184 const struct flash_area *fa;
185 const struct device *flash_dev;
186
187 fa = FIXED_PARTITION(SLOT1_PARTITION);
188
189 /* First erase the area so it's ready for use. */
190 flash_dev = flash_area_get_device(fa);
191
192 rc = flash_erase(flash_dev, fa->fa_off, fa->fa_size);
193 zassert_true(rc == 0, "flash area erase fail");
194
195 rc = flash_fill(flash_dev, 0xaa, fa->fa_off, fa->fa_size);
196 zassert_true(rc == 0, "flash device fill fail");
197
198 rc = flash_area_erase(fa, 0, fa->fa_size);
199 zassert_true(rc == 0, "flash area erase fail");
200
201 TC_PRINT("Flash area info:\n");
202 TC_PRINT("\tpointer:\t %p\n", &fa);
203 TC_PRINT("\toffset:\t %ld\n", (long)fa->fa_off);
204 TC_PRINT("\tsize:\t %ld\n", (long)fa->fa_size);
205
206 /* we work under assumption that flash_fill is working and tested */
207 i = 0;
208 while (erased && i < fa->fa_size) {
209 uint8_t buf[32];
210 int chunk = MIN(sizeof(buf), fa->fa_size - i);
211
212 rc = flash_read(flash_dev, fa->fa_off + i, buf, chunk);
213 zassert_equal(rc, 0, "Unexpected read fail with error %d", rc);
214 for (int ii = 0; ii < chunk; ++ii, ++i) {
215 if ((uint8_t)buf[ii] != (uint8_t)flash_area_erased_val(fa)) {
216 erased = false;
217 break;
218 }
219 }
220 }
221 zassert_true(erased, "Erase failed at dev abosolute offset index %d",
222 (int)(i + fa->fa_off));
223
224 rc = flash_fill(flash_dev, 0xaa, fa->fa_off, fa->fa_size);
225 zassert_true(rc == 0, "flash device fill fail");
226
227 rc = flash_area_flatten(fa, 0, fa->fa_size);
228
229 erased = true;
230 i = 0;
231 while (erased && i < fa->fa_size) {
232 uint8_t buf[32];
233 int chunk = MIN(sizeof(buf), fa->fa_size - i);
234
235 rc = flash_read(flash_dev, fa->fa_off + i, buf, chunk);
236 zassert_equal(rc, 0, "Unexpected read fail with error %d", rc);
237 for (int ii = 0; ii < chunk; ++ii, ++i) {
238 if ((uint8_t)buf[ii] != (uint8_t)flash_area_erased_val(fa)) {
239 erased = false;
240 break;
241 }
242 }
243 }
244 zassert_true(erased, "Flatten/Erase failed at dev absolute offset %d",
245 (int)(i + fa->fa_off));
246 }
247
ZTEST(flash_map,test_flash_area_copy)248 ZTEST(flash_map, test_flash_area_copy)
249 {
250 const struct flash_area *fa;
251 uint8_t src_buf[FLASH_AREA_COPY_SIZE], dst_buf[FLASH_AREA_COPY_SIZE],
252 copy_buf[32];
253 int rc;
254
255 /* Get source and destination flash areas */
256 fa = FIXED_PARTITION(SLOT1_PARTITION);
257
258 /* First erase the area so it's ready for use. */
259 rc = flash_area_erase(fa, 0, fa->fa_size);
260 zassert_true(rc == 0, "flash area erase fail");
261
262 /* Fill source area with test data */
263 memset(src_buf, 0xAB, sizeof(src_buf));
264 rc = flash_area_write(fa, 0, src_buf, sizeof(src_buf));
265 zassert_true(rc == 0, "Failed to write to source flash area");
266
267 /* Perform the copy operation */
268 rc = flash_area_copy(fa, 0, fa, FLASH_AREA_COPY_SIZE, sizeof(src_buf), copy_buf,
269 sizeof(copy_buf));
270 zassert_true(rc == 0, "flash_area_copy failed");
271
272 /* Verify the copied data */
273 rc = flash_area_read(fa, FLASH_AREA_COPY_SIZE, dst_buf, sizeof(dst_buf));
274 zassert_true(rc == 0, "Failed to read from destination flash area");
275 zassert_mem_equal(src_buf, dst_buf, sizeof(src_buf), "Data mismatch after copy");
276 }
277
ZTEST(flash_map,test_parameter_overflows)278 ZTEST(flash_map, test_parameter_overflows)
279 {
280 const struct flash_area *fa;
281 uint8_t dst_buf[FLASH_AREA_COPY_SIZE];
282 int rc;
283
284 fa = FIXED_PARTITION(SLOT1_PARTITION);
285 /* -1 cast to size_t gives us max size_t value, added to offset of 1,
286 * it will overflow to 0.
287 */
288 rc = flash_area_read(fa, 1, dst_buf, (size_t)(-1));
289 zassert_equal(rc, -EINVAL, "1: Overflow should have been detected");
290 /* Here we have offset 1 below size of area, with added max size_t
291 * it upper bound of read range should overflow to:
292 * (max(size_t) + fa->fa_size - 1) mod (max(size_t)) == fa->fa_size - 2
293 */
294 rc = flash_area_read(fa, fa->fa_size - 1, dst_buf, (size_t)(-1));
295 zassert_equal(rc, -EINVAL, "2: Overflow should have been detected");
296 }
297
298 ZTEST_SUITE(flash_map, NULL, NULL, NULL, NULL, NULL);
299