]>
git.ipfire.org Git - thirdparty/u-boot.git/blob - common/bloblist.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2018 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
13 #include <asm/global_data.h>
14 #include <u-boot/crc.h>
17 * A bloblist is a single contiguous chunk of memory with a header
18 * (struct bloblist_hdr) and a number of blobs in it.
20 * Each blob starts on a BLOBLIST_ALIGN boundary relative to the start of the
21 * bloblist and consists of a struct bloblist_rec, some padding to the required
22 * alignment for the blog and then the actual data. The padding ensures that the
23 * start address of the data in each blob is aligned as required. Note that
24 * each blob's *data* is aligned to BLOBLIST_ALIGN regardless of the alignment
25 * of the bloblist itself or the blob header.
27 * So far, only BLOBLIST_ALIGN alignment is supported.
30 DECLARE_GLOBAL_DATA_PTR
;
32 static const char *const tag_name
[] = {
33 [BLOBLISTT_NONE
] = "(none)",
34 [BLOBLISTT_EC_HOSTEVENT
] = "EC host event",
35 [BLOBLISTT_SPL_HANDOFF
] = "SPL hand-off",
36 [BLOBLISTT_VBOOT_CTX
] = "Chrome OS vboot context",
37 [BLOBLISTT_VBOOT_HANDOFF
] = "Chrome OS vboot hand-off",
38 [BLOBLISTT_ACPI_GNVS
] = "ACPI GNVS",
39 [BLOBLISTT_INTEL_VBT
] = "Intel Video-BIOS table",
40 [BLOBLISTT_TPM2_TCG_LOG
] = "TPM v2 log space",
41 [BLOBLISTT_TCPA_LOG
] = "TPM log space",
42 [BLOBLISTT_ACPI_TABLES
] = "ACPI tables for x86",
43 [BLOBLISTT_SMBIOS_TABLES
] = "SMBIOS tables for x86",
46 const char *bloblist_tag_name(enum bloblist_tag_t tag
)
48 if (tag
< 0 || tag
>= BLOBLISTT_COUNT
)
54 static struct bloblist_rec
*bloblist_first_blob(struct bloblist_hdr
*hdr
)
56 if (hdr
->alloced
<= hdr
->hdr_size
)
58 return (struct bloblist_rec
*)((void *)hdr
+ hdr
->hdr_size
);
61 static ulong
bloblist_blob_end_ofs(struct bloblist_hdr
*hdr
,
62 struct bloblist_rec
*rec
)
66 offset
= (void *)rec
- (void *)hdr
;
67 offset
+= rec
->hdr_size
+ ALIGN(rec
->size
, BLOBLIST_ALIGN
);
72 static struct bloblist_rec
*bloblist_next_blob(struct bloblist_hdr
*hdr
,
73 struct bloblist_rec
*rec
)
75 ulong offset
= bloblist_blob_end_ofs(hdr
, rec
);
77 if (offset
>= hdr
->alloced
)
79 return (struct bloblist_rec
*)((void *)hdr
+ offset
);
82 #define foreach_rec(_rec, _hdr) \
83 for (_rec = bloblist_first_blob(_hdr); \
85 _rec = bloblist_next_blob(_hdr, _rec))
87 static struct bloblist_rec
*bloblist_findrec(uint tag
)
89 struct bloblist_hdr
*hdr
= gd
->bloblist
;
90 struct bloblist_rec
*rec
;
95 foreach_rec(rec
, hdr
) {
103 static int bloblist_addrec(uint tag
, int size
, int align
,
104 struct bloblist_rec
**recp
)
106 struct bloblist_hdr
*hdr
= gd
->bloblist
;
107 struct bloblist_rec
*rec
;
108 int data_start
, new_alloced
;
111 align
= BLOBLIST_ALIGN
;
113 /* Figure out where the new data will start */
114 data_start
= map_to_sysmem(hdr
) + hdr
->alloced
+ sizeof(*rec
);
116 /* Align the address and then calculate the offset from ->alloced */
117 data_start
= ALIGN(data_start
, align
) - map_to_sysmem(hdr
);
119 /* Calculate the new allocated total */
120 new_alloced
= data_start
+ ALIGN(size
, align
);
122 if (new_alloced
> hdr
->size
) {
123 log(LOGC_BLOBLIST
, LOGL_ERR
,
124 "Failed to allocate %x bytes size=%x, need size=%x\n",
125 size
, hdr
->size
, new_alloced
);
126 return log_msg_ret("bloblist add", -ENOSPC
);
128 rec
= (void *)hdr
+ hdr
->alloced
;
131 rec
->hdr_size
= data_start
- hdr
->alloced
;
135 /* Zero the record data */
136 memset((void *)rec
+ rec
->hdr_size
, '\0', rec
->size
);
138 hdr
->alloced
= new_alloced
;
144 static int bloblist_ensurerec(uint tag
, struct bloblist_rec
**recp
, int size
,
147 struct bloblist_rec
*rec
;
149 rec
= bloblist_findrec(tag
);
151 if (size
&& size
!= rec
->size
) {
158 ret
= bloblist_addrec(tag
, size
, align
, &rec
);
167 void *bloblist_find(uint tag
, int size
)
169 struct bloblist_rec
*rec
;
171 rec
= bloblist_findrec(tag
);
174 if (size
&& size
!= rec
->size
)
177 return (void *)rec
+ rec
->hdr_size
;
180 void *bloblist_add(uint tag
, int size
, int align
)
182 struct bloblist_rec
*rec
;
184 if (bloblist_addrec(tag
, size
, align
, &rec
))
187 return (void *)rec
+ rec
->hdr_size
;
190 int bloblist_ensure_size(uint tag
, int size
, int align
, void **blobp
)
192 struct bloblist_rec
*rec
;
195 ret
= bloblist_ensurerec(tag
, &rec
, size
, align
);
198 *blobp
= (void *)rec
+ rec
->hdr_size
;
203 void *bloblist_ensure(uint tag
, int size
)
205 struct bloblist_rec
*rec
;
207 if (bloblist_ensurerec(tag
, &rec
, size
, 0))
210 return (void *)rec
+ rec
->hdr_size
;
213 int bloblist_ensure_size_ret(uint tag
, int *sizep
, void **blobp
)
215 struct bloblist_rec
*rec
;
218 ret
= bloblist_ensurerec(tag
, &rec
, *sizep
, 0);
223 *blobp
= (void *)rec
+ rec
->hdr_size
;
228 static int bloblist_resize_rec(struct bloblist_hdr
*hdr
,
229 struct bloblist_rec
*rec
,
232 int expand_by
; /* Number of bytes to expand by (-ve to contract) */
233 int new_alloced
; /* New value for @hdr->alloced */
234 ulong next_ofs
; /* Offset of the record after @rec */
236 expand_by
= ALIGN(new_size
- rec
->size
, BLOBLIST_ALIGN
);
237 new_alloced
= ALIGN(hdr
->alloced
+ expand_by
, BLOBLIST_ALIGN
);
239 log(LOGC_BLOBLIST
, LOGL_DEBUG
,
240 "Attempt to shrink blob size below 0 (%x)\n", new_size
);
241 return log_msg_ret("size", -EINVAL
);
243 if (new_alloced
> hdr
->size
) {
244 log(LOGC_BLOBLIST
, LOGL_ERR
,
245 "Failed to allocate %x bytes size=%x, need size=%x\n",
246 new_size
, hdr
->size
, new_alloced
);
247 return log_msg_ret("alloc", -ENOSPC
);
250 /* Move the following blobs up or down, if this is not the last */
251 next_ofs
= bloblist_blob_end_ofs(hdr
, rec
);
252 if (next_ofs
!= hdr
->alloced
) {
253 memmove((void *)hdr
+ next_ofs
+ expand_by
,
254 (void *)hdr
+ next_ofs
, new_alloced
- next_ofs
);
256 hdr
->alloced
= new_alloced
;
258 /* Zero the new part of the blob */
260 memset((void *)rec
+ rec
->hdr_size
+ rec
->size
, '\0',
261 new_size
- rec
->size
);
264 /* Update the size of this blob */
265 rec
->size
= new_size
;
270 int bloblist_resize(uint tag
, int new_size
)
272 struct bloblist_hdr
*hdr
= gd
->bloblist
;
273 struct bloblist_rec
*rec
;
276 rec
= bloblist_findrec(tag
);
278 return log_msg_ret("find", -ENOENT
);
279 ret
= bloblist_resize_rec(hdr
, rec
, new_size
);
281 return log_msg_ret("resize", ret
);
286 static u32
bloblist_calc_chksum(struct bloblist_hdr
*hdr
)
288 struct bloblist_rec
*rec
;
291 chksum
= crc32(0, (unsigned char *)hdr
,
292 offsetof(struct bloblist_hdr
, chksum
));
293 foreach_rec(rec
, hdr
) {
294 chksum
= crc32(chksum
, (void *)rec
, rec
->hdr_size
);
295 chksum
= crc32(chksum
, (void *)rec
+ rec
->hdr_size
, rec
->size
);
301 int bloblist_new(ulong addr
, uint size
, uint flags
)
303 struct bloblist_hdr
*hdr
;
305 if (size
< sizeof(*hdr
))
306 return log_ret(-ENOSPC
);
307 if (addr
& (BLOBLIST_ALIGN
- 1))
308 return log_ret(-EFAULT
);
309 hdr
= map_sysmem(addr
, size
);
310 memset(hdr
, '\0', sizeof(*hdr
));
311 hdr
->version
= BLOBLIST_VERSION
;
312 hdr
->hdr_size
= sizeof(*hdr
);
314 hdr
->magic
= BLOBLIST_MAGIC
;
316 hdr
->alloced
= hdr
->hdr_size
;
323 int bloblist_check(ulong addr
, uint size
)
325 struct bloblist_hdr
*hdr
;
328 hdr
= map_sysmem(addr
, sizeof(*hdr
));
329 if (hdr
->magic
!= BLOBLIST_MAGIC
)
330 return log_msg_ret("Bad magic", -ENOENT
);
331 if (hdr
->version
!= BLOBLIST_VERSION
)
332 return log_msg_ret("Bad version", -EPROTONOSUPPORT
);
333 if (size
&& hdr
->size
!= size
)
334 return log_msg_ret("Bad size", -EFBIG
);
335 chksum
= bloblist_calc_chksum(hdr
);
336 if (hdr
->chksum
!= chksum
) {
337 log(LOGC_BLOBLIST
, LOGL_ERR
, "Checksum %x != %x\n", hdr
->chksum
,
339 return log_msg_ret("Bad checksum", -EIO
);
346 int bloblist_finish(void)
348 struct bloblist_hdr
*hdr
= gd
->bloblist
;
350 hdr
->chksum
= bloblist_calc_chksum(hdr
);
355 void bloblist_get_stats(ulong
*basep
, ulong
*sizep
, ulong
*allocedp
)
357 struct bloblist_hdr
*hdr
= gd
->bloblist
;
359 *basep
= map_to_sysmem(gd
->bloblist
);
361 *allocedp
= hdr
->alloced
;
364 static void show_value(const char *prompt
, ulong value
)
366 printf("%s:%*s %-5lx ", prompt
, 8 - (int)strlen(prompt
), "", value
);
367 print_size(value
, "\n");
370 void bloblist_show_stats(void)
372 ulong base
, size
, alloced
;
374 bloblist_get_stats(&base
, &size
, &alloced
);
375 printf("base: %lx\n", base
);
376 show_value("size", size
);
377 show_value("alloced", alloced
);
378 show_value("free", size
- alloced
);
381 void bloblist_show_list(void)
383 struct bloblist_hdr
*hdr
= gd
->bloblist
;
384 struct bloblist_rec
*rec
;
386 printf("%-8s %8s Tag Name\n", "Address", "Size");
387 for (rec
= bloblist_first_blob(hdr
); rec
;
388 rec
= bloblist_next_blob(hdr
, rec
)) {
389 printf("%08lx %8x %3d %s\n",
390 (ulong
)map_to_sysmem((void *)rec
+ rec
->hdr_size
),
391 rec
->size
, rec
->tag
, bloblist_tag_name(rec
->tag
));
395 void bloblist_reloc(void *to
, uint to_size
, void *from
, uint from_size
)
397 struct bloblist_hdr
*hdr
;
399 memcpy(to
, from
, from_size
);
404 int bloblist_init(void)
410 * Wed expect to find an existing bloblist in the first phase of U-Boot
413 expected
= !u_boot_first_phase();
414 if (spl_prev_phase() == PHASE_TPL
&& !IS_ENABLED(CONFIG_TPL_BLOBLIST
))
417 ret
= bloblist_check(CONFIG_BLOBLIST_ADDR
,
418 CONFIG_BLOBLIST_SIZE
);
422 log(LOGC_BLOBLIST
, expected
? LOGL_WARNING
: LOGL_DEBUG
,
423 "Existing bloblist not found: creating new bloblist\n");
424 if (IS_ENABLED(CONFIG_BLOBLIST_ALLOC
)) {
425 void *ptr
= memalign(BLOBLIST_ALIGN
,
426 CONFIG_BLOBLIST_SIZE
);
429 return log_msg_ret("alloc", -ENOMEM
);
430 addr
= map_to_sysmem(ptr
);
432 addr
= CONFIG_BLOBLIST_ADDR
;
434 ret
= bloblist_new(addr
, CONFIG_BLOBLIST_SIZE
, 0);
436 log(LOGC_BLOBLIST
, LOGL_DEBUG
, "Found existing bloblist\n");