Sridhar Siricilla has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/46312 )
Change subject: soc/intel/common: Boot time optimization ......................................................................
soc/intel/common: Boot time optimization
Th CSE RW blob which will be used by coreboot to update CSE RW partition, is packed part of FW_MAIN_A and FW_MAIN_B. This increase the size of FW_MAIN_A and FW_MAIN_B. So, accordingly loads and hash calculation of FW_MAIN_A (or FW_MAIN_B) increases during verstage. The boot time impact is around 300ms.
The patch addresses boot time by pulling CSE RW blob outside of FW_MAIN_A/B. So, it creates new FMAP region within RW_SECTION_A and RW_SECTION_B and adds CSE RW blob in the new regions as a CBFS file.
Changes: 1. Makefile changes to accommodate CSE RW blob part of FW_MAIN_A_EXTN/ FW_MAIN_B_EXTN and add RW blob metadata file part of FW_MAIN_A/B. 2. Kconfig change to define CBFS name and default file name for RW blob metadata. 3. CSE Lite driver
BUG=b:169077783 TEST=verified on hatch. Yet to verify on JSL/TGL platforms.
Signed-off-by: Sridhar Siricilla sridhar.siricilla@intel.com Change-Id: If043c9cb99fb822b62633591bf9c5bd75dfe8349 --- M src/soc/intel/common/block/cse/Kconfig M src/soc/intel/common/block/cse/Makefile.inc M src/soc/intel/common/block/cse/cse_lite.c 3 files changed, 227 insertions(+), 60 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/12/46312/1
diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig index 1cb7d35..0172fc2 100644 --- a/src/soc/intel/common/block/cse/Kconfig +++ b/src/soc/intel/common/block/cse/Kconfig @@ -37,3 +37,15 @@ default "" help Intel CSE CBFS RW blob path and file name + +config SOC_INTEL_CSE_RW_METADATA_CBFS_NAME + string "CBFS entry name for CSE RW blob" + default "me_rw_metadata" + help + CBFS entry name for Intel CSE CBFS RW blob + +config SOC_INTEL_CSE_RW_METADATA_FILE + string "Intel CSE CBFS RW path and filename" + default "" + help + Intel CSE CBFS RW blob path and file name diff --git a/src/soc/intel/common/block/cse/Makefile.inc b/src/soc/intel/common/block/cse/Makefile.inc index 11cc3c2..9543156 100644 --- a/src/soc/intel/common/block/cse/Makefile.inc +++ b/src/soc/intel/common/block/cse/Makefile.inc @@ -4,11 +4,21 @@ ramstage-$(CONFIG_SOC_INTEL_CSE_LITE_SKU) += cse_lite.c smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_HECI_DISABLE_IN_SMM) += disable_heci.c
+ ifneq ($(CONFIG_SOC_INTEL_CSE_RW_FILE),"") -CSE_LITE_ME_RW = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME)) -regions-for-file-$(CSE_LITE_ME_RW) = FW_MAIN_A,FW_MAIN_B -cbfs-files-y += $(CSE_LITE_ME_RW) -$(CSE_LITE_ME_RW)-file := $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_FILE)) -$(CSE_LITE_ME_RW)-name := $(CSE_LITE_ME_RW) -$(CSE_LITE_ME_RW)-type := raw +CSE_LITE_RW = $(call strip_quotes, $(CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME)) +regions-for-file-$(CSE_LITE_RW) = FW_MAIN_A_EXTN,FW_MAIN_B_EXTN +cbfs-files-y += $(CSE_LITE_RW) +$(CSE_LITE_RW)-file := $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_FILE)) +$(CSE_LITE_RW)-name := $(CSE_LITE_RW) +$(CSE_LITE_RW)-type := raw +endif + +ifneq ($(CONFIG_SOC_INTEL_CSE_RW_METADATA_FILE),"") +CSE_LITE_RW_METADATA = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME)) +regions-for-file-$(CSE_LITE_RW_METADATA) = FW_MAIN_A,FW_MAIN_B +cbfs-files-y += $(CSE_LITE_RW_METADATA) +$(CSE_LITE_RW_METADATA)-file := $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_METADATA_FILE)) +$(CSE_LITE_RW_METADATA)-name := $(CSE_LITE_RW_METADATA) +$(CSE_LITE_RW_METADATA)-type := raw endif diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c index c9e4e1f..5b50828 100644 --- a/src/soc/intel/common/block/cse/cse_lite.c +++ b/src/soc/intel/common/block/cse/cse_lite.c @@ -12,6 +12,11 @@ #include <vb2_api.h> #include <soc/intel/common/reset.h>
+ +#define FMAP_FW_MAIN_A_EXTN_NAME "FW_MAIN_A_EXTN" + +#define FMAP_FW_MAIN_B_EXTN_NAME "FW_MAIN_B_EXTN" + /* CSE RW version size reserved in the CSE CBFS RW binary */ #define CSE_RW_VERSION_SZ 16
@@ -64,7 +69,13 @@ CSE_LITE_SKU_COMMUNICATION_ERROR = 6,
/* Fails to wipe CSE runtime data */ - CSE_LITE_SKU_DATA_WIPE_ERROR = 7 + CSE_LITE_SKU_DATA_WIPE_ERROR = 7, + + /* CSE RW is not found */ + CSE_LITE_SKU_RW_BLOB_NOT_FOUND = 8, + + /* CSE CBFS RW SHA-256 mismatch with the provided SHA */ + CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH = 9 };
/* @@ -157,6 +168,43 @@ struct cse_bp_info bp_info; } __packed;
+/* CSE CBFS RW metadata */ +struct cse_cbfs_rw_info { + + /* This struct version */ + uint8_t version; + + /* CSE CBFS RW version */ + struct fw_version fw_ver; + + /* Ifwi build version */ + uint8_t ifwi_build_version; + + /* Indicate CSE CBFS RW is compressed or not */ + uint8_t compressed; + + /* SHA-256 of CSE CBFS RW */ + uint8_t hash[VB2_SHA256_DIGEST_SIZE]; + + uint8_t reserved[5]; +}; + +/* CSE Boot Partition Descriptor Table Header */ +struct cse_bpdt { + + /* Signature:0x000055AA is expected for a valid BP */ + uint32_t signature; + + /* reserved field */ + uint8_t reserved[8]; + + /* ifwi build version */ + uint32_t ifwi_build_ver; + + /* FIT tool version */ + struct fw_version fit_tool_ver; +}; + static void cse_log_status_registers(void) { printk(BIOS_DEBUG, "cse_lite: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x " @@ -419,11 +467,38 @@ return true; }
+static bool cse_get_cbfs_rw(struct region_device *rdev) +{ + const char *fmap_fw_main_extn; + uint32_t cbfs_type = CBFS_TYPE_RAW; + static struct cbfsf fh; + struct vb2_context *ctx = vboot_get_context(); + if (ctx == NULL) + return false; + + if (vboot_is_firmware_slot_a(ctx)) + fmap_fw_main_extn = FMAP_FW_MAIN_A_EXTN_NAME; + else + fmap_fw_main_extn = FMAP_FW_MAIN_B_EXTN_NAME; + + if (cbfs_locate_file_in_region(&fh, fmap_fw_main_extn, + CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, &cbfs_type)) { + printk(BIOS_ERR, "cse_lite: Failed to locate %s in the %s", + CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, fmap_fw_main_extn); + + return false; + } + + cbfs_file_data(rdev, &fh); + + return true; +} + static bool cse_get_cbfs_rdev(struct region_device *source_rdev) { struct cbfsf file_desc;
- if (cbfs_boot_locate(&file_desc, CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, NULL) < 0) + if (cbfs_boot_locate(&file_desc, CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME, NULL) < 0) return false;
cbfs_file_data(source_rdev, &file_desc); @@ -503,15 +578,32 @@ return true; }
-static bool cse_get_cbfs_rw_version(const struct region_device *source_rdev, - void *cse_cbfs_rw_ver) +static bool cse_get_cbfs_rw_metadata(const struct region_device *source_info_rdev, + struct cse_cbfs_rw_info *source_info) {
- 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"); + if (rdev_readat(source_info_rdev, (void *) source_info, 0, + sizeof(struct cse_cbfs_rw_info)) != sizeof(struct cse_cbfs_rw_info)) { + printk(BIOS_ERR, "cse_lite: Failed to read CSE CBFW RW blob metadata\n"); return false; } + + printk(BIOS_SPEW, "cse_lite: version: %d\n", source_info->version); + printk(BIOS_SPEW, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n", + source_info->fw_ver.major, + source_info->fw_ver.minor, + source_info->fw_ver.hotfix, + source_info->fw_ver.build); + printk(BIOS_SPEW, "cse_lite: IFWI build version: 0x%x\n", + source_info->ifwi_build_version); + printk(BIOS_SPEW, "cse_lite: compressed blob: 0x%x\n", + source_info->compressed); + printk(BIOS_SPEW, "cse_lite: RW blob hash: "); + + for (uint8_t i = 0; i < 32; i++) + printk(BIOS_SPEW, "%x", source_info->hash[i]); + + printk(BIOS_SPEW, "\n"); return true; }
@@ -522,30 +614,27 @@ * 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) + const struct cse_cbfs_rw_info *source_info) { - 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); + source_info->fw_ver.major, + source_info->fw_ver.minor, + source_info->fw_ver.hotfix, + source_info->fw_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; + if (source_info->fw_ver.major != cse_rw_ver->major) + return source_info->fw_ver.major - cse_rw_ver->major; + else if (source_info->fw_ver.minor != cse_rw_ver->minor) + return source_info->fw_ver.minor - cse_rw_ver->minor; + else if (source_info->fw_ver.hotfix != cse_rw_ver->hotfix) + return source_info->fw_ver.hotfix - cse_rw_ver->hotfix; else - return cse_cbfs_rw_ver.build - cse_rw_ver->build; + return source_info->fw_ver.build - cse_rw_ver->build; }
/* Check if CSE RW data partition is valid or not */ @@ -557,6 +646,21 @@ return rw_bp->status != BP_STATUS_DATA_FAILURE; }
+static int cse_is_ifwi_build_version_latest(const struct cse_cbfs_rw_info *source_info, + const struct region_device *target_dev) +{ + uint32_t ifwi_build_ver; + uint8_t ifwi_build_ver_offset = offsetof(struct cse_bpdt, ifwi_build_ver); + + if (rdev_readat(target_dev, &ifwi_build_ver, ifwi_build_ver_offset, + sizeof(ifwi_build_ver)) != sizeof(ifwi_build_ver)) { + printk(BIOS_ERR, "cse_lite: Failed to read OEM Version CSE RW partition\n"); + return false; + } + + return (ifwi_build_ver == source_info->ifwi_build_version); +} + /* * It returns true if RW partition doesn't indicate BP_STATUS_DATA_FAILURE * otherwise false if any operation fails. @@ -587,8 +691,8 @@ return true; }
-static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf, size_t offset, - size_t size) +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"); @@ -599,36 +703,33 @@ }
static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info, - const struct region_device *source_rdev) + const struct cse_cbfs_rw_info *source_info) { - return !cse_check_version_mismatch(cse_bp_info, source_rdev); + return !cse_check_version_mismatch(cse_bp_info, source_info); }
static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info, - const struct region_device *source_rdev) + const struct cse_cbfs_rw_info *source_info) { - return cse_check_version_mismatch(cse_bp_info, source_rdev) < 0; + return cse_check_version_mismatch(cse_bp_info, source_info) < 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) + const struct cse_cbfs_rw_info *source_info, struct region_device *target_rdev) { return (!cse_is_rw_bp_sign_valid(target_rdev) || - !cse_is_rw_version_latest(cse_bp_info, source_rdev)); + !cse_is_rw_version_latest(cse_bp_info, source_info) || + !cse_is_ifwi_build_version_latest(source_info, target_rdev)); }
static bool cse_write_rw_region(const struct region_device *target_rdev, - const struct region_device *source_rdev) + const void *cse_cbfs_rw, const size_t cse_cbfs_rw_sz) { - 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); + uint32_t cse_cbfs_rw_wo_sign_sz = cse_cbfs_rw_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, @@ -639,21 +740,19 @@ 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) +static bool cse_update_rw(const struct cse_bp_info *cse_bp_info, const void *cse_cbfs_rw, + const size_t cse_blob_sz, struct region_device *target_rdev) { if (!cse_erase_rw_region(target_rdev)) return false;
- if (!cse_write_rw_region(target_rdev, source_rdev)) + if (!cse_write_rw_region(target_rdev, cse_cbfs_rw, cse_blob_sz)) return false;
printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n"); @@ -661,7 +760,7 @@ }
static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info, - const struct region_device *source_rdev) + const struct cse_cbfs_rw_info *source_info) { /* * To set CSE's operation mode to HMRFPO mode: @@ -671,7 +770,7 @@ if (!cse_boot_to_ro(cse_bp_info)) return false;
- if (cse_is_downgrade_instance(cse_bp_info, source_rdev) && + if (cse_is_downgrade_instance(cse_bp_info, source_info) && !cse_data_clear_request(cse_bp_info)) { printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n"); return false; @@ -680,20 +779,54 @@ 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) +/* The function calculates SHA-256 of CSE RW blob and compares it with the provided SHA value */ +static uint8_t cse_verify_rw_blob_sha256(const uint8_t *expected_rw_blob_sha, + const void *rw_blob, const size_t rw_blob_sz) + { - if (!cse_prep_for_rw_update(cse_bp_info, source_rdev)) + uint8_t rw_comp_sha[VB2_SHA256_DIGEST_SIZE]; + + if (!vb2_digest_buffer(rw_blob, rw_blob_sz, VB2_HASH_SHA256, rw_comp_sha, + VB2_SHA256_DIGEST_SIZE)) { + printk(BIOS_ERR, "cse_lite: CSE RW blob SHA-256 calculation has failed\n"); + return false; + } + + if (!memcmp(expected_rw_blob_sha, rw_comp_sha, VB2_SHA256_DIGEST_SIZE)) { + printk(BIOS_ERR, "cse_lite: Computed SHA is not matching with the given SHA\n"); + return false; + } + + return true; +} + +static uint8_t cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info, + const struct cse_cbfs_rw_info *source_info, struct region_device *target_rdev) +{ + + struct region_device source_rdev; + + if (!cse_get_cbfs_rw(&source_rdev)) + return CSE_LITE_SKU_RW_BLOB_NOT_FOUND; + + void *cse_cbfs_rw = rdev_mmap(&source_rdev, 0, region_device_sz(&source_rdev)); + + if (cse_verify_rw_blob_sha256(source_info->hash, cse_cbfs_rw, + region_device_sz(&source_rdev))) + return CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH; + + if (!cse_prep_for_rw_update(cse_bp_info, source_info)) return CSE_LITE_SKU_COMMUNICATION_ERROR;
- if (!cse_update_rw(cse_bp_info, source_rdev, target_rdev)) + if (!cse_update_rw(cse_bp_info, cse_cbfs_rw, region_device_sz(&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) + const struct region_device *source_info_rdev) { struct region_device target_rdev;
@@ -702,9 +835,17 @@ return CSE_LITE_SKU_RW_ACCESS_ERROR; }
- if (cse_is_update_required(cse_bp_info, source_rdev, &target_rdev)) { + struct cse_cbfs_rw_info source_info; + + /* Read CSE RW blob metadata */ + if (!cse_get_cbfs_rw_metadata(source_info_rdev, &source_info)) { + printk(BIOS_ERR, "cse_lite: Failed to get CSE RW blob metadata\n"); + return CSE_LITE_SKU_UNSPECIFIED; + } + + if (cse_is_update_required(cse_bp_info, &source_info, &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); + return cse_trigger_fw_update(cse_bp_info, &source_info, &target_rdev); }
if (!cse_is_rw_bp_status_valid(cse_bp_info)) @@ -736,11 +877,15 @@ 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 */ + /* + * If RW blob metadata is present in CBFS, then trigger CSE firmware update. + * The driver triggers if RW blob metadata is present in the CBFS and RW blob is not + * available. + */ 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); + struct region_device source_info_rdev; + if (cse_get_cbfs_rdev(&source_info_rdev)) { + rv = cse_fw_update(&cse_bp_info.bp_info, &source_info_rdev); if (rv) cse_trigger_recovery(rv); }