1 // SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause
3 * Copyright 2018 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
7 #define LOG_CATEGORY LOGC_BLOBLIST
10 #include <display_options.h>
15 #include <tables_csum.h>
16 #include <asm/global_data.h>
17 #include <u-boot/crc.h>
20 * A bloblist is a single contiguous chunk of memory with a header
21 * (struct bloblist_hdr) and a number of blobs in it.
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.
31 DECLARE_GLOBAL_DATA_PTR
;
33 static struct tag_name
{
34 enum bloblist_tag_t tag
;
37 { BLOBLISTT_VOID
, "(void)" },
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" },
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" },
52 /* BLOBLISTT_AREA_TF */
53 { BLOBLISTT_OPTEE_PAGABLE_PART
, "OP-TEE pagable part" },
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" },
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" },
65 /* BLOBLISTT_VENDOR_AREA */
68 const char *bloblist_tag_name(enum bloblist_tag_t tag
)
72 for (i
= 0; i
< ARRAY_SIZE(tag_name
); i
++) {
73 if (tag_name
[i
].tag
== tag
)
74 return tag_name
[i
].name
;
80 static struct bloblist_rec
*bloblist_first_blob(struct bloblist_hdr
*hdr
)
82 if (hdr
->used_size
<= hdr
->hdr_size
)
84 return (struct bloblist_rec
*)((void *)hdr
+ hdr
->hdr_size
);
87 static inline uint
rec_hdr_size(struct bloblist_rec
*rec
)
89 return (rec
->tag_and_hdr_size
& BLOBLISTR_HDR_SIZE_MASK
) >>
90 BLOBLISTR_HDR_SIZE_SHIFT
;
93 static inline uint
rec_tag(struct bloblist_rec
*rec
)
95 return (rec
->tag_and_hdr_size
& BLOBLISTR_TAG_MASK
) >>
99 static ulong
bloblist_blob_end_ofs(struct bloblist_hdr
*hdr
,
100 struct bloblist_rec
*rec
)
104 offset
= (void *)rec
- (void *)hdr
;
106 * The data section of next TE should start from an address aligned
107 * to 1 << hdr->align_log2.
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
);
116 static struct bloblist_rec
*bloblist_next_blob(struct bloblist_hdr
*hdr
,
117 struct bloblist_rec
*rec
)
119 ulong offset
= bloblist_blob_end_ofs(hdr
, rec
);
121 if (offset
>= hdr
->used_size
)
123 return (struct bloblist_rec
*)((void *)hdr
+ offset
);
126 #define foreach_rec(_rec, _hdr) \
127 for (_rec = bloblist_first_blob(_hdr); \
129 _rec = bloblist_next_blob(_hdr, _rec))
131 static struct bloblist_rec
*bloblist_findrec(uint tag
)
133 struct bloblist_hdr
*hdr
= gd
->bloblist
;
134 struct bloblist_rec
*rec
;
139 foreach_rec(rec
, hdr
) {
140 if (rec_tag(rec
) == tag
)
147 static int bloblist_addrec(uint tag
, int size
, int align_log2
,
148 struct bloblist_rec
**recp
)
150 struct bloblist_hdr
*hdr
= gd
->bloblist
;
151 struct bloblist_rec
*rec
;
152 int data_start
, aligned_start
, new_alloced
;
155 align_log2
= BLOBLIST_BLOB_ALIGN_LOG2
;
157 /* Figure out where the new data will start */
158 data_start
= map_to_sysmem(hdr
) + hdr
->used_size
+ sizeof(*rec
);
160 /* Align the address and then calculate the offset from used size */
161 aligned_start
= ALIGN(data_start
, 1U << align_log2
) - data_start
;
163 /* If we need to create a dummy record, create it */
165 int void_size
= aligned_start
- sizeof(*rec
);
166 struct bloblist_rec
*vrec
;
169 ret
= bloblist_addrec(BLOBLISTT_VOID
, void_size
, 0, &vrec
);
171 return log_msg_ret("void", ret
);
173 /* start the record after that */
174 data_start
= map_to_sysmem(hdr
) + hdr
->used_size
+ sizeof(*vrec
);
177 /* Calculate the new allocated total */
178 new_alloced
= data_start
- map_to_sysmem(hdr
) +
179 ALIGN(size
, 1U << align_log2
);
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
);
187 rec
= (void *)hdr
+ hdr
->used_size
;
189 rec
->tag_and_hdr_size
= tag
| sizeof(*rec
) << BLOBLISTR_HDR_SIZE_SHIFT
;
192 /* Zero the record data */
193 memset((void *)rec
+ rec_hdr_size(rec
), '\0', rec
->size
);
195 hdr
->used_size
= new_alloced
;
201 static int bloblist_ensurerec(uint tag
, struct bloblist_rec
**recp
, int size
,
204 struct bloblist_rec
*rec
;
206 rec
= bloblist_findrec(tag
);
208 if (size
&& size
!= rec
->size
) {
215 ret
= bloblist_addrec(tag
, size
, align_log2
, &rec
);
224 void *bloblist_find(uint tag
, int size
)
229 blob
= bloblist_get_blob(tag
, &blob_size
);
231 if (size
&& size
!= blob_size
)
237 void *bloblist_get_blob(uint tag
, int *sizep
)
239 struct bloblist_rec
*rec
;
241 rec
= bloblist_findrec(tag
);
247 return (void *)rec
+ rec_hdr_size(rec
);
250 void *bloblist_add(uint tag
, int size
, int align_log2
)
252 struct bloblist_rec
*rec
;
254 if (bloblist_addrec(tag
, size
, align_log2
, &rec
))
257 return (void *)rec
+ rec_hdr_size(rec
);
260 int bloblist_ensure_size(uint tag
, int size
, int align_log2
, void **blobp
)
262 struct bloblist_rec
*rec
;
265 ret
= bloblist_ensurerec(tag
, &rec
, size
, align_log2
);
268 *blobp
= (void *)rec
+ rec_hdr_size(rec
);
273 void *bloblist_ensure(uint tag
, int size
)
275 struct bloblist_rec
*rec
;
277 if (bloblist_ensurerec(tag
, &rec
, size
, 0))
280 return (void *)rec
+ rec_hdr_size(rec
);
283 int bloblist_ensure_size_ret(uint tag
, int *sizep
, void **blobp
)
285 struct bloblist_rec
*rec
;
288 ret
= bloblist_ensurerec(tag
, &rec
, *sizep
, 0);
293 *blobp
= (void *)rec
+ rec_hdr_size(rec
);
298 static int bloblist_resize_rec(struct bloblist_hdr
*hdr
,
299 struct bloblist_rec
*rec
,
302 int expand_by
; /* Number of bytes to expand by (-ve to contract) */
304 ulong next_ofs
; /* Offset of the record after @rec */
306 expand_by
= ALIGN(new_size
- rec
->size
, BLOBLIST_BLOB_ALIGN
);
307 new_alloced
= ALIGN(hdr
->used_size
+ expand_by
, BLOBLIST_BLOB_ALIGN
);
309 log_debug("Attempt to shrink blob size below 0 (%x)\n",
311 return log_msg_ret("size", -EINVAL
);
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
);
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
);
326 hdr
->used_size
= new_alloced
;
328 /* Zero the new part of the blob */
330 memset((void *)rec
+ rec_hdr_size(rec
) + rec
->size
, '\0',
331 new_size
- rec
->size
);
334 /* Update the size of this blob */
335 rec
->size
= new_size
;
340 int bloblist_resize(uint tag
, int new_size
)
342 struct bloblist_hdr
*hdr
= gd
->bloblist
;
343 struct bloblist_rec
*rec
;
346 rec
= bloblist_findrec(tag
);
348 return log_msg_ret("find", -ENOENT
);
349 ret
= bloblist_resize_rec(hdr
, rec
, new_size
);
351 return log_msg_ret("resize", ret
);
356 static u32
bloblist_calc_chksum(struct bloblist_hdr
*hdr
)
360 chksum
= table_compute_checksum(hdr
, hdr
->used_size
);
361 chksum
+= hdr
->chksum
;
366 int bloblist_new(ulong addr
, uint size
, uint flags
, uint align_log2
)
368 struct bloblist_hdr
*hdr
;
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
);
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
;
389 int bloblist_check(ulong addr
, uint size
)
391 struct bloblist_hdr
*hdr
;
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
);
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
);
416 int bloblist_finish(void)
418 struct bloblist_hdr
*hdr
= gd
->bloblist
;
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
));
427 ulong
bloblist_get_base(void)
429 return map_to_sysmem(gd
->bloblist
);
432 ulong
bloblist_get_size(void)
434 struct bloblist_hdr
*hdr
= gd
->bloblist
;
436 return hdr
->used_size
;
439 ulong
bloblist_get_total_size(void)
441 struct bloblist_hdr
*hdr
= gd
->bloblist
;
443 return hdr
->total_size
;
446 void bloblist_get_stats(ulong
*basep
, ulong
*tsizep
, ulong
*usizep
)
448 struct bloblist_hdr
*hdr
= gd
->bloblist
;
450 *basep
= map_to_sysmem(gd
->bloblist
);
451 *tsizep
= hdr
->total_size
;
452 *usizep
= hdr
->used_size
;
455 static void show_value(const char *prompt
, ulong value
)
457 printf("%s:%*s %-5lx ", prompt
, 10 - (int)strlen(prompt
), "", value
);
458 print_size(value
, "\n");
461 void bloblist_show_stats(void)
463 ulong base
, tsize
, usize
;
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
);
472 void bloblist_show_list(void)
474 struct bloblist_hdr
*hdr
= gd
->bloblist
;
475 struct bloblist_rec
*rec
;
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
)));
487 int bloblist_reloc(void *to
, uint to_size
)
489 struct bloblist_hdr
*hdr
;
494 if (to_size
< gd
->bloblist
->total_size
)
497 memcpy(to
, gd
->bloblist
, gd
->bloblist
->total_size
);
499 hdr
->total_size
= to_size
;
506 * Weak default function for getting bloblist from boot args.
508 int __weak
xferlist_from_boot_arg(ulong __always_unused
*addr
)
513 int bloblist_init(void)
515 bool fixed
= IS_ENABLED(CONFIG_BLOBLIST_FIXED
);
517 ulong addr
= 0, size
;
519 /* Check if a valid transfer list passed in */
520 if (!xferlist_from_boot_arg(&addr
)) {
521 size
= bloblist_get_total_size();
524 * If U-Boot is not in the first phase, an existing bloblist must
525 * be at a fixed address.
527 bool from_addr
= fixed
&& !xpl_is_first_phase();
530 * If Firmware Handoff is mandatory but no transfer list is
531 * observed, report it as an error.
533 if (IS_ENABLED(CONFIG_BLOBLIST_PASSAGE_MANDATORY
))
538 if (xpl_prev_phase() == PHASE_TPL
&&
539 !IS_ENABLED(CONFIG_TPL_BLOBLIST
))
542 addr
= IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED
,
543 CONFIG_BLOBLIST_ADDR
);
544 size
= CONFIG_BLOBLIST_SIZE
;
547 ret
= bloblist_check(addr
, size
);
550 log_warning("Bloblist at %lx not found (err=%d)\n",
553 /* Get the real size */
554 size
= gd
->bloblist
->total_size
;
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
563 if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC
)) {
564 void *ptr
= memalign(BLOBLIST_ALIGN
, size
);
567 return log_msg_ret("alloc", -ENOMEM
);
568 addr
= map_to_sysmem(ptr
);
570 return log_msg_ret("BLOBLIST_FIXED is not enabled",
573 log_debug("Creating new bloblist size %lx at %lx\n", size
,
575 ret
= bloblist_new(addr
, size
, 0, 0);
577 log_debug("Found existing bloblist size %lx at %lx\n", size
,
582 return log_msg_ret("ini", ret
);
583 gd
->flags
|= GD_FLG_BLOBLIST_READY
;
586 bloblist_show_stats();
587 bloblist_show_list();
593 int bloblist_maybe_init(void)
595 if (CONFIG_IS_ENABLED(BLOBLIST
) && !(gd
->flags
& GD_FLG_BLOBLIST_READY
))
596 return bloblist_init();
601 int bloblist_check_reg_conv(ulong rfdt
, ulong rzero
, ulong rsig
, ulong xlist
)
603 u64 version
= BLOBLIST_REGCONV_VER
;
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
));
612 sigval
= ((BLOBLIST_MAGIC
& ((1UL << BLOBLIST_REGCONV_SHIFT_32
) - 1)) |
613 ((version
& BLOBLIST_REGCONV_MASK
) << BLOBLIST_REGCONV_SHIFT_32
));
616 if (rzero
|| rsig
!= sigval
)
619 ret
= bloblist_check(xlist
, 0);
623 if (rfdt
!= (ulong
)bloblist_find(BLOBLISTT_CONTROL_FDT
, 0)) {
624 gd
->bloblist
= NULL
; /* Reset the gd bloblist pointer */