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>
This commit is contained in:
parent
d086e3d6e4
commit
c45e0bedb2
|
@ -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 downgrades CSE RW region
|
||||||
* If ver_cmp_status > 0, coreboot upgrades 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,
|
static int compare_cse_version(const struct fw_version *a, const struct fw_version *b)
|
||||||
const struct cse_rw_metadata *source_metadata)
|
|
||||||
{
|
{
|
||||||
const struct fw_version *cse_rw_ver;
|
if (a->major != b->major)
|
||||||
|
return a->major - b->major;
|
||||||
printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n",
|
else if (a->minor != b->minor)
|
||||||
source_metadata->version.major,
|
return a->minor - b->minor;
|
||||||
source_metadata->version.minor,
|
else if (a->hotfix != b->hotfix)
|
||||||
source_metadata->version.hotfix,
|
return a->hotfix - b->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;
|
|
||||||
else
|
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 */
|
/* 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info,
|
enum cse_update_status {
|
||||||
const struct cse_rw_metadata *source_metadata)
|
CSE_UPDATE_NOT_REQUIRED,
|
||||||
{
|
CSE_UPDATE_UPGRADE,
|
||||||
return !cse_check_version_mismatch(cse_bp_info, source_metadata);
|
CSE_UPDATE_DOWNGRADE,
|
||||||
}
|
CSE_UPDATE_CORRUPTED,
|
||||||
|
CSE_UPDATE_METADATA_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info,
|
static struct cse_rw_metadata source_metadata;
|
||||||
const struct cse_rw_metadata *source_metadata)
|
|
||||||
{
|
|
||||||
return cse_check_version_mismatch(cse_bp_info, source_metadata) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cse_is_update_required(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,
|
||||||
const struct cse_rw_metadata *source_metadata,
|
|
||||||
struct region_device *target_rdev)
|
struct region_device *target_rdev)
|
||||||
{
|
{
|
||||||
return (!cse_is_rw_bp_sign_valid(target_rdev) ||
|
int ret;
|
||||||
!cse_is_rw_version_latest(cse_bp_info, source_metadata));
|
|
||||||
|
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,
|
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,
|
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:
|
* To set CSE's operation mode to HMRFPO mode:
|
||||||
|
@ -640,17 +648,18 @@ static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info,
|
||||||
if (!cse_boot_to_ro(cse_bp_info))
|
if (!cse_boot_to_ro(cse_bp_info))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (cse_is_downgrade_instance(cse_bp_info, source_metadata) &&
|
if ((status == CSE_UPDATE_DOWNGRADE) || (status == CSE_UPDATE_CORRUPTED)) {
|
||||||
!cse_data_clear_request(cse_bp_info)) {
|
if (!cse_data_clear_request(cse_bp_info)) {
|
||||||
printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n");
|
printk(BIOS_ERR, "cse_lite: CSE data clear failed!\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cse_hmrfpo_enable();
|
return cse_hmrfpo_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info,
|
static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info,
|
||||||
const struct cse_rw_metadata *source_metadata,
|
enum cse_update_status status,
|
||||||
struct region_device *target_rdev)
|
struct region_device *target_rdev)
|
||||||
{
|
{
|
||||||
struct region_device source_rdev;
|
struct region_device source_rdev;
|
||||||
|
@ -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;
|
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))) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
rv = CSE_COMMUNICATION_ERROR;
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
@ -688,26 +697,21 @@ error_exit:
|
||||||
static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info)
|
static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info)
|
||||||
{
|
{
|
||||||
struct region_device target_rdev;
|
struct region_device target_rdev;
|
||||||
struct cse_rw_metadata source_metadata;
|
enum cse_update_status status;
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) {
|
if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) {
|
||||||
printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n");
|
printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n");
|
||||||
return CSE_LITE_SKU_RW_ACCESS_ERROR;
|
return CSE_LITE_SKU_RW_ACCESS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cse_is_update_required(cse_bp_info, &source_metadata, &target_rdev)) {
|
status = cse_check_update_status(cse_bp_info, &target_rdev);
|
||||||
printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
|
if (status == CSE_UPDATE_NOT_REQUIRED)
|
||||||
return cse_trigger_fw_update(cse_bp_info, &source_metadata, &target_rdev);
|
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)
|
void cse_fw_sync(void)
|
||||||
|
|
Loading…
Reference in New Issue