From ec321094f68d3fbfd13b2514aaa6405b1bcd4886 Mon Sep 17 00:00:00 2001 From: Rizwan Qureshi Date: Fri, 6 Sep 2019 20:28:43 +0530 Subject: soc/intel/common/basecode: Implement CSE update flow The following changes are done in this patch: 1. Get the CSE partition info containing version of CSE RW using GET_BOOT_PARTITION_INFO HECI command 2. Get the me_rw.version from the currently selected RW slot. 3. If the versions from the above 2 locations don't match start the update - If CSE's current boot partition is not RO, then * Set the CSE's next boot partition to RO using SET_BOOT_PARTITION HECI command. * Send global reset command to reset the system. - Enable HMRFPO (Host ME Region Flash Protection Override) operation mode using HMRFPO_ENABLE HECI command - Erase and Copy the CBFS CSE RW to CSE RW partition - Set the CSE's next boot partition to RW using SET_BOOT_PARTITION HECI command - Trigger global reset - The system should boot with the updated CSE RW partition. TEST=Verified basic update flows on hatch and helios. BUG=b:111330995 Change-Id: I12f6bba3324069d65edabaccd234006b0840e700 Signed-off-by: Rizwan Qureshi Signed-off-by: Sridhar Siricilla Signed-off-by: V Sowmya Reviewed-on: https://review.coreboot.org/c/coreboot/+/35403 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh Reviewed-by: Tim Wawrzynczak Reviewed-by: Angel Pons --- .../soc/intel/cse_fw_update/Layout_after.svg | 150 ++++++++++ .../soc/intel/cse_fw_update/Layout_before.svg | 95 ++++++ .../soc/intel/cse_fw_update/cse_fw_update.md | 127 ++++++++ Documentation/soc/intel/index.md | 1 + src/soc/intel/common/block/cse/Kconfig | 12 + src/soc/intel/common/block/cse/cse_lite.c | 324 +++++++++++++++++++-- 6 files changed, 689 insertions(+), 20 deletions(-) create mode 100644 Documentation/soc/intel/cse_fw_update/Layout_after.svg create mode 100644 Documentation/soc/intel/cse_fw_update/Layout_before.svg create mode 100644 Documentation/soc/intel/cse_fw_update/cse_fw_update.md diff --git a/Documentation/soc/intel/cse_fw_update/Layout_after.svg b/Documentation/soc/intel/cse_fw_update/Layout_after.svg new file mode 100644 index 0000000000..95720db6b5 --- /dev/null +++ b/Documentation/soc/intel/cse_fw_update/Layout_after.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + Page-1 + + Rectangle.116 + DESC + + DESC + + Rectangle.117 + CSE - RO + + CSE - RO + + Rectangle.118 + + + + Rectangle.119 + COREBOOT_RO + + COREBOOT_RO + + Rectangle.120 + RW_MISC + + RW_MISC + + Rectangle.121 + FW_MAIN_B + + FW_MAIN_B + + Rectangle.122 + FW_MAIN_A + + FW_MAIN_A + + Sheet.123 + 0x1FFFFFF + + 0x1FFFFFF + + Sheet.124 + 0x0 + + 0x0 + + Rectangle.125 + RW_LEGACY + + RW_LEGACY + + Right Brace.126 + + + + Sheet.127 + HW WP + + HW WP + + Right Brace.128 + + + + Sheet.129 + SPI Controller WP via descriptor + + SPI Controller WP via descriptor + + Sheet.130 + + Rectangle.423 + CSE-RW + + CSE-RW + + + Sheet.132 + + Rectangle.423 + CSE-RW + + CSE-RW + + + Rectangle.134 + CSE-RW + + CSE-RW + + Universal connector.473 + + + + Universal connector.136 + + + + Sheet.138 + CSE RW copied during an update + + CSE RW copied during an update + + Right Brace.139 + + + + Sheet.140 + GRP0 Protected + + GRP0 Protected + + diff --git a/Documentation/soc/intel/cse_fw_update/Layout_before.svg b/Documentation/soc/intel/cse_fw_update/Layout_before.svg new file mode 100644 index 0000000000..d03754880e --- /dev/null +++ b/Documentation/soc/intel/cse_fw_update/Layout_before.svg @@ -0,0 +1,95 @@ + + + + + + + + Page-1 + + Rectangle.178 + DESC + + DESC + + Rectangle.179 + CSME/PMC + + CSME/PMC + + Rectangle.180 + + + + Rectangle.181 + COREBOOT_RO + + COREBOOT_RO + + Rectangle.182 + RW_MISC + + RW_MISC + + Rectangle.183 + FW_MAIN_B + + FW_MAIN_B + + Rectangle.184 + FW_MAIN_A + + FW_MAIN_A + + Sheet.94 + 0x1FFFFFF + + 0x1FFFFFF + + Sheet.95 + 0x0 + + 0x0 + + Rectangle.106 + RW_LEGACY + + RW_LEGACY + + Right Brace.398 + + + + Sheet.96 + HW WP + + HW WP + + Right Brace.115 + + + + Sheet.97 + SPI Controller WP via descriptor + + SPI Controller WP via descriptor + + diff --git a/Documentation/soc/intel/cse_fw_update/cse_fw_update.md b/Documentation/soc/intel/cse_fw_update/cse_fw_update.md new file mode 100644 index 0000000000..98fe310113 --- /dev/null +++ b/Documentation/soc/intel/cse_fw_update/cse_fw_update.md @@ -0,0 +1,127 @@ +CSE FW update mechanism for devices in field + +## Introduction + +CSE Firmware and PMC Firmware are critical components of Intel SoCs. +CSE and PMC cooperate by providing platform services during boot and other +power transition flows. + +## Problem Statement + +Currently, on Chromium OS Systems, CSE region is not updatable. So, new CSE FW +versions that are released by Intel to address important functional and security +bugs post-product launch will not be available to the end-user. Hence, the proposed +solution allows in-field CSE FW update to propagate those bug fixes +to end user platforms. + +## Design Proposal + +### CSE FW design Proposal: + +Key Elements: + +- CSE FW layout is composed of two bootable partitions (RO Recovery Partition + and RW Normal Partition). + +- Boot partition selection: An API-based mechanism is used to decide from which partition + CSE will boot. + +- The HECI APIs below will be supported in this CSE FW: + + - HMRFPO_ENABLE: This command requests the CSE enter a mode in which writes to + the CSE region from the CSE are disabled. It also grants temporary write access + to the RW partition from the host (RO is still protected by GPR0). + + - GET_PARTITION_INFO: The command retrieves information for each boot partition from CSE + like version, start/end offsets of a partition within CSE region, and boot + partition status. Also, it provides below information: + - The current boot partition which was used during this boot, + - The boot partition that will be used on the next CSE reset + - The number of boot partitions available in the CSE region + + - SET_BOOT_PARTITION_INFO: This command allows the firmware to request the + CSE to boot from either its RO or RW partition at its next reset. + + - DATA_CLEAR: This command requests the CSE to reset its data partition back + to manufacturing defaults + +FW Layout, RW/RO Partitions: + +The CSE RO partition is the first in the CSE boot order, hence it will be used +out of G3. RO partition contains minimum CSE code capable to boot platform and +execute FW update of RW partition. In addition to CSE code, the RO partition also +contains PMC FW patch and other CSE-loadable platform FW components. + +RW partition contains fully operational CSE FW, PMC FW, other CSE loadable +platform FW components. + +Boot partition selection: + +CSE FW shall support 2 APIs to get boot partition info, and set boot partition +info to notify CSE to select the partition on the next boot. + +### HOST FW Design proposal: + +Key Elements: + +- Build time artifacts: + + CSE RW Version update binary - The FW shall pack CSE RW update blob and + corresponding version binary which contains version of the CSE RW blob. + +- FW Update: + + coreboot will implement the logic to compare the CSE's FW version with CBFS + CSE RW binary's version in the firmware slot (FW_MAIN_A/FW_MAIN_B) and update + the CSE RW region if there is a version mismatch. If there is no version + mismatch, firmware skips CSE FW update. + +- Handling of CSE FW Downgrade: + + coreboot will send DATA_CLEAR HECI command when there is a CSE FW downgrade. + This must be done to avoid data mismatch due to CSE FW downgrade. Further, + CSE will restore the data back to manufacturing defaults after data reset. + + +## Implementation Details + + +To enable CSE FW update flow the following changes are required in coreboot: + +* Descriptor change may be required to accommodate CSE binary. The CSE binary is tied with +a platform. So CSE size may vary from one platform to another. +* FMAP changes may be required to accommodate CSE binary and CSE RW blob in the RW CBFS region. +Please check platform specific CSE kit for CSE binary information. +* CSE Lite SKU binary and CSE RW blob +* Makefile change to pack CSE RW binaries in the CBFS +* Implementation of update flow: + - Get CSE boot partition info using GET_BOOT_PARTITION_INFO HECI command. + - Get the cbfs_me_rw.version from the currently selected RW slot. + - If the version from the above 2 locations don't match, then start CSE FW update. + - If CSE is not booting from RO, then + - Set the CSE's next boot partition to RO using SET_BOOT_PARTITION_INFO + HECI command. + - Send GLOBAL_RESET HECI command to reset the system. + - If RW update is a CSE FW downgrade, then coreboot has to send + DATA_CLEAR command to clear run time data of CSE. + - Enable HMRFPO Mode (Host ME Region Flash Protection Override) by + sending HMRFPO_ENABLE HECI command to CSE. + - Erase and Copy the CBFS CSE RW to CSE RW partition + - Set CSE's next boot partition to RW. + - Trigger Global Reset which resets both CSE and Host. + Then system should boot with the updated CSE. + +* The resulting flash layout is shown below: + +![Flash Layout](./Layout_before.svg) ![FlashLayout](./Layout_after.svg) + + + - Typical boot flow + + - Vboot selects the RW FW (FW_MAIN_A or FW_MAIN_B) to boot. + - coreboot skips CSE FW update flow if boot mode is recovery. + - If CSE RW blob is not locatable in the CBFS, then RW Firmware skips update flow + and sends SET_BOOT_PARTITION_INFO command to switch CSE to boot from RW + and issues Global Reset if CSE is already not booting from RW partition. + - The RW firmware will compare the CSE RW version with CSE RW blob in the slot. + - If there is a mismatch, then firmware will carry out update flow as explained before. diff --git a/Documentation/soc/intel/index.md b/Documentation/soc/intel/index.md index f30ff9a1d6..76b67dc46e 100644 --- a/Documentation/soc/intel/index.md +++ b/Documentation/soc/intel/index.md @@ -10,3 +10,4 @@ This section contains documentation about coreboot on specific Intel SOCs. - [MP Initialization](mp_init/mp_init.md) - [Firmware Interface Table](fit.md) - [Apollolake](apollolake/index.md) +- [CSE FW Update](cse_fw_update/cse_fw_update_model.md) diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig index 9f09d89656..b6f49c61e8 100644 --- a/src/soc/intel/common/block/cse/Kconfig +++ b/src/soc/intel/common/block/cse/Kconfig @@ -19,3 +19,15 @@ config SOC_INTEL_CSE_LITE_SKU depends on CHROMEOS help Enables CSE Lite SKU + +config SOC_INTEL_CSE_FMAP_NAME + string "Name of CSE Region in FMAP" + default "SI_ME" + help + Name of CSE region in FMAP + +config SOC_INTEL_CSE_RW_CBFS_NAME + string "CBFS entry name for CSE RW blob" + default "me_rw" + help + CBFS entry name for Intel CSE CBFS RW blob diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c index 8e43e35c47..a12f2d0d29 100644 --- a/src/soc/intel/common/block/cse/cse_lite.c +++ b/src/soc/intel/common/block/cse/cse_lite.c @@ -1,15 +1,30 @@ /* SPDX-License-Identifier: GPL-2.0-only */ #include #include -#include +#include +#include +#include +#include +#include #include +#include #include #include #include +#include + +/* CSE RW version size reserved in the CSE CBFS RW binary */ +#define CSE_RW_VERSION_SZ 16 /* Converts bp index to boot partition string */ #define GET_BP_STR(bp_index) (bp_index ? "RW" : "RO") +/* CSE RW boot partition signature */ +#define CSE_RW_SIGNATURE 0x000055aa + +/* CSE RW boot partition signature size */ +#define CSE_RW_SIGN_SIZE sizeof(uint32_t) + /* * CSE Firmware supports 3 boot partitions. For CSE Lite SKU, only 2 boot partitions are * used and 3rd boot partition is set to BP_STATUS_PARTITION_NOT_PRESENT. @@ -22,10 +37,10 @@ /* CSE Lite SKU's valid bootable partition identifiers */ enum boot_partition_id { - /* RO(BP1) contains recovery/minimal boot FW */ + /* RO(BP1) contains recovery/minimal boot firmware */ RO = 0, - /* RW(BP2) contains fully functional CSE Firmware */ + /* RW(BP2) contains fully functional CSE firmware */ RW = 1 }; @@ -162,6 +177,49 @@ static const struct cse_bp_entry *cse_get_bp_entry(enum boot_partition_id bp, return &cse_bp_info->bp_entries[bp]; } +static void cse_get_bp_entry_range(const struct cse_bp_info *cse_bp_info, + enum boot_partition_id bp, uint32_t *start_offset, uint32_t *end_offset) +{ + const struct cse_bp_entry *cse_bp; + + cse_bp = cse_get_bp_entry(bp, cse_bp_info); + + if (start_offset) + *start_offset = cse_bp->start_offset; + + if (end_offset) + *end_offset = cse_bp->end_offset; + +} + +static const struct fw_version *cse_get_bp_entry_version(enum boot_partition_id bp, + const struct cse_bp_info *bp_info) +{ + const struct cse_bp_entry *cse_bp; + + cse_bp = cse_get_bp_entry(bp, bp_info); + return &cse_bp->fw_ver; +} + +static const struct fw_version *cse_get_rw_version(const struct cse_bp_info *cse_bp_info) +{ + return cse_get_bp_entry_version(RW, cse_bp_info); +} + +static bool cse_is_rw_bp_status_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); + + if (rw_bp->status == BP_STATUS_PARTITION_NOT_PRESENT || + rw_bp->status == BP_STATUS_GENERAL_FAILURE) { + printk(BIOS_ERR, "cse_lite: RW BP (status:%u) is not valid\n", rw_bp->status); + return false; + } + return true; +} + static void cse_print_boot_partition_info(const struct cse_bp_info *cse_bp_info) { const struct cse_bp_entry *cse_bp; @@ -196,6 +254,9 @@ static void cse_print_boot_partition_info(const struct cse_bp_info *cse_bp_info) * - When CSE boots from RW partition (COM: Normal and CWS: Normal) * - When CSE boots from RO partition (COM: Soft Temp Disable and CWS: Normal) * - After HMRFPO_ENABLE command is issued to CSE (COM: SECOVER_MEI_MSG and CWS: Normal) + * The prerequisite check should be handled in cse_get_bp_info() and + * cse_set_next_boot_partition() since the CSE's current operation mode is changed between these + * cmd handler calls. */ static bool cse_is_bp_cmd_info_possible(void) { @@ -294,40 +355,259 @@ static bool cse_set_next_boot_partition(enum boot_partition_id bp) return true; } +/* Set the CSE's next boot partition and issues system reset */ +static bool cse_set_and_boot_from_next_bp(enum boot_partition_id bp) +{ + if (!cse_set_next_boot_partition(bp)) + return false; + + do_global_reset(); + + die("cse_lite: Failed to reset the system\n"); + + /* Control never reaches here */ + return false; +} + static bool cse_boot_to_rw(const struct cse_bp_info *cse_bp_info) { if (cse_get_current_bp(cse_bp_info) == RW) return true; - if (!cse_set_next_boot_partition(RW)) + return cse_set_and_boot_from_next_bp(RW); +} + +static bool cse_boot_to_ro(const struct cse_bp_info *cse_bp_info) +{ + if (cse_get_current_bp(cse_bp_info) == RO) + return true; + + return cse_set_and_boot_from_next_bp(RO); +} + +static bool cse_get_rw_rdev(struct region_device *rdev) +{ + if (fmap_locate_area_as_rdev_rw(CONFIG_SOC_INTEL_CSE_FMAP_NAME, rdev) < 0) { + printk(BIOS_ERR, "cse_lite: Failed to locate %s in FMAP\n", + CONFIG_SOC_INTEL_CSE_FMAP_NAME); return false; + } - do_global_reset(); + return true; +} + +static bool cse_get_cbfs_rdev(struct region_device *source_rdev) +{ + struct cbfsf file_desc; - die("cse_lite: Failed to reset system\n"); + if (cbfs_boot_locate(&file_desc, CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, NULL) < 0) + return false; - /* Control never reaches here */ - return false; + cbfs_file_data(source_rdev, &file_desc); + return true; } -static bool cse_is_rw_status_valid(const struct cse_bp_info *cse_bp_info) +static bool cse_is_rw_bp_sign_valid(const struct region_device *target_rdev) { - const struct cse_bp_entry *rw_bp; + uint32_t cse_bp_sign; - /* RW(BP2) alone represents RW partition */ - rw_bp = cse_get_bp_entry(RW, cse_bp_info); + if (rdev_readat(target_rdev, &cse_bp_sign, 0, CSE_RW_SIGN_SIZE) != CSE_RW_SIGN_SIZE) { + printk(BIOS_ERR, "cse_lite: Failed to read RW boot partition signature\n"); + return false; + } - if (rw_bp->status == BP_STATUS_PARTITION_NOT_PRESENT || - rw_bp->status == BP_STATUS_GENERAL_FAILURE) { - printk(BIOS_ERR, "cse_lite: RW BP (status:%u) is not valid\n", rw_bp->status); + return cse_bp_sign == CSE_RW_SIGNATURE; +} + +static bool cse_get_target_rdev(const struct cse_bp_info *cse_bp_info, + struct region_device *target_rdev) +{ + struct region_device cse_region_rdev; + size_t size; + uint32_t start_offset; + uint32_t end_offset; + + if (!cse_get_rw_rdev(&cse_region_rdev)) + return false; + + cse_get_bp_entry_range(cse_bp_info, RW, &start_offset, &end_offset); + size = end_offset + 1 - start_offset; + + if (rdev_chain(target_rdev, &cse_region_rdev, start_offset, size)) + return false; + + printk(BIOS_DEBUG, "cse_lite: CSE RW partition: offset = 0x%x, size = 0x%x\n", + (uint32_t)start_offset, (uint32_t) size); + + return true; +} + +static bool cse_get_cbfs_rw_version(const struct region_device *source_rdev, + void *cse_cbfs_rw_ver) +{ + + if (rdev_readat(source_rdev, (void *) cse_cbfs_rw_ver, 0, sizeof(struct fw_version)) + != sizeof(struct fw_version)) { + printk(BIOS_ERR, "cse_lite: Failed to read CSE CBFW RW version\n"); + return false; + } + return true; +} + +/* + * Compare versions of CSE CBFS RW and CSE RW partition + * If ver_cmp_status = 0, no update is required + * 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 region_device *source_rdev) +{ + struct fw_version cse_cbfs_rw_ver; + const struct fw_version *cse_rw_ver; + + if (!cse_get_cbfs_rw_version(source_rdev, &cse_cbfs_rw_ver)) + return false; + + printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n", + cse_cbfs_rw_ver.major, + cse_cbfs_rw_ver.minor, + cse_cbfs_rw_ver.hotfix, + cse_cbfs_rw_ver.build); + + cse_rw_ver = cse_get_rw_version(cse_bp_info); + + if (cse_cbfs_rw_ver.major != cse_rw_ver->major) + return cse_cbfs_rw_ver.major - cse_rw_ver->major; + else if (cse_cbfs_rw_ver.minor != cse_rw_ver->minor) + return cse_cbfs_rw_ver.minor - cse_rw_ver->minor; + else if (cse_cbfs_rw_ver.hotfix != cse_rw_ver->hotfix) + return cse_cbfs_rw_ver.hotfix - cse_rw_ver->hotfix; + else + return cse_cbfs_rw_ver.build - cse_rw_ver->build; +} + +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; } return true; } -static bool cse_is_rw_info_valid(struct cse_bp_info *cse_bp_info) +static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf, size_t offset, + size_t size) +{ + if (rdev_writeat(target_rdev, buf, offset, size) < 0) { + printk(BIOS_ERR, "cse_lite: Failed to update CSE firmware\n"); + return false; + } + + return true; +} + +static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info, + const struct region_device *source_rdev) +{ + return !cse_check_version_mismatch(cse_bp_info, source_rdev); +} + +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) +{ + return (!cse_is_rw_bp_sign_valid(target_rdev) || + !cse_is_rw_version_latest(cse_bp_info, source_rdev)); +} + +static bool cse_write_rw_region(const struct region_device *target_rdev, + const struct region_device *source_rdev) { - return cse_is_rw_status_valid(cse_bp_info); + void *cse_cbfs_rw = rdev_mmap(source_rdev, CSE_RW_VERSION_SZ, + region_device_sz(source_rdev) - CSE_RW_VERSION_SZ); + + /* Points to CSE CBFS RW image after boot partition signature */ + uint8_t *cse_cbfs_rw_wo_sign = (uint8_t *)cse_cbfs_rw + CSE_RW_SIGN_SIZE; + + /* Size of CSE CBFS RW image without boot partition signature */ + uint32_t cse_cbfs_rw_wo_sign_sz = region_device_sz(source_rdev) - + (CSE_RW_VERSION_SZ + CSE_RW_SIGN_SIZE); + + /* Update except CSE RW signature */ + if (!cse_copy_rw(target_rdev, cse_cbfs_rw_wo_sign, CSE_RW_SIGN_SIZE, + cse_cbfs_rw_wo_sign_sz)) + goto exit_rw_update; + + /* Update CSE RW signature to indicate update is complete */ + if (!cse_copy_rw(target_rdev, (void *)cse_cbfs_rw, 0, CSE_RW_SIGN_SIZE)) + goto exit_rw_update; + + rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign); + return true; + +exit_rw_update: + rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign); + return false; +} + +static bool cse_update_rw(const struct cse_bp_info *cse_bp_info, + const struct region_device *source_rdev, struct region_device *target_rdev) +{ + if (!cse_erase_rw_region(target_rdev)) + return false; + + if (!cse_write_rw_region(target_rdev, source_rdev)) + return false; + + printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n"); + return true; +} + +static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info) +{ + /* + * To set CSE's operation mode to HMRFPO mode: + * 1. Ensure CSE to boot from RO(BP1) + * 2. Send HMRFPO_ENABLE command to CSE + */ + if (!cse_boot_to_ro(cse_bp_info)) + 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)) + return CSE_LITE_SKU_COMMUNICATION_ERROR; + + if (!cse_update_rw(cse_bp_info, source_rdev, target_rdev)) + return CSE_LITE_SKU_FW_UPDATE_ERROR; + + return 0; +} + +static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info, + const struct region_device *source_rdev) +{ + struct region_device target_rdev; + + 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_rdev, &target_rdev)) { + printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n"); + return cse_trigger_fw_update(cse_bp_info, source_rdev, &target_rdev); + } + + if (!cse_is_rw_bp_status_valid(cse_bp_info)) + return CSE_LITE_SKU_RW_JUMP_ERROR; + + return 0; } void cse_fw_sync(void *unused) @@ -350,9 +630,13 @@ void cse_fw_sync(void *unused) cse_trigger_recovery(CSE_LITE_SKU_COMMUNICATION_ERROR); } - if (!cse_is_rw_info_valid(&cse_bp_info.bp_info)) { - printk(BIOS_ERR, "cse_lite: CSE RW partition is not valid\n"); - cse_trigger_recovery(CSE_LITE_SKU_RW_JUMP_ERROR); + /* If RW blob is present in CBFS, then trigger CSE firmware update */ + uint8_t rv; + struct region_device source_rdev; + if (cse_get_cbfs_rdev(&source_rdev)) { + rv = cse_fw_update(&cse_bp_info.bp_info, &source_rdev); + if (rv) + cse_trigger_recovery(rv); } if (!cse_boot_to_rw(&cse_bp_info.bp_info)) { -- cgit v1.2.3