summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/common/block/cse/Kconfig1
-rw-r--r--src/soc/intel/common/block/cse/cse_eop.c85
-rw-r--r--src/soc/intel/common/block/include/intelblocks/cse.h6
3 files changed, 92 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig
index 492213e732..94f8cd5ebc 100644
--- a/src/soc/intel/common/block/cse/Kconfig
+++ b/src/soc/intel/common/block/cse/Kconfig
@@ -74,6 +74,7 @@ config SOC_INTEL_CSE_RW_VERSION
config SOC_INTEL_CSE_SET_EOP
bool
default n
+ select PMC_IPC_ACPI_INTERFACE
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
diff --git a/src/soc/intel/common/block/cse/cse_eop.c b/src/soc/intel/common/block/cse/cse_eop.c
index 98e36f027c..330aa68260 100644
--- a/src/soc/intel/common/block/cse/cse_eop.c
+++ b/src/soc/intel/common/block/cse/cse_eop.c
@@ -3,16 +3,71 @@
#include <bootstate.h>
#include <console/console.h>
#include <intelblocks/cse.h>
+#include <intelblocks/pmc_ipc.h>
#include <security/vboot/vboot_common.h>
#include <soc/intel/common/reset.h>
#include <types.h>
+#define PMC_IPC_MEI_DISABLE_ID 0xa9
+#define PMC_IPC_MEI_DISABLE_SUBID_ENABLE 0
+#define PMC_IPC_MEI_DISABLE_SUBID_DISABLE 1
+
enum cse_eop_result {
CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED,
CSE_EOP_RESULT_SUCCESS,
CSE_EOP_RESULT_ERROR,
};
+static bool cse_disable_mei_bus(void)
+{
+ struct bus_disable_message {
+ uint8_t command;
+ uint8_t reserved[3];
+ } __packed msg = {
+ .command = MEI_BUS_DISABLE_COMMAND,
+ };
+ struct bus_disable_resp {
+ uint8_t command;
+ uint8_t status;
+ uint8_t reserved[2];
+ } __packed reply = {};
+
+ /* This is sent to the MEI client endpoint, not the MKHI endpoint */
+ int ret = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MEI_ADDR);
+ if (!ret) {
+ printk(BIOS_ERR, "HECI: Failed to send MEI bus disable command!\n");
+ return false;
+ }
+
+ size_t reply_sz = sizeof(reply);
+ if (!heci_receive(&reply, &reply_sz)) {
+ printk(BIOS_ERR, "HECI: Failed to receive a reply from CSE\n");
+ return false;
+ }
+
+ if (reply.status) {
+ printk(BIOS_ERR, "HECI: MEI_Bus_Disable Failed (status: %d)\n", reply.status);
+ return false;
+ }
+
+ return true;
+}
+
+static bool cse_disable_mei_devices(void)
+{
+ struct pmc_ipc_buffer req = { 0 };
+ struct pmc_ipc_buffer rsp;
+ uint32_t cmd;
+
+ cmd = pmc_make_ipc_cmd(PMC_IPC_MEI_DISABLE_ID, PMC_IPC_MEI_DISABLE_SUBID_DISABLE, 0);
+ if (pmc_send_ipc_cmd(cmd, &req, &rsp) != CB_SUCCESS) {
+ printk(BIOS_ERR, "CSE: Failed to disable MEI devices\n");
+ return false;
+ }
+
+ return true;
+}
+
static enum cse_eop_result cse_send_eop(void)
{
enum {
@@ -33,6 +88,16 @@ static enum cse_eop_result cse_send_eop(void)
} __packed resp = {};
size_t resp_size = sizeof(resp);
+ /* For a CSE-Lite SKU, if the CSE is running RO FW and the board is
+ running vboot in recovery mode, the CSE is expected to be in SOFT
+ TEMP DISABLE state. */
+ if (CONFIG(SOC_INTEL_CSE_LITE_SKU) && vboot_recovery_mode_enabled() &&
+ cse_is_hfs1_com_soft_temp_disable()) {
+ printk(BIOS_INFO, "HECI: coreboot in recovery mode; found CSE in expected SOFT "
+ "TEMP DISABLE state, skipping EOP\n");
+ return CSE_EOP_RESULT_SUCCESS;
+ }
+
/*
* Prerequisites:
* 1) HFSTS1 CWS is Normal
@@ -71,6 +136,22 @@ static enum cse_eop_result cse_send_eop(void)
}
}
+/*
+ * On EOP error, the BIOS is required to send an MEI bus disable message to the
+ * CSE, followed by disabling all MEI devices. After successfully completing
+ * this, it is safe to boot.
+ */
+static void cse_handle_eop_error(void)
+{
+ if (!cse_disable_mei_bus())
+ die("Failed to disable MEI bus while recovering from EOP error\n"
+ "Preventing system from booting into an insecure state.\n");
+
+ if (!cse_disable_mei_devices())
+ die("Error disabling MEI devices while recovering from EOP error\n"
+ "Preventing system from booting into an insecure state.\n");
+}
+
static void handle_cse_eop_result(enum cse_eop_result result)
{
switch (result) {
@@ -88,6 +169,10 @@ static void handle_cse_eop_result(enum cse_eop_result result)
likely something very broken in this case. */
if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled())
cse_trigger_vboot_recovery(CSE_EOP_FAIL);
+
+ /* In non-vboot builds or recovery mode, follow the BWG in order
+ to continue to boot securely. */
+ cse_handle_eop_error();
break;
}
}
diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h
index 43f3137d6a..153cb228da 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
+/* MEI bus disable command. Must be sent to MEI client endpoint, not MKHI */
+#define MEI_BUS_DISABLE_COMMAND 0xc
+
/* Set End-of-POST in CSE */
#define MKHI_END_OF_POST 0xc
@@ -220,6 +223,9 @@ int cse_hmrfpo_get_status(void);
/* Fixed Address MEI Header's ME Address field value */
#define HECI_MKHI_ADDR 0x07
+/* Fixed Address MEI Header's ME Address for MEI bus messages */
+#define HECI_MEI_ADDR 0x00
+
/* HMRFPO Status types */
/* Host can't access ME region */
#define MKHI_HMRFPO_DISABLED 0