cbfs: Pull handling of the CBFS_CACHE mem_pool into CBFS core

This patch pulls control of the memory pool serving allocations from the
CBFS_CACHE memlayout area into cbfs.c and makes it a core part of the
CBFS API. Previously, platforms would independently instantiate this as
part of boot_device_ro() (mostly through cbfs_spi.c). The new cbfs_cache
pool is exported as a global so these platforms can still use it to
directly back rdev_mmap() on their boot device, but the cbfs_cache can
now also use it to directly make allocations itself. This is used to
allow transparent decompression support in cbfs_map().

Signed-off-by: Julius Werner <jwerner@chromium.org>
Change-Id: I0d52b6a8f582a81a19fd0fd663bb89eab55a49d9
Reviewed-on: https://review.coreboot.org/c/coreboot/+/49333
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Julius Werner 2020-12-30 17:30:12 -08:00
parent 11075fc80e
commit 9b1f3cc6fb
10 changed files with 89 additions and 49 deletions

View File

@ -5,6 +5,7 @@ verstage-y += mem_pool.c
romstage-y += mem_pool.c romstage-y += mem_pool.c
ramstage-y += mem_pool.c ramstage-y += mem_pool.c
postcar-y += mem_pool.c postcar-y += mem_pool.c
smm-y += mem_pool.c
bootblock-y += iobuf.c bootblock-y += iobuf.c
verstage-y += iobuf.c verstage-y += iobuf.c

View File

@ -196,18 +196,16 @@ extern const struct region_device_ops mem_rdev_rw_ops;
MEM_REGION_DEV_INIT(base_, size_, &mem_rdev_rw_ops) \ MEM_REGION_DEV_INIT(base_, size_, &mem_rdev_rw_ops) \
struct mmap_helper_region_device { struct mmap_helper_region_device {
struct mem_pool pool; struct mem_pool *pool;
struct region_device rdev; struct region_device rdev;
}; };
#define MMAP_HELPER_REGION_INIT(ops_, offset_, size_) \ #define MMAP_HELPER_DEV_INIT(ops_, offset_, size_, mpool_) \
{ \ { \
.rdev = REGION_DEV_INIT((ops_), (offset_), (size_)), \ .rdev = REGION_DEV_INIT((ops_), (offset_), (size_)), \
.pool = (mpool_), \
} }
void mmap_helper_device_init(struct mmap_helper_region_device *mdev,
void *cache, size_t cache_size);
void *mmap_helper_rdev_mmap(const struct region_device *, size_t, size_t); void *mmap_helper_rdev_mmap(const struct region_device *, size_t, size_t);
int mmap_helper_rdev_munmap(const struct region_device *, void *); int mmap_helper_rdev_munmap(const struct region_device *, void *);

View File

