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 <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/38423
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Julius Werner
2019-12-11 17:09:39 -08:00
committed by Philipp Deppenwiese
parent 7d11513ab3
commit 1e37c9ca46
13 changed files with 364 additions and 33 deletions

View File

@@ -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).

View File

@@ -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>
static cb_err_t cbfs_boot_lookup(const struct cbfs_boot_device *cbd,
const char *name, union cbfs_mdata *mdata, size_t *data_offset)
{
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;
}
int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type)
{
struct region_device rdev;
if (cbfs_boot_region_device(&rdev))
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)
{
boot_device_init();
return vboot_locate_cbfs(rdev) &&
fmap_locate_area_as_rdev("COREBOOT", rdev);
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)
{
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

View File

@@ -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();