diff options
Diffstat (limited to 'src/soc/intel/common/block')
-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 |