1 // SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
2 /*
3  * Copyright 2018 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #define LOG_CATEGORY	LOGC_BLOBLIST
8 
9 #include <bloblist.h>
10 #include <display_options.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <mapmem.h>
14 #include <spl.h>
15 #include <tables_csum.h>
16 #include <asm/global_data.h>
17 #include <u-boot/crc.h>
18 
19 /*
20  * A bloblist is a single contiguous chunk of memory with a header
21  * (struct bloblist_hdr) and a number of blobs in it.
22  *
23  * Each blob starts on a BLOBLIST_ALIGN boundary relative to the start of the
24  * bloblist and consists of a struct bloblist_rec, some padding to the required
25  * alignment for the blog and then the actual data. The padding ensures that the
26  * start address of the data in each blob is aligned as required. Note that
27  * each blob's *data* is aligned to BLOBLIST_ALIGN regardless of the alignment
28  * of the bloblist itself or the blob header.
29  */
30 
31 DECLARE_GLOBAL_DATA_PTR;
32 
33 static struct tag_name {
34 	enum bloblist_tag_t tag;
35 	const char *name;
36 } tag_name[] = {
37 	{ BLOBLISTT_VOID, "(void)" },
38 
39 	/* BLOBLISTT_AREA_FIRMWARE_TOP */
40 	{ BLOBLISTT_CONTROL_FDT, "Control FDT" },
41 	{ BLOBLISTT_HOB_BLOCK, "HOB block" },
42 	{ BLOBLISTT_HOB_LIST, "HOB list" },
43 	{ BLOBLISTT_ACPI_TABLES, "ACPI tables for x86" },
44 	{ BLOBLISTT_TPM_EVLOG, "TPM event log defined by TCG EFI" },
45 	{ BLOBLISTT_TPM_CRB_BASE, "TPM Command Response Buffer address" },
46 
47 	/* BLOBLISTT_AREA_FIRMWARE */
48 	{ BLOBLISTT_TPM2_TCG_LOG, "TPM v2 log space" },
49 	{ BLOBLISTT_TCPA_LOG, "TPM log space" },
50 	{ BLOBLISTT_ACPI_GNVS, "ACPI GNVS" },
51 
52 	/* BLOBLISTT_AREA_TF */
53 	{ BLOBLISTT_OPTEE_PAGABLE_PART, "OP-TEE pagable part" },
54 
55 	/* BLOBLISTT_AREA_OTHER */
56 	{ BLOBLISTT_INTEL_VBT, "Intel Video-BIOS table" },
57 	{ BLOBLISTT_SMBIOS_TABLES, "SMBIOS tables for x86" },
58 	{ BLOBLISTT_VBOOT_CTX, "Chrome OS vboot context" },
59 
60 	/* BLOBLISTT_PROJECT_AREA */
61 	{ BLOBLISTT_U_BOOT_SPL_HANDOFF, "SPL hand-off" },
62 	{ BLOBLISTT_VBE, "VBE" },
63 	{ BLOBLISTT_U_BOOT_VIDEO, "SPL video handoff" },
64 
65 	/* BLOBLISTT_VENDOR_AREA */
66 };
67 
bloblist_tag_name(enum bloblist_tag_t tag)68 const char *bloblist_tag_name(enum bloblist_tag_t tag)
69 {
70 	int i;
71 
72 	for (i = 0; i < ARRAY_SIZE(tag_name); i++) {
73 		if (tag_name[i].tag == tag)
74 			return tag_name[i].name;
75 	}
76 
77 	return "invalid";
78 }
79 
bloblist_first_blob(struct bloblist_hdr * hdr)80 static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr)
81 {
82 	if (hdr->used_size <= hdr->hdr_size)
83 		return NULL;
84 	return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size);
85 }
86 
rec_hdr_size(struct bloblist_rec * rec)87 static inline uint rec_hdr_size(struct bloblist_rec *rec)
88 {
89 	return (rec->tag_and_hdr_size & BLOBLISTR_HDR_SIZE_MASK) >>
90 		BLOBLISTR_HDR_SIZE_SHIFT;
91 }
92 
rec_tag(struct bloblist_rec * rec)93 static inline uint rec_tag(struct bloblist_rec *rec)
94 {
95 	return (rec->tag_and_hdr_size & BLOBLISTR_TAG_MASK) >>
96 		BLOBLISTR_TAG_SHIFT;
97 }
98 
bloblist_blob_end_ofs(struct bloblist_hdr * hdr,struct bloblist_rec * rec)99 static ulong bloblist_blob_end_ofs(struct bloblist_hdr *hdr,
100 				   struct bloblist_rec *rec)
101 {
102 	ulong offset;
103 
104 	offset = (void *)rec - (void *)hdr;
105 	/*
106 	 * The data section of next TE should start from an address aligned
107 	 * to 1 << hdr->align_log2.
108 	 */
109 	offset += rec_hdr_size(rec) + rec->size;
110 	offset = round_up(offset + rec_hdr_size(rec), 1 << hdr->align_log2);
111 	offset -= rec_hdr_size(rec);
112 
113 	return offset;
114 }
115 
bloblist_next_blob(struct bloblist_hdr * hdr,struct bloblist_rec * rec)116 static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr,
117 					       struct bloblist_rec *rec)
118 {
119 	ulong offset = bloblist_blob_end_ofs(hdr, rec);
120 
121 	if (offset >= hdr->used_size)
122 		return NULL;
123 	return (struct bloblist_rec *)((void *)hdr + offset);
124 }
125 
126 #define foreach_rec(_rec, _hdr) \
127 	for (_rec = bloblist_first_blob(_hdr); \
128 	     _rec; \
129 	     _rec = bloblist_next_blob(_hdr, _rec))
130 
bloblist_findrec(uint tag)131 static struct bloblist_rec *bloblist_findrec(uint tag)
132 {
133 	struct bloblist_hdr *hdr = gd->bloblist;
134 	struct bloblist_rec *rec;
135 
136 	if (!hdr)
137 		return NULL;
138 
139 	foreach_rec(rec, hdr) {
140 		if (rec_tag(rec) == tag)
141 			return rec;
142 	}
143 
144 	return NULL;
145 }
146 
bloblist_addrec(uint tag,int size,int align_log2,struct bloblist_rec ** recp)147 static int bloblist_addrec(uint tag, int size, int align_log2,
148 			   struct bloblist_rec **recp)
149 {
150 	struct bloblist_hdr *hdr = gd->bloblist;
151 	struct bloblist_rec *rec;
152 	int data_start, aligned_start, new_alloced;
153 
154 	if (!align_log2)
155 		align_log2 = BLOBLIST_BLOB_ALIGN_LOG2;
156 
157 	/* Figure out where the new data will start */
158 	data_start = map_to_sysmem(hdr) + hdr->used_size + sizeof(*rec);
159 
160 	/* Align the address and then calculate the offset from used size */
161 	aligned_start = ALIGN(data_start, 1U << align_log2) - data_start;
162 
163 	/* If we need to create a dummy record, create it */
164 	if (aligned_start) {
165 		int void_size = aligned_start - sizeof(*rec);
166 		struct bloblist_rec *vrec;
167 		int ret;
168 
169 		ret = bloblist_addrec(BLOBLISTT_VOID, void_size, 0, &vrec);
170 		if (ret)
171 			return log_msg_ret("void", ret);
172 
173 		/* start the record after that */
174 		data_start = map_to_sysmem(hdr) + hdr->used_size + sizeof(*vrec);
175 	}
176 
177 	/* Calculate the new allocated total */
178 	new_alloced = data_start - map_to_sysmem(hdr) +
179 		ALIGN(size, 1U << align_log2);
180 
181 	if (new_alloced > hdr->total_size) {
182 		log_err("Failed to allocate %x bytes\n", size);
183 		log_err("Used size=%x, total size=%x\n",
184 			hdr->used_size, hdr->total_size);
185 		return log_msg_ret("bloblist add", -ENOSPC);
186 	}
187 	rec = (void *)hdr + hdr->used_size;
188 
189 	rec->tag_and_hdr_size = tag | sizeof(*rec) << BLOBLISTR_HDR_SIZE_SHIFT;
190 	rec->size = size;
191 
192 	/* Zero the record data */
193 	memset((void *)rec + rec_hdr_size(rec), '\0', rec->size);
194 
195 	hdr->used_size = new_alloced;
196 	*recp = rec;
197 
198 	return 0;
199 }
200 
bloblist_ensurerec(uint tag,struct bloblist_rec ** recp,int size,int align_log2)201 static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size,
202 			      int align_log2)
203 {
204 	struct bloblist_rec *rec;
205 
206 	rec = bloblist_findrec(tag);
207 	if (rec) {
208 		if (size && size != rec->size) {
209 			*recp = rec;
210 			return -ESPIPE;
211 		}
212 	} else {
213 		int ret;
214 
215 		ret = bloblist_addrec(tag, size, align_log2, &rec);
216 		if (ret)
217 			return ret;
218 	}
219 	*recp = rec;
220 
221 	return 0;
222 }
223 
bloblist_find(uint tag,int size)224 void *bloblist_find(uint tag, int size)
225 {
226 	void *blob = NULL;
227 	int blob_size;
228 
229 	blob = bloblist_get_blob(tag, &blob_size);
230 
231 	if (size && size != blob_size)
232 		return NULL;
233 
234 	return blob;
235 }
236 
bloblist_get_blob(uint tag,int * sizep)237 void *bloblist_get_blob(uint tag, int *sizep)
238 {
239 	struct bloblist_rec *rec;
240 
241 	rec = bloblist_findrec(tag);
242 	if (!rec)
243 		return NULL;
244 
245 	*sizep = rec->size;
246 
247 	return (void *)rec + rec_hdr_size(rec);
248 }
249 
bloblist_add(uint tag,int size,int align_log2)250 void *bloblist_add(uint tag, int size, int align_log2)
251 {
252 	struct bloblist_rec *rec;
253 
254 	if (bloblist_addrec(tag, size, align_log2, &rec))
255 		return NULL;
256 
257 	return (void *)rec + rec_hdr_size(rec);
258 }
259 
bloblist_ensure_size(uint tag,int size,int align_log2,void ** blobp)260 int bloblist_ensure_size(uint tag, int size, int align_log2, void **blobp)
261 {
262 	struct bloblist_rec *rec;
263 	int ret;
264 
265 	ret = bloblist_ensurerec(tag, &rec, size, align_log2);
266 	if (ret)
267 		return ret;
268 	*blobp = (void *)rec + rec_hdr_size(rec);
269 
270 	return 0;
271 }
272 
bloblist_ensure(uint tag,int size)273 void *bloblist_ensure(uint tag, int size)
274 {
275 	struct bloblist_rec *rec;
276 
277 	if (bloblist_ensurerec(tag, &rec, size, 0))
278 		return NULL;
279 
280 	return (void *)rec + rec_hdr_size(rec);
281 }
282 
bloblist_ensure_size_ret(uint tag,int * sizep,void ** blobp)283 int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp)
284 {
285 	struct bloblist_rec *rec;
286 	int ret;
287 
288 	ret = bloblist_ensurerec(tag, &rec, *sizep, 0);
289 	if (ret == -ESPIPE)
290 		*sizep = rec->size;
291 	else if (ret)
292 		return ret;
293 	*blobp = (void *)rec + rec_hdr_size(rec);
294 
295 	return 0;
296 }
297 
bloblist_resize_rec(struct bloblist_hdr * hdr,struct bloblist_rec * rec,int new_size)298 static int bloblist_resize_rec(struct bloblist_hdr *hdr,
299 			       struct bloblist_rec *rec,
300 			       int new_size)
301 {
302 	int expand_by;	/* Number of bytes to expand by (-ve to contract) */
303 	int new_alloced;
304 	ulong next_ofs;	/* Offset of the record after @rec */
305 
306 	expand_by = ALIGN(new_size - rec->size, BLOBLIST_BLOB_ALIGN);
307 	new_alloced = ALIGN(hdr->used_size + expand_by, BLOBLIST_BLOB_ALIGN);
308 	if (new_size < 0) {
309 		log_debug("Attempt to shrink blob size below 0 (%x)\n",
310 			  new_size);
311 		return log_msg_ret("size", -EINVAL);
312 	}
313 	if (new_alloced > hdr->total_size) {
314 		log_err("Failed to allocate %x bytes\n", new_size);
315 		log_err("Used size=%x, total size=%x\n",
316 			hdr->used_size, hdr->total_size);
317 		return log_msg_ret("alloc", -ENOSPC);
318 	}
319 
320 	/* Move the following blobs up or down, if this is not the last */
321 	next_ofs = bloblist_blob_end_ofs(hdr, rec);
322 	if (next_ofs != hdr->used_size) {
323 		memmove((void *)hdr + next_ofs + expand_by,
324 			(void *)hdr + next_ofs, new_alloced - next_ofs);
325 	}
326 	hdr->used_size = new_alloced;
327 
328 	/* Zero the new part of the blob */
329 	if (expand_by > 0) {
330 		memset((void *)rec + rec_hdr_size(rec) + rec->size, '\0',
331 		       new_size - rec->size);
332 	}
333 
334 	/* Update the size of this blob */
335 	rec->size = new_size;
336 
337 	return 0;
338 }
339 
bloblist_resize(uint tag,int new_size)340 int bloblist_resize(uint tag, int new_size)
341 {
342 	struct bloblist_hdr *hdr = gd->bloblist;
343 	struct bloblist_rec *rec;
344 	int ret;
345 
346 	rec = bloblist_findrec(tag);
347 	if (!rec)
348 		return log_msg_ret("find", -ENOENT);
349 	ret = bloblist_resize_rec(hdr, rec, new_size);
350 	if (ret)
351 		return log_msg_ret("resize", ret);
352 
353 	return 0;
354 }
355 
bloblist_calc_chksum(struct bloblist_hdr * hdr)356 static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr)
357 {
358 	u8 chksum;
359 
360 	chksum = table_compute_checksum(hdr, hdr->used_size);
361 	chksum += hdr->chksum;
362 
363 	return chksum;
364 }
365 
bloblist_new(ulong addr,uint size,uint flags,uint align_log2)366 int bloblist_new(ulong addr, uint size, uint flags, uint align_log2)
367 {
368 	struct bloblist_hdr *hdr;
369 
370 	if (size < sizeof(*hdr))
371 		return log_ret(-ENOSPC);
372 	if (addr & (BLOBLIST_ALIGN - 1))
373 		return log_ret(-EFAULT);
374 	hdr = map_sysmem(addr, size);
375 	memset(hdr, '\0', sizeof(*hdr));
376 	hdr->version = BLOBLIST_VERSION;
377 	hdr->hdr_size = sizeof(*hdr);
378 	hdr->flags = flags;
379 	hdr->magic = BLOBLIST_MAGIC;
380 	hdr->used_size = hdr->hdr_size;
381 	hdr->total_size = size;
382 	hdr->align_log2 = align_log2 ? align_log2 : BLOBLIST_BLOB_ALIGN_LOG2;
383 	hdr->chksum = 0;
384 	gd->bloblist = hdr;
385 
386 	return 0;
387 }
388 
bloblist_check(ulong addr,uint size)389 int bloblist_check(ulong addr, uint size)
390 {
391 	struct bloblist_hdr *hdr;
392 	u32 chksum;
393 
394 	hdr = map_sysmem(addr, sizeof(*hdr));
395 	if (hdr->magic != BLOBLIST_MAGIC)
396 		return log_msg_ret("Bad magic", -ENOENT);
397 	if (hdr->version != BLOBLIST_VERSION)
398 		return log_msg_ret("Bad version", -EPROTONOSUPPORT);
399 	if (!hdr->total_size || (size && hdr->total_size > size))
400 		return log_msg_ret("Bad total size", -EFBIG);
401 	if (hdr->used_size > hdr->total_size)
402 		return log_msg_ret("Bad used size", -ENOENT);
403 	if (hdr->hdr_size != sizeof(struct bloblist_hdr))
404 		return log_msg_ret("Bad header size", -ENOENT);
405 
406 	chksum = bloblist_calc_chksum(hdr);
407 	if (hdr->chksum != chksum) {
408 		log_err("Checksum %x != %x\n", hdr->chksum, chksum);
409 		return log_msg_ret("Bad checksum", -EIO);
410 	}
411 	gd->bloblist = hdr;
412 
413 	return 0;
414 }
415 
bloblist_finish(void)416 int bloblist_finish(void)
417 {
418 	struct bloblist_hdr *hdr = gd->bloblist;
419 
420 	hdr->chksum = bloblist_calc_chksum(hdr);
421 	log_debug("Finished bloblist size %lx at %lx\n", (ulong)hdr->used_size,
422 		  (ulong)map_to_sysmem(hdr));
423 
424 	return 0;
425 }
426 
bloblist_get_base(void)427 ulong bloblist_get_base(void)
428 {
429 	return map_to_sysmem(gd->bloblist);
430 }
431 
bloblist_get_size(void)432 ulong bloblist_get_size(void)
433 {
434 	struct bloblist_hdr *hdr = gd->bloblist;
435 
436 	return hdr->used_size;
437 }
438 
bloblist_get_total_size(void)439 ulong bloblist_get_total_size(void)
440 {
441 	struct bloblist_hdr *hdr = gd->bloblist;
442 
443 	return hdr->total_size;
444 }
445 
bloblist_get_stats(ulong * basep,ulong * tsizep,ulong * usizep)446 void bloblist_get_stats(ulong *basep, ulong *tsizep, ulong *usizep)
447 {
448 	struct bloblist_hdr *hdr = gd->bloblist;
449 
450 	*basep = map_to_sysmem(gd->bloblist);
451 	*tsizep = hdr->total_size;
452 	*usizep = hdr->used_size;
453 }
454 
show_value(const char * prompt,ulong value)455 static void show_value(const char *prompt, ulong value)
456 {
457 	printf("%s:%*s %-5lx  ", prompt, 10 - (int)strlen(prompt), "", value);
458 	print_size(value, "\n");
459 }
460 
bloblist_show_stats(void)461 void bloblist_show_stats(void)
462 {
463 	ulong base, tsize, usize;
464 
465 	bloblist_get_stats(&base, &tsize, &usize);
466 	printf("base:       %lx\n", base);
467 	show_value("total size", tsize);
468 	show_value("used size", usize);
469 	show_value("free", tsize - usize);
470 }
471 
bloblist_show_list(void)472 void bloblist_show_list(void)
473 {
474 	struct bloblist_hdr *hdr = gd->bloblist;
475 	struct bloblist_rec *rec;
476 
477 	printf("%-8s  %8s   Tag Name\n", "Address", "Size");
478 	for (rec = bloblist_first_blob(hdr); rec;
479 	     rec = bloblist_next_blob(hdr, rec)) {
480 		printf("%08lx  %8x  %4x %s\n",
481 		       (ulong)map_to_sysmem((void *)rec + rec_hdr_size(rec)),
482 		       rec->size, rec_tag(rec),
483 		       bloblist_tag_name(rec_tag(rec)));
484 	}
485 }
486 
bloblist_reloc(void * to,uint to_size)487 int bloblist_reloc(void *to, uint to_size)
488 {
489 	struct bloblist_hdr *hdr;
490 
491 	if (!to_size)
492 		return 0;
493 
494 	if (to_size < gd->bloblist->total_size)
495 		return -ENOSPC;
496 
497 	memcpy(to, gd->bloblist, gd->bloblist->total_size);
498 	hdr = to;
499 	hdr->total_size = to_size;
500 	gd->bloblist = to;
501 
502 	return 0;
503 }
504 
505 /*
506  * Weak default function for getting bloblist from boot args.
507  */
xferlist_from_boot_arg(ulong __always_unused * addr)508 int __weak xferlist_from_boot_arg(ulong __always_unused *addr)
509 {
510 	return -ENOENT;
511 }
512 
bloblist_init(void)513 int bloblist_init(void)
514 {
515 	bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED);
516 	int ret = 0;
517 	ulong addr = 0, size;
518 
519 	/* Check if a valid transfer list passed in */
520 	if (!xferlist_from_boot_arg(&addr)) {
521 		size = bloblist_get_total_size();
522 	} else {
523 		/*
524 		 * If U-Boot is not in the first phase, an existing bloblist must
525 		 * be at a fixed address.
526 		 */
527 		bool from_addr = fixed && !xpl_is_first_phase();
528 
529 		/*
530 		 * If Firmware Handoff is mandatory but no transfer list is
531 		 * observed, report it as an error.
532 		 */
533 		if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY))
534 			return -ENOENT;
535 
536 		ret = -ENOENT;
537 
538 		if (xpl_prev_phase() == PHASE_TPL &&
539 		    !IS_ENABLED(CONFIG_TPL_BLOBLIST))
540 			from_addr = false;
541 		if (fixed)
542 			addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED,
543 					      CONFIG_BLOBLIST_ADDR);
544 		size = CONFIG_BLOBLIST_SIZE;
545 
546 		if (from_addr)
547 			ret = bloblist_check(addr, size);
548 
549 		if (ret)
550 			log_warning("Bloblist at %lx not found (err=%d)\n",
551 				    addr, ret);
552 		else
553 			/* Get the real size */
554 			size = gd->bloblist->total_size;
555 	}
556 
557 	if (ret) {
558 		/*
559 		 * If we don't have a bloblist from a fixed address, or the one
560 		 * in the fixed address is not valid. we must allocate the
561 		 * memory for it now.
562 		 */
563 		if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) {
564 			void *ptr = memalign(BLOBLIST_ALIGN, size);
565 
566 			if (!ptr)
567 				return log_msg_ret("alloc", -ENOMEM);
568 			addr = map_to_sysmem(ptr);
569 		} else if (!fixed) {
570 			return log_msg_ret("BLOBLIST_FIXED is not enabled",
571 					   ret);
572 		}
573 		log_debug("Creating new bloblist size %lx at %lx\n", size,
574 			  addr);
575 		ret = bloblist_new(addr, size, 0, 0);
576 	} else {
577 		log_debug("Found existing bloblist size %lx at %lx\n", size,
578 			  addr);
579 	}
580 
581 	if (ret)
582 		return log_msg_ret("ini", ret);
583 	gd->flags |= GD_FLG_BLOBLIST_READY;
584 
585 #ifdef DEBUG
586 	bloblist_show_stats();
587 	bloblist_show_list();
588 #endif
589 
590 	return 0;
591 }
592 
bloblist_maybe_init(void)593 int bloblist_maybe_init(void)
594 {
595 	if (CONFIG_IS_ENABLED(BLOBLIST) && !(gd->flags & GD_FLG_BLOBLIST_READY))
596 		return bloblist_init();
597 
598 	return 0;
599 }
600 
bloblist_check_reg_conv(ulong rfdt,ulong rzero,ulong rsig,ulong xlist)601 int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig, ulong xlist)
602 {
603 	u64 version = BLOBLIST_REGCONV_VER;
604 	ulong sigval;
605 	int ret;
606 
607 	if ((IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_SPL_BUILD)) ||
608 			(IS_ENABLED(CONFIG_SPL_64BIT) && IS_ENABLED(CONFIG_SPL_BUILD))) {
609 		sigval = ((BLOBLIST_MAGIC & ((1ULL << BLOBLIST_REGCONV_SHIFT_64) - 1)) |
610 			 ((version  & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_64));
611 	} else {
612 		sigval = ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_32) - 1)) |
613 			 ((version  & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_32));
614 	}
615 
616 	if (rzero || rsig != sigval)
617 		return -EIO;
618 
619 	ret = bloblist_check(xlist, 0);
620 	if (ret)
621 		return ret;
622 
623 	if (rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) {
624 		gd->bloblist = NULL;  /* Reset the gd bloblist pointer */
625 		return -EIO;
626 	}
627 
628 	return 0;
629 }
630