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