1 /*
2  * Copyright (c) 2020-2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/drivers/flash.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/storage/flash_map.h>
12 
13 #if defined(CONFIG_NORDIC_QSPI_NOR)
14 #define TEST_AREA_DEV_NODE	DT_INST(0, nordic_qspi_nor)
15 #elif defined(CONFIG_SPI_NOR)
16 #define TEST_AREA_DEV_NODE	DT_INST(0, jedec_spi_nor)
17 #elif defined(CONFIG_FLASH_MSPI_NOR)
18 #define TEST_AREA_DEV_NODE	DT_INST(0, jedec_mspi_nor)
19 #else
20 #define TEST_AREA	storage_partition
21 #endif
22 
23 /* TEST_AREA is only defined for configurations that realy on
24  * fixed-partition nodes.
25  */
26 #ifdef TEST_AREA
27 #define TEST_AREA_OFFSET	FIXED_PARTITION_OFFSET(TEST_AREA)
28 #define TEST_AREA_SIZE		FIXED_PARTITION_SIZE(TEST_AREA)
29 #define TEST_AREA_MAX		(TEST_AREA_OFFSET + TEST_AREA_SIZE)
30 #define TEST_AREA_DEVICE	FIXED_PARTITION_DEVICE(TEST_AREA)
31 
32 #elif defined(TEST_AREA_DEV_NODE)
33 
34 #define TEST_AREA_DEVICE	DEVICE_DT_GET(TEST_AREA_DEV_NODE)
35 #define TEST_AREA_OFFSET	0xff000
36 
37 #if DT_NODE_HAS_PROP(TEST_AREA_DEV_NODE, size_in_bytes)
38 #define TEST_AREA_MAX DT_PROP(TEST_AREA_DEV_NODE, size_in_bytes)
39 #else
40 #define TEST_AREA_MAX (DT_PROP(TEST_AREA_DEV_NODE, size) / 8)
41 #endif
42 
43 #else
44 #error "Unsupported configuraiton"
45 #endif
46 
47 #define EXPECTED_SIZE	512
48 
49 #if !defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) &&		\
50 	!defined(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE)
51 #error There is no flash device enabled or it is missing Kconfig options
52 #endif
53 
54 static const struct device *const flash_dev = TEST_AREA_DEVICE;
55 static struct flash_pages_info page_info;
56 static uint8_t __aligned(4) expected[EXPECTED_SIZE];
57 static uint8_t erase_value;
58 static bool ebw_required;
59 
flash_driver_before(void * arg)60 static void flash_driver_before(void *arg)
61 {
62 	int rc;
63 
64 	ARG_UNUSED(arg);
65 
66 	TC_PRINT("Test will run on device %s\n", flash_dev->name);
67 	zassert_true(device_is_ready(flash_dev));
68 
69 	/* Check for erase is only needed when there is mix of devices */
70 	if (IS_ENABLED(CONFIG_FLASH_HAS_EXPLICIT_ERASE)) {
71 		const struct flash_parameters *fparams = flash_get_parameters(flash_dev);
72 
73 		erase_value = fparams->erase_value;
74 		ebw_required = flash_params_get_erase_cap(fparams) & FLASH_ERASE_C_EXPLICIT;
75 		/* For tests purposes use page (in nrf_qspi_nor page = 64 kB) */
76 		flash_get_page_info_by_offs(flash_dev, TEST_AREA_OFFSET,
77 					    &page_info);
78 	} else {
79 		TC_PRINT("No devices with erase requirement present\n");
80 		erase_value = 0x55;
81 		page_info.start_offset = TEST_AREA_OFFSET;
82 		page_info.size = TEST_AREA_MAX - TEST_AREA_OFFSET;
83 	}
84 
85 
86 	/* Check if test region is not empty */
87 	uint8_t buf[EXPECTED_SIZE];
88 
89 	rc = flash_read(flash_dev, TEST_AREA_OFFSET,
90 			buf, EXPECTED_SIZE);
91 	zassert_equal(rc, 0, "Cannot read flash");
92 
93 	/* Fill test buffer with random data */
94 	for (int i = 0, val = 0; i < EXPECTED_SIZE; i++, val++) {
95 		/* Skip erase value */
96 		if (val == erase_value) {
97 			val++;
98 		}
99 		expected[i] = val;
100 	}
101 
102 	/* Check if tested region fits in flash */
103 	zassert_true((TEST_AREA_OFFSET + EXPECTED_SIZE) <= TEST_AREA_MAX,
104 		     "Test area exceeds flash size");
105 
106 	/* Check if flash is cleared */
107 	if (IS_ENABLED(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && ebw_required) {
108 		bool is_buf_clear = true;
109 
110 		for (off_t i = 0; i < EXPECTED_SIZE; i++) {
111 			if (buf[i] != erase_value) {
112 				is_buf_clear = false;
113 				break;
114 			}
115 		}
116 
117 		if (!is_buf_clear) {
118 			/* Erase a nb of pages aligned to the EXPECTED_SIZE */
119 			rc = flash_erase(flash_dev, page_info.start_offset,
120 					(page_info.size *
121 					((EXPECTED_SIZE + page_info.size - 1)
122 					/ page_info.size)));
123 
124 			zassert_equal(rc, 0, "Flash memory not properly erased");
125 		}
126 	}
127 }
128 
ZTEST(flash_driver,test_read_unaligned_address)129 ZTEST(flash_driver, test_read_unaligned_address)
130 {
131 	int rc;
132 	uint8_t buf[EXPECTED_SIZE];
133 	const uint8_t canary = erase_value;
134 	uint32_t start;
135 
136 	if (IS_ENABLED(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && ebw_required) {
137 		start = page_info.start_offset;
138 		/* Erase a nb of pages aligned to the EXPECTED_SIZE */
139 		rc = flash_erase(flash_dev, page_info.start_offset,
140 				(page_info.size *
141 				((EXPECTED_SIZE + page_info.size - 1)
142 				/ page_info.size)));
143 
144 		zassert_equal(rc, 0, "Flash memory not properly erased");
145 	} else {
146 		start = TEST_AREA_OFFSET;
147 	}
148 
149 	rc = flash_write(flash_dev,
150 			 start,
151 			 expected, EXPECTED_SIZE);
152 	zassert_equal(rc, 0, "Cannot write to flash");
153 
154 	/* read buffer length*/
155 	for (off_t len = 0; len < 25; len++) {
156 		/* address offset */
157 		for (off_t ad_o = 0; ad_o < 4; ad_o++) {
158 			/* buffer offset; leave space for buffer guard */
159 			for (off_t buf_o = 1; buf_o < 5; buf_o++) {
160 				/* buffer overflow protection */
161 				buf[buf_o - 1] = canary;
162 				buf[buf_o + len] = canary;
163 				memset(buf + buf_o, 0, len);
164 				rc = flash_read(flash_dev,
165 						start + ad_o,
166 						buf + buf_o, len);
167 				zassert_equal(rc, 0, "Cannot read flash");
168 				zassert_equal(memcmp(buf + buf_o,
169 						expected + ad_o,
170 						len),
171 					0, "Flash read failed at len=%d, "
172 					"ad_o=%d, buf_o=%d", len, ad_o, buf_o);
173 				/* check buffer guards */
174 				zassert_equal(buf[buf_o - 1], canary,
175 					"Buffer underflow at len=%d, "
176 					"ad_o=%d, buf_o=%d", len, ad_o, buf_o);
177 				zassert_equal(buf[buf_o + len], canary,
178 					"Buffer overflow at len=%d, "
179 					"ad_o=%d, buf_o=%d", len, ad_o, buf_o);
180 			}
181 		}
182 	}
183 }
184 
ZTEST(flash_driver,test_flash_fill)185 ZTEST(flash_driver, test_flash_fill)
186 {
187 	uint8_t buf[EXPECTED_SIZE];
188 	int rc;
189 	off_t i;
190 
191 	if (IS_ENABLED(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && ebw_required) {
192 		/* Erase a nb of pages aligned to the EXPECTED_SIZE */
193 		rc = flash_erase(flash_dev, page_info.start_offset,
194 				(page_info.size *
195 				((EXPECTED_SIZE + page_info.size - 1)
196 				/ page_info.size)));
197 
198 		zassert_equal(rc, 0, "Flash memory not properly erased");
199 	} else {
200 		rc = flash_fill(flash_dev, 0x55, page_info.start_offset,
201 				(page_info.size *
202 				((EXPECTED_SIZE + page_info.size - 1)
203 				/ page_info.size)));
204 		zassert_equal(rc, 0, "Leveling memory with fill failed\n");
205 	}
206 
207 	/* Fill the device with 0xaa */
208 	rc = flash_fill(flash_dev, 0xaa, page_info.start_offset,
209 			(page_info.size *
210 			((EXPECTED_SIZE + page_info.size - 1)
211 			/ page_info.size)));
212 	zassert_equal(rc, 0, "Fill failed\n");
213 
214 	rc = flash_read(flash_dev, TEST_AREA_OFFSET,
215 			buf, EXPECTED_SIZE);
216 	zassert_equal(rc, 0, "Cannot read flash");
217 
218 	for (i = 0; i < EXPECTED_SIZE; i++) {
219 		if (buf[i] != 0xaa) {
220 			break;
221 		}
222 	}
223 	zassert_equal(i, EXPECTED_SIZE, "Expected device to be filled wth 0xaa");
224 }
225 
ZTEST(flash_driver,test_flash_flatten)226 ZTEST(flash_driver, test_flash_flatten)
227 {
228 	uint8_t buf[EXPECTED_SIZE];
229 	int rc;
230 	off_t i;
231 
232 	rc = flash_flatten(flash_dev, page_info.start_offset,
233 			   (page_info.size *
234 			   ((EXPECTED_SIZE + page_info.size - 1)
235 			   / page_info.size)));
236 
237 	zassert_equal(rc, 0, "Flash not leveled not properly erased");
238 
239 	/* Fill the device with 0xaa */
240 	rc = flash_fill(flash_dev, 0xaa, page_info.start_offset,
241 			(page_info.size *
242 			((EXPECTED_SIZE + page_info.size - 1)
243 			/ page_info.size)));
244 	zassert_equal(rc, 0, "Fill failed\n");
245 
246 	rc = flash_read(flash_dev, TEST_AREA_OFFSET,
247 			buf, EXPECTED_SIZE);
248 	zassert_equal(rc, 0, "Cannot read flash");
249 
250 	for (i = 0; i < EXPECTED_SIZE; i++) {
251 		if (buf[i] != 0xaa) {
252 			break;
253 		}
254 	}
255 	zassert_equal(i, EXPECTED_SIZE, "Expected device to be filled wth 0xaa");
256 }
257 
ZTEST(flash_driver,test_flash_erase)258 ZTEST(flash_driver, test_flash_erase)
259 {
260 	int rc;
261 	uint8_t read_buf[EXPECTED_SIZE];
262 	bool comparison_result;
263 	const struct flash_parameters *fparams = flash_get_parameters(flash_dev);
264 
265 	erase_value = fparams->erase_value;
266 
267 	/* Write test data */
268 	rc = flash_write(flash_dev, page_info.start_offset, expected, EXPECTED_SIZE);
269 	zassert_equal(rc, 0, "Cannot write to flash");
270 
271 	/* Confirm write operation */
272 	rc = flash_read(flash_dev, page_info.start_offset, read_buf, EXPECTED_SIZE);
273 	zassert_equal(rc, 0, "Cannot read flash");
274 
275 	comparison_result = true;
276 	for (int i = 0; i < EXPECTED_SIZE; i++) {
277 		if (read_buf[i] != expected[i]) {
278 			comparison_result = false;
279 			TC_PRINT("i=%d:\tread_buf[i]=%d\texpected[i]=%d\n", i, read_buf[i],
280 				 expected[i]);
281 		}
282 	}
283 	zassert_true(comparison_result, "Write operation failed");
284 	/* Cross check - confirm that expected data is pseudo-random */
285 	zassert_not_equal(read_buf[0], expected[1], "These values shall be different");
286 
287 	/* Erase a nb of pages aligned to the EXPECTED_SIZE */
288 	rc = flash_erase(
289 		flash_dev, page_info.start_offset,
290 		(page_info.size * ((EXPECTED_SIZE + page_info.size - 1) / page_info.size)));
291 	zassert_equal(rc, 0, "Flash memory not properly erased");
292 
293 	/* Confirm erase operation */
294 	rc = flash_read(flash_dev, page_info.start_offset, read_buf, EXPECTED_SIZE);
295 	zassert_equal(rc, 0, "Cannot read flash");
296 
297 	comparison_result = true;
298 	for (int i = 0; i < EXPECTED_SIZE; i++) {
299 		if (read_buf[i] != erase_value) {
300 			comparison_result = false;
301 			TC_PRINT("i=%d:\tread_buf[i]=%d\texpected=%d\n", i, read_buf[i],
302 				 erase_value);
303 		}
304 	}
305 	zassert_true(comparison_result, "Write operation failed");
306 	/* Cross check - confirm that expected data
307 	 * doesn't contain erase_value
308 	 */
309 	zassert_not_equal(expected[0], erase_value, "These values shall be different");
310 }
311 
312 struct test_cb_data_type {
313 	uint32_t page_counter; /* used to count how many pages was iterated */
314 	uint32_t exit_page;    /* terminate iteration when this page is reached */
315 };
316 
flash_callback(const struct flash_pages_info * info,void * data)317 static bool flash_callback(const struct flash_pages_info *info, void *data)
318 {
319 	struct test_cb_data_type *cb_data = (struct test_cb_data_type *)data;
320 
321 	cb_data->page_counter++;
322 
323 	if (cb_data->page_counter >= cb_data->exit_page) {
324 		return false;
325 	}
326 
327 	return true;
328 }
329 
ZTEST(flash_driver,test_get_size)330 ZTEST(flash_driver, test_get_size)
331 {
332 #if CONFIG_TEST_DRIVER_FLASH_SIZE != -1
333 	uint64_t size;
334 
335 	zassert_ok(flash_get_size(flash_dev, &size));
336 	zassert_equal(size, (uint64_t)CONFIG_TEST_DRIVER_FLASH_SIZE, "Expected %llu, got %llu\n",
337 		      (uint64_t)CONFIG_TEST_DRIVER_FLASH_SIZE, size);
338 #else
339 	/* The test is sipped only because there is no uniform way to get device size */
340 	ztest_test_skip();
341 #endif
342 }
343 
ZTEST(flash_driver,test_flash_page_layout)344 ZTEST(flash_driver, test_flash_page_layout)
345 {
346 	int rc;
347 	struct flash_pages_info page_info_off = {0};
348 	struct flash_pages_info page_info_idx = {0};
349 	size_t page_count;
350 	struct test_cb_data_type test_cb_data = {0};
351 
352 #if !defined(CONFIG_FLASH_PAGE_LAYOUT)
353 	ztest_test_skip();
354 #endif
355 
356 	/* Get page info with flash_get_page_info_by_offs() */
357 	rc = flash_get_page_info_by_offs(flash_dev, TEST_AREA_OFFSET, &page_info_off);
358 	zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc);
359 	TC_PRINT("start_offset=0x%lx\tsize=%d\tindex=%d\n", page_info_off.start_offset,
360 		 (int)page_info_off.size, page_info_off.index);
361 	zassert_true(page_info_off.start_offset >= 0, "start_offset is %d", rc);
362 	zassert_true(page_info_off.size > 0, "size is %d", rc);
363 	zassert_true(page_info_off.index >= 0, "index is %d", rc);
364 
365 	/* Get info for the same page with flash_get_page_info_by_idx() */
366 	rc = flash_get_page_info_by_idx(flash_dev, page_info_off.index, &page_info_idx);
367 	zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc);
368 	zassert_equal(page_info_off.start_offset, page_info_idx.start_offset);
369 	zassert_equal(page_info_off.size, page_info_idx.size);
370 	zassert_equal(page_info_off.index, page_info_idx.index);
371 
372 	page_count = flash_get_page_count(flash_dev);
373 	TC_PRINT("page_count=%d\n", (int)page_count);
374 	zassert_true(page_count > 0, "flash_get_page_count returned %d", rc);
375 	zassert_true(page_count >= page_info_off.index);
376 
377 	/* Test that callback is executed for every page */
378 	test_cb_data.exit_page = page_count + 1;
379 	flash_page_foreach(flash_dev, flash_callback, &test_cb_data);
380 	zassert_true(page_count == test_cb_data.page_counter,
381 		     "page_count = %d not equal to pages counted with cb = %d", page_count,
382 		     test_cb_data.page_counter);
383 
384 	/* Test that callback can cancell iteration */
385 	test_cb_data.page_counter = 0;
386 	test_cb_data.exit_page = page_count >> 1;
387 	flash_page_foreach(flash_dev, flash_callback, &test_cb_data);
388 	zassert_true(test_cb_data.exit_page == test_cb_data.page_counter,
389 		     "%d pages were iterated while it shall stop on page %d",
390 		     test_cb_data.page_counter, test_cb_data.exit_page);
391 }
392 
test_flash_copy_inner(const struct device * src_dev,off_t src_offset,const struct device * dst_dev,off_t dst_offset,off_t size,uint8_t * buf,size_t buf_size,int expected_result)393 static void test_flash_copy_inner(const struct device *src_dev, off_t src_offset,
394 				  const struct device *dst_dev, off_t dst_offset, off_t size,
395 				  uint8_t *buf, size_t buf_size, int expected_result)
396 {
397 	int actual_result;
398 
399 	if ((expected_result == 0) && (size != 0) && (src_offset != dst_offset)) {
400 		/* prepare for successful copy */
401 		zassert_ok(flash_flatten(flash_dev, page_info.start_offset, page_info.size));
402 		zassert_ok(flash_fill(flash_dev, 0xaa, page_info.start_offset, page_info.size));
403 		zassert_ok(flash_flatten(flash_dev, page_info.start_offset + page_info.size,
404 					 page_info.size));
405 	}
406 
407 	/* perform copy (if args are valid) */
408 	actual_result = flash_copy(src_dev, src_offset, dst_dev, dst_offset, size, buf, buf_size);
409 	zassert_equal(actual_result, expected_result,
410 		      "flash_copy(%p, %lx, %p, %lx, %zu, %p, %zu) failed: expected: %d actual: %d",
411 		      src_dev, src_offset, dst_dev, dst_offset, size, buf, buf_size,
412 		      expected_result, actual_result);
413 
414 	if ((expected_result == 0) && (size != 0) && (src_offset != dst_offset)) {
415 		/* verify a successful copy */
416 		off_t copy_size = MIN(size, EXPECTED_SIZE);
417 
418 		zassert_ok(flash_read(flash_dev, TEST_AREA_OFFSET, expected, copy_size));
419 		for (int i = 0; i < copy_size; i++) {
420 			zassert_equal(buf[i], 0xaa, "incorrect data (%02x) at %d", buf[i], i);
421 		}
422 	}
423 }
424 
ZTEST(flash_driver,test_flash_copy)425 ZTEST(flash_driver, test_flash_copy)
426 {
427 	uint8_t buf[EXPECTED_SIZE];
428 	const off_t off_max = (sizeof(off_t) == sizeof(int32_t)) ? INT32_MAX : INT64_MAX;
429 
430 	/*
431 	 * Rather than explicitly testing 128+ permutations of input,
432 	 * merge redundant cases:
433 	 *  - src_dev or dst_dev are invalid
434 	 *  - src_offset or dst_offset are invalid
435 	 *  - src_offset + size or dst_offset + size overflow
436 	 *  - buf is NULL
437 	 *  - buf size is invalid
438 	 */
439 	test_flash_copy_inner(NULL, -1, NULL, -1, -1, NULL, 0, -EINVAL);
440 	test_flash_copy_inner(NULL, -1, NULL, -1, -1, NULL, sizeof(buf), -EINVAL);
441 	test_flash_copy_inner(NULL, -1, NULL, -1, -1, buf, sizeof(buf), -EINVAL);
442 	test_flash_copy_inner(NULL, -1, NULL, -1, page_info.size, buf, sizeof(buf), -EINVAL);
443 	test_flash_copy_inner(NULL, -1, NULL, -1, page_info.size, buf, sizeof(buf), -EINVAL);
444 	test_flash_copy_inner(NULL, page_info.start_offset, NULL,
445 			      page_info.start_offset + page_info.size, page_info.size, buf,
446 			      sizeof(buf), -ENODEV);
447 	test_flash_copy_inner(flash_dev, page_info.start_offset, flash_dev,
448 			      page_info.start_offset + page_info.size, page_info.size, buf,
449 			      sizeof(buf), 0);
450 
451 	/* zero-sized copy should succeed */
452 	test_flash_copy_inner(flash_dev, page_info.start_offset, flash_dev,
453 			      page_info.start_offset + page_info.size, 0, buf, sizeof(buf), 0);
454 
455 	/* copy with same offset should succeed */
456 	test_flash_copy_inner(flash_dev, page_info.start_offset, flash_dev, page_info.start_offset,
457 			      page_info.size, buf, sizeof(buf), 0);
458 
459 	/* copy with integer overflow should fail */
460 	test_flash_copy_inner(flash_dev, off_max, flash_dev, page_info.start_offset, 42, buf,
461 			      sizeof(buf), -EINVAL);
462 
463 	/* copy with overlapping ranges should fail */
464 	test_flash_copy_inner(flash_dev, page_info.start_offset, flash_dev,
465 			      page_info.start_offset + 32, page_info.size - 32, buf, sizeof(buf),
466 			      -EINVAL);
467 }
468 
469 ZTEST_SUITE(flash_driver, NULL, NULL, flash_driver_before, NULL, NULL);
470