soc/intel/common/cse: Split CSE metadata into two CBFS files

This change splits CSE metadata structure (added to CBFS) into two
separate CBFS files (me_rw.hash and me_rw.version). Since `struct
cse_rw_metadata` is now used, it is dropped completely.

This change is being made in order to prepare for the upcoming changes
to stitch CSE binary at build time. Since the binary might not be
available pre-built, it complicates the order of operations for the
addition of CSE metadata structure and declaring hash and version as
CPPFLAGS_common. Instead rules can be enabled for individual CBFS file
targets for hash and version that ensure proper ordering as well.

BUG=b:184892226
TEST=Ensured that update works correctly on brya by forcing version
mismatch. In case of version match, no update is triggered.

Signed-off-by: Furquan Shaikh <furquan@google.com>
Change-Id: I7c9bb165e6a64415affcd0b3331628092195fa0d
Reviewed-on: https://review.coreboot.org/c/coreboot/+/58158
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
This commit is contained in:
Furquan Shaikh 2021-10-07 00:08:59 -07:00 committed by Felix Held
parent a0f8dc3bd5
commit d2da870499
4 changed files with 85 additions and 52 deletions

View File

@ -51,11 +51,17 @@ config SOC_INTEL_CSE_RW_CBFS_NAME
help help
CBFS entry name for Intel CSE CBFS RW blob CBFS entry name for Intel CSE CBFS RW blob
config SOC_INTEL_CSE_RW_METADATA_CBFS_NAME config SOC_INTEL_CSE_RW_HASH_CBFS_NAME
string "CBFS name for CSE RW metadata file" if SOC_INTEL_CSE_RW_UPDATE string "CBFS name for CSE RW hash file" if SOC_INTEL_CSE_RW_UPDATE
default "me_rw.metadata" default "me_rw.hash"
help help
CBFS name for Intel CSE CBFS RW metadata file CBFS name for Intel CSE CBFS RW hash file
config SOC_INTEL_CSE_RW_VERSION_CBFS_NAME
string "CBFS name for CSE RW version file" if SOC_INTEL_CSE_RW_UPDATE
default "me_rw.version"
help
CBFS name for Intel CSE CBFS RW version file
config SOC_INTEL_CSE_RW_FILE config SOC_INTEL_CSE_RW_FILE
string "Intel CSE CBFS RW path and filename" if SOC_INTEL_CSE_RW_UPDATE string "Intel CSE CBFS RW path and filename" if SOC_INTEL_CSE_RW_UPDATE

View File

