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