Sridhar Siricilla has uploaded this change for review.

View Change

soc/intel/common: Add support for CSE Lite driver to handle CSE RW and metadata

The patch modifies CSE Lite driver to support to have separate CBFS file
for metadata of RW blobs. So, the driver expects separate CBFS files for
CSE RW and it's metadata. Also, the driver initiates CSE Firmware update
path if it finds the metadata's CBFS file. The change gives flexibility to
modify RW blob's FMAP locations while maintaining uniform or little
modified CSE Lite driver. Currently, CSE RW blob and it's metadata were
unified into one RW blob.

TEST=Verified on hatch.
BRANCH=Puff

Signed-off-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Change-Id: I316344d23987d9907b64efafbe61f36ae7ade337
---
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, 128 insertions(+), 71 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/52/46552/1
diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig
index 1cb7d35..6512e3d 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..59ba0cb 100644
--- a/src/soc/intel/common/block/cse/Makefile.inc
+++ b/src/soc/intel/common/block/cse/Makefile.inc
@@ -4,11 +4,20 @@
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_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
+
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, FW_MAIN_B
+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
diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c
index c9e4e1f..7218a92 100644
--- a/src/soc/intel/common/block/cse/cse_lite.c
+++ b/src/soc/intel/common/block/cse/cse_lite.c
@@ -12,9 +12,6 @@
#include <vb2_api.h>
#include <soc/intel/common/reset.h>

-/* 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")

@@ -45,6 +42,9 @@

/* CSE recovery sub-error codes */
enum csme_failure_reason {
+
+ /* No error */
+ CSE_LITE_SKU_NO_ERROR = 0,
/* Unspecified error */
CSE_LITE_SKU_UNSPECIFIED = 1,

@@ -64,7 +64,10 @@
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,
};

/*
@@ -157,6 +160,13 @@
struct cse_bp_info bp_info;
} __packed;

+/* CSE CBFS RW metadata */
+struct cse_cbfs_rw_info {
+ /* CSE CBFS RW version */
+ struct fw_version fw_ver;
+ uint8_t reserved[8];
+};
+
static void cse_log_status_registers(void)
{
printk(BIOS_DEBUG, "cse_lite: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
@@ -423,7 +433,7 @@
{
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 +513,33 @@
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(struct region_device *rdev)
+{
+ struct cbfsf file_desc;
+
+ if (cbfs_boot_locate(&file_desc, CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, NULL) < 0)
+ return false;
+
+ cbfs_file_data(rdev, &file_desc);
+
+ return true;
+}
+
+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 CBFS RW metadata\n");
return false;
}
+
+ 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);
return true;
}

@@ -522,30 +550,26 @@
* 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 */
@@ -587,8 +611,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 +623,35 @@
}

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));
}

static bool cse_write_rw_region(const struct region_device *target_rdev,
const struct region_device *source_rdev)
{
- void *cse_cbfs_rw = rdev_mmap(source_rdev, CSE_RW_VERSION_SZ,
- region_device_sz(source_rdev) - CSE_RW_VERSION_SZ);
+
+ void *cse_cbfs_rw = rdev_mmap(source_rdev, 0, region_device_sz(source_rdev));

/* 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 = region_device_sz(source_rdev) - 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,29 +662,32 @@
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;
+ printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n");
+ rdev_munmap(source_rdev, cse_cbfs_rw);
+ return CSE_LITE_SKU_NO_ERROR;

exit_rw_update:
- rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign);
- return false;
+ rdev_munmap(source_rdev, cse_cbfs_rw);
+ return CSE_LITE_SKU_FW_UPDATE_ERROR;
}

static bool cse_update_rw(const struct cse_bp_info *cse_bp_info,
- const struct region_device *source_rdev, struct region_device *target_rdev)
+ 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;
+
if (!cse_erase_rw_region(target_rdev))
- return false;
+ return CSE_LITE_SKU_FW_UPDATE_ERROR;

- if (!cse_write_rw_region(target_rdev, source_rdev))
- return false;
-
- printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n");
- return true;
+ return cse_write_rw_region(target_rdev, &source_rdev);
}

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 +697,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 +706,18 @@
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)
+static enum csme_failure_reason 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)
{
- if (!cse_prep_for_rw_update(cse_bp_info, source_rdev))
+
+ 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))
- return CSE_LITE_SKU_FW_UPDATE_ERROR;
-
- return 0;
+ return cse_update_rw(cse_bp_info, target_rdev);
}

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 +726,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 CBFS RW 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 +768,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 CSE CBFS RW blob metadata is present in CBFS, then trigger CSE firmware update.
+ * The driver triggers recovery if CSE CBFS RW metadata is present in the CBFS and CSE
+ * CBFS 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);
}

To view, visit change 46552. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I316344d23987d9907b64efafbe61f36ae7ade337
Gerrit-Change-Number: 46552
Gerrit-PatchSet: 1
Gerrit-Owner: Sridhar Siricilla <sridhar.siricilla@intel.com>
Gerrit-Reviewer: Martin Roth <martinroth@google.com>
Gerrit-Reviewer: Patrick Georgi <pgeorgi@google.com>
Gerrit-Reviewer: Patrick Rudolph <siro@das-labor.org>
Gerrit-MessageType: newchange