diff options
-rw-r--r-- | src/soc/intel/common/block/cse/Kconfig | 8 | ||||
-rw-r--r-- | src/soc/intel/common/block/cse/Makefile.inc | 2 | ||||
-rw-r--r-- | src/soc/intel/common/block/cse/cse_eop.c | 108 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/cse.h | 6 |
4 files changed, 124 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig index 044c60bb76..492213e732 100644 --- a/src/soc/intel/common/block/cse/Kconfig +++ b/src/soc/intel/common/block/cse/Kconfig @@ -70,3 +70,11 @@ config SOC_INTEL_CSE_RW_VERSION This config contains the Intel CSE RW version of the blob that is provided by SOC_INTEL_CSE_RW_FILE config and the version must be set in the format major.minor.hotfix.build (ex: 14.0.40.1209). + +config SOC_INTEL_CSE_SET_EOP + bool + default n + help + This config ensures coreboot will send the CSE the End-of-POST message + just prior to loading the payload. This is a security feature so the + CSE will no longer respond to Pre-Boot commands. diff --git a/src/soc/intel/common/block/cse/Makefile.inc b/src/soc/intel/common/block/cse/Makefile.inc index 30eb78e091..e21efc6144 100644 --- a/src/soc/intel/common/block/cse/Makefile.inc +++ b/src/soc/intel/common/block/cse/Makefile.inc @@ -4,6 +4,8 @@ ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CSE) += cse.c romstage-$(CONFIG_SOC_INTEL_CSE_LITE_SKU) += cse_lite.c smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_HECI_DISABLE_IN_SMM) += disable_heci.c +ramstage-$(CONFIG_SOC_INTEL_CSE_SET_EOP) += cse_eop.c + ifeq ($(CONFIG_SOC_INTEL_CSE_RW_UPDATE),y) ifneq ($(CONFIG_SOC_INTEL_CSE_RW_FILE),"") CSE_LITE_ME_RW = $(call strip_quotes,$(CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME)) diff --git a/src/soc/intel/common/block/cse/cse_eop.c b/src/soc/intel/common/block/cse/cse_eop.c new file mode 100644 index 0000000000..98e36f027c --- /dev/null +++ b/src/soc/intel/common/block/cse/cse_eop.c @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <bootstate.h> +#include <console/console.h> +#include <intelblocks/cse.h> +#include <security/vboot/vboot_common.h> +#include <soc/intel/common/reset.h> +#include <types.h> + +enum cse_eop_result { + CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED, + CSE_EOP_RESULT_SUCCESS, + CSE_EOP_RESULT_ERROR, +}; + +static enum cse_eop_result cse_send_eop(void) +{ + enum { + EOP_REQUESTED_ACTION_CONTINUE = 0, + EOP_REQUESTED_ACTION_GLOBAL_RESET = 1, + }; + struct end_of_post_msg { + struct mkhi_hdr hdr; + } __packed msg = { + .hdr = { + .group_id = MKHI_GROUP_ID_GEN, + .command = MKHI_END_OF_POST, + }, + }; + struct end_of_post_resp { + struct mkhi_hdr hdr; + uint32_t requested_actions; + } __packed resp = {}; + size_t resp_size = sizeof(resp); + + /* + * Prerequisites: + * 1) HFSTS1 CWS is Normal + * 2) HFSTS1 COM is Normal + * 3) Only sent after DID (accomplished by compiling this into ramstage) + */ + if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal()) { + printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n"); + return CSE_EOP_RESULT_ERROR; + } + + printk(BIOS_INFO, "HECI: Sending End-of-Post\n"); + + if (!heci_send_receive(&msg, sizeof(msg), &resp, &resp_size)) { + printk(BIOS_ERR, "HECI: EOP send/receive fail\n"); + return CSE_EOP_RESULT_ERROR; + } + + if (resp.hdr.result) { + printk(BIOS_ERR, "HECI: EOP Resp Failed: %u\n", resp.hdr.result); + return CSE_EOP_RESULT_ERROR; + } + + printk(BIOS_INFO, "CSE: EOP requested action: "); + + switch (resp.requested_actions) { + case EOP_REQUESTED_ACTION_GLOBAL_RESET: + printk(BIOS_INFO, "global reset\n"); + return CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED; + case EOP_REQUESTED_ACTION_CONTINUE: + printk(BIOS_INFO, "continue boot\n"); + return CSE_EOP_RESULT_SUCCESS; + default: + printk(BIOS_INFO, "unknown %u\n", resp.requested_actions); + return CSE_EOP_RESULT_ERROR; + } +} + +static void handle_cse_eop_result(enum cse_eop_result result) +{ + switch (result) { + case CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED: + printk(BIOS_INFO, "CSE requested global reset in EOP response, resetting...\n"); + do_global_reset(); + break; + case CSE_EOP_RESULT_SUCCESS: + printk(BIOS_INFO, "CSE EOP successful, continuing boot\n"); + break; + case CSE_EOP_RESULT_ERROR: /* fallthrough */ + default: + printk(BIOS_ERR, "ERROR: Failed to send EOP to CSE, %d\n", result); + /* For vboot, trigger recovery mode if applicable, as there is + likely something very broken in this case. */ + if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled()) + cse_trigger_vboot_recovery(CSE_EOP_FAIL); + break; + } +} + +static void set_cse_end_of_post(void *unused) +{ + handle_cse_eop_result(cse_send_eop()); +} + +/* + * Ideally, to give coreboot maximum flexibility, sending EOP would be done as + * late possible, just before loading the payload, which would be BS_ON_EXIT + * here, but the platforms this is currently supported for all select + * HECI_DISABLE_USING_SMM, which runs in BS_ON_EXIT. Because sending EOP + * requires HECI to be up, and it is not trivial to control the order in which + * these callbacks are issued, it is called on BS_ON_ENTRY. + */ +BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, set_cse_end_of_post, NULL); diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h index eac57d9f5c..43f3137d6a 100644 --- a/src/soc/intel/common/block/include/intelblocks/cse.h +++ b/src/soc/intel/common/block/include/intelblocks/cse.h @@ -25,6 +25,9 @@ /* Get Firmware Version Command Id */ #define MKHI_GEN_GET_FW_VERSION 0x2 +/* Set End-of-POST in CSE */ +#define MKHI_END_OF_POST 0xc + /* 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 @@ -117,6 +120,9 @@ enum csme_failure_reason { /* CSE CBFS RW blob layout is not correct */ CSE_LITE_SKU_LAYOUT_MISMATCH_ERROR = 11, + + /* Error sending EOP to CSE */ + CSE_EOP_FAIL = 12, }; /* set up device for use in early boot enviroument with temp bar */ |