Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
MAULIK V VAGHELA | a4af1b5 | 2022-02-21 19:02:19 +0530 | [diff] [blame] | 3 | #include <acpi/acpi.h> |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 4 | #include <bootstate.h> |
| 5 | #include <console/console.h> |
| 6 | #include <intelblocks/cse.h> |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 7 | #include <intelblocks/pmc_ipc.h> |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 8 | #include <security/vboot/vboot_common.h> |
| 9 | #include <soc/intel/common/reset.h> |
Subrata Banik | c6e2552 | 2021-09-30 18:14:09 +0530 | [diff] [blame] | 10 | #include <soc/pci_devs.h> |
Tim Wawrzynczak | f004a72 | 2021-06-22 19:15:07 -0600 | [diff] [blame] | 11 | #include <timestamp.h> |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 12 | #include <types.h> |
| 13 | |
Sridhar Siricilla | 92bd71f | 2022-02-20 00:30:31 +0530 | [diff] [blame] | 14 | #define CSE_MAX_RETRY_CMD 3 |
| 15 | |
Sridhar Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 16 | enum 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 Siricilla | 92bd71f | 2022-02-20 00:30:31 +0530 | [diff] [blame] | 21 | CSE_CMD_RESULT_RETRY, |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 22 | }; |
| 23 | |
Sridhar Siricilla | 92bd71f | 2022-02-20 00:30:31 +0530 | [diff] [blame] | 24 | static 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 Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 37 | static enum cse_cmd_result cse_disable_mei_bus(void) |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 38 | { |
| 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 Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 51 | size_t reply_sz = sizeof(reply); |
Sridhar Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 52 | enum cse_tx_rx_status ret; |
Rizwan Qureshi | 957857d | 2021-08-30 16:43:57 +0530 | [diff] [blame] | 53 | |
Sridhar Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 54 | 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 Qureshi | 957857d | 2021-08-30 16:43:57 +0530 | [diff] [blame] | 58 | printk(BIOS_ERR, "HECI: Failed to Disable MEI bus\n"); |
Sridhar Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 59 | return decode_heci_send_receive_error(ret); |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | if (reply.status) { |
| 63 | printk(BIOS_ERR, "HECI: MEI_Bus_Disable Failed (status: %d)\n", reply.status); |
Sridhar Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 64 | return CSE_CMD_RESULT_ERROR; |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 65 | } |
| 66 | |
Sridhar Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 67 | return CSE_CMD_RESULT_SUCCESS; |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 68 | } |
| 69 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 70 | static enum cse_cmd_result cse_send_eop(void) |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 71 | { |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 72 | enum cse_tx_rx_status ret; |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 73 | 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 Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 85 | 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 Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 90 | |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 91 | /* 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 Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 98 | return CSE_CMD_RESULT_SUCCESS; |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 99 | } |
| 100 | |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 101 | /* |
| 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 Rhodes | b5b22a74 | 2021-08-25 21:47:00 +0100 | [diff] [blame] | 107 | |
| 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 Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 111 | return CSE_CMD_RESULT_ERROR; |
| 112 | return CSE_CMD_RESULT_DISABLED; |
Sean Rhodes | b5b22a74 | 2021-08-25 21:47:00 +0100 | [diff] [blame] | 113 | } |
| 114 | |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 115 | if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal()) { |
| 116 | printk(BIOS_ERR, "HECI: Prerequisites not met for sending EOP\n"); |
Sridhar Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 117 | return CSE_CMD_RESULT_ERROR; |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | printk(BIOS_INFO, "HECI: Sending End-of-Post\n"); |
| 121 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 122 | ret = heci_send_receive(&msg, sizeof(msg), &resp, &resp_size, HECI_MKHI_ADDR); |
Sridhar Siricilla | 92bd71f | 2022-02-20 00:30:31 +0530 | [diff] [blame] | 123 | if (ret) |
| 124 | return decode_heci_send_receive_error(ret); |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 125 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 126 | 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 Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 130 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 131 | printk(BIOS_INFO, "CSE: EOP requested action: "); |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 132 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 133 | 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 Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 144 | } |
| 145 | |
Sridhar Siricilla | 92bd71f | 2022-02-20 00:30:31 +0530 | [diff] [blame] | 146 | static 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 Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 158 | /* |
| 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 | */ |
| 163 | static void cse_handle_eop_error(void) |
| 164 | { |
Sridhar Siricilla | 073da0c | 2022-03-04 09:24:48 +0530 | [diff] [blame] | 165 | if (cse_send_cmd_retries(cse_disable_mei_bus)) |
Tim Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 166 | 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 Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 174 | static void handle_cse_eop_result(enum cse_cmd_result result) |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 175 | { |
| 176 | switch (result) { |
Sridhar Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 177 | case CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED: |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 178 | printk(BIOS_INFO, "CSE requested global reset in EOP response, resetting...\n"); |
| 179 | do_global_reset(); |
| 180 | break; |
Sridhar Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 181 | case CSE_CMD_RESULT_SUCCESS: |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 182 | printk(BIOS_INFO, "CSE EOP successful, continuing boot\n"); |
| 183 | break; |
Sridhar Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 184 | case CSE_CMD_RESULT_DISABLED: |
Sean Rhodes | b5b22a74 | 2021-08-25 21:47:00 +0100 | [diff] [blame] | 185 | printk(BIOS_INFO, "CSE is disabled, continuing boot\n"); |
| 186 | break; |
Sridhar Siricilla | 282c2a6 | 2022-03-10 00:32:37 +0530 | [diff] [blame] | 187 | case CSE_CMD_RESULT_ERROR: /* fallthrough */ |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 188 | default: |
Julius Werner | e966595 | 2022-01-21 17:06:20 -0800 | [diff] [blame] | 189 | printk(BIOS_ERR, "Failed to send EOP to CSE, %d\n", result); |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 190 | /* 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 Wawrzynczak | 9fdd2b2 | 2021-06-18 10:34:09 -0600 | [diff] [blame] | 194 | |
| 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 Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 198 | break; |
| 199 | } |
| 200 | } |
| 201 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 202 | static void do_send_end_of_post(void) |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 203 | { |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 204 | static bool eop_sent = false; |
Subrata Banik | 7c31d17 | 2022-02-01 00:11:29 +0530 | [diff] [blame] | 205 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 206 | if (eop_sent) { |
Wisley Chen | 9666986 | 2022-03-15 16:11:32 +0600 | [diff] [blame] | 207 | printk(BIOS_WARNING, "EOP already sent\n"); |
Subrata Banik | 7c31d17 | 2022-02-01 00:11:29 +0530 | [diff] [blame] | 208 | return; |
| 209 | } |
| 210 | |
MAULIK V VAGHELA | a4af1b5 | 2022-02-21 19:02:19 +0530 | [diff] [blame] | 211 | if (acpi_get_sleep_type() == ACPI_S3) { |
| 212 | printk(BIOS_INFO, "Skip sending EOP during S3 resume\n"); |
| 213 | return; |
| 214 | } |
| 215 | |
Subrata Banik | ac1bba8 | 2021-10-25 11:23:54 +0530 | [diff] [blame] | 216 | /* |
| 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 Compostella | e7a1204 | 2023-03-13 13:59:08 -0700 | [diff] [blame] | 225 | set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE); |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 226 | |
| 227 | timestamp_add_now(TS_ME_END_OF_POST_START); |
| 228 | handle_cse_eop_result(cse_send_cmd_retries(cse_send_eop)); |
Jakub Czapiga | ad6157e | 2022-02-15 11:50:31 +0100 | [diff] [blame] | 229 | timestamp_add_now(TS_ME_END_OF_POST_END); |
Subrata Banik | 37231fb | 2021-09-25 15:26:12 +0530 | [diff] [blame] | 230 | |
Subrata Banik | c6e2552 | 2021-09-30 18:14:09 +0530 | [diff] [blame] | 231 | set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE); |
Subrata Banik | 7c31d17 | 2022-02-01 00:11:29 +0530 | [diff] [blame] | 232 | |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 233 | eop_sent = true; |
Subrata Banik | 7c31d17 | 2022-02-01 00:11:29 +0530 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | void cse_send_end_of_post(void) |
| 237 | { |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 238 | return do_send_end_of_post(); |
Subrata Banik | 7c31d17 | 2022-02-01 00:11:29 +0530 | [diff] [blame] | 239 | } |
| 240 | |
Subrata Banik | adbef6d | 2022-11-24 23:45:44 +0530 | [diff] [blame] | 241 | static void send_cse_eop_with_late_finalize(void *unused) |
Subrata Banik | 7c31d17 | 2022-02-01 00:11:29 +0530 | [diff] [blame] | 242 | { |
Nick Vaccaro | 417fc15 | 2023-04-04 11:37:00 -0700 | [diff] [blame^] | 243 | do_send_end_of_post(); |
| 244 | if (CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE)) |
Subrata Banik | adbef6d | 2022-11-24 23:45:44 +0530 | [diff] [blame] | 245 | cse_late_finalize(); |
Tim Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | /* |
| 249 | * Ideally, to give coreboot maximum flexibility, sending EOP would be done as |
Subrata Banik | bee4bb5 | 2021-09-21 21:00:16 +0530 | [diff] [blame] | 250 | * 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 Wawrzynczak | 064ca18 | 2021-06-17 12:40:13 -0600 | [diff] [blame] | 256 | */ |
Subrata Banik | bee4bb5 | 2021-09-21 21:00:16 +0530 | [diff] [blame] | 257 | #if !CONFIG(HECI_DISABLE_USING_SMM) |
Subrata Banik | adbef6d | 2022-11-24 23:45:44 +0530 | [diff] [blame] | 258 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_BOOT, BS_ON_ENTRY, send_cse_eop_with_late_finalize, NULL); |
Subrata Banik | bee4bb5 | 2021-09-21 21:00:16 +0530 | [diff] [blame] | 259 | #else |
Subrata Banik | adbef6d | 2022-11-24 23:45:44 +0530 | [diff] [blame] | 260 | BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, send_cse_eop_with_late_finalize, NULL); |
Subrata Banik | bee4bb5 | 2021-09-21 21:00:16 +0530 | [diff] [blame] | 261 | #endif |