1 /*
2  * Copyright (c) 2017-2023 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Runtime Inc
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include "fcb_test.h"
12 #include <zephyr/storage/flash_map.h>
13 #include <zephyr/drivers/flash.h>
14 #include <zephyr/device.h>
15 
16 struct fcb test_fcb = {0};
17 #if defined(CONFIG_FCB_ALLOW_FIXED_ENDMARKER)
18 struct fcb test_fcb_crc_disabled = { .f_flags = FCB_FLAGS_CRC_DISABLED };
19 #endif
20 
21 uint8_t fcb_test_erase_value;
22 
23 #if defined(CONFIG_SOC_SERIES_STM32H7X)
24 	#define SECTOR_SIZE 0x20000 /* 128K */
25 #else
26 	#define SECTOR_SIZE 0x4000 /* 16K */
27 #endif
28 
29 /* Sectors for FCB are defined far from application code
30  * area. This test suite is the non bootable application so 1. image slot is
31  * suitable for it.
32  */
33 struct flash_sector test_fcb_sector[] = {
34 	[0] = {
35 		.fs_off = 0,
36 		.fs_size = SECTOR_SIZE
37 	},
38 	[1] = {
39 		.fs_off = SECTOR_SIZE,
40 		.fs_size = SECTOR_SIZE
41 	},
42 	[2] = {
43 		.fs_off = 2 * SECTOR_SIZE,
44 		.fs_size = SECTOR_SIZE
45 	},
46 	[3] = {
47 		.fs_off = 3 * SECTOR_SIZE,
48 		.fs_size = SECTOR_SIZE
49 	}
50 };
51 
52 
test_fcb_wipe(void)53 void test_fcb_wipe(void)
54 {
55 	int i;
56 	int rc;
57 	const struct flash_area *fap;
58 
59 	rc = flash_area_open(TEST_FCB_FLASH_AREA_ID, &fap);
60 	zassert_true(rc == 0, "flash area open call failure");
61 
62 	for (i = 0; i < ARRAY_SIZE(test_fcb_sector); i++) {
63 		rc = flash_area_flatten(fap, test_fcb_sector[i].fs_off,
64 				      test_fcb_sector[i].fs_size);
65 		zassert_true(rc == 0, "erase call failure");
66 	}
67 }
68 
fcb_test_empty_walk_cb(struct fcb_entry_ctx * entry_ctx,void * arg)69 int fcb_test_empty_walk_cb(struct fcb_entry_ctx *entry_ctx, void *arg)
70 {
71 	zassert_unreachable("fcb_test_empty_walk_cb");
72 	return 0;
73 }
74 
fcb_test_append_data(int msg_len,int off)75 uint8_t fcb_test_append_data(int msg_len, int off)
76 {
77 	return (msg_len ^ off);
78 }
79 
fcb_test_data_walk_cb(struct fcb_entry_ctx * entry_ctx,void * arg)80 int fcb_test_data_walk_cb(struct fcb_entry_ctx *entry_ctx, void *arg)
81 {
82 	uint16_t len;
83 	uint8_t test_data[128];
84 	int rc;
85 	int i;
86 	int *var_cnt = (int *)arg;
87 
88 	len = entry_ctx->loc.fe_data_len;
89 
90 	zassert_true(len == *var_cnt, "");
91 
92 	rc = flash_area_read(entry_ctx->fap,
93 			     FCB_ENTRY_FA_DATA_OFF(entry_ctx->loc),
94 			     test_data, len);
95 	zassert_true(rc == 0, "read call failure");
96 
97 	for (i = 0; i < len; i++) {
98 		zassert_true(test_data[i] == fcb_test_append_data(len, i),
99 		"fcb_test_append_data redout misrepresentation");
100 	}
101 	(*var_cnt)++;
102 	return 0;
103 }
104 
fcb_test_cnt_elems_cb(struct fcb_entry_ctx * entry_ctx,void * arg)105 int fcb_test_cnt_elems_cb(struct fcb_entry_ctx *entry_ctx, void *arg)
106 {
107 	struct append_arg *aa = (struct append_arg *)arg;
108 	int idx;
109 
110 	idx = entry_ctx->loc.fe_sector - &test_fcb_sector[0];
111 	aa->elem_cnts[idx]++;
112 	return 0;
113 }
114 
fcb_tc_pretest(int sectors,struct fcb * _fcb)115 void fcb_tc_pretest(int sectors, struct fcb *_fcb)
116 {
117 	int rc = 0;
118 
119 	test_fcb_wipe();
120 	_fcb->f_erase_value = fcb_test_erase_value;
121 	_fcb->f_sector_cnt = sectors;
122 	_fcb->f_sectors = test_fcb_sector; /* XXX */
123 
124 	rc = 0;
125 	rc = fcb_init(TEST_FCB_FLASH_AREA_ID, _fcb);
126 	if (rc != 0) {
127 		printf("%s rc == %xm, %d\n", __func__, rc, rc);
128 		zassert_true(rc == 0, "fbc initialization failure");
129 	}
130 }
131 
fcb_pretest_2_sectors(void * data)132 static void fcb_pretest_2_sectors(void *data)
133 {
134 	fcb_tc_pretest(2, &test_fcb);
135 }
136 
fcb_pretest_4_sectors(void * data)137 static void fcb_pretest_4_sectors(void *data)
138 {
139 	fcb_tc_pretest(4, &test_fcb);
140 }
141 
fcb_pretest_crc_disabled(void * data)142 static void fcb_pretest_crc_disabled(void *data)
143 {
144 #if defined(CONFIG_FCB_ALLOW_FIXED_ENDMARKER)
145 	fcb_tc_pretest(2, &test_fcb_crc_disabled);
146 #else
147 	ztest_test_skip();
148 #endif
149 }
150 
151 /*
152  * This actually is not a test; the function gets erase value from flash
153  * parameters, of the flash device that is used by tests, and stores it in
154  * global fcb_test_erase_value.
155  */
ZTEST(fcb_test_without_set,test_get_flash_erase_value)156 ZTEST(fcb_test_without_set, test_get_flash_erase_value)
157 {
158 	const struct flash_area *fa;
159 	const struct flash_parameters *fp;
160 	const struct device *dev;
161 	int rc = 0;
162 
163 	rc = flash_area_open(TEST_FCB_FLASH_AREA_ID, &fa);
164 	zassert_equal(rc, 0, "Failed top open flash area");
165 
166 	dev = fa->fa_dev;
167 	flash_area_close(fa);
168 
169 	zassert_true(dev != NULL, "Failed to obtain device");
170 
171 	fp = flash_get_parameters(dev);
172 	zassert_true(fp != NULL, "Failed to get flash device parameters");
173 
174 	fcb_test_erase_value = fp->erase_value;
175 }
176 
177 ZTEST_SUITE(fcb_test_without_set, NULL, NULL, NULL, NULL, NULL);
178 ZTEST_SUITE(fcb_test_with_2sectors_set, NULL, NULL, fcb_pretest_2_sectors, NULL, NULL);
179 ZTEST_SUITE(fcb_test_with_4sectors_set, NULL, NULL, fcb_pretest_4_sectors, NULL, NULL);
180 
181 ZTEST_SUITE(fcb_test_crc_disabled, NULL, NULL, fcb_pretest_crc_disabled, NULL, NULL);
182