blob: 265fe04bbc4a19e4718234540c72d50a511f2ea7 [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
Jeremy Compostella1d791882023-03-13 13:59:08 -070070static enum cse_cmd_result cse_receive_eop(void)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060071{
72 enum {
73 EOP_REQUESTED_ACTION_CONTINUE = 0,
74 EOP_REQUESTED_ACTION_GLOBAL_RESET = 1,
75 };
Jeremy Compostella1d791882023-03-13 13:59:08 -070076 enum cse_tx_rx_status ret;
77 struct end_of_post_resp {
78 struct mkhi_hdr hdr;
79 uint32_t requested_actions;
80 } __packed resp = {};
81 size_t resp_size = sizeof(resp);
82
83 ret = heci_receive(&resp, &resp_size);
84 if (ret)
85 return decode_heci_send_receive_error(ret);
86
87 if (resp.hdr.group_id != MKHI_GROUP_ID_GEN ||
88 resp.hdr.command != MKHI_END_OF_POST) {
89 printk(BIOS_ERR, "HECI: EOP Unexpected response group or command.\n");
90 if (CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC))
91 printk(BIOS_ERR, "HECI: It could be a HECI command conflict.\n");
92 return CSE_CMD_RESULT_ERROR;
93 }
94
95 if (resp.hdr.result) {
96 printk(BIOS_ERR, "HECI: EOP Resp Failed: %u\n", resp.hdr.result);
97 return CSE_CMD_RESULT_ERROR;
98 }
99
100 printk(BIOS_INFO, "CSE: EOP requested action: ");
101
102 switch (resp.requested_actions) {
103 case EOP_REQUESTED_ACTION_GLOBAL_RESET:
104 printk(BIOS_INFO, "global reset\n");
105 return CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED;
106 case EOP_REQUESTED_ACTION_CONTINUE:
107 printk(BIOS_INFO, "continue boot\n");
108 return CSE_CMD_RESULT_SUCCESS;
109 default:
110 printk(BIOS_INFO, "unknown %u\n", resp.requested_actions);
111 return CSE_CMD_RESULT_ERROR;
112 }
113}
114
115static enum cse_cmd_result cse_send_eop(void)
116{
117 enum cse_tx_rx_status ret;
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600118 struct end_of_post_msg {
119 struct mkhi_hdr hdr;
120 } __packed msg = {
121 .hdr = {
122 .group_id = MKHI_GROUP_ID_GEN,
123 .command = MKHI_END_OF_POST,
124 },
125 };
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600126
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600127 /*
128 * Prerequisites:
129 * 1) HFSTS1 CWS is Normal
130 * 2) HFSTS1 COM is Normal
131 * 3) Only sent after DID (accomplished by compiling this into ramstage)
132 */
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100133
134 if (cse_is_hfs1_com_soft_temp_disable()) {
135 printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n");
136 if (CONFIG(SOC_INTEL_CSE_LITE_SKU))
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530137 return CSE_CMD_RESULT_ERROR;
138 return CSE_CMD_RESULT_DISABLED;
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100139 }
140
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600141 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal()) {
142 printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n");
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530143 return CSE_CMD_RESULT_ERROR;
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600144 }
145
146 printk(BIOS_INFO, "HECI: Sending End-of-Post\n");
147
Jeremy Compostella1d791882023-03-13 13:59:08 -0700148 ret = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR);
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +0530149 if (ret)
150 return decode_heci_send_receive_error(ret);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600151
Jeremy Compostella1d791882023-03-13 13:59:08 -0700152 return CSE_CMD_RESULT_SUCCESS;
153}
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600154
Jeremy Compostella1d791882023-03-13 13:59:08 -0700155static enum cse_cmd_result cse_send_and_receive_eop(void)
156{
157 enum cse_cmd_result ret;
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600158
Jeremy Compostella1d791882023-03-13 13:59:08 -0700159 ret = cse_send_eop();
160 if (ret != CSE_CMD_RESULT_SUCCESS)
161 return ret;
162
163 return cse_receive_eop();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600164}
165
Sridhar Siricilla92bd71f2022-02-20 00:30:31 +0530166static enum cse_cmd_result cse_send_cmd_retries(enum cse_cmd_result (*cse_send_command)(void))
167{
168 size_t retry;
169 enum cse_cmd_result ret;
170 for (retry = 0; retry < CSE_MAX_RETRY_CMD; retry++) {
171 ret = cse_send_command();
172 if (ret != CSE_CMD_RESULT_RETRY)
173 break;
174 }
175 return ret;
176}
177
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600178/*
179 * On EOP error, the BIOS is required to send an MEI bus disable message to the
180 * CSE, followed by disabling all MEI devices. After successfully completing
181 * this, it is safe to boot.
182 */
183static void cse_handle_eop_error(void)
184{
Sridhar Siricilla073da0c2022-03-04 09:24:48 +0530185 if (cse_send_cmd_retries(cse_disable_mei_bus))
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600186 die("Failed to disable MEI bus while recovering from EOP error\n"
187 "Preventing system from booting into an insecure state.\n");
188
189 if (!cse_disable_mei_devices())
190 die("Error disabling MEI devices while recovering from EOP error\n"
191 "Preventing system from booting into an insecure state.\n");
192}
193
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530194static void handle_cse_eop_result(enum cse_cmd_result result)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600195{
196 switch (result) {
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530197 case CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED:
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600198 printk(BIOS_INFO, "CSE requested global reset in EOP response, resetting...\n");
199 do_global_reset();
200 break;
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530201 case CSE_CMD_RESULT_SUCCESS:
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600202 printk(BIOS_INFO, "CSE EOP successful, continuing boot\n");
203 break;
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530204 case CSE_CMD_RESULT_DISABLED:
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100205 printk(BIOS_INFO, "CSE is disabled, continuing boot\n");
206 break;
Sridhar Siricilla282c2a62022-03-10 00:32:37 +0530207 case CSE_CMD_RESULT_ERROR: /* fallthrough */
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600208 default:
Julius Wernere9665952022-01-21 17:06:20 -0800209 printk(BIOS_ERR, "Failed to send EOP to CSE, %d\n", result);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600210 /* For vboot, trigger recovery mode if applicable, as there is
211 likely something very broken in this case. */
212 if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled())
213 cse_trigger_vboot_recovery(CSE_EOP_FAIL);
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600214
215 /* In non-vboot builds or recovery mode, follow the BWG in order
216 to continue to boot securely. */
217 cse_handle_eop_error();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600218 break;
219 }
220}
221
Jeremy Compostella1d791882023-03-13 13:59:08 -0700222static void do_send_end_of_post(bool wait_for_completion)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600223{
Jeremy Compostella1d791882023-03-13 13:59:08 -0700224 static bool eop_sent = false, eop_complete = false;
225 enum cse_cmd_result ret;
Subrata Banik7c31d172022-02-01 00:11:29 +0530226
Jeremy Compostella1d791882023-03-13 13:59:08 -0700227 if (eop_complete) {
Wisley Chen96669862022-03-15 16:11:32 +0600228 printk(BIOS_WARNING, "EOP already sent\n");
Subrata Banik7c31d172022-02-01 00:11:29 +0530229 return;
230 }
231
MAULIK V VAGHELAa4af1b52022-02-21 19:02:19 +0530232 if (acpi_get_sleep_type() == ACPI_S3) {
233 printk(BIOS_INFO, "Skip sending EOP during S3 resume\n");
234 return;
235 }
236
Subrata Banikac1bba82021-10-25 11:23:54 +0530237 /*
238 * If CSE is already hidden then accessing CSE registers would be wrong and will
239 * receive junk, hence, return as CSE is already disabled.
240 */
241 if (!is_cse_enabled()) {
242 printk(BIOS_DEBUG, "CSE is disabled, cannot send End-of-Post (EOP) message\n");
243 return;
244 }
245
Jeremy Compostella1d791882023-03-13 13:59:08 -0700246 if (!eop_sent) {
247 set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE);
248 timestamp_add_now(TS_ME_END_OF_POST_START);
249 ret = cse_send_cmd_retries(cse_send_eop);
250 if (ret == CSE_CMD_RESULT_SUCCESS)
251 eop_sent = true;
252 }
Nick Vaccaro417fc152023-04-04 11:37:00 -0700253
Jeremy Compostella1d791882023-03-13 13:59:08 -0700254 if (!wait_for_completion)
255 return;
256
257 set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE);
258 ret = cse_receive_eop();
259 if (ret != CSE_CMD_RESULT_SUCCESS) {
260 ret = cse_send_cmd_retries(cse_send_and_receive_eop);
261 handle_cse_eop_result(ret);
262 }
Jakub Czapigaad6157e2022-02-15 11:50:31 +0100263 timestamp_add_now(TS_ME_END_OF_POST_END);
Subrata Banik37231fb2021-09-25 15:26:12 +0530264
Subrata Banikc6e25522021-09-30 18:14:09 +0530265 set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE);
Subrata Banik7c31d172022-02-01 00:11:29 +0530266
Jeremy Compostella1d791882023-03-13 13:59:08 -0700267 eop_complete = true;
268}
269
270/*
271 * Don't send EOP if the following conditions are met:
Sean Rhodes88ade912023-04-14 12:25:28 +0100272 * CSE Lite:
Jeremy Compostella1d791882023-03-13 13:59:08 -0700273 * 1. "The platform is running CSE-Lite SKU" AND
274 * 2. 'The CSE is running the RO FW" AND
275 * 3. "The board is in recovery mode"
276 *
Sean Rhodes88ade912023-04-14 12:25:28 +0100277 * Other CSE Type:
278 * 1. "The board is in recovery mode"
279 *
Jeremy Compostella1d791882023-03-13 13:59:08 -0700280 * The above conditions summarize that the CSE is in "SOFT TEMP DISABLE" state,
281 * hence, don't send the EOP command to CSE.
282 */
283static bool is_cse_eop_supported(void)
284{
Sean Rhodes88ade912023-04-14 12:25:28 +0100285 /* CSE Lite */
286 if ((CONFIG(SOC_INTEL_CSE_LITE_SKU) && vboot_recovery_mode_enabled()) &&
Jeremy Compostella1d791882023-03-13 13:59:08 -0700287 cse_is_hfs1_com_soft_temp_disable()) {
Sean Rhodes88ade912023-04-14 12:25:28 +0100288 printk(BIOS_INFO, "HECI: coreboot in recovery mode; found CSE Lite in expected "
289 "SOFT TEMP DISABLE state, skipping EOP\n");
Jeremy Compostella1d791882023-03-13 13:59:08 -0700290 return false;
291 }
Sean Rhodes88ade912023-04-14 12:25:28 +0100292 /* Other CSE Type */
293 if (cse_is_hfs1_com_soft_temp_disable()) {
294 printk(BIOS_INFO, "HECI: coreboot in recovery mode; found CSE in expected "
295 "SOFT TEMP DISABLE state, skipping EOP\n");
296 return false;
297 }
298
Jeremy Compostella1d791882023-03-13 13:59:08 -0700299 return true;
Subrata Banik7c31d172022-02-01 00:11:29 +0530300}
301
302void cse_send_end_of_post(void)
303{
Jeremy Compostella1d791882023-03-13 13:59:08 -0700304 if (!is_cse_eop_supported())
305 return;
306
307 return do_send_end_of_post(!CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC));
Subrata Banik7c31d172022-02-01 00:11:29 +0530308}
309
Subrata Banikadbef6d2022-11-24 23:45:44 +0530310static void send_cse_eop_with_late_finalize(void *unused)
Subrata Banik7c31d172022-02-01 00:11:29 +0530311{
Kapil Porwale1b59962023-04-26 00:33:53 +0530312 if (CONFIG(SOC_INTEL_CSE_SEND_EOP_BY_PAYLOAD)) {
313 printk(BIOS_INFO, "Deferring CSE EOP to payload\n");
314 return;
315 }
316
Jeremy Compostella1d791882023-03-13 13:59:08 -0700317 if (is_cse_eop_supported())
318 do_send_end_of_post(true);
319
320 if (CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE) ||
321 CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC))
Subrata Banikadbef6d2022-11-24 23:45:44 +0530322 cse_late_finalize();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600323}
324
325/*
326 * Ideally, to give coreboot maximum flexibility, sending EOP would be done as
Subrata Banikbee4bb52021-09-21 21:00:16 +0530327 * late possible. If HECI_DISABLE_USING_SMM is selected, then sending EOP must
328 * be performed before the HECI bus is disabled, so these boards use
329 * BS_PAYLOAD_LOAD, which happens before the HECI_DISABLE_USING_SMM Kconfig takes
330 * effect (EOP is sent using the HECI bus).
331 * Otherwise, EOP can be pushed a little later, and can be performed in
332 * BS_PAYLOAD_BOOT instead.
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600333 */
Subrata Banikbee4bb52021-09-21 21:00:16 +0530334#if !CONFIG(HECI_DISABLE_USING_SMM)
Subrata Banikadbef6d2022-11-24 23:45:44 +0530335BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, send_cse_eop_with_late_finalize, NULL);
Subrata Banikbee4bb52021-09-21 21:00:16 +0530336#else
Subrata Banikadbef6d2022-11-24 23:45:44 +0530337BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, send_cse_eop_with_late_finalize, NULL);
Subrata Banikbee4bb52021-09-21 21:00:16 +0530338#endif