cbfs: Introduce cbfs_ro_map() and cbfs_ro_load()

This patch introduces two new CBFS API functions which are equivalent to
cbfs_map() and cbfs_load(), respectively, with the difference that they
always operate on the read-only CBFS region ("COREBOOT" FMAP section).
Use it to replace some of the simple cases that needed to use
cbfs_locate_file_in_region().

Change-Id: I9c55b022b6502a333a9805ab0e4891dd7b97ef7f
Signed-off-by: Julius Werner <jwerner@chromium.org>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/39306
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Patrick Georgi <pgeorgi@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Julius Werner 2020-01-22 18:00:18 -08:00
parent 8c99c27df1
commit 9d0cc2aea9
6 changed files with 61 additions and 93 deletions

View File

@ -49,36 +49,28 @@ static enum cb_err get_cmos_value(unsigned long bit, unsigned long length,
return CB_SUCCESS;
}
static enum cb_err locate_cmos_layout(struct region_device *rdev)
static struct cmos_option_table *get_cmos_layout(void)
{
uint32_t cbfs_type = CBFS_COMPONENT_CMOS_LAYOUT;
static struct cbfsf fh;
static struct cmos_option_table *ct = NULL;
/*
* In case VBOOT is enabled and this function is called from SMM,
* we have multiple CMOS layout files and to locate them we'd need to
* include VBOOT into SMM...
*
* Support only one CMOS layout in the 'COREBOOT' region for now.
* Support only one CMOS layout in the RO CBFS for now.
*/
if (!region_device_sz(&(fh.data))) {
if (cbfs_locate_file_in_region(&fh, "COREBOOT", "cmos_layout.bin",
&cbfs_type)) {
if (!ct)
ct = cbfs_ro_map("cmos_layout.bin", NULL);
if (!ct)
printk(BIOS_ERR, "RTC: cmos_layout.bin could not be found. "
"Options are disabled\n");
return CB_CMOS_LAYOUT_NOT_FOUND;
}
}
cbfs_file_data(rdev, &fh);
return CB_SUCCESS;
return ct;
}
enum cb_err cmos_get_option(void *dest, const char *name)
{
struct cmos_option_table *ct;
struct region_device rdev;
struct cmos_entries *ce;
size_t namelen;
int found = 0;
@ -86,16 +78,9 @@ enum cb_err cmos_get_option(void *dest, const char *name)
/* Figure out how long name is */
namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
if (locate_cmos_layout(&rdev) != CB_SUCCESS) {
ct = get_cmos_layout();
if (!ct)
return CB_CMOS_LAYOUT_NOT_FOUND;
}
ct = rdev_mmap_full(&rdev);
if (!ct) {
printk(BIOS_ERR, "RTC: cmos_layout.bin could not be mapped. "
"Options are disabled\n");
return CB_CMOS_LAYOUT_NOT_FOUND;
}
/* find the requested entry record */
ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length);
@ -108,19 +93,15 @@ enum cb_err cmos_get_option(void *dest, const char *name)
}
if (!found) {
printk(BIOS_DEBUG, "No CMOS option '%s'.\n", name);
rdev_munmap(&rdev, ct);
return CB_CMOS_OPTION_NOT_FOUND;
}
if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, LB_CKS_LOC)) {
rdev_munmap(&rdev, ct);
if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, LB_CKS_LOC))
return CB_CMOS_CHECKSUM_INVALID;
}
if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS) {
rdev_munmap(&rdev, ct);
if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS)
return CB_CMOS_ACCESS_ERROR;
}
rdev_munmap(&rdev, ct);
return CB_SUCCESS;
}
@ -168,7 +149,6 @@ static enum cb_err set_cmos_value(unsigned long bit, unsigned long length,
enum cb_err cmos_set_option(const char *name, void *value)
{
struct cmos_option_table *ct;
struct region_device rdev;
struct cmos_entries *ce;
unsigned long length;
size_t namelen;
@ -177,16 +157,9 @@ enum cb_err cmos_set_option(const char *name, void *value)
/* Figure out how long name is */
namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
if (locate_cmos_layout(&rdev) != CB_SUCCESS) {
ct = get_cmos_layout();
if (!ct)
return CB_CMOS_LAYOUT_NOT_FOUND;
}
ct = rdev_mmap_full(&rdev);
if (!ct) {
printk(BIOS_ERR, "RTC: cmos_layout.bin could not be mapped. "
"Options are disabled\n");
return CB_CMOS_LAYOUT_NOT_FOUND;
}
/* find the requested entry record */
ce = (struct cmos_entries *)((unsigned char *)ct + ct->header_length);
@ -199,7 +172,6 @@ enum cb_err cmos_set_option(const char *name, void *value)
}
if (!found) {
printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name);
rdev_munmap(&rdev, ct);
return CB_CMOS_OPTION_NOT_FOUND;
}
@ -208,18 +180,13 @@ enum cb_err cmos_set_option(const char *name, void *value)
length = MAX(strlen((const char *)value) * 8, ce->length - 8);
/* make sure the string is null terminated */
if (set_cmos_value(ce->bit + ce->length - 8, 8, &(u8[]){0})
!= CB_SUCCESS) {
rdev_munmap(&rdev, ct);
return CB_CMOS_ACCESS_ERROR;
}
}
if (set_cmos_value(ce->bit, length, value) != CB_SUCCESS) {
rdev_munmap(&rdev, ct);
!= CB_SUCCESS)
return CB_CMOS_ACCESS_ERROR;
}
rdev_munmap(&rdev, ct);
if (set_cmos_value(ce->bit, length, value) != CB_SUCCESS)
return CB_CMOS_ACCESS_ERROR;
return CB_SUCCESS;
}

