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
11 #include <display_options.h>
16 #include <tables_csum.h>
17 #include <asm/global_data.h>
18 #include <u-boot/crc.h>
21 * A bloblist is a single contiguous chunk of memory with a header
22 * (struct bloblist_hdr) and a number of blobs in it.
24 * Each blob starts on a BLOBLIST_ALIGN boundary relative to the start of the
25 * bloblist and consists of a struct bloblist_rec, some padding to the required
26 * alignment for the blog and then the actual data. The padding ensures that the
27 * start address of the data in each blob is aligned as required. Note that
28 * each blob's *data* is aligned to BLOBLIST_ALIGN regardless of the alignment
29 * of the bloblist itself or the blob header.
32 DECLARE_GLOBAL_DATA_PTR
;
34 static struct tag_name
{
35 enum bloblist_tag_t tag
;
38 { BLOBLISTT_VOID
, "(void)" },
40 /* BLOBLISTT_AREA_FIRMWARE_TOP */
41 { BLOBLISTT_CONTROL_FDT
, "Control FDT" },
42 { BLOBLISTT_HOB_BLOCK
, "HOB block" },
43 { BLOBLISTT_HOB_LIST
, "HOB list" },
44 { BLOBLISTT_ACPI_TABLES
, "ACPI tables for x86" },
45 { BLOBLISTT_TPM_EVLOG
, "TPM event log defined by TCG EFI" },
46 { BLOBLISTT_TPM_CRB_BASE
, "TPM Command Response Buffer address" },
48 /* BLOBLISTT_AREA_FIRMWARE */
49 { BLOBLISTT_TPM2_TCG_LOG
, "TPM v2 log space" },
50 { BLOBLISTT_TCPA_LOG
, "TPM log space" },
51 { BLOBLISTT_ACPI_GNVS
, "ACPI GNVS" },
53 /* BLOBLISTT_AREA_TF */
54 { BLOBLISTT_OPTEE_PAGABLE_PART
, "OP-TEE pagable part" },
56 /* BLOBLISTT_AREA_OTHER */
57 { BLOBLISTT_INTEL_VBT
, "Intel Video-BIOS table" },
58 { BLOBLISTT_SMBIOS_TABLES
, "SMBIOS tables for x86" },
59 { BLOBLISTT_VBOOT_CTX
, "Chrome OS vboot context" },
61 /* BLOBLISTT_PROJECT_AREA */
62 { BLOBLISTT_U_BOOT_SPL_HANDOFF
, "SPL hand-off" },
63 { BLOBLISTT_VBE
, "VBE" },
64 { BLOBLISTT_U_BOOT_VIDEO
, "SPL video handoff" },
66 /* BLOBLISTT_VENDOR_AREA */
69 const char *bloblist_tag_name(enum bloblist_tag_t tag
)
73 for (i
= 0; i
< ARRAY_SIZE(tag_name
); i
++) {
74 if (tag_name
[i
].tag
== tag
)
75 return tag_name
[i
].name
;
81 static struct bloblist_rec
*bloblist_first_blob(struct bloblist_hdr
*hdr
)
83 if (hdr
->used_size
<= hdr
->hdr_size
)
85 return (struct bloblist_rec
*)((void *)hdr
+ hdr
->hdr_size
);
88 static inline uint
rec_hdr_size(struct bloblist_rec
*rec
)
90 return (rec
->tag_and_hdr_size
& BLOBLISTR_HDR_SIZE_MASK
) >>
91 BLOBLISTR_HDR_SIZE_SHIFT
;
94 static inline uint
rec_tag(struct bloblist_rec
*rec
)
96 return (rec
->tag_and_hdr_size
& BLOBLISTR_TAG_MASK
) >>
100 static ulong
bloblist_blob_end_ofs(struct bloblist_hdr
*hdr
,
101 struct bloblist_rec
*rec
)
105 offset
= (void *)rec
- (void *)hdr
;
107 * The data section of next TE should start from an address aligned
108 * to 1 << hdr->align_log2.
110 offset
+= rec_hdr_size(rec
) + rec
->size
;
111 offset
= round_up(offset
+ rec_hdr_size(rec
), 1 << hdr
->align_log2
);
112 offset
-= rec_hdr_size(rec
);
117 static struct bloblist_rec
*bloblist_next_blob(struct bloblist_hdr
*hdr
,
118 struct bloblist_rec
*rec
)
120 ulong offset
= bloblist_blob_end_ofs(hdr
, rec
);
122 if (offset
>= hdr
->used_size
)
124 return (struct bloblist_rec
*)((void *)hdr
+ offset
);
127 #define foreach_rec(_rec, _hdr) \
128 for (_rec = bloblist_first_blob(_hdr); \
130 _rec = bloblist_next_blob(_hdr, _rec))
132 static struct bloblist_rec
*bloblist_findrec(uint tag
)
134 struct bloblist_hdr
*hdr
= gd
->bloblist
;
135 struct bloblist_rec
*rec
;
140 foreach_rec(rec
, hdr
) {
141 if (rec_tag(rec
) == tag
)
148 static int bloblist_addrec(uint tag
, int size
, int align_log2
,
149 struct bloblist_rec
**recp
)
151 struct bloblist_hdr
*hdr
= gd
->bloblist
;
152 struct bloblist_rec
*rec
;
153 int data_start
, aligned_start
, new_alloced
;
156 align_log2
= BLOBLIST_BLOB_ALIGN_LOG2
;
158 /* Figure out where the new data will start */
159 data_start
= map_to_sysmem(hdr
) + hdr
->used_size
+ sizeof(*rec
);
161 /* Align the address and then calculate the offset from used size */
162 aligned_start
= ALIGN(data_start
, 1U << align_log2
) - data_start
;
164 /* If we need to create a dummy record, create it */
166 int void_size
= aligned_start
- sizeof(*rec
);
167 struct bloblist_rec
*vrec
;
170 ret
= bloblist_addrec(BLOBLISTT_VOID
, void_size
, 0, &vrec
);
172 return log_msg_ret("void", ret
);
174 /* start the record after that */
175 data_start
= map_to_sysmem(hdr
) + hdr
->used_size
+ sizeof(*vrec
);
178 /* Calculate the new allocated total */
179 new_alloced
= data_start
- map_to_sysmem(hdr
) +
180 ALIGN(size
, 1U << align_log2
);
182 if (new_alloced
> hdr
->total_size
) {
183 log_err("Failed to allocate %x bytes\n", size
);
184 log_err("Used size=%x, total size=%x\n",
185 hdr
->used_size
, hdr
->total_size
);
186 return log_msg_ret("bloblist add", -ENOSPC
);
188 rec
= (void *)hdr
+ hdr
->used_size
;
190 rec
->tag_and_hdr_size
= tag
| sizeof(*rec
) << BLOBLISTR_HDR_SIZE_SHIFT
;
193 /* Zero the record data */
194 memset((void *)rec
+ rec_hdr_size(rec
), '\0', rec
->size
);
196 hdr
->used_size
= new_alloced
;
202 static int bloblist_ensurerec(uint tag
, struct bloblist_rec
**recp
, int size
,
205 struct bloblist_rec
*rec
;
207 rec
= bloblist_findrec(tag
);
209 if (size
&& size
!= rec
->size
) {
216 ret
= bloblist_addrec(tag
, size
, align_log2
, &rec
);
225 void *bloblist_find(uint tag
, int size
)
227 struct bloblist_rec
*rec
;
229 rec
= bloblist_findrec(tag
);
232 if (size
&& size
!= rec
->size
)
235 return (void *)rec
+ rec_hdr_size(rec
);
238 void *bloblist_add(uint tag
, int size
, int align_log2
)
240 struct bloblist_rec
*rec
;
242 if (bloblist_addrec(tag
, size
, align_log2
, &rec
))
245 return (void *)rec
+ rec_hdr_size(rec
);
248 int bloblist_ensure_size(uint tag
, int size
, int align_log2
, void **blobp
)
250 struct bloblist_rec
*rec
;
253 ret
= bloblist_ensurerec(tag
, &rec
, size
, align_log2
);
256 *blobp
= (void *)rec
+ rec_hdr_size(rec
);
261 void *bloblist_ensure(uint tag
, int size
)
263 struct bloblist_rec
*rec
;
265 if (bloblist_ensurerec(tag
, &rec
, size
, 0))
268 return (void *)rec
+ rec_hdr_size(rec
);
271 int bloblist_ensure_size_ret(uint tag
, int *sizep
, void **blobp
)
273 struct bloblist_rec
*rec
;
276 ret
= bloblist_ensurerec(tag
, &rec
, *sizep
, 0);
281 *blobp
= (void *)rec
+ rec_hdr_size(rec
);
286 static int bloblist_resize_rec(struct bloblist_hdr
*hdr
,
287 struct bloblist_rec
*rec
,
290 int expand_by
; /* Number of bytes to expand by (-ve to contract) */
292 ulong next_ofs
; /* Offset of the record after @rec */
294 expand_by
= ALIGN(new_size
- rec
->size
, BLOBLIST_BLOB_ALIGN
);
295 new_alloced
= ALIGN(hdr
->used_size
+ expand_by
, BLOBLIST_BLOB_ALIGN
);
297 log_debug("Attempt to shrink blob size below 0 (%x)\n",
299 return log_msg_ret("size", -EINVAL
);
301 if (new_alloced
> hdr
->total_size
) {
302 log_err("Failed to allocate %x bytes\n", new_size
);
303 log_err("Used size=%x, total size=%x\n",
304 hdr
->used_size
, hdr
->total_size
);
305 return log_msg_ret("alloc", -ENOSPC
);
308 /* Move the following blobs up or down, if this is not the last */
309 next_ofs
= bloblist_blob_end_ofs(hdr
, rec
);
310 if (next_ofs
!= hdr
->used_size
) {
311 memmove((void *)hdr
+ next_ofs
+ expand_by
,
312 (void *)hdr
+ next_ofs
, new_alloced
- next_ofs
);
314 hdr
->used_size
= new_alloced
;
316 /* Zero the new part of the blob */
318 memset((void *)rec
+ rec_hdr_size(rec
) + rec
->size
, '\0',
319 new_size
- rec
->size
);
322 /* Update the size of this blob */
323 rec
->size
= new_size
;
328 int bloblist_resize(uint tag
, int new_size
)
330 struct bloblist_hdr
*hdr
= gd
->bloblist
;
331 struct bloblist_rec
*rec
;
334 rec
= bloblist_findrec(tag
);
336 return log_msg_ret("find", -ENOENT
);
337 ret
= bloblist_resize_rec(hdr
, rec
, new_size
);
339 return log_msg_ret("resize", ret
);
344 static u32
bloblist_calc_chksum(struct bloblist_hdr
*hdr
)
348 chksum
= table_compute_checksum(hdr
, hdr
->used_size
);
349 chksum
+= hdr
->chksum
;
354 int bloblist_new(ulong addr
, uint size
, uint flags
, uint align_log2
)
356 struct bloblist_hdr
*hdr
;
358 if (size
< sizeof(*hdr
))
359 return log_ret(-ENOSPC
);
360 if (addr
& (BLOBLIST_ALIGN
- 1))
361 return log_ret(-EFAULT
);
362 hdr
= map_sysmem(addr
, size
);
363 memset(hdr
, '\0', sizeof(*hdr
));
364 hdr
->version
= BLOBLIST_VERSION
;
365 hdr
->hdr_size
= sizeof(*hdr
);
367 hdr
->magic
= BLOBLIST_MAGIC
;
368 hdr
->used_size
= hdr
->hdr_size
;
369 hdr
->total_size
= size
;
370 hdr
->align_log2
= align_log2
? align_log2
: BLOBLIST_BLOB_ALIGN_LOG2
;
377 int bloblist_check(ulong addr
, uint size
)
379 struct bloblist_hdr
*hdr
;
382 hdr
= map_sysmem(addr
, sizeof(*hdr
));
383 if (hdr
->magic
!= BLOBLIST_MAGIC
)
384 return log_msg_ret("Bad magic", -ENOENT
);
385 if (hdr
->version
!= BLOBLIST_VERSION
)
386 return log_msg_ret("Bad version", -EPROTONOSUPPORT
);
387 if (!hdr
->total_size
|| (size
&& hdr
->total_size
> size
))
388 return log_msg_ret("Bad total size", -EFBIG
);
389 if (hdr
->used_size
> hdr
->total_size
)
390 return log_msg_ret("Bad used size", -ENOENT
);
391 if (hdr
->hdr_size
!= sizeof(struct bloblist_hdr
))
392 return log_msg_ret("Bad header size", -ENOENT
);
394 chksum
= bloblist_calc_chksum(hdr
);
395 if (hdr
->chksum
!= chksum
) {
396 log_err("Checksum %x != %x\n", hdr
->chksum
, chksum
);
397 return log_msg_ret("Bad checksum", -EIO
);
404 int bloblist_finish(void)
406 struct bloblist_hdr
*hdr
= gd
->bloblist
;
408 hdr
->chksum
= bloblist_calc_chksum(hdr
);
409 log_debug("Finished bloblist size %lx at %lx\n", (ulong
)hdr
->used_size
,
410 (ulong
)map_to_sysmem(hdr
));
415 ulong
bloblist_get_base(void)
417 return map_to_sysmem(gd
->bloblist
);
420 ulong
bloblist_get_size(void)
422 struct bloblist_hdr
*hdr
= gd
->bloblist
;
424 return hdr
->used_size
;
427 ulong
bloblist_get_total_size(void)
429 struct bloblist_hdr
*hdr
= gd
->bloblist
;
431 return hdr
->total_size
;
434 void bloblist_get_stats(ulong
*basep
, ulong
*tsizep
, ulong
*usizep
)
436 struct bloblist_hdr
*hdr
= gd
->bloblist
;
438 *basep
= map_to_sysmem(gd
->bloblist
);
439 *tsizep
= hdr
->total_size
;
440 *usizep
= hdr
->used_size
;
443 static void show_value(const char *prompt
, ulong value
)
445 printf("%s:%*s %-5lx ", prompt
, 10 - (int)strlen(prompt
), "", value
);
446 print_size(value
, "\n");
449 void bloblist_show_stats(void)
451 ulong base
, tsize
, usize
;
453 bloblist_get_stats(&base
, &tsize
, &usize
);
454 printf("base: %lx\n", base
);
455 show_value("total size", tsize
);
456 show_value("used size", usize
);
457 show_value("free", tsize
- usize
);
460 void bloblist_show_list(void)
462 struct bloblist_hdr
*hdr
= gd
->bloblist
;
463 struct bloblist_rec
*rec
;
465 printf("%-8s %8s Tag Name\n", "Address", "Size");
466 for (rec
= bloblist_first_blob(hdr
); rec
;
467 rec
= bloblist_next_blob(hdr
, rec
)) {
468 printf("%08lx %8x %4x %s\n",
469 (ulong
)map_to_sysmem((void *)rec
+ rec_hdr_size(rec
)),
470 rec
->size
, rec_tag(rec
),
471 bloblist_tag_name(rec_tag(rec
)));
475 int bloblist_reloc(void *to
, uint to_size
)
477 struct bloblist_hdr
*hdr
;
479 if (to_size
< gd
->bloblist
->total_size
)
482 memcpy(to
, gd
->bloblist
, gd
->bloblist
->total_size
);
484 hdr
->total_size
= to_size
;
491 * Weak default function for getting bloblist from boot args.
493 int __weak
xferlist_from_boot_arg(ulong __always_unused addr
,
494 ulong __always_unused size
)
499 int bloblist_init(void)
501 bool fixed
= IS_ENABLED(CONFIG_BLOBLIST_FIXED
);
505 * If U-Boot is not in the first phase, an existing bloblist must be
506 * at a fixed address.
508 bool from_addr
= fixed
&& !u_boot_first_phase();
510 * If U-Boot is in the first phase that an arch custom routine should
511 * install the bloblist passed from previous loader to this fixed
514 bool from_boot_arg
= fixed
&& u_boot_first_phase();
516 if (spl_prev_phase() == PHASE_TPL
&& !IS_ENABLED(CONFIG_TPL_BLOBLIST
))
519 addr
= IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED
,
520 CONFIG_BLOBLIST_ADDR
);
521 size
= CONFIG_BLOBLIST_SIZE
;
524 ret
= xferlist_from_boot_arg(addr
, size
);
526 ret
= bloblist_check(addr
, size
);
529 log_warning("Bloblist at %lx not found (err=%d)\n",
532 /* Get the real size */
533 size
= gd
->bloblist
->total_size
;
537 * If we don't have a bloblist from a fixed address, or the one
538 * in the fixed address is not valid. we must allocate the
541 if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC
)) {
542 void *ptr
= memalign(BLOBLIST_ALIGN
, size
);
545 return log_msg_ret("alloc", -ENOMEM
);
546 addr
= map_to_sysmem(ptr
);
548 return log_msg_ret("BLOBLIST_FIXED is not enabled",
551 log_debug("Creating new bloblist size %lx at %lx\n", size
,
553 ret
= bloblist_new(addr
, size
, 0, 0);
555 log_debug("Found existing bloblist size %lx at %lx\n", size
,
559 return log_msg_ret("ini", ret
);
560 gd
->flags
|= GD_FLG_BLOBLIST_READY
;
563 bloblist_show_stats();
564 bloblist_show_list();
570 int bloblist_maybe_init(void)
572 if (CONFIG_IS_ENABLED(BLOBLIST
) && !(gd
->flags
& GD_FLG_BLOBLIST_READY
))
573 return bloblist_init();
578 int bloblist_check_reg_conv(ulong rfdt
, ulong rzero
, ulong rsig
)
580 if (rzero
|| rsig
!= (BLOBLIST_MAGIC
| BLOBLIST_REGCONV_VER
) ||
581 rfdt
!= (ulong
)bloblist_find(BLOBLISTT_CONTROL_FDT
, 0)) {
582 gd
->bloblist
= NULL
; /* Reset the gd bloblist pointer */