aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commonlib/Makefile.inc7
-rw-r--r--src/commonlib/bsd/cbfs_mcache.c143
-rw-r--r--src/commonlib/bsd/include/commonlib/bsd/cb_err.h1
-rw-r--r--src/commonlib/bsd/include/commonlib/bsd/cbfs_private.h21
-rw-r--r--src/commonlib/include/commonlib/cbmem_id.h6
-rw-r--r--src/include/cbfs.h23
-rw-r--r--src/include/memlayout.h3
-rw-r--r--src/include/symbols.h1
-rw-r--r--src/lib/Kconfig21
-rw-r--r--src/lib/cbfs.c112
-rw-r--r--src/lib/coreboot_table.c11
-rw-r--r--src/security/vboot/vboot_common.h8
-rw-r--r--src/security/vboot/vboot_loader.c40
13 files changed, 364 insertions, 33 deletions
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 <assert.h>
+#include <commonlib/bsd/cbfs_private.h>
+
+/*
+ * 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 <cbmem.h>
#include <commonlib/cbfs.h>
#include <program_loading.h>
-#include <stddef.h>
-#include <stdint.h>
+#include <types.h>
/***********************************************
* 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 <assert.h>
#include <boot_device.h>
#include <cbfs.h>
+#include <cbmem.h>
#include <commonlib/bsd/cbfs_private.h>
#include <commonlib/bsd/compression.h>
#include <commonlib/endian.h>
@@ -16,22 +17,33 @@
#include <symbols.h>
#include <timestamp.h>
-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 <commonlib/region.h>
+#include <cbfs.h>
#include <vb2_api.h>
/*
@@ -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 <boot_device.h>
#include <cbfs.h>
+#include <cbmem.h>
+#include <commonlib/bsd/cbfs_private.h>
#include <console/console.h>
#include <ec/google/chromeec/ec.h>
#include <rmodule.h>
@@ -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;
}