From 1e37c9ca465a14d55adeacb332354771543437b5 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Wed, 11 Dec 2019 17:09:39 -0800 Subject: cbfs: Add metadata cache This patch adds a new CBFS "mcache" (metadata cache) -- a memory buffer that stores the headers of all CBFS files. Similar to the existing FMAP cache, this cache should reduce the amount of SPI accesses we need to do every boot: rather than having to re-read all CBFS headers from SPI flash every time we're looking for a file, we can just walk the same list in this in-memory copy and finally use it to directly access the flash at the right position for the file data. This patch adds the code to support the cache but doesn't enable it on any platform. The next one will turn it on by default. Change-Id: I5b1084bfdad1c6ab0ee1b143ed8dd796827f4c65 Signed-off-by: Julius Werner Reviewed-on: https://review.coreboot.org/c/coreboot/+/38423 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/commonlib/Makefile.inc | 7 + src/commonlib/bsd/cbfs_mcache.c | 143 +++++++++++++++++++++ src/commonlib/bsd/include/commonlib/bsd/cb_err.h | 1 + .../bsd/include/commonlib/bsd/cbfs_private.h | 21 +++ src/commonlib/include/commonlib/cbmem_id.h | 6 +- src/include/cbfs.h | 23 +++- src/include/memlayout.h | 3 + src/include/symbols.h | 1 + src/lib/Kconfig | 21 +++ src/lib/cbfs.c | 112 ++++++++++++++-- src/lib/coreboot_table.c | 11 +- src/security/vboot/vboot_common.h | 8 +- src/security/vboot/vboot_loader.c | 40 +++++- 13 files changed, 364 insertions(+), 33 deletions(-) create mode 100644 src/commonlib/bsd/cbfs_mcache.c diff --git a/src/commonlib/Makefile.inc b/src/commonlib/Makefile.inc index b2225cb114..1a38e4a89f 100644 --- a/src/commonlib/Makefile.inc +++ b/src/commonlib/Makefile.inc @@ -37,6 +37,13 @@ postcar-y += bsd/cbfs_private.c ramstage-y += bsd/cbfs_private.c smm-y += bsd/cbfs_private.c +bootblock-y += bsd/cbfs_mcache.c +verstage-y += bsd/cbfs_mcache.c +romstage-y += bsd/cbfs_mcache.c +postcar-y += bsd/cbfs_mcache.c +ramstage-y += bsd/cbfs_mcache.c +smm-y += bsd/cbfs_mcache.c + decompressor-y += bsd/lz4_wrapper.c bootblock-y += bsd/lz4_wrapper.c verstage-y += bsd/lz4_wrapper.c diff --git a/src/commonlib/bsd/cbfs_mcache.c b/src/commonlib/bsd/cbfs_mcache.c new file mode 100644 index 0000000000..f54b6631af --- /dev/null +++ b/src/commonlib/bsd/cbfs_mcache.c @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later */ + +#include +#include + +/* + * A CBFS metadata cache is an in memory data structure storing CBFS file headers (= metadata). + * It is defined by its start pointer and size. It contains a sequence of variable-length + * union mcache_entry entries. There is no overall header structure for the cache. + * + * Each mcache_entry is the raw metadata for a CBFS file (including attributes) in the same form + * as stored on flash (i.e. values in big-endian), except that the CBFS magic signature in the + * first 8 bytes ('LARCHIVE') is overwritten with mcache-internal bookkeeping data. The first 4 + * bytes are a magic number (MCACHE_MAGIC_FILE) and the next 4 bytes are the absolute offset in + * bytes on the cbfs_dev_t that this metadata blob was found at. (Note that depending on the + * implementation of cbfs_dev_t, this offset may still be relative to the start of a subregion + * of the underlying storage device.) + * + * The length of an mcache_entry (i.e. length of the underlying metadata blob) is encoded in the + * metadata (entry->file.h.offset). The next mcache_entry begins at the next + * CBFS_MCACHE_ALIGNMENT boundary after that. The cache is terminated by a special 4-byte + * mcache_entry that consists only of a magic number (MCACHE_MAGIC_END or MCACHE_MAGIC_FULL). + */ + +#define MCACHE_MAGIC_FILE 0x454c4946 /* 'FILE' */ +#define MCACHE_MAGIC_FULL 0x4c4c5546 /* 'FULL' */ +#define MCACHE_MAGIC_END 0x444e4524 /* '$END' */ + +union mcache_entry { + union cbfs_mdata file; + struct { /* These fields exactly overlap file.h.magic */ + uint32_t magic; + uint32_t offset; + }; +}; + +struct cbfs_mcache_build_args { + void *mcache; + void *end; + int count; +}; + +static cb_err_t build_walker(cbfs_dev_t dev, size_t offset, const union cbfs_mdata *mdata, + size_t already_read, void *arg) +{ + struct cbfs_mcache_build_args *args = arg; + union mcache_entry *entry = args->mcache; + const uint32_t data_offset = be32toh(mdata->h.offset); + + if (args->end - args->mcache < data_offset) + return CB_CBFS_CACHE_FULL; + + if (cbfs_copy_fill_metadata(args->mcache, mdata, already_read, dev, offset)) + return CB_CBFS_IO; + + entry->magic = MCACHE_MAGIC_FILE; + entry->offset = offset; + + args->mcache += ALIGN_UP(data_offset, CBFS_MCACHE_ALIGNMENT); + args->count++; + + return CB_CBFS_NOT_FOUND; +} + +cb_err_t cbfs_mcache_build(cbfs_dev_t dev, void *mcache, size_t size, + struct vb2_hash *metadata_hash) +{ + struct cbfs_mcache_build_args args = { + .mcache = mcache, + .end = mcache + ALIGN_DOWN(size, CBFS_MCACHE_ALIGNMENT) + - sizeof(uint32_t), /* leave space for terminating magic */ + .count = 0, + }; + + assert(size > sizeof(uint32_t) && IS_ALIGNED((uintptr_t)mcache, CBFS_MCACHE_ALIGNMENT)); + cb_err_t ret = cbfs_walk(dev, build_walker, &args, metadata_hash, 0); + union mcache_entry *entry = args.mcache; + if (ret == CB_CBFS_NOT_FOUND) { + ret = CB_SUCCESS; + entry->magic = MCACHE_MAGIC_END; + } else if (ret == CB_CBFS_CACHE_FULL) { + ERROR("mcache overflow, should increase CBFS_MCACHE size!\n"); + entry->magic = MCACHE_MAGIC_FULL; + } + + LOG("mcache @%p built for %d files, used %#zx of %#zx bytes\n", mcache, + args.count, args.mcache + sizeof(entry->magic) - mcache, size); + return ret; +} + +cb_err_t cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name, + union cbfs_mdata *mdata_out, size_t *data_offset_out) +{ + const size_t namesize = strlen(name) + 1; /* Count trailing \0 so we can memcmp() it. */ + const void *end = mcache + mcache_size; + const void *current = mcache; + + while (current + sizeof(uint32_t) < end) { + const union mcache_entry *entry = current; + + if (entry->magic == MCACHE_MAGIC_END) + return CB_CBFS_NOT_FOUND; + if (entry->magic == MCACHE_MAGIC_FULL) + return CB_CBFS_CACHE_FULL; + + assert(entry->magic == MCACHE_MAGIC_FILE); + const uint32_t data_offset = be32toh(entry->file.h.offset); + const uint32_t data_length = be32toh(entry->file.h.len); + if (namesize <= data_offset - offsetof(union cbfs_mdata, filename) && + memcmp(name, entry->file.filename, namesize) == 0) { + LOG("Found '%s' @%#x size %#x in mcache @%p\n", + name, entry->offset, data_length, current); + *data_offset_out = entry->offset + data_offset; + memcpy(mdata_out, &entry->file, data_offset); + return CB_SUCCESS; + } + + current += ALIGN_UP(data_offset, CBFS_MCACHE_ALIGNMENT); + } + + ERROR("CBFS mcache overflow!\n"); + return CB_ERR; +} + +size_t cbfs_mcache_real_size(const void *mcache, size_t mcache_size) +{ + const void *end = mcache + mcache_size; + const void *current = mcache; + + while (current + sizeof(uint32_t) < end) { + const union mcache_entry *entry = current; + + if (entry->magic == MCACHE_MAGIC_FULL || entry->magic == MCACHE_MAGIC_END) { + current += sizeof(entry->magic); + break; + } + + assert(entry->magic == MCACHE_MAGIC_FILE); + current += ALIGN_UP(be32toh(entry->file.h.offset), CBFS_MCACHE_ALIGNMENT); + } + + return current - mcache; +} diff --git a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h index e5aa852617..b61b956524 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cb_err.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cb_err.h @@ -39,6 +39,7 @@ enum cb_err { CB_CBFS_IO = -400, /**< Underlying I/O error */ CB_CBFS_NOT_FOUND = -401, /**< File not found in directory */ CB_CBFS_HASH_MISMATCH = -402, /**< Master hash validation failed */ + CB_CBFS_CACHE_FULL = -403, /**< Metadata cache overflowed */ }; /* Don't typedef the enum directly, so the size is unambiguous for serialization. */ diff --git a/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h b/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h index aaee62f4c3..64dcf9f5ba 100644 --- a/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h +++ b/src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h @@ -113,4 +113,25 @@ cb_err_t cbfs_copy_fill_metadata(union cbfs_mdata *dst, const union cbfs_mdata * cb_err_t cbfs_lookup(cbfs_dev_t dev, const char *name, union cbfs_mdata *mdata_out, size_t *data_offset_out, struct vb2_hash *metadata_hash); +/* Both base address and size of CBFS mcaches must be aligned to this value! */ +#define CBFS_MCACHE_ALIGNMENT sizeof(uint32_t) /* Largest data type used in CBFS */ + +/* Build an in-memory CBFS metadata cache out of the CBFS on |dev| into a |mcache_size| bytes + * memory area at |mcache|. Also verify |metadata_hash| unless it is NULL. If this returns + * CB_CBFS_CACHE_FULL, the mcache is still valid and can be used, but lookups may return + * CB_CBFS_CACHE_FULL for files that didn't fit to indicate that the caller needs to fall back + * to cbfs_lookup(). */ +cb_err_t cbfs_mcache_build(cbfs_dev_t dev, void *mcache, size_t mcache_size, + struct vb2_hash *metadata_hash); + +/* + * Find a file named |name| in a CBFS metadata cache and copy its metadata into |mdata_out|. + * Pass out offset to the file data (on the original CBFS device used for cbfs_mcache_build()). + */ +cb_err_t cbfs_mcache_lookup(const void *mcache, size_t mcache_size, const char *name, + union cbfs_mdata *mdata_out, size_t *data_offset_out); + +/* Returns the amount of bytes actually used by the CBFS metadata cache in |mcache|. */ +size_t cbfs_mcache_real_size(const void *mcache, size_t mcache_size); + #endif /* _COMMONLIB_BSD_CBFS_PRIVATE_H_ */ diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h index 6b4d60469e..ab7cf63843 100644 --- a/src/commonlib/include/commonlib/cbmem_id.h +++ b/src/commonlib/include/commonlib/cbmem_id.h @@ -67,6 +67,8 @@ #define CBMEM_ID_ROM2 0x524f4d32 #define CBMEM_ID_ROM3 0x524f4d33 #define CBMEM_ID_FMAP 0x464d4150 +#define CBMEM_ID_CBFS_RO_MCACHE 0x524d5346 +#define CBMEM_ID_CBFS_RW_MCACHE 0x574d5346 #define CBMEM_ID_FSP_LOGO 0x4c4f474f #define CBMEM_ID_SMM_COMBUFFER 0x53534d32 @@ -129,5 +131,7 @@ { CBMEM_ID_ROM1, "VGA ROM #1 "}, \ { CBMEM_ID_ROM2, "VGA ROM #2 "}, \ { CBMEM_ID_ROM3, "VGA ROM #3 "}, \ - { CBMEM_ID_FMAP, "FMAP "}, + { CBMEM_ID_FMAP, "FMAP "}, \ + { CBMEM_ID_CBFS_RO_MCACHE, "RO MCACHE "}, \ + { CBMEM_ID_CBFS_RW_MCACHE, "RW MCACHE "} #endif /* _CBMEM_ID_H_ */ diff --git a/src/include/cbfs.h b/src/include/cbfs.h index a35597d5b1..32ed7f899e 100644 --- a/src/include/cbfs.h +++ b/src/include/cbfs.h @@ -3,10 +3,10 @@ #ifndef _CBFS_H_ #define _CBFS_H_ +#include #include #include -#include -#include +#include /*********************************************** * Perform CBFS operations on the boot device. * @@ -42,8 +42,21 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset, /* Load stage into memory filling in prog. Return 0 on success. < 0 on error. */ int cbfs_prog_stage_load(struct prog *prog); -/* Returns the region device of the currently active CBFS. - Return < 0 on error, 0 on success. */ -int cbfs_boot_region_device(struct region_device *rdev); +struct cbfs_boot_device { + struct region_device rdev; + void *mcache; + size_t mcache_size; +}; + +/* Helper to fill out |mcache| and |mcache_size| in a cbfs_boot_device. */ +void cbfs_boot_device_find_mcache(struct cbfs_boot_device *cbd, uint32_t id); + +/* + * Retrieves the currently active CBFS boot device. If |force_ro| is set, will + * always return the read-only CBFS instead (this only makes a difference when + * CONFIG(VBOOT) is enabled). May perform certain CBFS initialization tasks. + * Returns NULL on error (e.g. boot device IO error). + */ +const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro); #endif diff --git a/src/include/memlayout.h b/src/include/memlayout.h index bd1d6846f0..bf830b7d24 100644 --- a/src/include/memlayout.h +++ b/src/include/memlayout.h @@ -71,6 +71,9 @@ _ = ASSERT(sz >= FMAP_SIZE, \ STR(FMAP does not fit in FMAP_CACHE! (sz < FMAP_SIZE))); +#define CBFS_MCACHE(addr, sz) \ + REGION(cbfs_mcache, addr, sz, 4) + #if ENV_ROMSTAGE_OR_BEFORE #define PRERAM_CBFS_CACHE(addr, size) \ REGION(preram_cbfs_cache, addr, size, 4) \ diff --git a/src/include/symbols.h b/src/include/symbols.h index 371d84bf9b..6fe24f5e44 100644 --- a/src/include/symbols.h +++ b/src/include/symbols.h @@ -33,6 +33,7 @@ DECLARE_REGION(stack) DECLARE_REGION(preram_cbfs_cache) DECLARE_REGION(postram_cbfs_cache) DECLARE_REGION(cbfs_cache) +DECLARE_REGION(cbfs_mcache) DECLARE_REGION(fmap_cache) DECLARE_REGION(tpm_tcpa_log) diff --git a/src/lib/Kconfig b/src/lib/Kconfig index d6e7e51d5c..ab2b9c59b9 100644 --- a/src/lib/Kconfig +++ b/src/lib/Kconfig @@ -80,3 +80,24 @@ config ESPI_DEBUG help This option enables eSPI library helper functions for displaying debug information. + +config NO_CBFS_MCACHE + bool + default y + help + Disables the CBFS metadata cache. This means that your platform does + not need to provide a CBFS_MCACHE section in memlayout and can save + the associated CAR/SRAM size. In that case every single CBFS file + lookup must re-read the same CBFS directory entries from flash to find + the respective file. + +config CBFS_MCACHE_RW_PERCENTAGE + int + depends on VBOOT && !NO_CBFS_MCACHE + default 25 if CHROMEOS # Chrome OS stores many L10n files in RO only + default 50 + help + The amount of the CBFS_MCACHE area that's used for the RW CBFS, in + percent from 0 to 100. The remaining area will be used for the RO + CBFS. Default is an even 50/50 split. When VBOOT is disabled, this + will automatically be 0 (meaning the whole MCACHE is used for RO). diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index 447d91f1be..3b7d4292d0 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -16,22 +17,33 @@ #include #include -int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type) +static cb_err_t cbfs_boot_lookup(const struct cbfs_boot_device *cbd, + const char *name, union cbfs_mdata *mdata, size_t *data_offset) { - struct region_device rdev; + cb_err_t err = CB_CBFS_CACHE_FULL; + if (!CONFIG(NO_CBFS_MCACHE) && !ENV_SMM) + err = cbfs_mcache_lookup(cbd->mcache, cbd->mcache_size, + name, mdata, data_offset); + if (err == CB_CBFS_CACHE_FULL) + err = cbfs_lookup(&cbd->rdev, name, mdata, data_offset, NULL); + return err; +} - if (cbfs_boot_region_device(&rdev)) +int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type) +{ + const struct cbfs_boot_device *cbd = cbfs_get_boot_device(false); + if (!cbd) return -1; size_t data_offset; - cb_err_t err = cbfs_lookup(&rdev, name, &fh->mdata, &data_offset, NULL); + cb_err_t err = cbfs_boot_lookup(cbd, name, &fh->mdata, &data_offset); if (CONFIG(VBOOT_ENABLE_CBFS_FALLBACK) && err == CB_CBFS_NOT_FOUND) { printk(BIOS_INFO, "CBFS: Fall back to RO region for %s\n", name); - if (fmap_locate_area_as_rdev("COREBOOT", &rdev)) + if (!(cbd = cbfs_get_boot_device(true))) return -1; - err = cbfs_lookup(&rdev, name, &fh->mdata, &data_offset, NULL); + err = cbfs_boot_lookup(cbd, name, &fh->mdata, &data_offset); } if (err) return -1; @@ -39,7 +51,8 @@ int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type) size_t msize = be32toh(fh->mdata.h.offset); if (rdev_chain(&fh->metadata, &addrspace_32bit.rdev, (uintptr_t)&fh->mdata, msize) || - rdev_chain(&fh->data, &rdev, data_offset, be32toh(fh->mdata.h.len))) + rdev_chain(&fh->data, &cbd->rdev, data_offset, + be32toh(fh->mdata.h.len))) return -1; if (type) { if (!*type) @@ -333,9 +346,86 @@ out: return 0; } -int cbfs_boot_region_device(struct region_device *rdev) +void cbfs_boot_device_find_mcache(struct cbfs_boot_device *cbd, uint32_t id) +{ + if (CONFIG(NO_CBFS_MCACHE) || ENV_SMM) + return; + + const struct cbmem_entry *entry; + if (cbmem_possibly_online() && + (entry = cbmem_entry_find(id))) { + cbd->mcache = cbmem_entry_start(entry); + cbd->mcache_size = cbmem_entry_size(entry); + } else if (ENV_ROMSTAGE_OR_BEFORE) { + u8 *boundary = _ecbfs_mcache - REGION_SIZE(cbfs_mcache) * + CONFIG_CBFS_MCACHE_RW_PERCENTAGE / 100; + boundary = (u8 *)ALIGN_DOWN((uintptr_t)boundary, + CBFS_MCACHE_ALIGNMENT); + if (id == CBMEM_ID_CBFS_RO_MCACHE) { + cbd->mcache = _cbfs_mcache; + cbd->mcache_size = boundary - _cbfs_mcache; + } else if (id == CBMEM_ID_CBFS_RW_MCACHE) { + cbd->mcache = boundary; + cbd->mcache_size = _ecbfs_mcache - boundary; + } + } +} + +const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro) +{ + static struct cbfs_boot_device ro; + + /* Ensure we always init RO mcache, even if first file is from RW. + Otherwise it may not be available when needed in later stages. */ + if (ENV_INITIAL_STAGE && !force_ro && !region_device_sz(&ro.rdev)) + cbfs_get_boot_device(true); + + if (!force_ro) { + const struct cbfs_boot_device *rw = vboot_get_cbfs_boot_device(); + /* This will return NULL if vboot isn't enabled, didn't run yet + or decided to boot into recovery mode. */ + if (rw) + return rw; + } + + if (region_device_sz(&ro.rdev)) + return &ro; + + if (fmap_locate_area_as_rdev("COREBOOT", &ro.rdev)) + return NULL; + + cbfs_boot_device_find_mcache(&ro, CBMEM_ID_CBFS_RO_MCACHE); + + if (ENV_INITIAL_STAGE && !CONFIG(NO_CBFS_MCACHE)) { + cb_err_t err = cbfs_mcache_build(&ro.rdev, ro.mcache, + ro.mcache_size, NULL); + if (err && err != CB_CBFS_CACHE_FULL) + die("Failed to build RO mcache"); + } + + return &ro; +} + +#if !CONFIG(NO_CBFS_MCACHE) +static void mcache_to_cbmem(const struct cbfs_boot_device *cbd, u32 cbmem_id) +{ + if (!cbd) + return; + + size_t real_size = cbfs_mcache_real_size(cbd->mcache, cbd->mcache_size); + void *cbmem_mcache = cbmem_add(cbmem_id, real_size); + if (!cbmem_mcache) { + printk(BIOS_ERR, "ERROR: Cannot allocate CBMEM mcache %#x (%#zx bytes)!\n", + cbmem_id, real_size); + return; + } + memcpy(cbmem_mcache, cbd->mcache, real_size); +} + +static void cbfs_mcache_migrate(int unused) { - boot_device_init(); - return vboot_locate_cbfs(rdev) && - fmap_locate_area_as_rdev("COREBOOT", rdev); + mcache_to_cbmem(vboot_get_cbfs_boot_device(), CBMEM_ID_CBFS_RW_MCACHE); + mcache_to_cbmem(cbfs_get_boot_device(true), CBMEM_ID_CBFS_RO_MCACHE); } +ROMSTAGE_CBMEM_INIT_HOOK(cbfs_mcache_migrate) +#endif diff --git a/src/lib/coreboot_table.c b/src/lib/coreboot_table.c index 69ded3c700..4cbf3c742e 100644 --- a/src/lib/coreboot_table.c +++ b/src/lib/coreboot_table.c @@ -220,11 +220,8 @@ static void lb_boot_media_params(struct lb_header *header) { struct lb_boot_media_params *bmp; const struct region_device *boot_dev; - struct region_device cbfs_dev; - - boot_device_init(); - - if (cbfs_boot_region_device(&cbfs_dev)) + const struct cbfs_boot_device *cbd = cbfs_get_boot_device(false); + if (!cbd) return; boot_dev = boot_device_ro(); @@ -235,8 +232,8 @@ static void lb_boot_media_params(struct lb_header *header) bmp->tag = LB_TAG_BOOT_MEDIA_PARAMS; bmp->size = sizeof(*bmp); - bmp->cbfs_offset = region_device_offset(&cbfs_dev); - bmp->cbfs_size = region_device_sz(&cbfs_dev); + bmp->cbfs_offset = region_device_offset(&cbd->rdev); + bmp->cbfs_size = region_device_sz(&cbd->rdev); bmp->boot_media_size = region_device_sz(boot_dev); bmp->fmap_offset = get_fmap_flash_offset(); diff --git a/src/security/vboot/vboot_common.h b/src/security/vboot/vboot_common.h index e64f6632a7..512da0e91f 100644 --- a/src/security/vboot/vboot_common.h +++ b/src/security/vboot/vboot_common.h @@ -3,6 +3,7 @@ #define __VBOOT_VBOOT_COMMON_H__ #include +#include #include /* @@ -50,14 +51,17 @@ int vboot_developer_mode_enabled(void); int vboot_recovery_mode_enabled(void); int vboot_can_enable_udc(void); void vboot_run_logic(void); -int vboot_locate_cbfs(struct region_device *rdev); +const struct cbfs_boot_device *vboot_get_cbfs_boot_device(void); #else /* !CONFIG_VBOOT */ static inline int vboot_developer_mode_enabled(void) { return 0; } static inline int vboot_recovery_mode_enabled(void) { return 0; } /* If VBOOT is not enabled, we are okay enabling USB device controller (UDC). */ static inline int vboot_can_enable_udc(void) { return 1; } static inline void vboot_run_logic(void) {} -static inline int vboot_locate_cbfs(struct region_device *rdev) { return -1; } +static inline const struct cbfs_boot_device *vboot_get_cbfs_boot_device(void) +{ + return NULL; +} #endif void vboot_save_data(struct vb2_context *ctx); diff --git a/src/security/vboot/vboot_loader.c b/src/security/vboot/vboot_loader.c index bca4c3e3b7..9c6e56e9af 100644 --- a/src/security/vboot/vboot_loader.c +++ b/src/security/vboot/vboot_loader.c @@ -1,6 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include +#include +#include #include #include #include @@ -22,12 +25,27 @@ _Static_assert(!CONFIG(VBOOT_RETURN_FROM_VERSTAGE) || int vboot_executed; +static void build_rw_mcache(void) +{ + if (CONFIG(NO_CBFS_MCACHE)) + return; + + const struct cbfs_boot_device *cbd = vboot_get_cbfs_boot_device(); + if (!cbd) /* Don't build RW mcache in recovery mode. */ + return; + cb_err_t err = cbfs_mcache_build(&cbd->rdev, cbd->mcache, + cbd->mcache_size, NULL); + if (err && err != CB_CBFS_CACHE_FULL) + die("Failed to build RW mcache."); /* TODO: -> recovery? */ +} + void vboot_run_logic(void) { if (verification_should_run()) { /* Note: this path is not used for VBOOT_RETURN_FROM_VERSTAGE */ verstage_main(); vboot_executed = 1; + build_rw_mcache(); } else if (verstage_should_load()) { struct cbfsf file; struct prog verstage = @@ -55,21 +73,29 @@ void vboot_run_logic(void) return; vboot_executed = 1; + build_rw_mcache(); } } -int vboot_locate_cbfs(struct region_device *rdev) +const struct cbfs_boot_device *vboot_get_cbfs_boot_device(void) { - struct vb2_context *ctx; - /* Don't honor vboot results until the vboot logic has run. */ if (!vboot_logic_executed()) - return -1; + return NULL; - ctx = vboot_get_context(); + static struct cbfs_boot_device cbd; + if (region_device_sz(&cbd.rdev)) + return &cbd; + struct vb2_context *ctx = vboot_get_context(); if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) - return -1; + return NULL; + + boot_device_init(); + if (vboot_locate_firmware(ctx, &cbd.rdev)) + return NULL; + + cbfs_boot_device_find_mcache(&cbd, CBMEM_ID_CBFS_RW_MCACHE); - return vboot_locate_firmware(ctx, rdev); + return &cbd; } -- cgit v1.2.3