@ -7,40 +7,43 @@ smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_HECI_DISABLE_IN_SMM) += disable_heci.c
ramstage-$(CONFIG_SOC_INTEL_CSE_SET_EOP) += cse_eop.c ramstage-$(CONFIG_SOC_INTEL_CSE_SET_EOP) += cse_eop.c
ifeq ($(CONFIG_SOC_INTEL_CSE_RW_UPDATE),y) ifeq ($(CONFIG_SOC_INTEL_CSE_RW_UPDATE),y)
ifneq ($(CONFIG_SOC_INTEL_CSE_RW_FILE),"")
ifeq ($(CONFIG_SOC_INTEL_CSE_RW_FILE),"")
$(error "CSE RW file path is missing and need to be set by mainboard config")
endif
ifeq ($(CONFIG_SOC_INTEL_CSE_RW_VERSION),"")
$(error "CSE RW version is missing and need to be set by mainboard config")
endif
CSE_RW_FILE=$(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_FILE))
CSE_LITE_ME_RW = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME)) CSE_LITE_ME_RW = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME))
regions-for-file-$(CSE_LITE_ME_RW) = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_A_FMAP_NAME)), \ regions-for-file-$(CSE_LITE_ME_RW) = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_A_FMAP_NAME)), \
$(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_B_FMAP_NAME)) $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_B_FMAP_NAME))
cbfs-files-y += $(CSE_LITE_ME_RW) cbfs-files-y += $(CSE_LITE_ME_RW)
$(CSE_LITE_ME_RW)-file := $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_FILE)) $(CSE_LITE_ME_RW)-file := $(CSE_RW_FILE)
$(CSE_LITE_ME_RW)-name := $(CSE_LITE_ME_RW) $(CSE_LITE_ME_RW)-name := $(CSE_LITE_ME_RW)
$(CSE_LITE_ME_RW)-type := raw $(CSE_LITE_ME_RW)-type := raw
else
$(error "CSE RW file path is missing and need to be set by mainboard config")
endif
# Extract the CSE RW firmware version and update the cse_rw_metadata structure $(obj)/cse_rw.version:
ifneq ($(CONFIG_SOC_INTEL_CSE_RW_VERSION),"") @echo '$(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_VERSION))' > $@
CSE_RW_VERSION:=$(subst ., ,$(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_VERSION)))
MAJOR := $(word 1, $(CSE_RW_VERSION))
MINOR := $(word 2, $(CSE_RW_VERSION))
HOTFIX := $(word 3, $(CSE_RW_VERSION))
BUILD := $(word 4, $(CSE_RW_VERSION))
CPPFLAGS_common += -DCSE_RW_MAJOR=$(MAJOR) -DCSE_RW_MINOR=$(MINOR) -DCSE_RW_HOTFIX=$(HOTFIX) -DCSE_RW_BUILD=$(BUILD)
else
$(error "CSE RW version is missing and need to be set by mainboard config")
endif
# Compute the hash of the CSE RW binary and update the cse_rw_metadata structure CSE_RW_VERSION = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_VERSION_CBFS_NAME))
CSE_RW_PATH := $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_FILE)) regions-for-file-$(CSE_RW_VERSION) = FW_MAIN_A,FW_MAIN_B
HASH := $(shell openssl dgst -sha256 -hex $(CSE_RW_PATH) | cut -d " " -f2 | fold -w2 | paste -sd',' -) cbfs-files-y += $(CSE_RW_VERSION)
CPPFLAGS_common += -DCSE_RW_SHA256=$(HASH) $(CSE_RW_VERSION)-file := $(obj)/cse_rw.version
$(CSE_RW_VERSION)-name := $(CSE_RW_VERSION)
$(CSE_RW_VERSION)-type := raw
$(obj)/cse_rw.hash: $(CSE_RW_FILE)
openssl dgst -sha256 -binary $< > $@
CSE_RW_HASH = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_HASH_CBFS_NAME))
regions-for-file-$(CSE_RW_HASH) = FW_MAIN_A,FW_MAIN_B
cbfs-files-y += $(CSE_RW_HASH)
$(CSE_RW_HASH)-file := $(obj)/cse_rw.hash
$(CSE_RW_HASH)-name := $(CSE_RW_HASH)
$(CSE_RW_HASH)-type := raw
# Add the CSE RW metadata file to FW_MAIN_A/B
CSE_RW_METADATA = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME))
regions-for-file-$(CSE_RW_METADATA) = FW_MAIN_A,FW_MAIN_B
cbfs-files-y += $(CSE_RW_METADATA)
$(CSE_RW_METADATA)-file := cse_rw_metadata.c:struct
$(CSE_RW_METADATA)-name := $(CSE_RW_METADATA)
$(CSE_RW_METADATA)-type := raw
endif endif

View File

