blob: 3a08a7381cf54daa769a0d6ac460be74dd258a97 [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
14enum cse_eop_result {
15 CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED,
16 CSE_EOP_RESULT_SUCCESS,
17 CSE_EOP_RESULT_ERROR,
Sean Rhodesb5b22a742021-08-25 21:47:00 +010018 CSE_EOP_RESULT_DISABLED,
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060019};
20
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060021static bool cse_disable_mei_bus(void)
22{
23 struct bus_disable_message {
24 uint8_t command;
25 uint8_t reserved[3];
26 } __packed msg = {
27 .command = MEI_BUS_DISABLE_COMMAND,
28 };
29 struct bus_disable_resp {
30 uint8_t command;
31 uint8_t status;
32 uint8_t reserved[2];
33 } __packed reply = {};
34
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060035 size_t reply_sz = sizeof(reply);
Rizwan Qureshi957857d2021-08-30 16:43:57 +053036
37 if (!heci_send_receive(&msg, sizeof(msg), &reply, &reply_sz, HECI_MEI_ADDR)) {
38 printk(BIOS_ERR, "HECI: Failed to Disable MEI bus\n");
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060039 return false;
40 }
41
42 if (reply.status) {
43 printk(BIOS_ERR, "HECI: MEI_Bus_Disable Failed (status: %d)\n", reply.status);
44 return false;
45 }
46
47 return true;
48}
49
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060050static enum cse_eop_result cse_send_eop(void)
51{
52 enum {
53 EOP_REQUESTED_ACTION_CONTINUE = 0,
54 EOP_REQUESTED_ACTION_GLOBAL_RESET = 1,
55 };
56 struct end_of_post_msg {
57 struct mkhi_hdr hdr;
58 } __packed msg = {
59 .hdr = {
60 .group_id = MKHI_GROUP_ID_GEN,
61 .command = MKHI_END_OF_POST,
62 },
63 };
64 struct end_of_post_resp {
65 struct mkhi_hdr hdr;
66 uint32_t requested_actions;
67 } __packed resp = {};
68 size_t resp_size = sizeof(resp);
69
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -060070 /* For a CSE-Lite SKU, if the CSE is running RO FW and the board is
71 running vboot in recovery mode, the CSE is expected to be in SOFT
72 TEMP DISABLE state. */
73 if (CONFIG(SOC_INTEL_CSE_LITE_SKU) && vboot_recovery_mode_enabled() &&
74 cse_is_hfs1_com_soft_temp_disable()) {
75 printk(BIOS_INFO, "HECI: coreboot in recovery mode; found CSE in expected SOFT "
76 "TEMP DISABLE state, skipping EOP\n");
77 return CSE_EOP_RESULT_SUCCESS;
78 }
79
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060080 /*
81 * Prerequisites:
82 * 1) HFSTS1 CWS is Normal
83 * 2) HFSTS1 COM is Normal
84 * 3) Only sent after DID (accomplished by compiling this into ramstage)
85 */
Sean Rhodesb5b22a742021-08-25 21:47:00 +010086
87 if (cse_is_hfs1_com_soft_temp_disable()) {
88 printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n");
89 if (CONFIG(SOC_INTEL_CSE_LITE_SKU))
90 return CSE_EOP_RESULT_ERROR;
91 return CSE_EOP_RESULT_DISABLED;
92 }
93
Tim Wawrzynczak064ca182021-06-17 12:40:13 -060094 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal()) {
95 printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n");
96 return CSE_EOP_RESULT_ERROR;
97 }
98
99 printk(BIOS_INFO, "HECI: Sending End-of-Post\n");
100
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530101 if (!heci_send_receive(&msg, sizeof(msg), &resp, &resp_size, HECI_MKHI_ADDR)) {
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600102 printk(BIOS_ERR, "HECI: EOP send/receive fail\n");
103 return CSE_EOP_RESULT_ERROR;
104 }
105
106 if (resp.hdr.result) {
107 printk(BIOS_ERR, "HECI: EOP Resp Failed: %u\n", resp.hdr.result);
108 return CSE_EOP_RESULT_ERROR;
109 }
110
111 printk(BIOS_INFO, "CSE: EOP requested action: ");
112
113 switch (resp.requested_actions) {
114 case EOP_REQUESTED_ACTION_GLOBAL_RESET:
115 printk(BIOS_INFO, "global reset\n");
116 return CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED;
117 case EOP_REQUESTED_ACTION_CONTINUE:
118 printk(BIOS_INFO, "continue boot\n");
119 return CSE_EOP_RESULT_SUCCESS;
120 default:
121 printk(BIOS_INFO, "unknown %u\n", resp.requested_actions);
122 return CSE_EOP_RESULT_ERROR;
123 }
124}
125
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600126/*
127 * On EOP error, the BIOS is required to send an MEI bus disable message to the
128 * CSE, followed by disabling all MEI devices. After successfully completing
129 * this, it is safe to boot.
130 */
131static void cse_handle_eop_error(void)
132{
133 if (!cse_disable_mei_bus())
134 die("Failed to disable MEI bus while recovering from EOP error\n"
135 "Preventing system from booting into an insecure state.\n");
136
137 if (!cse_disable_mei_devices())
138 die("Error disabling MEI devices while recovering from EOP error\n"
139 "Preventing system from booting into an insecure state.\n");
140}
141
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600142static void handle_cse_eop_result(enum cse_eop_result result)
143{
144 switch (result) {
145 case CSE_EOP_RESULT_GLOBAL_RESET_REQUESTED:
146 printk(BIOS_INFO, "CSE requested global reset in EOP response, resetting...\n");
147 do_global_reset();
148 break;
149 case CSE_EOP_RESULT_SUCCESS:
150 printk(BIOS_INFO, "CSE EOP successful, continuing boot\n");
151 break;
Sean Rhodesb5b22a742021-08-25 21:47:00 +0100152 case CSE_EOP_RESULT_DISABLED:
153 printk(BIOS_INFO, "CSE is disabled, continuing boot\n");
154 break;
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600155 case CSE_EOP_RESULT_ERROR: /* fallthrough */
156 default:
Julius Wernere9665952022-01-21 17:06:20 -0800157 printk(BIOS_ERR, "Failed to send EOP to CSE, %d\n", result);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600158 /* For vboot, trigger recovery mode if applicable, as there is
159 likely something very broken in this case. */
160 if (CONFIG(VBOOT) && !vboot_recovery_mode_enabled())
161 cse_trigger_vboot_recovery(CSE_EOP_FAIL);
Tim Wawrzynczak9fdd2b22021-06-18 10:34:09 -0600162
163 /* In non-vboot builds or recovery mode, follow the BWG in order
164 to continue to boot securely. */
165 cse_handle_eop_error();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600166 break;
167 }
168}
169
Subrata Banik7c31d172022-02-01 00:11:29 +0530170static void do_send_end_of_post(void)
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600171{
Subrata Banik7c31d172022-02-01 00:11:29 +0530172 static bool eop_sent = false;
173
174 if (eop_sent) {
175 printk(BIOS_ERR, "EOP already sent\n");
176 return;
177 }
178
MAULIK V VAGHELAa4af1b52022-02-21 19:02:19 +0530179 if (acpi_get_sleep_type() == ACPI_S3) {
180 printk(BIOS_INFO, "Skip sending EOP during S3 resume\n");
181 return;
182 }
183
Subrata Banikac1bba82021-10-25 11:23:54 +0530184 /*
185 * If CSE is already hidden then accessing CSE registers would be wrong and will
186 * receive junk, hence, return as CSE is already disabled.
187 */
188 if (!is_cse_enabled()) {
189 printk(BIOS_DEBUG, "CSE is disabled, cannot send End-of-Post (EOP) message\n");
190 return;
191 }
192
Subrata Banikc6e25522021-09-30 18:14:09 +0530193 set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE);
Subrata Banik37231fb2021-09-25 15:26:12 +0530194
Tim Wawrzynczakf004a722021-06-22 19:15:07 -0600195 timestamp_add_now(TS_ME_BEFORE_END_OF_POST);
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600196 handle_cse_eop_result(cse_send_eop());
Tim Wawrzynczakf004a722021-06-22 19:15:07 -0600197 timestamp_add_now(TS_ME_AFTER_END_OF_POST);
Subrata Banik37231fb2021-09-25 15:26:12 +0530198
Subrata Banikc6e25522021-09-30 18:14:09 +0530199 set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE);
Subrata Banik7c31d172022-02-01 00:11:29 +0530200
201 eop_sent = true;
202}
203
204void cse_send_end_of_post(void)
205{
206 return do_send_end_of_post();
207}
208
209static void set_cse_end_of_post(void *unused)
210{
211 return do_send_end_of_post();
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600212}
213
214/*
215 * Ideally, to give coreboot maximum flexibility, sending EOP would be done as
Subrata Banikbee4bb52021-09-21 21:00:16 +0530216 * late possible. If HECI_DISABLE_USING_SMM is selected, then sending EOP must
217 * be performed before the HECI bus is disabled, so these boards use
218 * BS_PAYLOAD_LOAD, which happens before the HECI_DISABLE_USING_SMM Kconfig takes
219 * effect (EOP is sent using the HECI bus).
220 * Otherwise, EOP can be pushed a little later, and can be performed in
221 * BS_PAYLOAD_BOOT instead.
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600222 */
Subrata Banikbee4bb52021-09-21 21:00:16 +0530223#if !CONFIG(HECI_DISABLE_USING_SMM)
224BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, set_cse_end_of_post, NULL);
225#else
Tim Wawrzynczak064ca182021-06-17 12:40:13 -0600226BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, set_cse_end_of_post, NULL);
Subrata Banikbee4bb52021-09-21 21:00:16 +0530227#endif