"Das U-Boot" Source Tree
at master 611 lines 15 kB view raw
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 31DECLARE_GLOBAL_DATA_PTR; 32 33static 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 68const 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 80static 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 87static 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 93static 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 99static 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 116static 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 131static 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 147static 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 201static 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 224void *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 237void *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 250void *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 260int 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 273void *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 283int 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 298static 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 340int 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 356static 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 366int 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 389int 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 416int 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 427ulong bloblist_get_base(void) 428{ 429 return map_to_sysmem(gd->bloblist); 430} 431 432ulong bloblist_get_size(void) 433{ 434 struct bloblist_hdr *hdr = gd->bloblist; 435 436 return hdr->used_size; 437} 438 439ulong bloblist_get_total_size(void) 440{ 441 struct bloblist_hdr *hdr = gd->bloblist; 442 443 return hdr->total_size; 444} 445 446void 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 455static 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 461void 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 472void 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 487int bloblist_reloc(void *to, uint to_size) 488{ 489 struct bloblist_hdr *hdr; 490 491 if (to_size < gd->bloblist->total_size) 492 return -ENOSPC; 493 494 memcpy(to, gd->bloblist, gd->bloblist->total_size); 495 hdr = to; 496 hdr->total_size = to_size; 497 gd->bloblist = to; 498 499 return 0; 500} 501 502/* 503 * Weak default function for getting bloblist from boot args. 504 */ 505int __weak xferlist_from_boot_arg(ulong __always_unused addr, 506 ulong __always_unused size) 507{ 508 return -ENOENT; 509} 510 511int bloblist_init(void) 512{ 513 bool fixed = IS_ENABLED(CONFIG_BLOBLIST_FIXED); 514 int ret = -ENOENT; 515 ulong addr = 0, size; 516 /* 517 * If U-Boot is not in the first phase, an existing bloblist must be 518 * at a fixed address. 519 */ 520 bool from_addr = fixed && !xpl_is_first_phase(); 521 /* 522 * If U-Boot is in the first phase that an arch custom routine should 523 * install the bloblist passed from previous loader to this fixed 524 * address. 525 */ 526 bool from_boot_arg = fixed && xpl_is_first_phase(); 527 528 if (xpl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST)) 529 from_addr = false; 530 if (fixed) 531 addr = IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, 532 CONFIG_BLOBLIST_ADDR); 533 size = CONFIG_BLOBLIST_SIZE; 534 535 if (from_boot_arg) 536 ret = xferlist_from_boot_arg(addr, size); 537 else if (from_addr) 538 ret = bloblist_check(addr, size); 539 540 if (ret) 541 log_warning("Bloblist at %lx not found (err=%d)\n", 542 addr, ret); 543 else 544 /* Get the real size */ 545 size = gd->bloblist->total_size; 546 547 if (ret) { 548 /* 549 * If we don't have a bloblist from a fixed address, or the one 550 * in the fixed address is not valid. we must allocate the 551 * memory for it now. 552 */ 553 if (CONFIG_IS_ENABLED(BLOBLIST_ALLOC)) { 554 void *ptr = memalign(BLOBLIST_ALIGN, size); 555 556 if (!ptr) 557 return log_msg_ret("alloc", -ENOMEM); 558 addr = map_to_sysmem(ptr); 559 } else if (!fixed) { 560 return log_msg_ret("BLOBLIST_FIXED is not enabled", 561 ret); 562 } 563 log_debug("Creating new bloblist size %lx at %lx\n", size, 564 addr); 565 ret = bloblist_new(addr, size, 0, 0); 566 } else { 567 log_debug("Found existing bloblist size %lx at %lx\n", size, 568 addr); 569 } 570 if (ret) 571 return log_msg_ret("ini", ret); 572 gd->flags |= GD_FLG_BLOBLIST_READY; 573 574#ifdef DEBUG 575 bloblist_show_stats(); 576 bloblist_show_list(); 577#endif 578 579 return 0; 580} 581 582int bloblist_maybe_init(void) 583{ 584 if (CONFIG_IS_ENABLED(BLOBLIST) && !(gd->flags & GD_FLG_BLOBLIST_READY)) 585 return bloblist_init(); 586 587 return 0; 588} 589 590int bloblist_check_reg_conv(ulong rfdt, ulong rzero, ulong rsig) 591{ 592 u64 version = BLOBLIST_REGCONV_VER; 593 ulong sigval; 594 595 if ((IS_ENABLED(CONFIG_64BIT) && !IS_ENABLED(CONFIG_SPL_BUILD)) || 596 (IS_ENABLED(CONFIG_SPL_64BIT) && IS_ENABLED(CONFIG_SPL_BUILD))) { 597 sigval = ((BLOBLIST_MAGIC & ((1ULL << BLOBLIST_REGCONV_SHIFT_64) - 1)) | 598 ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_64)); 599 } else { 600 sigval = ((BLOBLIST_MAGIC & ((1UL << BLOBLIST_REGCONV_SHIFT_32) - 1)) | 601 ((version & BLOBLIST_REGCONV_MASK) << BLOBLIST_REGCONV_SHIFT_32)); 602 } 603 604 if (rzero || rsig != sigval || 605 rfdt != (ulong)bloblist_find(BLOBLISTT_CONTROL_FDT, 0)) { 606 gd->bloblist = NULL; /* Reset the gd bloblist pointer */ 607 return -EIO; 608 } 609 610 return 0; 611}