View File

@ -23,9 +23,12 @@ int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type);
NOTE: Since this may return a direct pointer to memory-mapped hardware,
compressed files are NOT transparently decompressed (unlike cbfs_load()). */
void *cbfs_map(const char *name, size_t *size_out);
/* Removes a mapping previously allocated with cbfs_map(). Should try to unmap
mappings in strict LIFO order where possible, since mapping backends often
don't support more complicated cases. */
/* Like cbfs_map(), except that it will always read from the read-only CBFS
("COREBOOT" FMAP region), even when CONFIG(VBOOT) is enabled. */
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 order where possible, since mapping backends often don't support
more complicated cases. */
int cbfs_unmap(void *mapping);
/* Locate file in a specific region of fmap. Return 0 on success. < 0 on error*/
int cbfs_locate_file_in_region(struct cbfsf *fh, const char *region_name,
@ -34,6 +37,9 @@ int cbfs_locate_file_in_region(struct cbfsf *fh, const char *region_name,
success or 0 on error. File will get decompressed as necessary. Same
decompression requirements as cbfs_load_and_decompress(). */
size_t cbfs_load(const char *name, void *buf, size_t buf_size);
/* Like cbfs_load(), except that it will always read from the read-only CBFS
("COREBOOT" FMAP region), even when CONFIG(VBOOT) is enabled. */
size_t cbfs_ro_load(const char *name, void *buf, size_t buf_size);
/* Load |in_size| bytes from |rdev| at |offset| to the |buffer_size| bytes
* large |buffer|, decompressing it according to |compression| in the process.
* Returns the decompressed file size, or 0 on error.

View File

@ -70,12 +70,12 @@ int cbfs_boot_locate(struct cbfsf *fh, const char *name, uint32_t *type)
return 0;
}
void *cbfs_map(const char *name, size_t *size_out)
static void *_cbfs_map(const char *name, size_t *size_out, bool force_ro)
{
struct region_device rdev;
union cbfs_mdata mdata;
if (cbfs_boot_lookup(name, false, &mdata, &rdev))
if (cbfs_boot_lookup(name, force_ro, &mdata, &rdev))
return NULL;
if (size_out != NULL)
@ -84,6 +84,16 @@ void *cbfs_map(const char *name, size_t *size_out)
return rdev_mmap_full(&rdev);
}
void *cbfs_map(const char *name, size_t *size_out)
{
return _cbfs_map(name, size_out, false);
}
void *cbfs_ro_map(const char *name, size_t *size_out)
{
return _cbfs_map(name, size_out, true);
}
int cbfs_unmap(void *mapping)
{
/* This works because munmap() only works on the root rdev and never
@ -281,12 +291,13 @@ void *cbfs_boot_map_optionrom_revision(uint16_t vendor, uint16_t device, uint8_t
return cbfs_map(name, NULL);
}
size_t cbfs_load(const char *name, void *buf, size_t buf_size)
static size_t _cbfs_load(const char *name, void *buf, size_t buf_size,
bool force_ro)
{
struct region_device rdev;
union cbfs_mdata mdata;
if (cbfs_boot_lookup(name, false, &mdata, &rdev))
if (cbfs_boot_lookup(name, force_ro, &mdata, &rdev))
return 0;
uint32_t compression = CBFS_COMPRESS_NONE;
@ -302,6 +313,16 @@ size_t cbfs_load(const char *name, void *buf, size_t buf_size)
buf, buf_size, compression);
}
size_t cbfs_load(const char *name, void *buf, size_t buf_size)
{
return _cbfs_load(name, buf, buf_size, false);
}
size_t cbfs_ro_load(const char *name, void *buf, size_t buf_size)
{
return _cbfs_load(name, buf, buf_size, true);
}
int cbfs_prog_stage_load(struct prog *pstage)
{
struct cbfs_stage stage;

View File

@ -107,9 +107,6 @@ void sdram_initialize(struct pei_data *pei_data)
{
int (*entry)(struct pei_data *pei_data) __attribute__((regparm(1)));
uint32_t type = CBFS_TYPE_MRC;
struct cbfsf f;
printk(BIOS_DEBUG, "Starting UEFI PEI System Agent\n");
/*
@ -130,13 +127,10 @@ void sdram_initialize(struct pei_data *pei_data)
/*
* Locate and call UEFI System Agent binary. The binary needs to be at a fixed offset
* in the flash and can therefore only reside in the COREBOOT fmap region.
* in the flash and can therefore only reside in the COREBOOT fmap region. We don't care
* about leaking the mapping.
*/
if (cbfs_locate_file_in_region(&f, "COREBOOT", "mrc.bin", &type) < 0)
die("mrc.bin not found!");
/* We don't care about leaking the mapping */
entry = rdev_mmap_full(&f.data);
entry = cbfs_ro_map("mrc.bin", NULL);
if (entry) {
int rv = entry(pei_data);

View File

@ -80,8 +80,6 @@ void raminit(struct pei_data *pei_data)
struct memory_info *mem_info;
pei_wrapper_entry_t entry;
int ret;
struct cbfsf f;
uint32_t type = CBFS_TYPE_MRC;
broadwell_fill_pei_data(pei_data);
@ -114,15 +112,10 @@ void raminit(struct pei_data *pei_data)
pei_data->saved_data_size = 0;
}
/* Determine if mrc.bin is in the cbfs. */
if (cbfs_locate_file_in_region(&f, "COREBOOT", "mrc.bin", &type) < 0)
die("mrc.bin not found!");
/* We don't care about leaking the mapping */
entry = (pei_wrapper_entry_t)rdev_mmap_full(&f.data);
if (entry == NULL) {
printk(BIOS_DEBUG, "Couldn't find mrc.bin\n");
return;
}
entry = cbfs_ro_map("mrc.bin", NULL);
if (entry == NULL)
die("mrc.bin not found!");
printk(BIOS_DEBUG, "Starting Memory Reference Code\n");

View File

@ -49,29 +49,16 @@ void disable_rom_shadow(void)
void *locate_rmu_file(size_t *rmu_file_len)
{
struct cbfsf fh;
size_t fsize;
void *rmu_data;
uint32_t type;
/* Locate the rmu.bin file in the read-only region of the flash */
type = CBFS_TYPE_RAW;
if (cbfs_locate_file_in_region(&fh, "COREBOOT", "rmu.bin", &type))
rmu_data = cbfs_ro_map("rmu.bin", &fsize);
if (!rmu_data)
return NULL;
/* Get the file size */
fsize = region_device_sz(&fh.data);
if (rmu_file_len != NULL)
*rmu_file_len = fsize;
/* Get the data address */
rmu_data = rdev_mmap(&fh.data, 0, fsize);
/* Since the SPI flash is directly mapped into memory, we do not need
* the mapping provided by the rdev service. Unmap the file to prevent
* a memory leak. Return/leak the SPI flash address for the rmu.bin
* file data which will be directly accessed by FSP MemoryInit.
*/
rdev_munmap(&fh.data, rmu_data);
return rmu_data;
}