blob: 53a4fa555e67d40d25bc35c2f4241dc320034dd7 [file] [log] [blame]
Tim Wawrzynczak064ca182021-06-17 12:40:13 -06001/* SPDX-License-Identifier: GPL-2.0-only */
2
MAULIK V VAGHELAa4af1b52022-02-21 19:02:19 +05303#include <acpi/acpi.h>
Tim Wawrzynczak064ca182021-06-17 12:40:13 -06004#include <bootstate.h>
5#include <console/console.h>
6#include <intelblocks/cse.h>
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -06007#include <intelblocks/pmc_ipc.h>
Tim Wawrzynczak064ca182021-06-17 12:40:13 -06008#include <security/vboot/vboot_common.h>
9#include <soc/intel/common/reset.h>
Subrata Banikc6e25522021-09-30 18:14:09 +053010#include <soc/pci_devs.h>
Tim Wawrzynczakf004a722021-06-22 19:15:07 -060011#include <timestamp.h>
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060012#include <types.h>
13
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +053014#define CSE_MAX_RETRY_CMD 3
15
Sridhar Siricilla282c2a62022-03-10 00:32:37 +053016enum cse_cmd_result {
17 CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED,
18 CSE_CMD_RESULT_SUCCESS,
19 CSE_CMD_RESULT_ERROR,
20 CSE_CMD_RESULT_DISABLED,
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +053021 CSE_CMD_RESULT_RETRY,
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060022};
23
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +053024static enum cse_cmd_result decode_heci_send_receive_error(enum cse_tx_rx_status ret)
25{
26 switch (ret) {
27 case CSE_TX_ERR_CSE_NOT_READY:
28 case CSE_RX_ERR_CSE_NOT_READY:
29 case CSE_RX_ERR_RESP_LEN_MISMATCH:
30 case CSE_RX_ERR_TIMEOUT:
31 return CSE_CMD_RESULT_RETRY;
32 default:
33 return CSE_CMD_RESULT_ERROR;
34 }
35}
36
Sridhar Siricilla073da0c2022-03-04 09:24:48 +053037static enum cse_cmd_result cse_disable_mei_bus(void)
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060038{
39 struct bus_disable_message {
40 uint8_t command;
41 uint8_t reserved[3];
42 } __packed msg = {
43 .command = MEI_BUS_DISABLE_COMMAND,
44 };
45 struct bus_disable_resp {
46 uint8_t command;
47 uint8_t status;
48 uint8_t reserved[2];
49 } __packed reply = {};
50
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060051 size_t reply_sz = sizeof(reply);
Sridhar Siricilla073da0c2022-03-04 09:24:48 +053052 enum cse_tx_rx_status ret;
Rizwan Qureshi957857d2021-08-30 16:43:57 +053053
Sridhar Siricilla073da0c2022-03-04 09:24:48 +053054 printk(BIOS_DEBUG, "HECI, Sending MEI BIOS DISABLE command\n");
55 ret = heci_send_receive(&msg, sizeof(msg), &reply, &reply_sz, HECI_MEI_ADDR);
56
57 if (ret) {
Rizwan Qureshi957857d2021-08-30 16:43:57 +053058 printk(BIOS_ERR, "HECI: Failed to Disable MEI bus\n");
Sridhar Siricilla073da0c2022-03-04 09:24:48 +053059 return decode_heci_send_receive_error(ret);
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060060 }
61
62 if (reply.status) {
63 printk(BIOS_ERR, "HECI: MEI_Bus_Disable Failed (status: %d)\n", reply.status);
Sridhar Siricilla073da0c2022-03-04 09:24:48 +053064 return CSE_CMD_RESULT_ERROR;
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060065 }
66
Sridhar Siricilla073da0c2022-03-04 09:24:48 +053067 return CSE_CMD_RESULT_SUCCESS;
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060068}
69
Nick Vaccaro417fc152023-04-04 11:37:00 -070070static enum cse_cmd_result cse_send_eop(void)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060071{
Nick Vaccaro417fc152023-04-04 11:37:00 -070072 enum cse_tx_rx_status ret;
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060073 enum {
74 EOP_REQUESTED_ACTION_CONTINUE = 0,
75 EOP_REQUESTED_ACTION_GLOBAL_RESET = 1,
76 };
77 struct end_of_post_msg {
78 struct mkhi_hdr hdr;
79 } __packed msg = {
80 .hdr = {
81 .group_id = MKHI_GROUP_ID_GEN,
82 .command = MKHI_END_OF_POST,
83 },
84 };
Nick Vaccaro417fc152023-04-04 11:37:00 -070085 struct end_of_post_resp {
86 struct mkhi_hdr hdr;
87 uint32_t requested_actions;
88 } __packed resp = {};
89 size_t resp_size = sizeof(resp);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060090
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060091 /* For a CSE-Lite SKU, if the CSE is running RO FW and the board is
92 running vboot in recovery mode, the CSE is expected to be in SOFT
93 TEMP DISABLE state. */
94 if (CONFIG(SOC_INTEL_CSE_LITE_SKU) && vboot_recovery_mode_enabled() &&
95 cse_is_hfs1_com_soft_temp_disable()) {
96 printk(BIOS_INFO, "HECI: coreboot in recovery mode; found CSE in expected SOFT "
97 "TEMP DISABLE state, skipping EOP\n");
Sridhar Siricilla282c2a62022-03-10 00:32:37 +053098 return CSE_CMD_RESULT_SUCCESS;
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060099 }
100
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600101 /*
102 * Prerequisites:
103 * 1) HFSTS1 CWS is Normal
104 * 2) HFSTS1 COM is Normal
105 * 3) Only sent after DID (accomplished by compiling this into ramstage)
106 */
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100107
108 if (cse_is_hfs1_com_soft_temp_disable()) {
109 printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n");
110 if (CONFIG(SOC_INTEL_CSE_LITE_SKU))
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530111 return CSE_CMD_RESULT_ERROR;
112 return CSE_CMD_RESULT_DISABLED;
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100113 }
114
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600115 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal()) {
116 printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n");
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530117 return CSE_CMD_RESULT_ERROR;
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600118 }
119
120 printk(BIOS_INFO, "HECI: Sending End-of-Post\n");
121
Nick Vaccaro417fc152023-04-04 11:37:00 -0700122 ret = heci_send_receive(&msg, sizeof(msg), &resp, &resp_size, HECI_MKHI_ADDR);
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +0530123 if (ret)
124 return decode_heci_send_receive_error(ret);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600125
Nick Vaccaro417fc152023-04-04 11:37:00 -0700126 if (resp.hdr.result) {
127 printk(BIOS_ERR, "HECI: EOP Resp Failed: %u\n", resp.hdr.result);
128 return CSE_CMD_RESULT_ERROR;
129 }
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600130
Nick Vaccaro417fc152023-04-04 11:37:00 -0700131 printk(BIOS_INFO, "CSE: EOP requested action: ");
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600132
Nick Vaccaro417fc152023-04-04 11:37:00 -0700133 switch (resp.requested_actions) {
134 case EOP_REQUESTED_ACTION_GLOBAL_RESET:
135 printk(BIOS_INFO, "global reset\n");
136 return CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED;
137 case EOP_REQUESTED_ACTION_CONTINUE:
138 printk(BIOS_INFO, "continue boot\n");
139 return CSE_CMD_RESULT_SUCCESS;
140 default:
141 printk(BIOS_INFO, "unknown %u\n", resp.requested_actions);
142 return CSE_CMD_RESULT_ERROR;
143 }
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600144}
145
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +0530146static enum cse_cmd_result cse_send_cmd_retries(enum cse_cmd_result (*cse_send_command)(void))
147{
148 size_t retry;
149 enum cse_cmd_result ret;
150 for (retry = 0; retry < CSE_MAX_RETRY_CMD; retry++) {
151 ret = cse_send_command();
152 if (ret != CSE_CMD_RESULT_RETRY)
153 break;
154 }
155 return ret;
156}
157
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600158/*
159 * On EOP error, the BIOS is required to send an MEI bus disable message to the
160 * CSE, followed by disabling all MEI devices. After successfully completing
161 * this, it is safe to boot.
162 */
163static void cse_handle_eop_error(void)
164{
Sridhar Siricilla073da0c2022-03-04 09:24:48 +0530165 if (cse_send_cmd_retries(cse_disable_mei_bus))
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600166 die("Failed to disable MEI bus while recovering from EOP error\n"
167 "Preventing system from booting into an insecure state.\n");
168
169 if (!cse_disable_mei_devices())
170 die("Error disabling MEI devices while recovering from EOP error\n"
171 "Preventing system from booting into an insecure state.\n");
172}
173
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530174static void handle_cse_eop_result(enum cse_cmd_result result)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600175{
176 switch (result) {
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530177 case CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED:
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600178 printk(BIOS_INFO, "CSE requested global reset in EOP response, resetting...\n");
179 do_global_reset();
180 break;
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530181 case CSE_CMD_RESULT_SUCCESS:
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600182 printk(BIOS_INFO, "CSE EOP successful, continuing boot\n");
183 break;
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530184 case CSE_CMD_RESULT_DISABLED:
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100185 printk(BIOS_INFO, "CSE is disabled, continuing boot\n");
186 break;
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530187 case CSE_CMD_RESULT_ERROR: /* fallthrough */
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600188 default:
Julius Wernere9665952022-01-21 17:06:20 -0800189 printk(BIOS_ERR, "Failed to send EOP to CSE, %d\n", result);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600190 /* For vboot, trigger recovery mode if applicable, as there is
191 likely something very broken in this case. */
192 if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled())
193 cse_trigger_vboot_recovery(CSE_EOP_FAIL);
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600194
195 /* In non-vboot builds or recovery mode, follow the BWG in order
196 to continue to boot securely. */
197 cse_handle_eop_error();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600198 break;
199 }
200}
201
Nick Vaccaro417fc152023-04-04 11:37:00 -0700202static void do_send_end_of_post(void)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600203{
Nick Vaccaro417fc152023-04-04 11:37:00 -0700204 static bool eop_sent = false;
Subrata Banik7c31d172022-02-01 00:11:29 +0530205
Nick Vaccaro417fc152023-04-04 11:37:00 -0700206 if (eop_sent) {
Wisley Chen96669862022-03-15 16:11:32 +0600207 printk(BIOS_WARNING, "EOP already sent\n");
Subrata Banik7c31d172022-02-01 00:11:29 +0530208 return;
209 }
210
MAULIK V VAGHELAa4af1b52022-02-21 19:02:19 +0530211 if (acpi_get_sleep_type() == ACPI_S3) {
212 printk(BIOS_INFO, "Skip sending EOP during S3 resume\n");
213 return;
214 }
215
Subrata Banikac1bba82021-10-25 11:23:54 +0530216 /*
217 * If CSE is already hidden then accessing CSE registers would be wrong and will
218 * receive junk, hence, return as CSE is already disabled.
219 */
220 if (!is_cse_enabled()) {
221 printk(BIOS_DEBUG, "CSE is disabled, cannot send End-of-Post (EOP) message\n");
222 return;
223 }
224
Jeremy Compostellae7a12042023-03-13 13:59:08 -0700225 set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE);
Nick Vaccaro417fc152023-04-04 11:37:00 -0700226
227 timestamp_add_now(TS_ME_END_OF_POST_START);
228 handle_cse_eop_result(cse_send_cmd_retries(cse_send_eop));
Jakub Czapigaad6157e2022-02-15 11:50:31 +0100229 timestamp_add_now(TS_ME_END_OF_POST_END);
Subrata Banik37231fb2021-09-25 15:26:12 +0530230
Subrata Banikc6e25522021-09-30 18:14:09 +0530231 set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE);
Subrata Banik7c31d172022-02-01 00:11:29 +0530232
Nick Vaccaro417fc152023-04-04 11:37:00 -0700233 eop_sent = true;
Subrata Banik7c31d172022-02-01 00:11:29 +0530234}
235
236void cse_send_end_of_post(void)
237{
Nick Vaccaro417fc152023-04-04 11:37:00 -0700238 return do_send_end_of_post();
Subrata Banik7c31d172022-02-01 00:11:29 +0530239}
240
Subrata Banikadbef6d2022-11-24 23:45:44 +0530241static void send_cse_eop_with_late_finalize(void *unused)
Subrata Banik7c31d172022-02-01 00:11:29 +0530242{
Nick Vaccaro417fc152023-04-04 11:37:00 -0700243 do_send_end_of_post();
244 if (CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE))
Subrata Banikadbef6d2022-11-24 23:45:44 +0530245 cse_late_finalize();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600246}
247
248/*
249 * Ideally, to give coreboot maximum flexibility, sending EOP would be done as
Subrata Banikbee4bb52021-09-21 21:00:16 +0530250 * late possible. If HECI_DISABLE_USING_SMM is selected, then sending EOP must
251 * be performed before the HECI bus is disabled, so these boards use
252 * BS_PAYLOAD_LOAD, which happens before the HECI_DISABLE_USING_SMM Kconfig takes
253 * effect (EOP is sent using the HECI bus).
254 * Otherwise, EOP can be pushed a little later, and can be performed in
255 * BS_PAYLOAD_BOOT instead.
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600256 */
Subrata Banikbee4bb52021-09-21 21:00:16 +0530257#if !CONFIG(HECI_DISABLE_USING_SMM)
Subrata Banikadbef6d2022-11-24 23:45:44 +0530258BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, send_cse_eop_with_late_finalize, NULL);
Subrata Banikbee4bb52021-09-21 21:00:16 +0530259#else
Subrata Banikadbef6d2022-11-24 23:45:44 +0530260BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, send_cse_eop_with_late_finalize, NULL);
Subrata Banikbee4bb52021-09-21 21:00:16 +0530261#endif