1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018, Google Inc. All rights reserved.
4  */
5 
6 #include <common.h>
7 #include <bloblist.h>
8 #include <log.h>
9 #include <mapmem.h>
10 #include <asm/global_data.h>
11 #include <test/suites.h>
12 #include <test/test.h>
13 #include <test/ut.h>
14 
15 DECLARE_GLOBAL_DATA_PTR;
16 
17 /* Declare a new bloblist test */
18 #define BLOBLIST_TEST(_name, _flags) \
19 		UNIT_TEST(_name, _flags, bloblist_test)
20 
21 enum {
22 	TEST_TAG		= BLOBLISTT_U_BOOT_SPL_HANDOFF,
23 	TEST_TAG2		= BLOBLISTT_VBOOT_CTX,
24 	TEST_TAG_MISSING	= 0x10000,
25 
26 	TEST_SIZE		= 10,
27 	TEST_SIZE2		= 20,
28 	TEST_SIZE_LARGE		= 0x3e0,
29 
30 	TEST_ADDR		= CONFIG_BLOBLIST_ADDR,
31 	TEST_BLOBLIST_SIZE	= 0x400,
32 
33 	ERASE_BYTE		= '\xff',
34 };
35 
36 static const char test1_str[] = "the eyes are open";
37 static const char test2_str[] = "the mouth moves";
38 
clear_bloblist(void)39 static struct bloblist_hdr *clear_bloblist(void)
40 {
41 	struct bloblist_hdr *hdr;
42 
43 	/*
44 	 * Clear out any existing bloblist so we have a clean slate. Zero the
45 	 * header so that existing records are removed, but set everything else
46 	 * to 0xff for testing purposes.
47 	 */
48 	hdr = map_sysmem(CONFIG_BLOBLIST_ADDR, TEST_BLOBLIST_SIZE);
49 	memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
50 	memset(hdr, '\0', sizeof(*hdr));
51 
52 	return hdr;
53 }
54 
check_zero(void * data,int size)55 static int check_zero(void *data, int size)
56 {
57 	u8 *ptr;
58 	int i;
59 
60 	for (ptr = data, i = 0; i < size; i++, ptr++) {
61 		if (*ptr)
62 			return -EINVAL;
63 	}
64 
65 	return 0;
66 }
67 
bloblist_test_init(struct unit_test_state * uts)68 static int bloblist_test_init(struct unit_test_state *uts)
69 {
70 	struct bloblist_hdr *hdr;
71 
72 	hdr = clear_bloblist();
73 	ut_asserteq(-ENOENT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
74 	ut_asserteq_ptr(NULL, bloblist_check_magic(TEST_ADDR));
75 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
76 	ut_asserteq_ptr(hdr, bloblist_check_magic(TEST_ADDR));
77 	hdr->version++;
78 	ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR,
79 						     TEST_BLOBLIST_SIZE));
80 
81 	ut_asserteq(-ENOSPC, bloblist_new(TEST_ADDR, 0x10, 0));
82 	ut_asserteq(-EFAULT, bloblist_new(1, TEST_BLOBLIST_SIZE, 0));
83 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
84 
85 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
86 	ut_assertok(bloblist_finish());
87 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
88 
89 	hdr->magic++;
90 	ut_asserteq_ptr(NULL, bloblist_check_magic(TEST_ADDR));
91 	hdr->magic--;
92 
93 	hdr->flags++;
94 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
95 
96 	return 1;
97 }
98 BLOBLIST_TEST(bloblist_test_init, 0);
99 
bloblist_test_blob(struct unit_test_state * uts)100 static int bloblist_test_blob(struct unit_test_state *uts)
101 {
102 	struct bloblist_hdr *hdr;
103 	struct bloblist_rec *rec, *rec2;
104 	char *data;
105 
106 	/* At the start there should be no records */
107 	hdr = clear_bloblist();
108 	ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
109 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
110 	ut_asserteq(TEST_BLOBLIST_SIZE, bloblist_get_size());
111 	ut_asserteq(TEST_ADDR, bloblist_get_base());
112 	ut_asserteq(map_to_sysmem(hdr), TEST_ADDR);
113 
114 	/* Add a record and check that we can find it */
115 	data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
116 	rec = (void *)(hdr + 1);
117 	ut_asserteq_addr(rec + 1, data);
118 	data = bloblist_find(TEST_TAG, TEST_SIZE);
119 	ut_asserteq_addr(rec + 1, data);
120 
121 	/* Check the data is zeroed */
122 	ut_assertok(check_zero(data, TEST_SIZE));
123 
124 	/* Check the 'ensure' method */
125 	ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
126 	ut_assertnull(bloblist_ensure(TEST_TAG, TEST_SIZE2));
127 	rec2 = (struct bloblist_rec *)(data + ALIGN(TEST_SIZE, BLOBLIST_ALIGN));
128 	ut_assertok(check_zero(data, TEST_SIZE));
129 
130 	/* Check for a non-existent record */
131 	ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
132 	ut_asserteq_addr(rec2 + 1, bloblist_ensure(TEST_TAG2, TEST_SIZE2));
133 	ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0));
134 
135 	return 0;
136 }
137 BLOBLIST_TEST(bloblist_test_blob, 0);
138 
139 /* Check bloblist_ensure_size_ret() */
bloblist_test_blob_ensure(struct unit_test_state * uts)140 static int bloblist_test_blob_ensure(struct unit_test_state *uts)
141 {
142 	void *data, *data2;
143 	int size;
144 
145 	/* At the start there should be no records */
146 	clear_bloblist();
147 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
148 
149 	/* Test with an empty bloblist */
150 	size = TEST_SIZE;
151 	ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
152 	ut_asserteq(TEST_SIZE, size);
153 	ut_assertok(check_zero(data, TEST_SIZE));
154 
155 	/* Check that we get the same thing again */
156 	ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data2));
157 	ut_asserteq(TEST_SIZE, size);
158 	ut_asserteq_addr(data, data2);
159 
160 	/* Check that the size remains the same */
161 	size = TEST_SIZE2;
162 	ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
163 	ut_asserteq(TEST_SIZE, size);
164 
165 	/* Check running out of space */
166 	size = TEST_SIZE_LARGE;
167 	ut_asserteq(-ENOSPC, bloblist_ensure_size_ret(TEST_TAG2, &size, &data));
168 
169 	return 0;
170 }
171 BLOBLIST_TEST(bloblist_test_blob_ensure, 0);
172 
bloblist_test_bad_blob(struct unit_test_state * uts)173 static int bloblist_test_bad_blob(struct unit_test_state *uts)
174 {
175 	struct bloblist_hdr *hdr;
176 	void *data;
177 
178 	hdr = clear_bloblist();
179 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
180 	data = hdr + 1;
181 	data += sizeof(struct bloblist_rec);
182 	ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
183 	ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
184 
185 	return 0;
186 }
187 BLOBLIST_TEST(bloblist_test_bad_blob, 0);
188 
bloblist_test_checksum(struct unit_test_state * uts)189 static int bloblist_test_checksum(struct unit_test_state *uts)
190 {
191 	struct bloblist_hdr *hdr;
192 	char *data, *data2;
193 
194 	hdr = clear_bloblist();
195 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
196 	ut_assertok(bloblist_finish());
197 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
198 
199 	/*
200 	 * Now change things amd make sure that the checksum notices. We cannot
201 	 * change the size or alloced fields, since that will crash the code.
202 	 * It has to rely on these being correct.
203 	 */
204 	hdr->flags--;
205 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
206 	hdr->flags++;
207 
208 	hdr->size--;
209 	ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
210 	hdr->size++;
211 
212 	hdr->spare++;
213 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
214 	hdr->spare--;
215 
216 	hdr->chksum++;
217 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
218 	hdr->chksum--;
219 
220 	/* Make sure the checksum changes when we add blobs */
221 	data = bloblist_add(TEST_TAG, TEST_SIZE, 0);
222 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
223 
224 	data2 = bloblist_add(TEST_TAG2, TEST_SIZE2, 0);
225 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
226 	ut_assertok(bloblist_finish());
227 
228 	/* It should also change if we change the data */
229 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
230 	*data += 1;
231 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
232 	*data -= 1;
233 
234 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
235 	*data2 += 1;
236 	ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
237 	*data2 -= 1;
238 
239 	/*
240 	 * Changing data outside the range of valid data should not affect
241 	 * the checksum.
242 	 */
243 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
244 	data[TEST_SIZE]++;
245 	data2[TEST_SIZE2]++;
246 	ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
247 
248 	return 0;
249 }
250 BLOBLIST_TEST(bloblist_test_checksum, 0);
251 
252 /* Test the 'bloblist info' command */
bloblist_test_cmd_info(struct unit_test_state * uts)253 static int bloblist_test_cmd_info(struct unit_test_state *uts)
254 {
255 	struct bloblist_hdr *hdr;
256 	char *data, *data2;
257 
258 	hdr = clear_bloblist();
259 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
260 	data = bloblist_ensure(TEST_TAG, TEST_SIZE);
261 	data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
262 
263 	console_record_reset_enable();
264 	ut_silence_console(uts);
265 	console_record_reset();
266 	run_command("bloblist info", 0);
267 	ut_assert_nextline("base:     %lx", (ulong)map_to_sysmem(hdr));
268 	ut_assert_nextline("size:     400    1 KiB");
269 	ut_assert_nextline("alloced:  70     112 Bytes");
270 	ut_assert_nextline("free:     390    912 Bytes");
271 	ut_assert_console_end();
272 	ut_unsilence_console(uts);
273 
274 	return 0;
275 }
276 BLOBLIST_TEST(bloblist_test_cmd_info, 0);
277 
278 /* Test the 'bloblist list' command */
bloblist_test_cmd_list(struct unit_test_state * uts)279 static int bloblist_test_cmd_list(struct unit_test_state *uts)
280 {
281 	struct bloblist_hdr *hdr;
282 	char *data, *data2;
283 
284 	hdr = clear_bloblist();
285 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
286 	data = bloblist_ensure(TEST_TAG, TEST_SIZE);
287 	data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
288 
289 	console_record_reset_enable();
290 	ut_silence_console(uts);
291 	console_record_reset();
292 	run_command("bloblist list", 0);
293 	ut_assert_nextline("Address       Size   Tag Name");
294 	ut_assert_nextline("%08lx  %8x  8000 SPL hand-off",
295 			   (ulong)map_to_sysmem(data), TEST_SIZE);
296 	ut_assert_nextline("%08lx  %8x   106 Chrome OS vboot context",
297 			   (ulong)map_to_sysmem(data2), TEST_SIZE2);
298 	ut_assert_console_end();
299 	ut_unsilence_console(uts);
300 
301 	return 0;
302 }
303 BLOBLIST_TEST(bloblist_test_cmd_list, 0);
304 
305 /* Test alignment of bloblist blobs */
bloblist_test_align(struct unit_test_state * uts)306 static int bloblist_test_align(struct unit_test_state *uts)
307 {
308 	struct bloblist_hdr *hdr;
309 	ulong addr;
310 	char *data;
311 	int i;
312 
313 	/* At the start there should be no records */
314 	hdr = clear_bloblist();
315 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
316 	ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
317 
318 	/* Check the default alignment */
319 	for (i = 0; i < 3; i++) {
320 		int size = i * 3;
321 		ulong addr;
322 		char *data;
323 		int j;
324 
325 		data = bloblist_add(i, size, 0);
326 		ut_assertnonnull(data);
327 		addr = map_to_sysmem(data);
328 		ut_asserteq(0, addr & (BLOBLIST_ALIGN - 1));
329 
330 		/* Only the bytes in the blob data should be zeroed */
331 		for (j = 0; j < size; j++)
332 			ut_asserteq(0, data[j]);
333 		for (; j < BLOBLIST_ALIGN; j++)
334 			ut_asserteq(ERASE_BYTE, data[j]);
335 	}
336 
337 	/* Check larger alignment */
338 	for (i = 0; i < 3; i++) {
339 		int align = 32 << i;
340 
341 		data = bloblist_add(3 + i, i * 4, align);
342 		ut_assertnonnull(data);
343 		addr = map_to_sysmem(data);
344 		ut_asserteq(0, addr & (align - 1));
345 	}
346 
347 	/* Check alignment with an bloblist starting on a smaller alignment */
348 	hdr = map_sysmem(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE);
349 	memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
350 	memset(hdr, '\0', sizeof(*hdr));
351 	ut_assertok(bloblist_new(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE,
352 				 0));
353 
354 	data = bloblist_add(1, 5, BLOBLIST_ALIGN * 2);
355 	ut_assertnonnull(data);
356 	addr = map_to_sysmem(data);
357 	ut_asserteq(0, addr & (BLOBLIST_ALIGN * 2 - 1));
358 
359 	return 0;
360 }
361 BLOBLIST_TEST(bloblist_test_align, 0);
362 
363 /* Test relocation of a bloblist */
bloblist_test_reloc(struct unit_test_state * uts)364 static int bloblist_test_reloc(struct unit_test_state *uts)
365 {
366 	const uint large_size = TEST_BLOBLIST_SIZE;
367 	const uint small_size = 0x20;
368 	void *old_ptr, *new_ptr;
369 	void *blob1, *blob2;
370 	ulong new_addr;
371 	ulong new_size;
372 
373 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
374 	old_ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
375 
376 	/* Add one blob and then one that won't fit */
377 	blob1 = bloblist_add(TEST_TAG, small_size, 0);
378 	ut_assertnonnull(blob1);
379 	blob2 = bloblist_add(TEST_TAG2, large_size, 0);
380 	ut_assertnull(blob2);
381 
382 	/* Relocate the bloblist somewhere else, a bit larger */
383 	new_addr = TEST_ADDR + TEST_BLOBLIST_SIZE;
384 	new_size = TEST_BLOBLIST_SIZE + 0x100;
385 	new_ptr = map_sysmem(new_addr, TEST_BLOBLIST_SIZE);
386 	bloblist_reloc(new_ptr, new_size, old_ptr, TEST_BLOBLIST_SIZE);
387 	gd->bloblist = new_ptr;
388 
389 	/* Check the old blob is there and that we can now add the bigger one */
390 	ut_assertnonnull(bloblist_find(TEST_TAG, small_size));
391 	ut_assertnull(bloblist_find(TEST_TAG2, small_size));
392 	blob2 = bloblist_add(TEST_TAG2, large_size, 0);
393 	ut_assertnonnull(blob2);
394 
395 	return 0;
396 }
397 BLOBLIST_TEST(bloblist_test_reloc, 0);
398 
399 /* Test expansion of a blob */
bloblist_test_grow(struct unit_test_state * uts)400 static int bloblist_test_grow(struct unit_test_state *uts)
401 {
402 	const uint small_size = 0x20;
403 	void *blob1, *blob2, *blob1_new;
404 	struct bloblist_hdr *hdr;
405 	void *ptr;
406 
407 	ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
408 	hdr = ptr;
409 	memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
410 
411 	/* Create two blobs */
412 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
413 	blob1 = bloblist_add(TEST_TAG, small_size, 0);
414 	ut_assertnonnull(blob1);
415 	ut_assertok(check_zero(blob1, small_size));
416 	strcpy(blob1, test1_str);
417 
418 	blob2 = bloblist_add(TEST_TAG2, small_size, 0);
419 	ut_assertnonnull(blob2);
420 	strcpy(blob2, test2_str);
421 
422 	ut_asserteq(sizeof(struct bloblist_hdr) +
423 		    sizeof(struct bloblist_rec) * 2 + small_size * 2,
424 		    hdr->alloced);
425 
426 	/* Resize the first one */
427 	ut_assertok(bloblist_resize(TEST_TAG, small_size + 4));
428 
429 	/* The first one should not have moved, just got larger */
430 	blob1_new = bloblist_find(TEST_TAG, small_size + 4);
431 	ut_asserteq_ptr(blob1, blob1_new);
432 
433 	/* The new space should be zeroed */
434 	ut_assertok(check_zero(blob1 + small_size, 4));
435 
436 	/* The second one should have moved */
437 	blob2 = bloblist_find(TEST_TAG2, small_size);
438 	ut_assertnonnull(blob2);
439 	ut_asserteq_str(test2_str, blob2);
440 
441 	/* The header should have more bytes in use */
442 	hdr = ptr;
443 	ut_asserteq(sizeof(struct bloblist_hdr) +
444 		    sizeof(struct bloblist_rec) * 2 + small_size * 2 +
445 		    BLOBLIST_ALIGN,
446 		    hdr->alloced);
447 
448 	return 0;
449 }
450 BLOBLIST_TEST(bloblist_test_grow, 0);
451 
452 /* Test shrinking of a blob */
bloblist_test_shrink(struct unit_test_state * uts)453 static int bloblist_test_shrink(struct unit_test_state *uts)
454 {
455 	const uint small_size = 0x20;
456 	void *blob1, *blob2, *blob1_new;
457 	struct bloblist_hdr *hdr;
458 	int new_size;
459 	void *ptr;
460 
461 	ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
462 
463 	/* Create two blobs */
464 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
465 	blob1 = bloblist_add(TEST_TAG, small_size, 0);
466 	ut_assertnonnull(blob1);
467 	strcpy(blob1, test1_str);
468 
469 	blob2 = bloblist_add(TEST_TAG2, small_size, 0);
470 	ut_assertnonnull(blob2);
471 	strcpy(blob2, test2_str);
472 
473 	hdr = ptr;
474 	ut_asserteq(sizeof(struct bloblist_hdr) +
475 		    sizeof(struct bloblist_rec) * 2 + small_size * 2,
476 		    hdr->alloced);
477 
478 	/* Resize the first one */
479 	new_size = small_size - BLOBLIST_ALIGN - 4;
480 	ut_assertok(bloblist_resize(TEST_TAG, new_size));
481 
482 	/* The first one should not have moved, just got smaller */
483 	blob1_new = bloblist_find(TEST_TAG, new_size);
484 	ut_asserteq_ptr(blob1, blob1_new);
485 
486 	/* The second one should have moved */
487 	blob2 = bloblist_find(TEST_TAG2, small_size);
488 	ut_assertnonnull(blob2);
489 	ut_asserteq_str(test2_str, blob2);
490 
491 	/* The header should have fewer bytes in use */
492 	hdr = ptr;
493 	ut_asserteq(sizeof(struct bloblist_hdr) +
494 		    sizeof(struct bloblist_rec) * 2 + small_size * 2 -
495 		    BLOBLIST_ALIGN,
496 		    hdr->alloced);
497 
498 	return 0;
499 }
500 BLOBLIST_TEST(bloblist_test_shrink, 0);
501 
502 /* Test failing to adjust a blob size */
bloblist_test_resize_fail(struct unit_test_state * uts)503 static int bloblist_test_resize_fail(struct unit_test_state *uts)
504 {
505 	const uint small_size = 0x20;
506 	struct bloblist_hdr *hdr;
507 	void *blob1, *blob2;
508 	int new_size;
509 	void *ptr;
510 
511 	ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
512 
513 	/* Create two blobs */
514 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
515 	blob1 = bloblist_add(TEST_TAG, small_size, 0);
516 	ut_assertnonnull(blob1);
517 
518 	blob2 = bloblist_add(TEST_TAG2, small_size, 0);
519 	ut_assertnonnull(blob2);
520 
521 	hdr = ptr;
522 	ut_asserteq(sizeof(struct bloblist_hdr) +
523 		    sizeof(struct bloblist_rec) * 2 + small_size * 2,
524 		    hdr->alloced);
525 
526 	/* Resize the first one, to check the boundary conditions */
527 	ut_asserteq(-EINVAL, bloblist_resize(TEST_TAG, -1));
528 
529 	new_size = small_size + (hdr->size - hdr->alloced);
530 	ut_asserteq(-ENOSPC, bloblist_resize(TEST_TAG, new_size + 1));
531 	ut_assertok(bloblist_resize(TEST_TAG, new_size));
532 
533 	return 0;
534 }
535 BLOBLIST_TEST(bloblist_test_resize_fail, 0);
536 
537 /* Test expanding the last blob in a bloblist */
bloblist_test_resize_last(struct unit_test_state * uts)538 static int bloblist_test_resize_last(struct unit_test_state *uts)
539 {
540 	const uint small_size = 0x20;
541 	struct bloblist_hdr *hdr;
542 	void *blob1, *blob2, *blob2_new;
543 	int alloced_val;
544 	void *ptr;
545 
546 	ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE);
547 	memset(ptr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
548 	hdr = ptr;
549 
550 	/* Create two blobs */
551 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
552 	blob1 = bloblist_add(TEST_TAG, small_size, 0);
553 	ut_assertnonnull(blob1);
554 
555 	blob2 = bloblist_add(TEST_TAG2, small_size, 0);
556 	ut_assertnonnull(blob2);
557 
558 	/* Check the byte after the last blob */
559 	alloced_val = sizeof(struct bloblist_hdr) +
560 		    sizeof(struct bloblist_rec) * 2 + small_size * 2;
561 	ut_asserteq(alloced_val, hdr->alloced);
562 	ut_asserteq_ptr((void *)hdr + alloced_val, blob2 + small_size);
563 	ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + hdr->alloced));
564 
565 	/* Resize the second one, checking nothing changes */
566 	ut_asserteq(0, bloblist_resize(TEST_TAG2, small_size + 4));
567 
568 	blob2_new = bloblist_find(TEST_TAG2, small_size + 4);
569 	ut_asserteq_ptr(blob2, blob2_new);
570 
571 	/*
572 	 * the new blob should encompass the byte we checked now, so it should
573 	 * be zeroed. This zeroing should affect only the four new bytes added
574 	 * to the blob.
575 	 */
576 	ut_asserteq(0, *((u8 *)hdr + alloced_val));
577 	ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + alloced_val + 4));
578 
579 	/* Check that the new top of the allocated blobs has not been touched */
580 	alloced_val += BLOBLIST_ALIGN;
581 	ut_asserteq(alloced_val, hdr->alloced);
582 	ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + hdr->alloced));
583 
584 	return 0;
585 }
586 BLOBLIST_TEST(bloblist_test_resize_last, 0);
587 
588 /* Check a completely full bloblist */
bloblist_test_blob_maxsize(struct unit_test_state * uts)589 static int bloblist_test_blob_maxsize(struct unit_test_state *uts)
590 {
591 	void *ptr;
592 	int size;
593 
594 	/* At the start there should be no records */
595 	clear_bloblist();
596 	ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
597 
598 	/* Add a blob that takes up all space */
599 	size = TEST_BLOBLIST_SIZE - sizeof(struct bloblist_hdr) -
600 		sizeof(struct bloblist_rec);
601 	ptr = bloblist_add(TEST_TAG, size, 0);
602 	ut_assertnonnull(ptr);
603 
604 	ptr = bloblist_add(TEST_TAG, size + 1, 0);
605 	ut_assertnull(ptr);
606 
607 	return 0;
608 }
609 BLOBLIST_TEST(bloblist_test_blob_maxsize, 0);
610 
do_ut_bloblist(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])611 int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
612 		   char *const argv[])
613 {
614 	struct unit_test *tests = UNIT_TEST_SUITE_START(bloblist_test);
615 	const int n_ents = UNIT_TEST_SUITE_COUNT(bloblist_test);
616 
617 	return cmd_ut_category("bloblist", "bloblist_test_",
618 			       tests, n_ents, argc, argv);
619 }
620