cbfs.c
1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 3 #include <assert.h> 4 #include <boot_device.h> 5 #include <cbfs.h> 6 #include <cbmem.h> 7 #include <commonlib/bsd/cbfs_private.h> 8 #include <commonlib/bsd/compression.h> 9 #include <commonlib/list.h> 10 #include <console/console.h> 11 #include <fmap.h> 12 #include <lib.h> 13 #include <metadata_hash.h> 14 #include <security/tpm/tspi/crtm.h> 15 #include <security/vboot/vboot_common.h> 16 #include <security/vboot/misc.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <symbols.h> 20 #include <thread.h> 21 #include <timestamp.h> 22 23 #if ENV_X86 && (ENV_POSTCAR || ENV_SMM) 24 struct mem_pool cbfs_cache = MEM_POOL_INIT(NULL, 0, 0); 25 #elif CONFIG(POSTRAM_CBFS_CACHE_IN_BSS) && ENV_RAMSTAGE 26 static u8 cache_buffer[CONFIG_RAMSTAGE_CBFS_CACHE_SIZE]; 27 struct mem_pool cbfs_cache = 28 MEM_POOL_INIT(cache_buffer, sizeof(cache_buffer), CONFIG_CBFS_CACHE_ALIGN); 29 #else 30 struct mem_pool cbfs_cache = 31 MEM_POOL_INIT(_cbfs_cache, REGION_SIZE(cbfs_cache), CONFIG_CBFS_CACHE_ALIGN); 32 #endif 33 34 static void switch_to_postram_cache(int unused) 35 { 36 if (_preram_cbfs_cache != _postram_cbfs_cache) 37 mem_pool_init(&cbfs_cache, _postram_cbfs_cache, REGION_SIZE(postram_cbfs_cache), 38 CONFIG_CBFS_CACHE_ALIGN); 39 } 40 CBMEM_CREATION_HOOK(switch_to_postram_cache); 41 42 enum cb_err _cbfs_boot_lookup(const char *name, bool force_ro, 43 union cbfs_mdata *mdata, struct region_device *rdev) 44 { 45 const struct cbfs_boot_device *cbd = cbfs_get_boot_device(force_ro); 46 if (!cbd) 47 return CB_ERR; 48 49 size_t data_offset; 50 enum cb_err err = CB_CBFS_CACHE_FULL; 51 if (!CONFIG(NO_CBFS_MCACHE) && !ENV_SMM && cbd->mcache_size) 52 err = cbfs_mcache_lookup(cbd->mcache, cbd->mcache_size, 53 name, mdata, &data_offset); 54 if (err == CB_CBFS_CACHE_FULL) { 55 struct vb2_hash *metadata_hash = NULL; 56 if (CONFIG(TOCTOU_SAFETY)) { 57 if (ENV_SMM) /* Cannot provide TOCTOU safety for SMM */ 58 dead_code(); 59 if (!cbd->mcache_size) 60 die("Cannot access CBFS TOCTOU-safely in " ENV_STRING " before CBMEM init!\n"); 61 /* We can only reach this for the RW CBFS -- an mcache overflow in the 62 RO CBFS would have been caught when building the mcache in cbfs_get 63 boot_device(). (Note that TOCTOU_SAFETY implies !NO_CBFS_MCACHE.) */ 64 assert(cbd == vboot_get_cbfs_boot_device()); 65 if (!CONFIG(VBOOT) 66 || vb2api_get_metadata_hash(vboot_get_context(), &metadata_hash) 67 != VB2_SUCCESS) 68 die("Failed to get RW metadata hash"); 69 } 70 err = cbfs_lookup(&cbd->rdev, name, mdata, &data_offset, metadata_hash); 71 } 72 73 if (CONFIG(VBOOT_ENABLE_CBFS_FALLBACK) && !force_ro && err == CB_CBFS_NOT_FOUND) { 74 printk(BIOS_INFO, "CBFS: Fall back to RO region for %s\n", name); 75 return _cbfs_boot_lookup(name, true, mdata, rdev); 76 } 77 if (err) { 78 if (err == CB_CBFS_NOT_FOUND) 79 printk(BIOS_WARNING, "CBFS: '%s' not found.\n", name); 80 else if (err == CB_CBFS_HASH_MISMATCH) 81 printk(BIOS_ERR, "CBFS ERROR: metadata hash mismatch!\n"); 82 else 83 printk(BIOS_ERR, "CBFS ERROR: error %d when looking up '%s'\n", 84 err, name); 85 return err; 86 } 87 88 if (rdev_chain(rdev, &cbd->rdev, data_offset, be32toh(mdata->h.len))) 89 return CB_ERR; 90 91 return CB_SUCCESS; 92 } 93 94 void cbfs_unmap(void *mapping) 95 { 96 /* 97 * This is save to call with mappings that weren't allocated in the cache (e.g. x86 98 * direct mappings) -- mem_pool_free() just does nothing for addresses it doesn't 99 * recognize. This hardcodes the assumption that if platforms implement an rdev_mmap() 100 * that requires a free() for the boot_device, they need to implement it via the 101 * cbfs_cache mem_pool. 102 */ 103 mem_pool_free(&cbfs_cache, mapping); 104 } 105 106 static inline bool fsps_env(void) 107 { 108 /* FSP-S is assumed to be loaded in ramstage. */ 109 if (ENV_RAMSTAGE) 110 return true; 111 return false; 112 } 113 114 static inline bool fspm_env(void) 115 { 116 /* FSP-M is assumed to be loaded in romstage. */ 117 if (ENV_RAMINIT) 118 return true; 119 return false; 120 } 121 122 static inline bool cbfs_lz4_enabled(void) 123 { 124 if (fsps_env() && CONFIG(FSP_COMPRESS_FSP_S_LZ4)) 125 return true; 126 if (fspm_env() && CONFIG(FSP_COMPRESS_FSP_M_LZ4)) 127 return true; 128 129 if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) && !CONFIG(COMPRESS_PRERAM_STAGES)) 130 return false; 131 132 if (ENV_SMM) 133 return false; 134 135 return true; 136 } 137 138 static inline bool cbfs_lzma_enabled(void) 139 { 140 if (fsps_env() && CONFIG(FSP_COMPRESS_FSP_S_LZMA)) 141 return true; 142 if (fspm_env() && CONFIG(FSP_COMPRESS_FSP_M_LZMA)) 143 return true; 144 145 /* Payload loader (ramstage) always needs LZMA. */ 146 if (ENV_PAYLOAD_LOADER) 147 return true; 148 /* Only other use of LZMA is ramstage compression. */ 149 if (!CONFIG(COMPRESS_RAMSTAGE_LZMA)) 150 return false; 151 /* If there is a postcar, it loads the ramstage. */ 152 if (CONFIG(POSTCAR_STAGE)) 153 return ENV_POSTCAR; 154 /* If there is no postcar but a separate romstage, it loads the ramstage. */ 155 if (CONFIG(SEPARATE_ROMSTAGE)) 156 return ENV_SEPARATE_ROMSTAGE; 157 /* Otherwise, the combined bootblock+romstage loads the ramstage. */ 158 return ENV_BOOTBLOCK; 159 } 160 161 static bool cbfs_file_hash_mismatch(const void *buffer, size_t size, 162 const union cbfs_mdata *mdata, bool skip_verification) 163 { 164 /* Avoid linking hash functions when verification and measurement are disabled. */ 165 if (!CONFIG(CBFS_VERIFICATION) && !CONFIG(TPM_MEASURED_BOOT)) 166 return false; 167 168 const struct vb2_hash *hash = NULL; 169 170 if (CONFIG(CBFS_VERIFICATION) && !skip_verification) { 171 hash = cbfs_file_hash(mdata); 172 if (!hash) { 173 ERROR("'%s' does not have a file hash!\n", mdata->h.filename); 174 return true; 175 } 176 177 vb2_error_t rv = vb2_hash_verify(vboot_hwcrypto_allowed(), buffer, size, hash); 178 if (rv != VB2_SUCCESS) { 179 ERROR("'%s' file hash mismatch!\n", mdata->h.filename); 180 if (CONFIG(VBOOT_CBFS_INTEGRATION) && !vboot_recovery_mode_enabled() 181 && vboot_logic_executed()) 182 vboot_fail_and_reboot(vboot_get_context(), VB2_RECOVERY_FW_BODY, 183 rv); 184 return true; 185 } 186 } 187 188 if (CONFIG(TPM_MEASURED_BOOT) && !ENV_SMM) { 189 struct vb2_hash calculated_hash; 190 191 /* No need to re-hash file if we already have it from verification. */ 192 if (!hash || hash->algo != TPM_MEASURE_ALGO) { 193 if (vb2_hash_calculate(vboot_hwcrypto_allowed(), buffer, size, 194 TPM_MEASURE_ALGO, &calculated_hash)) 195 hash = NULL; 196 else 197 hash = &calculated_hash; 198 } 199 200 if (!hash || 201 tspi_cbfs_measurement(mdata->h.filename, be32toh(mdata->h.type), hash)) 202 ERROR("failed to measure '%s' into TPM log\n", mdata->h.filename); 203 /* We intentionally continue to boot on measurement errors. */ 204 } 205 206 return false; 207 } 208 209 static size_t cbfs_load_and_decompress(const struct region_device *rdev, void *buffer, 210 size_t buffer_size, uint32_t compression, 211 const union cbfs_mdata *mdata, bool skip_verification) 212 { 213 size_t in_size = region_device_sz(rdev); 214 size_t out_size = 0; 215 void *map; 216 217 DEBUG("Decompressing %zu bytes from '%s' to %p with algo %d\n", 218 in_size, mdata->h.filename, buffer, compression); 219 220 if (CONFIG(CBFS_VERIFICATION) && !CONFIG(CBFS_ALLOW_UNVERIFIED_DECOMPRESSION) && 221 skip_verification && compression != CBFS_COMPRESS_NONE) { 222 ERROR("Refusing to decompress unverified file '%s' with algo %d\n", 223 mdata->h.filename, compression); 224 return 0; 225 } 226 227 switch (compression) { 228 case CBFS_COMPRESS_NONE: 229 if (buffer_size < in_size) 230 return 0; 231 if (rdev_readat(rdev, buffer, 0, in_size) != in_size) 232 return 0; 233 if (cbfs_file_hash_mismatch(buffer, in_size, mdata, skip_verification)) 234 return 0; 235 return in_size; 236 237 case CBFS_COMPRESS_LZ4: 238 if (!cbfs_lz4_enabled()) 239 return 0; 240 241 /* cbfs_prog_stage_load() takes care of in-place LZ4 decompression by 242 setting up the rdev to be in memory. */ 243 map = rdev_mmap_full(rdev); 244 if (map == NULL) 245 return 0; 246 247 if (!cbfs_file_hash_mismatch(map, in_size, mdata, skip_verification)) { 248 timestamp_add_now(TS_ULZ4F_START); 249 out_size = ulz4fn(map, in_size, buffer, buffer_size); 250 timestamp_add_now(TS_ULZ4F_END); 251 } 252 253 rdev_munmap(rdev, map); 254 255 return out_size; 256 257 case CBFS_COMPRESS_LZMA: 258 if (!cbfs_lzma_enabled()) 259 return 0; 260 map = rdev_mmap_full(rdev); 261 if (map == NULL) 262 return 0; 263 264 if (!cbfs_file_hash_mismatch(map, in_size, mdata, skip_verification)) { 265 /* Note: timestamp not useful for memory-mapped media (x86) */ 266 timestamp_add_now(TS_ULZMA_START); 267 out_size = ulzman(map, in_size, buffer, buffer_size); 268 timestamp_add_now(TS_ULZMA_END); 269 } 270 271 rdev_munmap(rdev, map); 272 273 return out_size; 274 275 default: 276 return 0; 277 } 278 } 279 280 struct cbfs_preload_context { 281 struct region_device rdev; 282 struct thread_handle handle; 283 struct list_node list_node; 284 void *buffer; 285 char name[]; 286 }; 287 288 static struct list_node cbfs_preload_context_list; 289 290 static struct cbfs_preload_context *alloc_cbfs_preload_context(size_t additional) 291 { 292 struct cbfs_preload_context *context; 293 size_t size = sizeof(*context) + additional; 294 295 context = mem_pool_alloc(&cbfs_cache, size); 296 297 if (!context) 298 return NULL; 299 300 memset(context, 0, size); 301 302 return context; 303 } 304 305 static void append_cbfs_preload_context(struct cbfs_preload_context *context) 306 { 307 list_append(&context->list_node, &cbfs_preload_context_list); 308 } 309 310 static void free_cbfs_preload_context(struct cbfs_preload_context *context) 311 { 312 list_remove(&context->list_node); 313 314 mem_pool_free(&cbfs_cache, context); 315 } 316 317 static enum cb_err cbfs_preload_thread_entry(void *arg) 318 { 319 struct cbfs_preload_context *context = arg; 320 321 if (rdev_read_full(&context->rdev, context->buffer) < 0) { 322 ERROR("%s(name='%s') readat failed\n", __func__, context->name); 323 return CB_ERR; 324 } 325 326 return CB_SUCCESS; 327 } 328 329 void cbfs_preload(const char *name) 330 { 331 struct region_device rdev; 332 union cbfs_mdata mdata; 333 struct cbfs_preload_context *context; 334 bool force_ro = false; 335 size_t size; 336 337 if (!CONFIG(CBFS_PRELOAD)) 338 dead_code(); 339 340 /* We don't want to cross the vboot boundary */ 341 if (ENV_SEPARATE_ROMSTAGE && CONFIG(VBOOT_STARTS_IN_ROMSTAGE)) 342 return; 343 344 DEBUG("%s(name='%s')\n", __func__, name); 345 346 if (_cbfs_boot_lookup(name, force_ro, &mdata, &rdev)) 347 return; 348 349 size = region_device_sz(&rdev); 350 351 context = alloc_cbfs_preload_context(strlen(name) + 1); 352 if (!context) { 353 ERROR("%s(name='%s') failed to allocate preload context\n", __func__, name); 354 return; 355 } 356 357 context->buffer = mem_pool_alloc(&cbfs_cache, size); 358 if (context->buffer == NULL) { 359 ERROR("%s(name='%s') failed to allocate %zu bytes for preload buffer\n", 360 __func__, name, size); 361 goto out; 362 } 363 364 context->rdev = rdev; 365 strcpy(context->name, name); 366 367 append_cbfs_preload_context(context); 368 369 if (thread_run(&context->handle, cbfs_preload_thread_entry, context) == 0) 370 return; 371 372 ERROR("%s(name='%s') failed to start preload thread\n", __func__, name); 373 mem_pool_free(&cbfs_cache, context->buffer); 374 375 out: 376 free_cbfs_preload_context(context); 377 } 378 379 static struct cbfs_preload_context *find_cbfs_preload_context(const char *name) 380 { 381 struct cbfs_preload_context *context; 382 383 list_for_each(context, cbfs_preload_context_list, list_node) { 384 if (strcmp(context->name, name) == 0) 385 return context; 386 } 387 388 return NULL; 389 } 390 391 static enum cb_err get_preload_rdev(struct region_device *rdev, const char *name) 392 { 393 enum cb_err err; 394 struct cbfs_preload_context *context; 395 396 if (!CONFIG(CBFS_PRELOAD) || !ENV_SUPPORTS_COOP) 397 return CB_ERR_ARG; 398 399 context = find_cbfs_preload_context(name); 400 if (!context) 401 return CB_ERR_ARG; 402 403 err = thread_join(&context->handle); 404 if (err != CB_SUCCESS) { 405 ERROR("%s(name='%s') Preload thread failed: %u\n", __func__, name, err); 406 407 goto out; 408 } 409 410 if (rdev_chain_mem(rdev, context->buffer, region_device_sz(&context->rdev)) != 0) { 411 ERROR("%s(name='%s') chaining failed\n", __func__, name); 412 413 err = CB_ERR; 414 goto out; 415 } 416 417 err = CB_SUCCESS; 418 419 DEBUG("%s(name='%s') preload successful\n", __func__, name); 420 421 out: 422 free_cbfs_preload_context(context); 423 424 return err; 425 } 426 427 static void *do_alloc(union cbfs_mdata *mdata, struct region_device *rdev, 428 cbfs_allocator_t allocator, void *arg, size_t *size_out, 429 bool skip_verification) 430 { 431 size_t size = region_device_sz(rdev); 432 void *loc = NULL; 433 434 uint32_t compression = CBFS_COMPRESS_NONE; 435 const struct cbfs_file_attr_compression *cattr = cbfs_find_attr(mdata, 436 CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*cattr)); 437 if (cattr) { 438 compression = be32toh(cattr->compression); 439 size = be32toh(cattr->decompressed_size); 440 } 441 442 if (size_out) 443 *size_out = size; 444 445 /* allocator == NULL means do a cbfs_map() */ 446 if (allocator) { 447 loc = allocator(arg, size, mdata); 448 } else if (compression == CBFS_COMPRESS_NONE) { 449 void *mapping = rdev_mmap_full(rdev); 450 if (!mapping) 451 return NULL; 452 if (cbfs_file_hash_mismatch(mapping, size, mdata, skip_verification)) { 453 rdev_munmap(rdev, mapping); 454 return NULL; 455 } 456 return mapping; 457 } else if (!cbfs_cache.size) { 458 /* In order to use the cbfs_cache you need to add a CBFS_CACHE to your 459 * memlayout. */ 460 ERROR("Cannot map compressed file %s without cbfs_cache\n", mdata->h.filename); 461 return NULL; 462 } else { 463 loc = mem_pool_alloc(&cbfs_cache, size); 464 } 465 466 if (!loc) { 467 ERROR("'%s' allocation failure\n", mdata->h.filename); 468 return NULL; 469 } 470 471 size = cbfs_load_and_decompress(rdev, loc, size, compression, mdata, skip_verification); 472 if (!size) 473 return NULL; 474 475 return loc; 476 } 477 478 void *_cbfs_alloc(const char *name, cbfs_allocator_t allocator, void *arg, 479 size_t *size_out, bool force_ro, enum cbfs_type *type) 480 { 481 struct region_device rdev; 482 bool preload_successful = false; 483 union cbfs_mdata mdata; 484 485 DEBUG("%s(name='%s', alloc=%p(%p), force_ro=%s, type=%d)\n", __func__, name, allocator, 486 arg, force_ro ? "true" : "false", type ? *type : -1); 487 488 if (_cbfs_boot_lookup(name, force_ro, &mdata, &rdev)) 489 return NULL; 490 491 if (type) { 492 const enum cbfs_type real_type = be32toh(mdata.h.type); 493 if (*type == CBFS_TYPE_QUERY) 494 *type = real_type; 495 else if (*type != real_type) { 496 ERROR("'%s' type mismatch (is %u, expected %u)\n", 497 mdata.h.filename, real_type, *type); 498 return NULL; 499 } 500 } 501 502 /* Update the rdev with the preload content */ 503 if (!force_ro && get_preload_rdev(&rdev, name) == CB_SUCCESS) 504 preload_successful = true; 505 506 void *ret = do_alloc(&mdata, &rdev, allocator, arg, size_out, false); 507 508 /* When using cbfs_preload we need to free the preload buffer after populating the 509 * destination buffer. We know we must have a mem_rdev here, so extra mmap is fine. */ 510 if (preload_successful) 511 cbfs_unmap(rdev_mmap_full(&rdev)); 512 513 return ret; 514 } 515 516 void *_cbfs_unverified_area_alloc(const char *area, const char *name, 517 cbfs_allocator_t allocator, void *arg, size_t *size_out) 518 { 519 struct region_device area_rdev, file_rdev; 520 union cbfs_mdata mdata; 521 size_t data_offset; 522 523 DEBUG("%s(area='%s', name='%s', alloc=%p(%p))\n", __func__, area, name, allocator, arg); 524 525 if (fmap_locate_area_as_rdev(area, &area_rdev)) 526 return NULL; 527 528 if (cbfs_lookup(&area_rdev, name, &mdata, &data_offset, NULL)) { 529 ERROR("'%s' not found in '%s'\n", name, area); 530 return NULL; 531 } 532 533 if (rdev_chain(&file_rdev, &area_rdev, data_offset, be32toh(mdata.h.len))) 534 return NULL; 535 536 return do_alloc(&mdata, &file_rdev, allocator, arg, size_out, true); 537 } 538 539 void *_cbfs_default_allocator(void *arg, size_t size, const union cbfs_mdata *unused) 540 { 541 struct _cbfs_default_allocator_arg *darg = arg; 542 if (size > darg->buf_size) 543 return NULL; 544 return darg->buf; 545 } 546 547 void *_cbfs_cbmem_allocator(void *arg, size_t size, const union cbfs_mdata *unused) 548 { 549 return cbmem_add((uintptr_t)arg, size); 550 } 551 552 enum cb_err cbfs_prog_stage_load(struct prog *pstage) 553 { 554 union cbfs_mdata mdata; 555 struct region_device rdev; 556 enum cb_err err; 557 558 prog_locate_hook(pstage); 559 560 if ((err = _cbfs_boot_lookup(prog_name(pstage), false, &mdata, &rdev))) 561 return err; 562 563 assert(be32toh(mdata.h.type) == CBFS_TYPE_STAGE); 564 pstage->cbfs_type = CBFS_TYPE_STAGE; 565 566 enum cbfs_compression compression = CBFS_COMPRESS_NONE; 567 const struct cbfs_file_attr_compression *cattr = cbfs_find_attr(&mdata, 568 CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*cattr)); 569 if (cattr) 570 compression = be32toh(cattr->compression); 571 572 const struct cbfs_file_attr_stageheader *sattr = cbfs_find_attr(&mdata, 573 CBFS_FILE_ATTR_TAG_STAGEHEADER, sizeof(*sattr)); 574 if (!sattr) 575 return CB_ERR; 576 prog_set_area(pstage, (void *)(uintptr_t)be64toh(sattr->loadaddr), 577 be32toh(sattr->memlen)); 578 prog_set_entry(pstage, prog_start(pstage) + 579 be32toh(sattr->entry_offset), NULL); 580 581 /* Hacky way to not load programs over read only media. The stages 582 * that would hit this path initialize themselves. */ 583 if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) && 584 !CONFIG(NO_XIP_EARLY_STAGES) && CONFIG(BOOT_DEVICE_MEMORY_MAPPED)) { 585 void *mapping = rdev_mmap_full(&rdev); 586 rdev_munmap(&rdev, mapping); 587 if (cbfs_file_hash_mismatch(mapping, region_device_sz(&rdev), &mdata, false)) 588 return CB_CBFS_HASH_MISMATCH; 589 if (mapping == prog_start(pstage)) 590 return CB_SUCCESS; 591 } 592 593 /* LZ4 stages can be decompressed in-place to save mapping scratch space. Load the 594 compressed data to the end of the buffer and point &rdev to that memory location. */ 595 if (cbfs_lz4_enabled() && compression == CBFS_COMPRESS_LZ4) { 596 size_t in_size = region_device_sz(&rdev); 597 void *compr_start = prog_start(pstage) + prog_size(pstage) - in_size; 598 if (rdev_readat(&rdev, compr_start, 0, in_size) != in_size) 599 return CB_ERR; 600 rdev_chain_mem(&rdev, compr_start, in_size); 601 } 602 603 size_t fsize = cbfs_load_and_decompress(&rdev, prog_start(pstage), prog_size(pstage), 604 compression, &mdata, false); 605 if (!fsize) 606 return CB_ERR; 607 608 /* Clear area not covered by file. */ 609 memset(prog_start(pstage) + fsize, 0, prog_size(pstage) - fsize); 610 611 prog_segment_loaded((uintptr_t)prog_start(pstage), prog_size(pstage), 612 SEG_FINAL); 613 614 return CB_SUCCESS; 615 } 616 617 void cbfs_boot_device_find_mcache(struct cbfs_boot_device *cbd, uint32_t id) 618 { 619 if (CONFIG(NO_CBFS_MCACHE) || ENV_SMM) 620 return; 621 622 if (cbd->mcache_size) 623 return; 624 625 const struct cbmem_entry *entry; 626 if (ENV_HAS_CBMEM && 627 (entry = cbmem_entry_find(id))) { 628 cbd->mcache = cbmem_entry_start(entry); 629 cbd->mcache_size = cbmem_entry_size(entry); 630 } else if (ENV_ROMSTAGE_OR_BEFORE) { 631 u8 *boundary = _ecbfs_mcache - REGION_SIZE(cbfs_mcache) * 632 CONFIG_CBFS_MCACHE_RW_PERCENTAGE / 100; 633 boundary = (u8 *)ALIGN_DOWN((uintptr_t)boundary, CBFS_MCACHE_ALIGNMENT); 634 if (id == CBMEM_ID_CBFS_RO_MCACHE) { 635 cbd->mcache = _cbfs_mcache; 636 cbd->mcache_size = boundary - _cbfs_mcache; 637 } else if (id == CBMEM_ID_CBFS_RW_MCACHE) { 638 cbd->mcache = boundary; 639 cbd->mcache_size = _ecbfs_mcache - boundary; 640 } 641 } 642 } 643 644 enum cb_err cbfs_init_boot_device(const struct cbfs_boot_device *cbd, 645 struct vb2_hash *mdata_hash) 646 { 647 /* If we have an mcache, mcache_build() will also check mdata hash. */ 648 if (!CONFIG(NO_CBFS_MCACHE) && !ENV_SMM && cbd->mcache_size > 0) 649 return cbfs_mcache_build(&cbd->rdev, cbd->mcache, cbd->mcache_size, mdata_hash); 650 651 /* No mcache and no verification means we have nothing special to do. */ 652 if (!CONFIG(CBFS_VERIFICATION) || !mdata_hash) 653 return CB_SUCCESS; 654 655 /* Verification only: use cbfs_walk() without a walker() function to just run through 656 the CBFS once, will return NOT_FOUND by default. */ 657 enum cb_err err = cbfs_walk(&cbd->rdev, NULL, NULL, mdata_hash, 0); 658 if (err == CB_CBFS_NOT_FOUND) 659 err = CB_SUCCESS; 660 return err; 661 } 662 663 const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro) 664 { 665 static struct cbfs_boot_device ro; 666 667 /* Ensure we always init RO mcache, even if the first file is from the RW CBFS. 668 Otherwise it may not be available when needed in later stages. */ 669 if (ENV_INITIAL_STAGE && !force_ro && !region_device_sz(&ro.rdev)) 670 cbfs_get_boot_device(true); 671 672 if (!force_ro) { 673 const struct cbfs_boot_device *rw = vboot_get_cbfs_boot_device(); 674 /* This will return NULL if vboot isn't enabled, didn't run yet or decided to 675 boot into recovery mode. */ 676 if (rw) 677 return rw; 678 } 679 680 /* In rare cases post-RAM stages may run this before cbmem_initialize(), so we can't 681 lock in the result of find_mcache() on the first try and should keep trying every 682 time until an mcache is found. */ 683 cbfs_boot_device_find_mcache(&ro, CBMEM_ID_CBFS_RO_MCACHE); 684 685 if (region_device_sz(&ro.rdev)) 686 return &ro; 687 688 if (fmap_locate_area_as_rdev("COREBOOT", &ro.rdev)) 689 die("Cannot locate primary CBFS"); 690 691 if (ENV_INITIAL_STAGE) { 692 enum cb_err err = cbfs_init_boot_device(&ro, metadata_hash_get()); 693 if (err == CB_CBFS_HASH_MISMATCH) 694 die("RO CBFS metadata hash verification failure"); 695 else if (CONFIG(TOCTOU_SAFETY) && err == CB_CBFS_CACHE_FULL) 696 die("RO mcache overflow breaks TOCTOU safety!\n"); 697 else if (err && err != CB_CBFS_CACHE_FULL) 698 die("RO CBFS initialization error: %d", err); 699 } 700 701 return &ro; 702 } 703 704 #if !CONFIG(NO_CBFS_MCACHE) 705 static void mcache_to_cbmem(const struct cbfs_boot_device *cbd, u32 cbmem_id) 706 { 707 if (!cbd) 708 return; 709 710 size_t real_size = cbfs_mcache_real_size(cbd->mcache, cbd->mcache_size); 711 void *cbmem_mcache = cbmem_add(cbmem_id, real_size); 712 if (!cbmem_mcache) { 713 printk(BIOS_ERR, "Cannot allocate CBMEM mcache %#x (%#zx bytes)!\n", 714 cbmem_id, real_size); 715 return; 716 } 717 memcpy(cbmem_mcache, cbd->mcache, real_size); 718 } 719 720 static void cbfs_mcache_migrate(int unused) 721 { 722 mcache_to_cbmem(vboot_get_cbfs_boot_device(), CBMEM_ID_CBFS_RW_MCACHE); 723 mcache_to_cbmem(cbfs_get_boot_device(true), CBMEM_ID_CBFS_RO_MCACHE); 724 } 725 CBMEM_CREATION_HOOK(cbfs_mcache_migrate); 726 #endif