diff options
author | Furquan Shaikh <furquan@google.com> | 2021-10-06 23:28:03 -0700 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2021-10-14 13:11:57 +0000 |
commit | c45e0bedb26002b32cf6ecaca26a56214c28a8b5 (patch) | |
tree | 333f33e67e928218653881d8307f8ca011f7ad98 | |
parent | d086e3d6e42036b1ec0fc2173db5386279ac838b (diff) |
soc/intel/common/cse: Reorganize firmware update checks for CSE Lite
`cse_fw_update()` is currently checking whether an update is required
by comparing versions once and then again comparing versions later in
`cse_is_downgrade_instance()` to determine if the update is an upgrade
or downgrade. Additionally, if CSE RW partition is corrupt (determined
based on `cse_is_rw_bp_sign_valid()`), `cse_is_downgrade_instance()`
ends up using the corrupted version information to determine if it is
a downgrade instance.
This change reorganizes the firmware update checks to return different
status values:
1. CSE_UPDATE_NOT_REQUIRED: No update required. Versions match.
2. CSE_UPDATE_UPGRADE: Update required and it is an upgrade.
3. CSE_UPDATE_DOWNGRADE: Update required and it is a
downgrade (requires data clear).
4. CSE_UPDATE_CORRUPTED: `cse_is_rw_bp_sign_valid()` failed and hence
requires data clear.
5. CSE_UPDATE_METADATA_ERROR: Unable to read CSE metadata from CBFS.
This change also prepares the file for follow up changes which
completely drop cse_rw_metadata structure.
BUG=b:184892226
Change-Id: Iabecab8e373e65a11ba7fe1bfc125467571a0588
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/58157
Reviewed-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r-- | src/soc/intel/common/block/cse/cse_lite.c | 118 |
1 files changed, 61 insertions, 57 deletions
diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c index 762de2a10d..b381c48103 100644 --- a/src/soc/intel/common/block/cse/cse_lite.c +++ b/src/soc/intel/common/block/cse/cse_lite.c @@ -502,27 +502,16 @@ static bool cse_get_source_rdev(struct region_device *rdev) * If ver_cmp_status < 0, coreboot downgrades CSE RW region * If ver_cmp_status > 0, coreboot upgrades CSE RW region */ -static int cse_check_version_mismatch(const struct cse_bp_info *cse_bp_info, - const struct cse_rw_metadata *source_metadata) -{ - const struct fw_version *cse_rw_ver; - - printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n", - source_metadata->version.major, - source_metadata->version.minor, - source_metadata->version.hotfix, - source_metadata->version.build); - - cse_rw_ver = cse_get_rw_version(cse_bp_info); - - if (source_metadata->version.major != cse_rw_ver->major) - return source_metadata->version.major - cse_rw_ver->major; - else if (source_metadata->version.minor != cse_rw_ver->minor) - return source_metadata->version.minor - cse_rw_ver->minor; - else if (source_metadata->version.hotfix != cse_rw_ver->hotfix) - return source_metadata->version.hotfix - cse_rw_ver->hotfix; +static int compare_cse_version(const struct fw_version *a, const struct fw_version *b) +{ + if (a->major != b->major) + return a->major - b->major; + else if (a->minor != b->minor) + return a->minor - b->minor; + else if (a->hotfix != b->hotfix) + return a->hotfix - b->hotfix; else - return source_metadata->version.build - cse_rw_ver->build; + return a->build - b->build; } /* The function calculates SHA-256 of CSE RW blob and compares it with the provided SHA value */ @@ -568,24 +557,43 @@ static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf return true; } -static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info, - const struct cse_rw_metadata *source_metadata) -{ - return !cse_check_version_mismatch(cse_bp_info, source_metadata); -} +enum cse_update_status { + CSE_UPDATE_NOT_REQUIRED, + CSE_UPDATE_UPGRADE, + CSE_UPDATE_DOWNGRADE, + CSE_UPDATE_CORRUPTED, + CSE_UPDATE_METADATA_ERROR, +}; -static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info, - const struct cse_rw_metadata *source_metadata) -{ - return cse_check_version_mismatch(cse_bp_info, source_metadata) < 0; -} +static struct cse_rw_metadata source_metadata; -static bool cse_is_update_required(const struct cse_bp_info *cse_bp_info, - const struct cse_rw_metadata *source_metadata, - struct region_device *target_rdev) +static enum cse_update_status cse_check_update_status(const struct cse_bp_info *cse_bp_info, + struct region_device *target_rdev) { - return (!cse_is_rw_bp_sign_valid(target_rdev) || - !cse_is_rw_version_latest(cse_bp_info, source_metadata)); + int ret; + + if (!cse_is_rw_bp_sign_valid(target_rdev)) + return CSE_UPDATE_CORRUPTED; + + if (cbfs_load(CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME, &source_metadata, + sizeof(source_metadata)) != sizeof(source_metadata)) { + printk(BIOS_ERR, "cse_lite: Failed to get CSE CBFS RW metadata\n"); + return CSE_UPDATE_METADATA_ERROR; + } + + printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n", + source_metadata.version.major, + source_metadata.version.minor, + source_metadata.version.hotfix, + source_metadata.version.build); + + ret = compare_cse_version(&source_metadata.version, cse_get_rw_version(cse_bp_info)); + if (ret == 0) + return CSE_UPDATE_NOT_REQUIRED; + else if (ret < 0) + return CSE_UPDATE_DOWNGRADE; + else + return CSE_UPDATE_UPGRADE; } static bool cse_write_rw_region(const struct region_device *target_rdev, @@ -630,7 +638,7 @@ static enum csme_failure_reason cse_update_rw(const struct cse_bp_info *cse_bp_i } static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info, - const struct cse_rw_metadata *source_metadata) + enum cse_update_status status) { /* * To set CSE's operation mode to HMRFPO mode: @@ -640,18 +648,19 @@ static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info, if (!cse_boot_to_ro(cse_bp_info)) return false; - if (cse_is_downgrade_instance(cse_bp_info, source_metadata) && - !cse_data_clear_request(cse_bp_info)) { - printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n"); - return false; + if ((status == CSE_UPDATE_DOWNGRADE) || (status == CSE_UPDATE_CORRUPTED)) { + if (!cse_data_clear_request(cse_bp_info)) { + printk(BIOS_ERR, "cse_lite: CSE data clear failed!\n"); + return false; + } } return cse_hmrfpo_enable(); } static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info, - const struct cse_rw_metadata *source_metadata, - struct region_device *target_rdev) + enum cse_update_status status, + struct region_device *target_rdev) { struct region_device source_rdev; enum csme_failure_reason rv; @@ -666,13 +675,13 @@ static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info * return CSE_LITE_SKU_RW_BLOB_NOT_FOUND; } - if (!cse_verify_cbfs_rw_sha256(source_metadata->sha256, cse_cbfs_rw, + if (!cse_verify_cbfs_rw_sha256(source_metadata.sha256, cse_cbfs_rw, region_device_sz(&source_rdev))) { rv = CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH; goto error_exit; } - if (!cse_prep_for_rw_update(cse_bp_info, source_metadata)) { + if (!cse_prep_for_rw_update(cse_bp_info, status)) { rv = CSE_COMMUNICATION_ERROR; goto error_exit; } @@ -688,26 +697,21 @@ error_exit: static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info) { struct region_device target_rdev; - struct cse_rw_metadata source_metadata; - - /* Read CSE CBFS RW metadata */ - if (cbfs_load(CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME, &source_metadata, - sizeof(source_metadata)) != sizeof(source_metadata)) { - printk(BIOS_ERR, "cse_lite: Failed to get CSE CBFS RW metadata\n"); - return CSE_LITE_SKU_RW_METADATA_NOT_FOUND; - } + enum cse_update_status status; if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) { printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n"); return CSE_LITE_SKU_RW_ACCESS_ERROR; } - if (cse_is_update_required(cse_bp_info, &source_metadata, &target_rdev)) { - printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n"); - return cse_trigger_fw_update(cse_bp_info, &source_metadata, &target_rdev); - } + status = cse_check_update_status(cse_bp_info, &target_rdev); + if (status == CSE_UPDATE_NOT_REQUIRED) + return CSE_NO_ERROR; + if (status == CSE_UPDATE_METADATA_ERROR) + return CSE_LITE_SKU_RW_METADATA_NOT_FOUND; - return 0; + printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n"); + return cse_trigger_fw_update(cse_bp_info, status, &target_rdev); } void cse_fw_sync(void) |