summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/block/cse/Kconfig8
-rw-r--r--src/soc/intel/common/block/cse/Makefile.inc2
-rw-r--r--src/soc/intel/common/block/cse/cse_eop.c108
-rw-r--r--src/soc/intel/common/block/include/intelblocks/cse.h6
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 */