@ -287,12 +287,6 @@ const struct region_device_ops mem_rdev_rw_ops = {
.eraseat = mdev_eraseat, .eraseat = mdev_eraseat,
}; };
void mmap_helper_device_init(struct mmap_helper_region_device *mdev,
void *cache, size_t cache_size)
{
mem_pool_init(&mdev->pool, cache, cache_size);
}
void *mmap_helper_rdev_mmap(const struct region_device *rd, size_t offset, void *mmap_helper_rdev_mmap(const struct region_device *rd, size_t offset,
size_t size) size_t size)
{ {
@ -301,13 +295,13 @@ void *mmap_helper_rdev_mmap(const struct region_device *rd, size_t offset,
mdev = container_of((void *)rd, __typeof__(*mdev), rdev); mdev = container_of((void *)rd, __typeof__(*mdev), rdev);
mapping = mem_pool_alloc(&mdev->pool, size); mapping = mem_pool_alloc(mdev->pool, size);
if (mapping == NULL) if (mapping == NULL)
return NULL; return NULL;
if (rd->ops->readat(rd, mapping, offset, size) != size) { if (rd->ops->readat(rd, mapping, offset, size) != size) {
mem_pool_free(&mdev->pool, mapping); mem_pool_free(mdev->pool, mapping);
return NULL; return NULL;
} }
@ -320,7 +314,7 @@ int mmap_helper_rdev_munmap(const struct region_device *rd, void *mapping)
mdev = container_of((void *)rd, __typeof__(*mdev), rdev); mdev = container_of((void *)rd, __typeof__(*mdev), rdev);
mem_pool_free(&mdev->pool, mapping); mem_pool_free(mdev->pool, mapping);
return 0; return 0;
} }

View File

@ -7,6 +7,7 @@
*/ */
#include <boot_device.h> #include <boot_device.h>
#include <cbfs.h>
#include <console/console.h> #include <console/console.h>
#include <spi_flash.h> #include <spi_flash.h>
#include <symbols.h> #include <symbols.h>
@ -77,21 +78,7 @@ static const struct region_device_ops spi_ops = {
}; };
static struct mmap_helper_region_device mdev = static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&spi_ops, 0, CONFIG_ROM_SIZE); MMAP_HELPER_DEV_INIT(&spi_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
static void switch_to_postram_cache(int unused)
{
/*
* Call boot_device_init() to ensure spi_flash is initialized before
* backing mdev with postram cache. This prevents the mdev backing from
* being overwritten if spi_flash was not accessed before dram was up.
*/
boot_device_init();
if (_preram_cbfs_cache != _postram_cbfs_cache)
mmap_helper_device_init(&mdev, _postram_cbfs_cache,
REGION_SIZE(postram_cbfs_cache));
}
ROMSTAGE_CBMEM_INIT_HOOK(switch_to_postram_cache);
void boot_device_init(void) void boot_device_init(void)
{ {
@ -105,8 +92,6 @@ void boot_device_init(void)
return; return;
spi_flash_init_done = true; spi_flash_init_done = true;
mmap_helper_device_init(&mdev, _cbfs_cache, REGION_SIZE(cbfs_cache));
} }
/* Return the CBFS boot device. */ /* Return the CBFS boot device. */

View File

@ -5,6 +5,7 @@
#include <cbmem.h> #include <cbmem.h>
#include <commonlib/cbfs.h> #include <commonlib/cbfs.h>
#include <commonlib/mem_pool.h>
#include <program_loading.h> #include <program_loading.h>
#include <types.h> #include <types.h>
#include <vb2_sha.h> #include <vb2_sha.h>
@ -26,7 +27,7 @@ static inline void *cbfs_ro_map(const char *name, size_t *size_out);
/* Removes a previously allocated CBFS mapping. Should try to unmap mappings in strict LIFO /* Removes a previously allocated CBFS mapping. Should try to unmap mappings in strict LIFO
order where possible, since mapping backends often don't support more complicated cases. */ order where possible, since mapping backends often don't support more complicated cases. */
int cbfs_unmap(void *mapping); void cbfs_unmap(void *mapping);
/* Load a file from CBFS into a buffer. Returns amount of loaded bytes on success or 0 on error. /* Load a file from CBFS into a buffer. Returns amount of loaded bytes on success or 0 on error.
File will get decompressed as necessary. */ File will get decompressed as necessary. */
@ -38,10 +39,21 @@ static inline size_t cbfs_ro_load(const char *name, void *buf, size_t buf_size);
/* Load stage into memory filling in prog. Return 0 on success. < 0 on error. */ /* Load stage into memory filling in prog. Return 0 on success. < 0 on error. */
int cbfs_prog_stage_load(struct prog *prog); int cbfs_prog_stage_load(struct prog *prog);
/********************************************************************************************** /**********************************************************************************************
* BOOT DEVICE HELPER APIs * * BOOT DEVICE HELPER APIs *
**********************************************************************************************/ **********************************************************************************************/
/*
* The shared memory pool for backing mapped CBFS files, and other CBFS allocation needs.
* On x86 platforms, this would only be needed to transparently map compressed files, but it
* would require a permanent CBMEM carveout to be safe to use during S3 resume. Since it's not
* clear whether this feature is necessary or worth the wasted memory, it is currently disabled
* but could be added behind a Kconfig later if desired.
*/
#define CBFS_CACHE_AVAILABLE (!CONFIG(ARCH_X86))
extern struct mem_pool cbfs_cache;
/* /*
* Data structure that represents "a" CBFS boot device, with optional metadata cache. Generally * Data structure that represents "a" CBFS boot device, with optional metadata cache. Generally
* we only have one of these, or two (RO and RW) when CONFIG(VBOOT) is set. The region device * we only have one of these, or two (RO and RW) when CONFIG(VBOOT) is set. The region device
@ -95,6 +107,7 @@ void *cbfs_boot_map_optionrom_revision(uint16_t vendor, uint16_t device, uint8_t
size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset, size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
size_t in_size, void *buffer, size_t buffer_size, uint32_t compression); size_t in_size, void *buffer, size_t buffer_size, uint32_t compression);
/********************************************************************************************** /**********************************************************************************************
* INTERNAL HELPERS FOR INLINES, DO NOT USE. * * INTERNAL HELPERS FOR INLINES, DO NOT USE. *
**********************************************************************************************/ **********************************************************************************************/

View File

@ -32,9 +32,9 @@ DECLARE_OPTIONAL_REGION(timestamp)
DECLARE_REGION(preram_cbmem_console) DECLARE_REGION(preram_cbmem_console)
DECLARE_REGION(cbmem_init_hooks) DECLARE_REGION(cbmem_init_hooks)
DECLARE_REGION(stack) DECLARE_REGION(stack)
DECLARE_REGION(preram_cbfs_cache) DECLARE_OPTIONAL_REGION(preram_cbfs_cache)
DECLARE_REGION(postram_cbfs_cache) DECLARE_OPTIONAL_REGION(postram_cbfs_cache)
DECLARE_REGION(cbfs_cache) DECLARE_OPTIONAL_REGION(cbfs_cache)
DECLARE_REGION(cbfs_mcache) DECLARE_REGION(cbfs_mcache)
DECLARE_REGION(fmap_cache) DECLARE_REGION(fmap_cache)
DECLARE_REGION(tpm_tcpa_log) DECLARE_REGION(tpm_tcpa_log)

View File

@ -18,6 +18,18 @@
#include <symbols.h> #include <symbols.h>
#include <timestamp.h> #include <timestamp.h>
#if CBFS_CACHE_AVAILABLE
struct mem_pool cbfs_cache = MEM_POOL_INIT(_cbfs_cache, REGION_SIZE(cbfs_cache));
static void switch_to_postram_cache(int unused)
{
if (_preram_cbfs_cache != _postram_cbfs_cache)
mem_pool_init(&cbfs_cache, _postram_cbfs_cache,
REGION_SIZE(postram_cbfs_cache));
}
ROMSTAGE_CBMEM_INIT_HOOK(switch_to_postram_cache);
#endif
cb_err_t cbfs_boot_lookup(const char *name, bool force_ro, cb_err_t cbfs_boot_lookup(const char *name, bool force_ro,
union cbfs_mdata *mdata, struct region_device *rdev) union cbfs_mdata *mdata, struct region_device *rdev)
{ {
@ -101,14 +113,48 @@ void *_cbfs_map(const char *name, size_t *size_out, bool force_ro)
if (size_out != NULL) if (size_out != NULL)
*size_out = region_device_sz(&rdev); *size_out = region_device_sz(&rdev);
return rdev_mmap_full(&rdev); uint32_t compression = CBFS_COMPRESS_NONE;
const struct cbfs_file_attr_compression *attr = cbfs_find_attr(&mdata,
CBFS_FILE_ATTR_TAG_COMPRESSION, sizeof(*attr));
if (attr)
compression = be32toh(attr->compression);
if (compression == CBFS_COMPRESS_NONE)
return rdev_mmap_full(&rdev);
if (!CBFS_CACHE_AVAILABLE) {
ERROR("Cannot map compressed file %s on x86\n", mdata.h.filename);
return NULL;
}
size_t size = be32toh(attr->decompressed_size);
void *buf = mem_pool_alloc(&cbfs_cache, size);
if (!buf) {
ERROR("CBFS cache out of memory when mapping %s\n", mdata.h.filename);
return NULL;
}
size = cbfs_load_and_decompress(&rdev, 0, region_device_sz(&rdev), buf, size,
compression);
if (!size)
return NULL;
if (size_out != NULL)
*size_out = size;
return buf;
} }
int cbfs_unmap(void *mapping) void cbfs_unmap(void *mapping)
{ {
/* This works because munmap() only works on the root rdev and never cares about which /*
chained subregion something was mapped from. */ * This is save to call with mappings that weren't allocated in the cache (e.g. x86
return rdev_munmap(boot_device_ro(), mapping); * direct mappings) -- mem_pool_free() just does nothing for addresses it doesn't
* recognize. This hardcodes the assumption that if platforms implement an rdev_mmap()
* that requires a free() for the boot_device, they need to implement it via the
* cbfs_cache mem_pool.
*/
if (CBFS_CACHE_AVAILABLE)
mem_pool_free(&cbfs_cache, mapping);
} }
int cbfs_locate_file_in_region(struct cbfsf *fh, const char *region_name, int cbfs_locate_file_in_region(struct cbfsf *fh, const char *region_name,
@ -158,6 +204,9 @@ static inline bool cbfs_lz4_enabled(void)
if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) && !CONFIG(COMPRESS_PRERAM_STAGES)) if ((ENV_BOOTBLOCK || ENV_SEPARATE_VERSTAGE) && !CONFIG(COMPRESS_PRERAM_STAGES))
return false; return false;
if (ENV_SMM)
return false;
return true; return true;
} }
@ -174,6 +223,8 @@ static inline bool cbfs_lzma_enabled(void)
return false; return false;
if ((ENV_ROMSTAGE || ENV_POSTCAR) && !CONFIG(COMPRESS_RAMSTAGE)) if ((ENV_ROMSTAGE || ENV_POSTCAR) && !CONFIG(COMPRESS_RAMSTAGE))
return false; return false;
if (ENV_SMM)
return false;
return true; return true;
} }

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
#include <boot_device.h> #include <boot_device.h>
#include <cbfs.h>
#include <symbols.h> #include <symbols.h>
#include <device/mmio.h> #include <device/mmio.h>
#include <soc/addressmap.h> #include <soc/addressmap.h>
@ -42,7 +43,7 @@ static const struct region_device_ops unleashed_sd_ops = {
}; };
static struct mmap_helper_region_device sd_mdev = static struct mmap_helper_region_device sd_mdev =
MMAP_HELPER_REGION_INIT(&unleashed_sd_ops, 0, CONFIG_ROM_SIZE); MMAP_HELPER_DEV_INIT(&unleashed_sd_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
const struct region_device *boot_device_ro(void) const struct region_device *boot_device_ro(void)
{ {
@ -79,8 +80,6 @@ void boot_device_init(void)
} }
if (MSEL_SPI2SD(m)) { if (MSEL_SPI2SD(m)) {
spi_sdcard_init(&card, 2, 0); spi_sdcard_init(&card, 2, 0);
mmap_helper_device_init(&sd_mdev,
_cbfs_cache, REGION_SIZE(cbfs_cache));
return; return;
} }
die("Wrong configuration of MSEL\n"); die("Wrong configuration of MSEL\n");

View File

@ -2,6 +2,8 @@
#include <device/mmio.h> #include <device/mmio.h>
#include <assert.h> #include <assert.h>
#include <boot_device.h>
#include <cbfs.h>
#include <commonlib/region.h> #include <commonlib/region.h>
#include <console/console.h> #include <console/console.h>
#include <soc/clk.h> #include <soc/clk.h>
@ -160,13 +162,11 @@ static const struct region_device_ops exynos_spi_ops = {
}; };
static struct mmap_helper_region_device mdev = static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE); MMAP_HELPER_DEV_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
void exynos_init_spi_boot_device(void) void exynos_init_spi_boot_device(void)
{ {
boot_slave_regs = (void *)EXYNOS5_SPI1_BASE; boot_slave_regs = (void *)EXYNOS5_SPI1_BASE;
mmap_helper_device_init(&mdev, _cbfs_cache, REGION_SIZE(cbfs_cache));
} }
const struct region_device *exynos_spi_boot_device(void) const struct region_device *exynos_spi_boot_device(void)

View File

@ -2,6 +2,7 @@
#include <device/mmio.h> #include <device/mmio.h>
#include <assert.h> #include <assert.h>
#include <cbfs.h>
#include <console/console.h> #include <console/console.h>
#include <soc/cpu.h> #include <soc/cpu.h>
#include <soc/spi.h> #include <soc/spi.h>
@ -268,13 +269,11 @@ static const struct region_device_ops exynos_spi_ops = {
}; };
static struct mmap_helper_region_device mdev = static struct mmap_helper_region_device mdev =
MMAP_HELPER_REGION_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE); MMAP_HELPER_DEV_INIT(&exynos_spi_ops, 0, CONFIG_ROM_SIZE, &cbfs_cache);
void exynos_init_spi_boot_device(void) void exynos_init_spi_boot_device(void)
{ {
boot_slave = &exynos_spi_slaves[1]; boot_slave = &exynos_spi_slaves[1];
mmap_helper_device_init(&mdev, _cbfs_cache, REGION_SIZE(cbfs_cache));
} }
const struct region_device *exynos_spi_boot_device(void) const struct region_device *exynos_spi_boot_device(void)