]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
427 | ulong bloblist_get_base(void) | |
428 | { | |
429 | return map_to_sysmem(gd->bloblist); | |
430 | } | |
431 | ||
432 | ulong bloblist_get_size(void) | |
433 | { | |
434 | struct bloblist_hdr *hdr = gd->bloblist; | |
435 | ||
436 | return hdr->used_size; | |
437 | } | |
438 | ||
439 | ulong bloblist_get_total_size(void) | |
440 | { | |
441 | struct bloblist_hdr *hdr = gd->bloblist; | |
442 | ||
443 | return hdr->total_size; | |
444 | } | |
445 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | */ | |
508 | int __weak xferlist_from_boot_arg(ulong __always_unused *addr) | |
509 | { | |
510 | return -ENOENT; | |
511 | } | |
512 | ||
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 | ||
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 | ||
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 | } |