diff options
author | Sridhar Siricilla <sridhar.siricilla@intel.com> | 2020-04-19 23:39:02 +0530 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2020-08-24 09:12:34 +0000 |
commit | 2f6d5551b015d009a94c61b6741bc33a0e01b410 (patch) | |
tree | f53445b8cedbc4c47786bec707a510fcc163eab0 /src/soc | |
parent | 0d431acf6c1d51a4f65113c09d7f06cd4868e62e (diff) |
soc/intel/common: Add downgrade support for CSE Firmware
Add downgrade support for CSE RW firmware.
When CSE FW is downgraded, CSE may get into data compatibility issues.
To avoid such issues, coreboot sends DATA CLEAR HECI command to CSE to
clear CSE run time data on proactive basis during a downgrade and
when CSE indicates a data mismatch error through GET_BOOT_PARTITION_INFO.
BUG=b:144894771
TEST=Verified on hatch
Signed-off-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Change-Id: I0a3a3036e448e5a743398f6b27e8e62965dbff3c
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40561
Reviewed-by: V Sowmya <v.sowmya@intel.com>
Reviewed-by: Jamie Ryu <jamie.m.ryu@intel.com>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/soc')
-rw-r--r-- | src/soc/intel/common/block/cse/cse_lite.c | 94 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/cse.h | 1 |
2 files changed, 92 insertions, 3 deletions
diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c index a8948be202..edb08dacb2 100644 --- a/src/soc/intel/common/block/cse/cse_lite.c +++ b/src/soc/intel/common/block/cse/cse_lite.c @@ -84,6 +84,11 @@ enum bp_status { /* This value is returned when a partition is not present per initial image layout */ BP_STATUS_PARTITION_NOT_PRESENT = 2, + /* + * This value is returned when unexpected issues are detected in CSE Data area + * and CSE TCB-SVN downgrade scenario. + */ + BP_STATUS_DATA_FAILURE = 3, }; /* @@ -459,6 +464,44 @@ static bool cse_get_target_rdev(const struct cse_bp_info *cse_bp_info, return true; } +static bool cse_data_clear_request(const struct cse_bp_info *cse_bp_info) +{ + struct data_clr_request { + struct mkhi_hdr hdr; + uint8_t reserved[4]; + } __packed; + + struct data_clr_request data_clr_rq = { + .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON, + .hdr.command = MKHI_BUP_COMMON_DATA_CLEAR, + .reserved = {0}, + }; + + if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_soft_temp_disable() || + cse_get_current_bp(cse_bp_info) != RO) { + printk(BIOS_ERR, "cse_lite: CSE doesn't meet DATA CLEAR cmd prerequisites\n"); + return false; + } + + printk(BIOS_DEBUG, "cse_lite: Sending DATA CLEAR HECI command\n"); + + struct mkhi_hdr data_clr_rsp; + size_t data_clr_rsp_sz = sizeof(data_clr_rsp); + + if (!heci_send_receive(&data_clr_rq, sizeof(data_clr_rq), &data_clr_rsp, + &data_clr_rsp_sz)) { + return false; + } + + if (data_clr_rsp.result) { + printk(BIOS_ERR, "cse_lite: CSE DATA CLEAR command response failed: %d\n", + data_clr_rsp.result); + return false; + } + + return true; +} + static bool cse_get_cbfs_rw_version(const struct region_device *source_rdev, void *cse_cbfs_rw_ver) { @@ -504,9 +547,38 @@ static int cse_check_version_mismatch(const struct cse_bp_info *cse_bp_info, return cse_cbfs_rw_ver.build - cse_rw_ver->build; } -static bool cse_erase_rw_region(const struct region_device *target_rdev) +/* Check if CSE RW data partition is valid or not */ +static bool cse_is_rw_dp_valid(const struct cse_bp_info *cse_bp_info) { + const struct cse_bp_entry *rw_bp; + + rw_bp = cse_get_bp_entry(RW, cse_bp_info); + return rw_bp->status != BP_STATUS_DATA_FAILURE; +} + +/* + * It returns true if RW partition doesn't indicate BP_STATUS_DATA_FAILURE + * otherwise false if any operation fails. + */ +static bool cse_fix_data_failure_err(const struct cse_bp_info *cse_bp_info) +{ + /* + * If RW partition status indicates BP_STATUS_DATA_FAILURE, + * - Send DATA CLEAR HECI command to CSE + * - Send SET BOOT PARTITION INFO(RW) command to set CSE's next partition + * - Issue GLOBAL RESET HECI command. + */ + if (cse_is_rw_dp_valid(cse_bp_info)) + return true; + + if (!cse_data_clear_request(cse_bp_info)) + return false; + return cse_boot_to_rw(cse_bp_info); +} + +static bool cse_erase_rw_region(const struct region_device *target_rdev) +{ if (rdev_eraseat(target_rdev, 0, region_device_sz(target_rdev)) < 0) { printk(BIOS_ERR, "cse_lite: CSE RW partition could not be erased\n"); return false; @@ -531,6 +603,12 @@ static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info, return !cse_check_version_mismatch(cse_bp_info, source_rdev); } +static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info, + const struct region_device *source_rdev) +{ + return cse_check_version_mismatch(cse_bp_info, source_rdev) < 0; +} + static bool cse_is_update_required(const struct cse_bp_info *cse_bp_info, const struct region_device *source_rdev, struct region_device *target_rdev) { @@ -581,7 +659,8 @@ static bool cse_update_rw(const struct cse_bp_info *cse_bp_info, return true; } -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 region_device *source_rdev) { /* * To set CSE's operation mode to HMRFPO mode: @@ -591,13 +670,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_rdev) && + !cse_data_clear_request(cse_bp_info)) { + printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n"); + return false; + } + return cse_hmrfpo_enable(); } static uint8_t cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info, const struct region_device *source_rdev, struct region_device *target_rdev) { - if (!cse_prep_for_rw_update(cse_bp_info)) + if (!cse_prep_for_rw_update(cse_bp_info, source_rdev)) return CSE_LITE_SKU_COMMUNICATION_ERROR; if (!cse_update_rw(cse_bp_info, source_rdev, target_rdev)) @@ -647,6 +732,9 @@ void cse_fw_sync(void *unused) cse_trigger_recovery(CSE_LITE_SKU_COMMUNICATION_ERROR); } + if (!cse_fix_data_failure_err(&cse_bp_info.bp_info)) + cse_trigger_recovery(CSE_LITE_SKU_DATA_WIPE_ERROR); + /* If RW blob is present in CBFS, then trigger CSE firmware update */ uint8_t rv; struct region_device source_rdev; diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h index 5466ba6a74..a67010cb7a 100644 --- a/src/soc/intel/common/block/include/intelblocks/cse.h +++ b/src/soc/intel/common/block/include/intelblocks/cse.h @@ -27,6 +27,7 @@ /* Boot partition info and set boot partition info command ids */ #define MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO 0x1c #define MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO 0x1d +#define MKHI_BUP_COMMON_DATA_CLEAR 0x20 /* ME Current Working States */ #define ME_HFS1_CWS_NORMAL 0x5 |