blob: 98e36f027c5830a0f47b03f7653d0864cf4c016e [file] [log] [blame]
/* 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);