@ -565,29 +565,53 @@ enum cse_update_status {
CSE_UPDATE_METADATA_ERROR, CSE_UPDATE_METADATA_ERROR,
}; };
static struct cse_rw_metadata source_metadata; static bool read_ver_field(const char *start, char **curr, size_t size, uint16_t *ver_field)
{
if ((*curr - start) >= size) {
printk(BIOS_ERR, "cse_lite: Version string read overflow!\n");
return false;
}
*ver_field = skip_atoi(curr);
(*curr)++;
return true;
}
static enum cse_update_status cse_check_update_status(const struct cse_bp_info *cse_bp_info, static enum cse_update_status cse_check_update_status(const struct cse_bp_info *cse_bp_info,
struct region_device *target_rdev) struct region_device *target_rdev)
{ {
int ret; int ret;
struct fw_version cbfs_rw_version;
char *version_str, *ptr;
size_t size;
if (!cse_is_rw_bp_sign_valid(target_rdev)) if (!cse_is_rw_bp_sign_valid(target_rdev))
return CSE_UPDATE_CORRUPTED; return CSE_UPDATE_CORRUPTED;
if (cbfs_load(CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME, &source_metadata, ptr = version_str = cbfs_map(CONFIG_SOC_INTEL_CSE_RW_VERSION_CBFS_NAME, &size);
sizeof(source_metadata)) != sizeof(source_metadata)) { if (!version_str) {
printk(BIOS_ERR, "cse_lite: Failed to get CSE CBFS RW metadata\n"); printk(BIOS_ERR, "cse_lite: Failed to get %s\n",
CONFIG_SOC_INTEL_CSE_RW_VERSION_CBFS_NAME);
return CSE_UPDATE_METADATA_ERROR;
}
if (!read_ver_field(version_str, &ptr, size, &cbfs_rw_version.major) ||
!read_ver_field(version_str, &ptr, size, &cbfs_rw_version.minor) ||
!read_ver_field(version_str, &ptr, size, &cbfs_rw_version.hotfix) ||
!read_ver_field(version_str, &ptr, size, &cbfs_rw_version.build)) {
cbfs_unmap(version_str);
return CSE_UPDATE_METADATA_ERROR; return CSE_UPDATE_METADATA_ERROR;
} }
printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n", printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n",
source_metadata.version.major, cbfs_rw_version.major,
source_metadata.version.minor, cbfs_rw_version.minor,
source_metadata.version.hotfix, cbfs_rw_version.hotfix,
source_metadata.version.build); cbfs_rw_version.build);
ret = compare_cse_version(&source_metadata.version, cse_get_rw_version(cse_bp_info)); cbfs_unmap(version_str);
ret = compare_cse_version(&cbfs_rw_version, cse_get_rw_version(cse_bp_info));
if (ret == 0) if (ret == 0)
return CSE_UPDATE_NOT_REQUIRED; return CSE_UPDATE_NOT_REQUIRED;
else if (ret < 0) else if (ret < 0)
@ -664,6 +688,7 @@ static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *
{ {
struct region_device source_rdev; struct region_device source_rdev;
enum csme_failure_reason rv; enum csme_failure_reason rv;
uint8_t *cbfs_rw_hash;
if (!cse_get_source_rdev(&source_rdev)) if (!cse_get_source_rdev(&source_rdev))
return CSE_LITE_SKU_RW_BLOB_NOT_FOUND; return CSE_LITE_SKU_RW_BLOB_NOT_FOUND;
@ -675,8 +700,16 @@ static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *
return CSE_LITE_SKU_RW_BLOB_NOT_FOUND; return CSE_LITE_SKU_RW_BLOB_NOT_FOUND;
} }
if (!cse_verify_cbfs_rw_sha256(source_metadata.sha256, cse_cbfs_rw, cbfs_rw_hash = cbfs_map(CONFIG_SOC_INTEL_CSE_RW_HASH_CBFS_NAME, NULL);
region_device_sz(&source_rdev))) { if (!cbfs_rw_hash) {
printk(BIOS_ERR, "cse_lite: Failed to get %s\n",
CONFIG_SOC_INTEL_CSE_RW_HASH_CBFS_NAME);
rv = CSE_LITE_SKU_RW_METADATA_NOT_FOUND;
goto error_exit;
}
if (!cse_verify_cbfs_rw_sha256(cbfs_rw_hash, cse_cbfs_rw,
region_device_sz(&source_rdev))) {
rv = CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH; rv = CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH;
goto error_exit; goto error_exit;
} }
@ -690,6 +723,7 @@ static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *
target_rdev); target_rdev);
error_exit: error_exit:
cbfs_unmap(cbfs_rw_hash);
rdev_munmap(&source_rdev, cse_cbfs_rw); rdev_munmap(&source_rdev, cse_cbfs_rw);
return rv; return rv;
} }

View File

@ -76,16 +76,6 @@ struct fw_version {
uint16_t build; uint16_t build;
} __packed; } __packed;
/*
* CSE RW metadata structure
* fw_version - CSE RW firmware version
* sha256 - Hash of the CSE RW binary.
*/
struct cse_rw_metadata {
struct fw_version version;
uint8_t sha256[VB2_SHA256_DIGEST_SIZE];
};
/* CSE recovery sub-error codes */ /* CSE recovery sub-error codes */
enum csme_failure_reason { enum csme_failure_reason {
/* No error */ /* No error */