xref: /aosp_15_r20/external/coreboot/payloads/libpayload/tests/libcbfs/cbfs-lookup-test.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <libpayload-config.h>
4 #include <cbfs.h>
5 #include <cbfs_glue.h>
6 #include <commonlib/bsd/cb_err.h>
7 #include <commonlib/bsd/cbfs_mdata.h>
8 #include <endian.h>
9 #include <mocks/cbfs_util.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sysinfo.h>
13 #include <tests/test.h>
14 
15 #include "../libcbfs/cbfs.c"
16 
17 /* Mocks */
18 
19 unsigned long virtual_offset = 0;
20 struct sysinfo_t lib_sysinfo;
21 
ulzman(const unsigned char * src,unsigned long srcn,unsigned char * dst,unsigned long dstn)22 unsigned long ulzman(const unsigned char *src, unsigned long srcn, unsigned char *dst,
23 		     unsigned long dstn)
24 {
25 	assert_true(dstn != 0);
26 	check_expected(srcn);
27 	check_expected(dstn);
28 	memcpy(dst, src, dstn);
29 	return dstn;
30 }
31 
ulz4fn(const void * src,size_t srcn,void * dst,size_t dstn)32 size_t ulz4fn(const void *src, size_t srcn, void *dst, size_t dstn)
33 {
34 	assert_non_null(dstn);
35 	check_expected(srcn);
36 	check_expected(dstn);
37 	memcpy(dst, src, dstn);
38 	return dstn;
39 }
40 
41 static size_t test_fmap_offset = 0;
42 static size_t test_fmap_size = 0;
43 static enum cb_err test_fmap_result = CB_SUCCESS;
44 
set_fmap_locate_area_results(size_t offset,size_t size,size_t result)45 static void set_fmap_locate_area_results(size_t offset, size_t size, size_t result)
46 {
47 	test_fmap_offset = offset;
48 	test_fmap_size = size;
49 	test_fmap_result = result;
50 }
51 
fmap_locate_area(const char * name,size_t * offset,size_t * size)52 enum cb_err fmap_locate_area(const char *name, size_t *offset, size_t *size)
53 {
54 	*offset = test_fmap_offset;
55 	*size = test_fmap_size;
56 	return test_fmap_result;
57 }
58 
cbfs_mcache_lookup(const void * mcache,size_t mcache_size,const char * name,union cbfs_mdata * mdata_out,size_t * data_offset_out)59 enum cb_err cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name,
60 			       union cbfs_mdata *mdata_out, size_t *data_offset_out)
61 {
62 	assert_non_null(mcache);
63 	assert_true(mcache_size > 0 && mcache_size % CBFS_MCACHE_ALIGNMENT == 0);
64 	assert_non_null(mdata_out);
65 	assert_non_null(data_offset_out);
66 
67 	check_expected(name);
68 
69 	enum cb_err ret = mock_type(enum cb_err);
70 	if (ret != CB_SUCCESS)
71 		return ret;
72 
73 	memcpy(mdata_out, mock_ptr_type(const union cbfs_mdata *), sizeof(union cbfs_mdata));
74 	*data_offset_out = mock_type(size_t);
75 	return CB_SUCCESS;
76 }
77 
expect_cbfs_mcache_lookup(const char * name,enum cb_err err,const union cbfs_mdata * mdata,size_t data_offset_out)78 static void expect_cbfs_mcache_lookup(const char *name, enum cb_err err,
79 				      const union cbfs_mdata *mdata, size_t data_offset_out)
80 {
81 	expect_string(cbfs_mcache_lookup, name, name);
82 	will_return(cbfs_mcache_lookup, err);
83 
84 	if (err == CB_SUCCESS) {
85 		will_return(cbfs_mcache_lookup, mdata);
86 		will_return(cbfs_mcache_lookup, data_offset_out);
87 	}
88 }
89 
cbfs_lookup(cbfs_dev_t dev,const char * name,union cbfs_mdata * mdata_out,size_t * data_offset_out,struct vb2_hash * metadata_hash)90 enum cb_err cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out,
91 			size_t *data_offset_out, struct vb2_hash *metadata_hash)
92 {
93 	assert_non_null(dev);
94 	check_expected(name);
95 
96 	enum cb_err ret = mock_type(enum cb_err);
97 	if (ret != CB_SUCCESS)
98 		return ret;
99 
100 	memcpy(mdata_out, mock_ptr_type(const union cbfS_mdata *), sizeof(union cbfs_mdata));
101 	*data_offset_out = mock_type(size_t);
102 	return CB_SUCCESS;
103 }
104 
expect_cbfs_lookup(const char * name,enum cb_err err,const union cbfs_mdata * mdata,size_t data_offset_out)105 static void expect_cbfs_lookup(const char *name, enum cb_err err, const union cbfs_mdata *mdata,
106 			       size_t data_offset_out)
107 {
108 	expect_string(cbfs_lookup, name, name);
109 	will_return(cbfs_lookup, err);
110 
111 	if (err == CB_SUCCESS) {
112 		will_return(cbfs_lookup, mdata);
113 		will_return(cbfs_lookup, data_offset_out);
114 	}
115 }
116 
cbfs_find_attr(const union cbfs_mdata * mdata,uint32_t attr_tag,size_t size_check)117 const void *cbfs_find_attr(const union cbfs_mdata *mdata, uint32_t attr_tag, size_t size_check)
118 {
119 	return mock_ptr_type(void *);
120 }
121 
122 static bool force_single_boot_device_size_failure = false;
123 
boot_device_read(void * buf,size_t offset,size_t size)124 ssize_t boot_device_read(void *buf, size_t offset, size_t size)
125 {
126 	memcpy(buf, (void *)offset, size);
127 	if (force_single_boot_device_size_failure) {
128 		force_single_boot_device_size_failure = false;
129 		return CB_ERR;
130 	}
131 	return size;
132 }
133 
134 /* Utils */
135 
get_cbfs_file_size(const void * file_ptr)136 static size_t get_cbfs_file_size(const void *file_ptr)
137 {
138 	const struct cbfs_file *f = file_ptr;
139 	return be32toh(f->offset) + be32toh(f->len);
140 }
141 
create_cbfs(const struct cbfs_test_file * files[],const size_t nfiles,uint8_t * buffer,const size_t buffer_size)142 static void create_cbfs(const struct cbfs_test_file *files[], const size_t nfiles,
143 			uint8_t *buffer, const size_t buffer_size)
144 {
145 	uint8_t *data_ptr = buffer;
146 	size_t file_size = 0;
147 	memset(buffer, 0, buffer_size);
148 	for (size_t i = 0; i < nfiles; ++i) {
149 		if (files[i] == NULL) {
150 			file_size = CBFS_ALIGNMENT;
151 			assert_true(&data_ptr[file_size] < &buffer[buffer_size]);
152 		} else {
153 			file_size = get_cbfs_file_size(files[i]);
154 			assert_true(&data_ptr[file_size] < &buffer[buffer_size]);
155 			memcpy(data_ptr, files[i], file_size);
156 		}
157 		data_ptr = &data_ptr[file_size];
158 		data_ptr = &buffer[ALIGN_UP((uintptr_t)data_ptr - (uintptr_t)buffer,
159 					    CBFS_ALIGNMENT)];
160 	}
161 }
162 
get_created_cbfs_file_start_offset(const struct cbfs_test_file * files[],const size_t nfile)163 static size_t get_created_cbfs_file_start_offset(const struct cbfs_test_file *files[],
164 						 const size_t nfile)
165 {
166 	size_t offset_out = 0;
167 	size_t offset = 0;
168 	for (size_t i = 0; i < nfile; ++i) {
169 		offset = files[i] ? get_cbfs_file_size(files[i]) : CBFS_ALIGNMENT;
170 		offset_out = ALIGN_UP(offset_out + offset, CBFS_ALIGNMENT);
171 	}
172 	return offset_out;
173 }
174 
175 /* Setup */
176 
177 static uint8_t
178 	aligned_cbfs_ro_buffer[(sizeof(struct cbfs_test_file) + CBFS_ALIGNMENT * 50)] __aligned(
179 		CBFS_ALIGNMENT);
180 static const size_t aligned_cbfs_ro_buffer_size = sizeof(aligned_cbfs_ro_buffer);
181 static uint8_t
182 	aligned_cbfs_rw_buffer[(sizeof(struct cbfs_test_file) + CBFS_ALIGNMENT * 50)] __aligned(
183 		CBFS_ALIGNMENT);
184 static const size_t aligned_cbfs_rw_buffer_size = sizeof(aligned_cbfs_rw_buffer);
185 
186 static uint8_t *unaligned_cbfs_ro_buffer = &aligned_cbfs_ro_buffer[5];
187 static const size_t unaligned_cbfs_ro_buffer_size = aligned_cbfs_ro_buffer_size - 5;
188 static uint8_t *unaligned_cbfs_rw_buffer = &aligned_cbfs_rw_buffer[5];
189 static const size_t unaligned_cbfs_rw_buffer_size = aligned_cbfs_rw_buffer_size - 5;
190 
191 struct cbfs_test_state {
192 	uint8_t *cbfs_ro_buf;
193 	uint64_t cbfs_ro_size;
194 	uint8_t *cbfs_rw_buf;
195 	uint64_t cbfs_rw_size;
196 
197 	size_t mcache_ro_offset;
198 	size_t mcache_ro_size;
199 	size_t mcache_rw_offset;
200 	size_t mcache_rw_size;
201 
202 	struct cbfs_test_setup {
203 		bool unaligned;
204 		bool init_ro;
205 		bool init_rw;
206 	} ex;
207 };
208 
209 
210 /* Because of how CMocka works, it should be called in the test function, or in the setup
211    function only if CBFS API capable of initializing RO CBFS boot device is called. */
setup_cbfs_boot_device(struct cbfs_test_state * s)212 static void setup_cbfs_boot_device(struct cbfs_test_state *s)
213 {
214 	set_fmap_locate_area_results(0, 0, CB_SUCCESS);
215 	lib_sysinfo.cbfs_ro_mcache_offset = 0;
216 	lib_sysinfo.cbfs_ro_mcache_size = 0;
217 	memset((void *)cbfs_get_boot_device(true), 0, sizeof(struct cbfs_boot_device));
218 	if (s->ex.init_ro) {
219 		set_fmap_locate_area_results((size_t)s->cbfs_ro_buf, s->cbfs_ro_size,
220 					     CB_SUCCESS);
221 		lib_sysinfo.cbfs_ro_mcache_offset = s->mcache_ro_offset;
222 		lib_sysinfo.cbfs_ro_mcache_size = s->mcache_ro_size;
223 	}
224 
225 	lib_sysinfo.cbfs_offset = 0;
226 	lib_sysinfo.cbfs_size = 0;
227 	lib_sysinfo.cbfs_rw_mcache_offset = 0;
228 	lib_sysinfo.cbfs_rw_mcache_size = 0;
229 	memset((void *)cbfs_get_boot_device(false), 0, sizeof(struct cbfs_boot_device));
230 	if (s->ex.init_rw) {
231 		lib_sysinfo.cbfs_offset = (uint64_t)s->cbfs_rw_buf;
232 		lib_sysinfo.cbfs_size = s->cbfs_rw_size;
233 		lib_sysinfo.cbfs_rw_mcache_offset = s->mcache_rw_offset;
234 		lib_sysinfo.cbfs_rw_mcache_size = s->mcache_rw_size;
235 	}
236 }
237 
setup_cbfs_test(void ** state)238 static int setup_cbfs_test(void **state)
239 {
240 	struct cbfs_test_state *s = calloc(1, sizeof(*s));
241 
242 	if (!s)
243 		return 1;
244 
245 	if (*state)
246 		memcpy(&s->ex, *state, sizeof(s->ex));
247 
248 	if (s->ex.init_ro) {
249 		if (s->ex.unaligned) {
250 			s->cbfs_ro_buf = unaligned_cbfs_ro_buffer;
251 			s->cbfs_ro_size = unaligned_cbfs_ro_buffer_size;
252 		} else {
253 			s->cbfs_ro_buf = aligned_cbfs_ro_buffer;
254 			s->cbfs_ro_size = aligned_cbfs_ro_buffer_size;
255 		}
256 	}
257 
258 	if (s->ex.init_rw) {
259 		if (s->ex.unaligned) {
260 			s->cbfs_rw_buf = unaligned_cbfs_rw_buffer;
261 			s->cbfs_rw_size = unaligned_cbfs_rw_buffer_size;
262 		} else {
263 			s->cbfs_rw_buf = aligned_cbfs_rw_buffer;
264 			s->cbfs_rw_size = aligned_cbfs_rw_buffer_size;
265 		}
266 	}
267 
268 	*state = s;
269 
270 	return 0;
271 }
272 
teardown_cbfs_test(void ** state)273 static int teardown_cbfs_test(void **state)
274 {
275 	if (*state)
276 		free(*state);
277 
278 	return 0;
279 }
280 
281 /* Tests */
282 
test_cbfs_boot_device_init(void ** state)283 static void test_cbfs_boot_device_init(void **state)
284 {
285 	const struct cbfs_boot_device *cbd = NULL;
286 
287 	/* No valid RO, should fail */
288 	set_fmap_locate_area_results(0, 0, CB_ERR);
289 	lib_sysinfo.cbfs_offset = 0;
290 	lib_sysinfo.cbfs_size = 0;
291 	lib_sysinfo.cbfs_rw_mcache_size = 0;
292 	lib_sysinfo.cbfs_rw_mcache_offset = 0;
293 	lib_sysinfo.cbfs_ro_mcache_offset = 0;
294 	lib_sysinfo.cbfs_ro_mcache_size = 0;
295 	assert_int_equal(NULL, cbfs_get_boot_device(true));
296 	assert_null(cbfs_ro_map("file", NULL));
297 
298 	/* Valid RO */
299 	set_fmap_locate_area_results(0x12345678, 0x90ABCDEF, CB_SUCCESS);
300 	lib_sysinfo.cbfs_ro_mcache_offset = 0x600D41C3;
301 	lib_sysinfo.cbfs_ro_mcache_size = 0xBADBEEFF;
302 	cbd = cbfs_get_boot_device(true);
303 	assert_non_null(cbd);
304 	assert_int_equal(0x12345678, cbd->dev.offset);
305 	assert_int_equal(0x90ABCDEF, cbd->dev.size);
306 	assert_int_equal(0xBADBEEFF, cbd->mcache_size);
307 	assert_int_equal(0x600D41C3, cbd->mcache);
308 
309 	lib_sysinfo.cbfs_offset = 0xAABBCCDD;
310 	lib_sysinfo.cbfs_size = 0x1000;
311 	lib_sysinfo.cbfs_rw_mcache_offset = 0x8F8F8F8F;
312 	lib_sysinfo.cbfs_rw_mcache_size = 0x500;
313 	cbd = cbfs_get_boot_device(false);
314 	assert_non_null(cbd);
315 	assert_int_equal(0xAABBCCDD, cbd->dev.offset);
316 	assert_int_equal(0x1000, cbd->dev.size);
317 	assert_int_equal(0x8F8F8F8F, cbd->mcache);
318 	assert_int_equal(0x500, cbd->mcache_size);
319 }
320 
321 /* This test checks cbfs_map() basic cases and covers only RW CBFS. */
test_cbfs_map(void ** state)322 void test_cbfs_map(void **state)
323 {
324 	struct cbfs_test_state *s = *state;
325 	void *mapping = NULL;
326 	size_t size_out = 0;
327 	const struct cbfs_test_file *cbfs_files[] = {
328 		&test_file_int_1, &test_file_2, NULL, &test_file_int_3,
329 		&test_file_int_2, NULL,		NULL, &test_file_1,
330 	};
331 	uint8_t *cbfs_buf = NULL;
332 	size_t foffset = 0;
333 
334 	setup_cbfs_boot_device(s);
335 	cbfs_buf = s->cbfs_rw_buf;
336 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_rw_buf, s->cbfs_rw_size);
337 
338 	size_out = 0;
339 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 0);
340 	expect_cbfs_lookup(TEST_DATA_INT_1_FILENAME, CB_SUCCESS,
341 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
342 			   foffset + be32toh(test_file_int_1.header.offset));
343 	will_return(cbfs_find_attr, NULL);
344 	mapping = cbfs_map(TEST_DATA_INT_1_FILENAME, &size_out);
345 	assert_non_null(mapping);
346 	assert_int_equal(TEST_DATA_INT_1_SIZE, size_out);
347 	assert_memory_equal(test_data_int_1, mapping, TEST_DATA_INT_1_SIZE);
348 	cbfs_unmap(mapping);
349 
350 	size_out = 0;
351 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 1);
352 	expect_cbfs_lookup(TEST_DATA_2_FILENAME, CB_SUCCESS,
353 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
354 			   foffset + be32toh(test_file_2.header.offset));
355 	will_return(cbfs_find_attr, &test_file_2.attrs_and_data);
356 	expect_value(ulzman, srcn, TEST_DATA_2_SIZE);
357 	expect_value(ulzman, dstn, TEST_DATA_2_SIZE);
358 	mapping = cbfs_map(TEST_DATA_2_FILENAME, &size_out);
359 	assert_non_null(mapping);
360 	assert_int_equal(TEST_DATA_2_SIZE, size_out);
361 	assert_memory_equal(test_data_2, mapping, TEST_DATA_2_SIZE);
362 	cbfs_unmap(mapping);
363 
364 	size_out = 0;
365 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 3);
366 	expect_cbfs_lookup(TEST_DATA_INT_3_FILENAME, CB_SUCCESS,
367 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
368 			   foffset + be32toh(test_file_int_3.header.offset));
369 	will_return(cbfs_find_attr, &test_file_int_3.attrs_and_data);
370 	expect_value(ulz4fn, srcn, TEST_DATA_INT_3_SIZE);
371 	expect_value(ulz4fn, dstn, TEST_DATA_INT_3_SIZE);
372 	mapping = cbfs_map(TEST_DATA_INT_3_FILENAME, &size_out);
373 	assert_non_null(mapping);
374 	assert_int_equal(TEST_DATA_INT_3_SIZE, size_out);
375 	assert_memory_equal(test_data_int_3, mapping, TEST_DATA_INT_3_SIZE);
376 	cbfs_unmap(mapping);
377 
378 	size_out = 0;
379 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 4);
380 	expect_cbfs_lookup(TEST_DATA_INT_2_FILENAME, CB_SUCCESS,
381 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
382 			   foffset + be32toh(test_file_int_2.header.offset));
383 	will_return(cbfs_find_attr, NULL);
384 	mapping = cbfs_map(TEST_DATA_INT_2_FILENAME, &size_out);
385 	assert_non_null(mapping);
386 	assert_int_equal(TEST_DATA_INT_2_SIZE, size_out);
387 	assert_memory_equal(test_data_int_2, mapping, TEST_DATA_INT_2_SIZE);
388 	cbfs_unmap(mapping);
389 
390 	size_out = 0;
391 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 7);
392 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
393 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
394 			   foffset + be32toh(test_file_1.header.offset));
395 	will_return(cbfs_find_attr, NULL);
396 	mapping = cbfs_map(TEST_DATA_1_FILENAME, &size_out);
397 	assert_non_null(mapping);
398 	assert_int_equal(TEST_DATA_1_SIZE, size_out);
399 	assert_memory_equal(test_data_1, mapping, TEST_DATA_1_SIZE);
400 	cbfs_unmap(mapping);
401 
402 	size_out = 0;
403 	expect_cbfs_lookup("invalid_file", CB_CBFS_NOT_FOUND, 0, 0);
404 	if (s->ex.init_rw && CONFIG(LP_ENABLE_CBFS_FALLBACK))
405 		expect_cbfs_lookup("invalid_file", CB_CBFS_NOT_FOUND, 0, 0);
406 	mapping = cbfs_map("invalid_file", &size_out);
407 	assert_null(mapping);
408 }
409 
test_cbfs_invalid_compression_algo(void ** state)410 static void test_cbfs_invalid_compression_algo(void **state)
411 {
412 	struct cbfs_test_state *s = *state;
413 	void *mapping = NULL;
414 	size_t size_out = 0;
415 	uint8_t *cbfs_buf = NULL;
416 	struct cbfs_test_file *f;
417 	struct cbfs_file_attr_compression *comp;
418 	const struct cbfs_test_file *cbfs_files[] = {
419 		&test_file_2,
420 	};
421 
422 	setup_cbfs_boot_device(s);
423 	cbfs_buf = s->cbfs_rw_buf;
424 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_rw_buf, s->cbfs_rw_size);
425 
426 	f = (struct cbfs_test_file *)cbfs_buf;
427 	comp = (struct cbfs_file_attr_compression *)&f->attrs_and_data[0];
428 	comp->compression = 0xFFFFFFF0;
429 
430 	size_out = 0;
431 	expect_cbfs_lookup(TEST_DATA_2_FILENAME, CB_SUCCESS, (const union cbfs_mdata *)cbfs_buf,
432 			   be32toh(test_file_1.header.offset));
433 	will_return(cbfs_find_attr, comp);
434 	mapping = cbfs_map(TEST_DATA_2_FILENAME, &size_out);
435 	assert_null(mapping);
436 }
437 
test_cbfs_io_error(void ** state)438 static void test_cbfs_io_error(void **state)
439 {
440 	struct cbfs_test_state *s = *state;
441 	setup_cbfs_boot_device(s);
442 
443 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_CBFS_IO, 0, 0);
444 	assert_null(cbfs_map(TEST_DATA_1_FILENAME, NULL));
445 }
446 
test_cbfs_successful_fallback_to_ro(void ** state)447 static void test_cbfs_successful_fallback_to_ro(void **state)
448 {
449 	struct cbfs_test_state *s = *state;
450 	void *mapping = NULL;
451 	size_t size_out = 0;
452 	const struct cbfs_test_file *cbfs_files[] = {
453 		&test_file_1,	  &test_file_2,	    &test_file_int_1,
454 		&test_file_int_1, &test_file_int_2, &test_file_int_3,
455 	};
456 	uint8_t *cbfs_buf = NULL;
457 	size_t foffset = 0;
458 
459 	if (!CONFIG(LP_ENABLE_CBFS_FALLBACK)) {
460 		print_message("Skipping test, because LP_ENABLE_CBFS_FALLBACK == 0\n");
461 		skip();
462 	}
463 
464 	setup_cbfs_boot_device(s);
465 	cbfs_buf = s->cbfs_ro_buf;
466 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_ro_buf, s->cbfs_ro_size);
467 	if (s->ex.init_rw)
468 		create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files) - 2, s->cbfs_rw_buf,
469 			    s->cbfs_rw_size);
470 
471 	size_out = 0;
472 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 1);
473 	expect_cbfs_lookup(TEST_DATA_2_FILENAME, CB_CBFS_NOT_FOUND, 0, 0);
474 	expect_cbfs_lookup(TEST_DATA_2_FILENAME, CB_SUCCESS,
475 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
476 			   foffset + be32toh(test_file_2.header.offset));
477 	will_return(cbfs_find_attr, &test_file_2.attrs_and_data);
478 	expect_value(ulzman, srcn, TEST_DATA_2_SIZE);
479 	expect_value(ulzman, dstn, TEST_DATA_2_SIZE);
480 	mapping = cbfs_map(TEST_DATA_2_FILENAME, &size_out);
481 	assert_non_null(mapping);
482 	assert_int_equal(TEST_DATA_2_SIZE, size_out);
483 	assert_memory_equal(test_data_2, mapping, TEST_DATA_2_SIZE);
484 	cbfs_unmap(mapping);
485 
486 	size_out = 0;
487 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 5);
488 	expect_cbfs_lookup(TEST_DATA_INT_3_FILENAME, CB_CBFS_NOT_FOUND, 0, 0);
489 	expect_cbfs_lookup(TEST_DATA_INT_3_FILENAME, CB_SUCCESS,
490 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
491 			   foffset + be32toh(test_file_int_3.header.offset));
492 	will_return(cbfs_find_attr, &test_file_int_3.attrs_and_data);
493 	expect_value(ulz4fn, srcn, TEST_DATA_INT_3_SIZE);
494 	expect_value(ulz4fn, dstn, TEST_DATA_INT_3_SIZE);
495 	mapping = cbfs_map(TEST_DATA_INT_3_FILENAME, &size_out);
496 	assert_non_null(mapping);
497 	assert_int_equal(TEST_DATA_INT_3_SIZE, size_out);
498 	assert_memory_equal(test_data_int_3, mapping, TEST_DATA_INT_3_SIZE);
499 	cbfs_unmap(mapping);
500 }
501 
test_cbfs_load(void ** state)502 static void test_cbfs_load(void **state)
503 {
504 	struct cbfs_test_state *s = *state;
505 	size_t size_out = 0;
506 	const struct cbfs_test_file *cbfs_files[] = {
507 		&test_file_int_1, &test_file_2, NULL, &test_file_int_3,
508 		&test_file_int_2, NULL,		NULL, &test_file_1,
509 	};
510 	uint8_t *cbfs_buf = NULL;
511 	uint8_t load_buf[1 * KiB];
512 	size_t foffset = 0;
513 
514 	setup_cbfs_boot_device(s);
515 	cbfs_buf = s->cbfs_rw_buf;
516 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_rw_buf, s->cbfs_rw_size);
517 
518 	/* Successful load */
519 	size_out = 0;
520 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 0);
521 	expect_cbfs_lookup(TEST_DATA_INT_1_FILENAME, CB_SUCCESS,
522 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
523 			   foffset + be32toh(test_file_int_1.header.offset));
524 	will_return(cbfs_find_attr, NULL);
525 	size_out = cbfs_load(TEST_DATA_INT_1_FILENAME, load_buf, sizeof(load_buf));
526 	assert_int_equal(TEST_DATA_INT_1_SIZE, size_out);
527 	assert_memory_equal(test_data_int_1, load_buf, TEST_DATA_INT_1_SIZE);
528 
529 	/* Buffer too small */
530 	size_out = 0;
531 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 7);
532 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
533 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
534 			   foffset + be32toh(test_file_1.header.offset));
535 	will_return(cbfs_find_attr, NULL);
536 	size_out = cbfs_load(TEST_DATA_1_FILENAME, load_buf, TEST_DATA_1_SIZE / 2);
537 	assert_int_equal(0, size_out);
538 }
539 
test_cbfs_map_with_mcache(void ** state)540 static void test_cbfs_map_with_mcache(void **state)
541 {
542 	struct cbfs_test_state *s = *state;
543 	void *mapping = NULL;
544 	size_t size_out = 0;
545 	const struct cbfs_test_file *cbfs_files[] = {
546 		&test_file_int_2, &test_file_1,	    NULL,
547 		&test_file_int_3, &test_file_int_1, &test_file_2,
548 	};
549 	uint8_t *cbfs_buf = NULL;
550 	size_t foffset = 0;
551 
552 	/* Will not be accessed, just needs to be valid. */
553 	s->mcache_ro_offset = ALIGN_UP(0x1000, CBFS_MCACHE_ALIGNMENT);
554 	s->mcache_ro_size = ALIGN_UP(0x500, CBFS_MCACHE_ALIGNMENT);
555 	s->mcache_rw_offset = ALIGN_UP(0x3000, CBFS_MCACHE_ALIGNMENT);
556 	s->mcache_rw_size = ALIGN_UP(0x600, CBFS_MCACHE_ALIGNMENT);
557 	setup_cbfs_boot_device(s);
558 	cbfs_buf = s->cbfs_rw_buf;
559 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_rw_buf, s->cbfs_rw_size);
560 
561 	size_out = 0;
562 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 4);
563 	expect_cbfs_mcache_lookup(TEST_DATA_INT_1_FILENAME, CB_SUCCESS,
564 				  (const union cbfs_mdata *)&cbfs_buf[foffset],
565 				  foffset + be32toh(test_file_int_1.header.offset));
566 	will_return(cbfs_find_attr, NULL);
567 	mapping = cbfs_map(TEST_DATA_INT_1_FILENAME, &size_out);
568 	assert_non_null(mapping);
569 	assert_int_equal(TEST_DATA_INT_1_SIZE, size_out);
570 	assert_memory_equal(test_data_int_1, mapping, TEST_DATA_INT_1_SIZE);
571 	cbfs_unmap(mapping);
572 }
573 
test_cbfs_boot_device_read_failure(void ** state)574 static void test_cbfs_boot_device_read_failure(void **state)
575 {
576 	struct cbfs_test_state *s = *state;
577 	void *mapping = NULL;
578 	size_t size_out = 0;
579 	const struct cbfs_test_file *cbfs_files[] = {
580 		&test_file_int_3, &test_file_1,	    NULL,
581 		&test_file_int_3, &test_file_int_1, &test_file_2,
582 	};
583 	uint8_t *cbfs_buf = NULL;
584 	size_t foffset = 0;
585 
586 	setup_cbfs_boot_device(s);
587 	cbfs_buf = s->cbfs_rw_buf;
588 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_rw_buf, s->cbfs_rw_size);
589 
590 	size_out = 0;
591 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 1);
592 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
593 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
594 			   foffset + be32toh(test_file_1.header.offset));
595 	will_return(cbfs_find_attr, NULL);
596 	force_single_boot_device_size_failure = true;
597 	mapping = cbfs_map(TEST_DATA_1_FILENAME, &size_out);
598 	assert_null(mapping);
599 }
600 
601 /* This test uses RW CBFS only */
test_cbfs_unverified_area_map(void ** state)602 static void test_cbfs_unverified_area_map(void **state)
603 {
604 	struct cbfs_test_state *s = *state;
605 	void *mapping = NULL;
606 	size_t size_out = 0;
607 	const struct cbfs_test_file *cbfs_files[] = {
608 		&test_file_int_1, &test_file_2, NULL, &test_file_int_3,
609 		&test_file_int_2, NULL,		NULL, &test_file_1,
610 	};
611 	uint8_t *cbfs_buf = NULL;
612 	size_t foffset = 0;
613 
614 	cbfs_buf = s->cbfs_rw_buf;
615 	set_fmap_locate_area_results((size_t)cbfs_buf, s->cbfs_rw_size, CB_SUCCESS);
616 	create_cbfs(cbfs_files, ARRAY_SIZE(cbfs_files), s->cbfs_rw_buf, s->cbfs_rw_size);
617 
618 	size_out = 0;
619 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 0);
620 	expect_cbfs_lookup(TEST_DATA_INT_1_FILENAME, CB_SUCCESS,
621 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
622 			   foffset + be32toh(test_file_int_1.header.offset));
623 	will_return(cbfs_find_attr, NULL);
624 	mapping = cbfs_unverified_area_map("TEST_AREA", TEST_DATA_INT_1_FILENAME, &size_out);
625 	assert_non_null(mapping);
626 	assert_int_equal(TEST_DATA_INT_1_SIZE, size_out);
627 	assert_memory_equal(test_data_int_1, mapping, TEST_DATA_INT_1_SIZE);
628 	cbfs_unmap(mapping);
629 
630 	size_out = 0;
631 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 1);
632 	expect_cbfs_lookup(TEST_DATA_2_FILENAME, CB_SUCCESS,
633 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
634 			   foffset + be32toh(test_file_2.header.offset));
635 	will_return(cbfs_find_attr, &test_file_2.attrs_and_data);
636 	expect_value(ulzman, srcn, TEST_DATA_2_SIZE);
637 	expect_value(ulzman, dstn, TEST_DATA_2_SIZE);
638 	mapping = cbfs_unverified_area_map("TEST_AREA", TEST_DATA_2_FILENAME, &size_out);
639 	assert_non_null(mapping);
640 	assert_int_equal(TEST_DATA_2_SIZE, size_out);
641 	assert_memory_equal(test_data_2, mapping, TEST_DATA_2_SIZE);
642 	cbfs_unmap(mapping);
643 
644 	size_out = 0;
645 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 3);
646 	expect_cbfs_lookup(TEST_DATA_INT_3_FILENAME, CB_SUCCESS,
647 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
648 			   foffset + be32toh(test_file_int_3.header.offset));
649 	will_return(cbfs_find_attr, &test_file_int_3.attrs_and_data);
650 	expect_value(ulz4fn, srcn, TEST_DATA_INT_3_SIZE);
651 	expect_value(ulz4fn, dstn, TEST_DATA_INT_3_SIZE);
652 	mapping = cbfs_unverified_area_map("TEST_AREA", TEST_DATA_INT_3_FILENAME, &size_out);
653 	assert_non_null(mapping);
654 	assert_int_equal(TEST_DATA_INT_3_SIZE, size_out);
655 	assert_memory_equal(test_data_int_3, mapping, TEST_DATA_INT_3_SIZE);
656 	cbfs_unmap(mapping);
657 
658 	size_out = 0;
659 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 4);
660 	expect_cbfs_lookup(TEST_DATA_INT_2_FILENAME, CB_SUCCESS,
661 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
662 			   foffset + be32toh(test_file_int_2.header.offset));
663 	will_return(cbfs_find_attr, NULL);
664 	mapping = cbfs_unverified_area_map("TEST_AREA", TEST_DATA_INT_2_FILENAME, &size_out);
665 	assert_non_null(mapping);
666 	assert_int_equal(TEST_DATA_INT_2_SIZE, size_out);
667 	assert_memory_equal(test_data_int_2, mapping, TEST_DATA_INT_2_SIZE);
668 	cbfs_unmap(mapping);
669 
670 	size_out = 0;
671 	foffset = get_created_cbfs_file_start_offset(cbfs_files, 7);
672 	expect_cbfs_lookup(TEST_DATA_1_FILENAME, CB_SUCCESS,
673 			   (const union cbfs_mdata *)&cbfs_buf[foffset],
674 			   foffset + be32toh(test_file_1.header.offset));
675 	will_return(cbfs_find_attr, NULL);
676 	mapping = cbfs_unverified_area_map("TEST_AREA", TEST_DATA_1_FILENAME, &size_out);
677 	assert_non_null(mapping);
678 	assert_int_equal(TEST_DATA_1_SIZE, size_out);
679 	assert_memory_equal(test_data_1, mapping, TEST_DATA_1_SIZE);
680 	cbfs_unmap(mapping);
681 
682 	size_out = 0;
683 	expect_cbfs_lookup("invalid_file", CB_CBFS_NOT_FOUND, 0, 0);
684 	mapping = cbfs_unverified_area_map("TEST_AREA", "invalid_file", &size_out);
685 	assert_null(mapping);
686 }
687 
688 #define TEST_CBFS_NAME_ALIGN_RO_RW(fn, test_name, enable_unaligned, enable_init_ro,            \
689 				   enable_init_rw)                                             \
690 	((struct CMUnitTest){                                                                  \
691 		.name = (test_name),                                                           \
692 		.test_func = (fn),                                                             \
693 		.setup_func = setup_cbfs_test,                                                 \
694 		.teardown_func = teardown_cbfs_test,                                           \
695 		.initial_state =                                                               \
696 			&(struct cbfs_test_setup){                                             \
697 				.unaligned = enable_unaligned,                                 \
698 				.init_ro = enable_init_ro,                                     \
699 				.init_rw = enable_init_rw,                                     \
700 			},                                                                     \
701 	})
702 
703 #define TEST_CBFS_LOOKUP(fn)                                                                   \
704 	EMPTY_WRAP(TEST_CBFS_NAME_ALIGN_RO_RW(fn, #fn ", RW, aligned", false, false, true),    \
705 		   TEST_CBFS_NAME_ALIGN_RO_RW(fn, #fn ", RW, unaligned", true, false, true))
706 
707 #define TEST_CBFS_RO_FALLBACK(fn)                                                              \
708 	EMPTY_WRAP(TEST_CBFS_NAME_ALIGN_RO_RW(fn, #fn ", RW+RO, aligned", false, true, true),  \
709 		   TEST_CBFS_NAME_ALIGN_RO_RW(fn, #fn ", RW+RO, unaligned", true, true, true), \
710 		   TEST_CBFS_NAME_ALIGN_RO_RW(fn, #fn ", RO, aligned", false, true, false),    \
711 		   TEST_CBFS_NAME_ALIGN_RO_RW(fn, #fn ", RO, unaligned", true, true, false))
712 
713 
main(void)714 int main(void)
715 {
716 	const struct CMUnitTest tests[] = {
717 		cmocka_unit_test(test_cbfs_boot_device_init),
718 		TEST_CBFS_LOOKUP(test_cbfs_map),
719 		TEST_CBFS_LOOKUP(test_cbfs_invalid_compression_algo),
720 		TEST_CBFS_LOOKUP(test_cbfs_io_error),
721 		TEST_CBFS_RO_FALLBACK(test_cbfs_successful_fallback_to_ro),
722 		TEST_CBFS_LOOKUP(test_cbfs_load),
723 		TEST_CBFS_LOOKUP(test_cbfs_map_with_mcache),
724 		TEST_CBFS_LOOKUP(test_cbfs_boot_device_read_failure),
725 		TEST_CBFS_LOOKUP(test_cbfs_unverified_area_map),
726 	};
727 
728 	return lp_run_group_tests(tests, NULL, NULL);
729 }
730