xref: /aosp_15_r20/external/coreboot/tests/lib/fmap-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <stdlib.h>
4 #include <string.h>
5 
6 #include <tests/test.h>
7 
8 #include <fmap.h>
9 #include <commonlib/region.h>
10 
11 #include <tests/lib/fmap/fmap_data.h>
12 #include <tests/lib/fmap/fmap_config.h>
13 
14 static struct region_device flash_rdev_rw;
15 static struct region_device flash_rdev_ro;
16 static char *flash_buffer = NULL;
17 static size_t flash_buffer_size = 0;
18 
prepare_flash_buffer(void)19 static void prepare_flash_buffer(void)
20 {
21 	/* Prepare flash buffer with dummy data and FMAP */
22 	flash_buffer = malloc(FMAP_SECTION_FLASH_SIZE);
23 	flash_buffer_size = FMAP_SECTION_FLASH_SIZE;
24 
25 	/* Fill first part of buffer with dummy data */
26 	for (int i = 0; i < FMAP_SECTION_FMAP_START; ++i)
27 		flash_buffer[i] = 'a' + i % ('z' - 'a');
28 
29 	/* Copy FMAP section into buffer */
30 	memcpy(flash_buffer + FMAP_SECTION_FMAP_START, tests_fmap_bin, FMAP_SIZE);
31 
32 	/* Fill rest of buffer with dummy data */
33 	for (int i = FMAP_SECTION_FMAP_START + FMAP_SECTION_FMAP_SIZE;
34 	     i < FMAP_SECTION_FLASH_SIZE; ++i)
35 		flash_buffer[i] = 'a' + i % ('z' - 'a');
36 }
37 
setup_fmap(void ** state)38 static int setup_fmap(void **state)
39 {
40 	prepare_flash_buffer();
41 	rdev_chain_mem_rw(&flash_rdev_rw, flash_buffer, FMAP_SECTION_FLASH_SIZE);
42 	rdev_chain_mem(&flash_rdev_ro, flash_buffer, FMAP_SECTION_FLASH_SIZE);
43 	return 0;
44 }
45 
teardown_fmap(void ** state)46 static int teardown_fmap(void **state)
47 {
48 	rdev_chain_mem_rw(&flash_rdev_rw, NULL, 0);
49 	rdev_chain_mem(&flash_rdev_ro, NULL, 0);
50 
51 	free(flash_buffer);
52 	flash_buffer = NULL;
53 	flash_buffer_size = 0;
54 
55 	return 0;
56 }
57 
boot_device_init(void)58 void boot_device_init(void)
59 {
60 	/* Setup in unit test setup function */
61 }
62 
boot_device_ro(void)63 const struct region_device *boot_device_ro(void)
64 {
65 	return &flash_rdev_ro;
66 }
67 
boot_device_rw(void)68 const struct region_device *boot_device_rw(void)
69 {
70 	return &flash_rdev_rw;
71 }
72 
test_fmap_locate_area_as_rdev(void ** state)73 static void test_fmap_locate_area_as_rdev(void **state)
74 {
75 	const char buffer[] = "abcdefghijk0123456789";
76 	struct region_device rdev;
77 
78 	assert_int_not_equal(-1, fmap_locate_area_as_rdev("RO_VPD", &rdev));
79 	assert_ptr_equal(flash_buffer + FMAP_SECTION_RO_VPD_START, rdev_mmap_full(&rdev));
80 	assert_int_equal(FMAP_SECTION_RO_VPD_SIZE, region_device_sz(&rdev));
81 
82 	/* Check if locating area second time works */
83 	assert_int_not_equal(-1, fmap_locate_area_as_rdev("RO_VPD", &rdev));
84 	assert_ptr_equal(flash_buffer + FMAP_SECTION_RO_VPD_START, rdev_mmap_full(&rdev));
85 	assert_int_equal(FMAP_SECTION_RO_VPD_SIZE, region_device_sz(&rdev));
86 
87 	assert_int_not_equal(-1, fmap_locate_area_as_rdev("RECOVERY_MRC_CACHE", &rdev));
88 	assert_ptr_equal(flash_buffer + FMAP_SECTION_RECOVERY_MRC_CACHE_START,
89 			 rdev_mmap_full(&rdev));
90 	assert_int_equal(FMAP_SECTION_RECOVERY_MRC_CACHE_SIZE, region_device_sz(&rdev));
91 
92 	/* Expect error when writing to read-only area */
93 	assert_int_equal(-1, rdev_writeat(&rdev, buffer, 0, sizeof(buffer)));
94 
95 	/* Expect error when looking for incorrect area */
96 	assert_int_equal(-1, fmap_locate_area_as_rdev("NONEXISTENT_AREA", &rdev));
97 	assert_int_equal(-1, fmap_locate_area_as_rdev("", &rdev));
98 	assert_int_equal(-1, fmap_locate_area_as_rdev(NULL, &rdev));
99 
100 	/* Function fmap_locate_area_as_rdev is not tested with NULL
101 	   as region_device pointer as it is not allowed. */
102 }
103 
test_fmap_locate_area_as_rdev_rw(void ** state)104 static void test_fmap_locate_area_as_rdev_rw(void **state)
105 {
106 	struct region_device rdev;
107 	size_t ro_rw_section_size = FMAP_SECTION_MISC_RW_SIZE;
108 	char *buffer1 = malloc(ro_rw_section_size);
109 	char *buffer2 = malloc(ro_rw_section_size);
110 	char *dummy_data = malloc(ro_rw_section_size);
111 
112 	/* Fill buffer with dummy data */
113 	for (int i = 0; i < ro_rw_section_size; ++i)
114 		dummy_data[i] = '0' + i % ('9' - '0');
115 
116 	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("RW_SECTION_A", &rdev));
117 	assert_ptr_equal(flash_buffer + FMAP_SECTION_RW_SECTION_A_START, rdev_mmap_full(&rdev));
118 	assert_int_equal(FMAP_SECTION_RW_SECTION_A_SIZE, region_device_sz(&rdev));
119 
120 	/* Check if locating area second time works */
121 	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("RW_SECTION_A", &rdev));
122 	assert_ptr_equal(flash_buffer + FMAP_SECTION_RW_SECTION_A_START, rdev_mmap_full(&rdev));
123 	assert_int_equal(FMAP_SECTION_RW_SECTION_A_SIZE, region_device_sz(&rdev));
124 
125 	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("MISC_RW", &rdev));
126 	assert_ptr_equal(flash_buffer + FMAP_SECTION_MISC_RW_START, rdev_mmap_full(&rdev));
127 	assert_int_equal(FMAP_SECTION_MISC_RW_SIZE, region_device_sz(&rdev));
128 
129 
130 	/* Expect error when looking for incorrect area */
131 	assert_int_equal(-1, fmap_locate_area_as_rdev_rw("NONEXISTENT_AREA", &rdev));
132 	assert_int_equal(-1, fmap_locate_area_as_rdev_rw("", &rdev));
133 
134 	/* Expect error when passing invalid references */
135 	assert_int_equal(-1, fmap_locate_area_as_rdev_rw(NULL, &rdev));
136 
137 	/* Function fmap_locate_area_as_rdev_rw is not tested with NULL
138 	   as region_device pointer as it is not allowed. */
139 
140 	/* Test if returned section region device is writable */
141 	assert_int_not_equal(-1, fmap_locate_area_as_rdev_rw("MISC_RW", &rdev));
142 	assert_int_equal(ro_rw_section_size,
143 			 rdev_readat(&rdev, buffer1, 0, ro_rw_section_size));
144 	assert_int_equal(ro_rw_section_size,
145 			 rdev_writeat(&rdev, dummy_data, 0, ro_rw_section_size));
146 	/* Check if written data is visible and correct after locating area as RO */
147 	assert_int_not_equal(-1, fmap_locate_area_as_rdev("MISC_RW", &rdev));
148 	assert_int_equal(ro_rw_section_size,
149 			 rdev_readat(&rdev, buffer2, 0, ro_rw_section_size));
150 	assert_memory_not_equal(buffer1, buffer2, ro_rw_section_size);
151 	assert_memory_equal(dummy_data, buffer2, ro_rw_section_size);
152 
153 	free(buffer1);
154 	free(buffer2);
155 	free(dummy_data);
156 }
157 
test_fmap_locate_area(void ** state)158 static void test_fmap_locate_area(void **state)
159 {
160 	struct region ar;
161 
162 	/* Try to locate named area */
163 	assert_int_not_equal(-1, fmap_locate_area("COREBOOT", &ar));
164 	assert_int_equal(FMAP_SECTION_COREBOOT_START, region_offset(&ar));
165 	assert_int_equal(FMAP_SECTION_COREBOOT_SIZE, region_sz(&ar));
166 
167 	/* Check if locating area second time works */
168 	assert_int_not_equal(-1, fmap_locate_area("COREBOOT", &ar));
169 	assert_int_equal(FMAP_SECTION_COREBOOT_START, region_offset(&ar));
170 	assert_int_equal(FMAP_SECTION_COREBOOT_SIZE, region_sz(&ar));
171 
172 	/* Look for another area */
173 	assert_int_not_equal(-1, fmap_locate_area("GBB", &ar));
174 	assert_int_equal(FMAP_SECTION_GBB_START, region_offset(&ar));
175 	assert_int_equal(FMAP_SECTION_GBB_SIZE, region_sz(&ar));
176 
177 	/* Expect error when looking for incorrect area */
178 	assert_int_equal(-1, fmap_locate_area("NONEXISTENT_AREA", &ar));
179 	assert_int_equal(-1, fmap_locate_area("", &ar));
180 	assert_int_equal(-1, fmap_locate_area(NULL, &ar));
181 
182 	/* Expect error when passing invalid region pointer */
183 	assert_int_equal(-1, fmap_locate_area("SHARED_DATA", NULL));
184 }
185 
test_fmap_find_region_name(void ** state)186 static void test_fmap_find_region_name(void **state)
187 {
188 	(void)state;
189 	struct region ar;
190 	char found_area_name[FMAP_STRLEN] = "";
191 	const char *area_name = "RW_PRESERVE";
192 
193 	/* Find area by name */
194 	assert_int_not_equal(-1, fmap_locate_area(area_name, &ar));
195 
196 	/* Find name of previously located region */
197 	assert_int_not_equal(-1, fmap_find_region_name(&ar, found_area_name));
198 	assert_string_equal(area_name, found_area_name);
199 
200 	/* Expect error when passing invalid buffer */
201 	assert_int_equal(-1, fmap_find_region_name(&ar, NULL));
202 
203 	/* Expect error when passing invalid region pointer */
204 	assert_int_equal(-1, fmap_find_region_name(NULL, found_area_name));
205 
206 	/* Try to find area outside of flash region */
207 	ar.offset = FMAP_SECTION_FLASH_START + FMAP_SECTION_FLASH_SIZE + 0x100;
208 	ar.size = 0x1000;
209 	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
210 
211 	/* Try to find area with correct offset and incorrect size */
212 	ar.offset = FMAP_SECTION_COREBOOT_START;
213 	ar.size = FMAP_SECTION_COREBOOT_SIZE / 4;
214 	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
215 
216 	/* Try to find area with correct size and incorrect offset */
217 	ar.offset = FMAP_SECTION_GBB_START - 0x100;
218 	ar.size = FMAP_SECTION_GBB_START;
219 	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
220 
221 	/* Try to find area with correct offset overlapping with another area */
222 	ar.offset = FMAP_SECTION_MISC_RW_START;
223 	ar.size = FMAP_SECTION_MISC_RW_START + 0x1000;
224 	assert_int_equal(-1, fmap_find_region_name(&ar, found_area_name));
225 }
226 
test_fmap_read_area(void ** state)227 static void test_fmap_read_area(void **state)
228 {
229 	const unsigned int section_size = FMAP_SECTION_RW_SECTION_A_SIZE;
230 	const unsigned int section_start = FMAP_SECTION_RW_SECTION_A_START;
231 	char *buffer = malloc(section_size);
232 
233 	/* Find and read area data. Compare with memory device simulating flash. */
234 	assert_int_equal(section_size, fmap_read_area("RW_SECTION_A", buffer, section_size));
235 	assert_memory_equal(flash_buffer + section_start, buffer, section_size);
236 
237 	/* Expect error when reading incorrect area */
238 	assert_int_equal(-1, fmap_read_area("NONEXISTENT_SECTION", buffer, section_size));
239 	assert_int_equal(-1, fmap_read_area("", buffer, section_size));
240 	assert_int_equal(-1, fmap_read_area(NULL, buffer, section_size));
241 
242 	/* Function fmap_read_area is not tested with NULL
243 	   as output buffer pointer as it is not allowed. */
244 
245 	free(buffer);
246 }
247 
test_fmap_overwrite_area(void ** state)248 static void test_fmap_overwrite_area(void **state)
249 {
250 	const char *section_name = "FW_MAIN_A";
251 	const unsigned int section_size = FMAP_SECTION_FW_MAIN_A_SIZE;
252 	char *buffer1 = malloc(section_size);
253 	char *buffer2 = malloc(section_size);
254 	char *new_data = malloc(section_size / 2);
255 	char *zero_buffer = malloc(section_size / 2);
256 	memset(zero_buffer, 0, section_size / 2);
257 	memset(new_data, 0x42, section_size / 2);
258 
259 	/* Save buffer for future comparisons */
260 	assert_int_equal(section_size, fmap_read_area(section_name, buffer1, section_size));
261 
262 	/* Overwrite part of section. */
263 	assert_int_equal(section_size / 2,
264 			 fmap_overwrite_area(section_name, new_data, section_size / 2));
265 
266 	/* Read and check if memory has changed as expected */
267 	assert_int_equal(section_size, fmap_read_area(section_name, buffer2, section_size));
268 	assert_memory_not_equal(buffer1, buffer2, section_size);
269 	/* Check if requested section area was overwritten properly */
270 	assert_memory_equal(buffer2, new_data, section_size / 2);
271 	/* Check if rest of section was zero-filled */
272 	assert_memory_equal(buffer2 + (section_size / 2), zero_buffer, section_size / 2);
273 
274 	/* Expect error when overwriting incorrect section */
275 	assert_int_equal(
276 		-1, fmap_overwrite_area("NONEXISTENT_SECTION", new_data, section_size / 2));
277 	assert_int_equal(-1, fmap_overwrite_area(NULL, new_data, section_size / 2));
278 
279 	/* Function fmap_overwrite_area is not tested with NULL
280 	   as input buffer pointer as it is not allowed. */
281 
282 	free(buffer1);
283 	free(buffer2);
284 	free(new_data);
285 	free(zero_buffer);
286 }
287 
main(void)288 int main(void)
289 {
290 	const struct CMUnitTest tests[] = {
291 		cmocka_unit_test_setup_teardown(test_fmap_locate_area_as_rdev, setup_fmap,
292 						teardown_fmap),
293 		cmocka_unit_test_setup_teardown(test_fmap_locate_area_as_rdev_rw, setup_fmap,
294 						teardown_fmap),
295 		cmocka_unit_test_setup_teardown(test_fmap_locate_area, setup_fmap,
296 						teardown_fmap),
297 		cmocka_unit_test_setup_teardown(test_fmap_find_region_name, setup_fmap,
298 						teardown_fmap),
299 		cmocka_unit_test_setup_teardown(test_fmap_read_area, setup_fmap, teardown_fmap),
300 		cmocka_unit_test_setup_teardown(test_fmap_overwrite_area, setup_fmap,
301 						teardown_fmap),
302 	};
303 
304 	return cb_run_group_tests(tests, NULL, NULL);
305 }
306