soc/intel/common/block/cse: Add BWG error recovery to EOP failure
This patch adds functionality to attempt to allow booting in a secure configuration (albeit with potentially reduced functionality) when the CSE EOP message fails in any way. These steps come from the CSME BWG (13.5, 15.0, 16.), and tell the CSE to disable the MEI bus, which disables further communication from the host. This is followed by requesting the PMC to disable the MEI devices. If these steps are successful, then the boot firmware can continue to boot to the OS. Otherwise, die() is called, prefering not to boot over leaving the insecure MEI bus available. BUG=b:191362590 TEST=Set FSP UPD to disable sending EOP; called this function from a BS_PAYLOAD_LOAD, ON_ENTRY entry; observed that with just cse_mei_bus_disable() called, Linux can no longer communicate over MEI: [ 16.198759] mei_me 0000:00:16.0: wait hw ready failed [ 16.204488] mei_me 0000:00:16.0: hw_start failed ret = -62 [ 16.210804] mei_me 0000:00:16.0: H_RST is set = 0x80000031 [ 18.245909] mei_me 0000:00:16.0: wait hw ready failed [ 18.251601] mei_me 0000:00:16.0: hw_start failed ret = -62 [ 18.257785] mei_me 0000:00:16.0: reset: reached maximal consecutive.. [ 18.267622] mei_me 0000:00:16.0: reset failed ret = -19 [ 18.273580] mei_me 0000:00:16.0: link layer initialization failed. [ 18.280521] mei_me 0000:00:16.0: init hw failure. [ 18.285880] mei_me 0000:00:16.0: initialization failed. Calling both error recovery functions causes all of the slot 16 devices to fail to enumerate in the OS Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Change-Id: I06abf36a9d9d8a5f2afba6002dd5695dd2107db1 Reviewed-on: https://review.coreboot.org/c/coreboot/+/55675 Reviewed-by: Furquan Shaikh <furquan@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
a96e9cb0b4
commit
9fdd2b264b
|
@ -74,6 +74,7 @@ config SOC_INTEL_CSE_RW_VERSION
|
||||||
config SOC_INTEL_CSE_SET_EOP
|
config SOC_INTEL_CSE_SET_EOP
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
select PMC_IPC_ACPI_INTERFACE
|
||||||
help
|
help
|
||||||
This config ensures coreboot will send the CSE the End-of-POST message
|
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
|
just prior to loading the payload. This is a security feature so the
|
||||||
|
|
|
@ -3,16 +3,71 @@
|
||||||
#include <bootstate.h>
|
#include <bootstate.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <intelblocks/cse.h>
|
#include <intelblocks/cse.h>
|
||||||
|
#include <intelblocks/pmc_ipc.h>
|
||||||
#include <security/vboot/vboot_common.h>
|
#include <security/vboot/vboot_common.h>
|
||||||
#include <soc/intel/common/reset.h>
|
#include <soc/intel/common/reset.h>
|
||||||
#include <types.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 {
|
enum cse_eop_result {
|
||||||
CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED,
|
CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED,
|
||||||
CSE_EOP_RESULT_SUCCESS,
|
CSE_EOP_RESULT_SUCCESS,
|
||||||
CSE_EOP_RESULT_ERROR,
|
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)
|
static enum cse_eop_result cse_send_eop(void)
|
||||||
{
|
{
|
||||||
enum {
|
enum {
|
||||||
|
@ -33,6 +88,16 @@ static enum cse_eop_result cse_send_eop(void)
|
||||||
} __packed resp = {};
|
} __packed resp = {};
|
||||||
size_t resp_size = sizeof(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:
|
* Prerequisites:
|
||||||
* 1) HFSTS1 CWS is Normal
|
* 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)
|
static void handle_cse_eop_result(enum cse_eop_result result)
|
||||||
{
|
{
|
||||||
switch (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. */
|
likely something very broken in this case. */
|
||||||
if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled())
|
if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled())
|
||||||
cse_trigger_vboot_recovery(CSE_EOP_FAIL);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
/* Get Firmware Version Command Id */
|
/* Get Firmware Version Command Id */
|
||||||
#define MKHI_GEN_GET_FW_VERSION 0x2
|
#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 */
|
/* Set End-of-POST in CSE */
|
||||||
#define MKHI_END_OF_POST 0xc
|
#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 */
|
/* Fixed Address MEI Header's ME Address field value */
|
||||||
#define HECI_MKHI_ADDR 0x07
|
#define HECI_MKHI_ADDR 0x07
|
||||||
|
|
||||||
|
/* Fixed Address MEI Header's ME Address for MEI bus messages */
|
||||||
|
#define HECI_MEI_ADDR 0x00
|
||||||
|
|
||||||
/* HMRFPO Status types */
|
/* HMRFPO Status types */
|
||||||
/* Host can't access ME region */
|
/* Host can't access ME region */
|
||||||
#define MKHI_HMRFPO_DISABLED 0
|
#define MKHI_HMRFPO_DISABLED 0
|
||||||
|
|
Loading…
Reference in New Issue