blob: edb35c43539acc829b86c60c9713876512e14450 [file] [log] [blame]
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05301/* SPDX-License-Identifier: GPL-2.0-only */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05302#include <bootstate.h>
3#include <console/console.h>
Rizwan Qureshiec321092019-09-06 20:28:43 +05304#include <boot_device.h>
5#include <cbfs.h>
6#include <commonlib/cbfs.h>
7#include <commonlib/region.h>
8#include <fmap.h>
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05309#include <intelblocks/cse.h>
10#include <security/vboot/vboot_common.h>
Sridhar Siricilla87e36c42020-05-03 19:08:18 +053011#include <security/vboot/misc.h>
12#include <vb2_api.h>
Rizwan Qureshiec321092019-09-06 20:28:43 +053013#include <soc/intel/common/reset.h>
14
15/* CSE RW version size reserved in the CSE CBFS RW binary */
16#define CSE_RW_VERSION_SZ 16
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053017
18/* Converts bp index to boot partition string */
19#define GET_BP_STR(bp_index) (bp_index ? "RW" : "RO")
20
Rizwan Qureshiec321092019-09-06 20:28:43 +053021/* CSE RW boot partition signature */
22#define CSE_RW_SIGNATURE 0x000055aa
23
24/* CSE RW boot partition signature size */
25#define CSE_RW_SIGN_SIZE sizeof(uint32_t)
26
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053027/*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053028 * CSE Firmware supports 3 boot partitions. For CSE Lite SKU, only 2 boot partitions are
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053029 * used and 3rd boot partition is set to BP_STATUS_PARTITION_NOT_PRESENT.
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053030 * CSE Lite SKU Image Layout:
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053031 * ------------- ------------------- ---------------------
32 * |CSE REGION | => | RO | RW | DATA | => | BP1 | BP2 | DATA |
33 * ------------- ------------------- ---------------------
34 */
35#define CSE_MAX_BOOT_PARTITIONS 3
36
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053037/* CSE Lite SKU's valid bootable partition identifiers */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053038enum boot_partition_id {
Rizwan Qureshiec321092019-09-06 20:28:43 +053039 /* RO(BP1) contains recovery/minimal boot firmware */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053040 RO = 0,
41
Rizwan Qureshiec321092019-09-06 20:28:43 +053042 /* RW(BP2) contains fully functional CSE firmware */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053043 RW = 1
44};
45
Sridhar Siricilla87e36c42020-05-03 19:08:18 +053046/* CSE recovery sub-error codes */
47enum csme_failure_reason {
48 /* Unspecified error */
49 CSE_LITE_SKU_UNSPECIFIED = 1,
50
51 /* CSE fails to boot from RW */
52 CSE_LITE_SKU_RW_JUMP_ERROR = 2,
53
54 /* CSE RW boot partition access error */
55 CSE_LITE_SKU_RW_ACCESS_ERROR = 3,
56
57 /* Fails to set next boot partition as RW */
58 CSE_LITE_SKU_RW_SWITCH_ERROR = 4,
59
60 /* CSE firmware update failure */
61 CSE_LITE_SKU_FW_UPDATE_ERROR = 5,
62
63 /* Fails to communicate with CSE */
64 CSE_LITE_SKU_COMMUNICATION_ERROR = 6,
65
66 /* Fails to wipe CSE runtime data */
67 CSE_LITE_SKU_DATA_WIPE_ERROR = 7
68};
69
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053070/*
71 * Boot partition status.
72 * The status is returned in response to MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO cmd.
73 */
74enum bp_status {
75 /* This value is returned when a partition has no errors */
76 BP_STATUS_SUCCESS = 0,
77
78 /*
79 * This value is returned when a partition should be present based on layout, but it is
80 * not valid.
81 */
82 BP_STATUS_GENERAL_FAILURE = 1,
83
84 /* This value is returned when a partition is not present per initial image layout */
85 BP_STATUS_PARTITION_NOT_PRESENT = 2,
86
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +053087 /*
88 * This value is returned when unexpected issues are detected in CSE Data area
89 * and CSE TCB-SVN downgrade scenario.
90 */
91 BP_STATUS_DATA_FAILURE = 3,
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053092};
93
94/*
95 * Boot Partition Info Flags
96 * The flags are returned in response to MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO cmd.
97 */
98enum bp_info_flags {
99
100 /* Redundancy Enabled: It indicates CSE supports RO(BP1) and RW(BP2) regions */
101 BP_INFO_REDUNDANCY_EN = 1 << 0,
102
103 /* It indicates RO(BP1) supports Minimal Recovery Mode */
104 BP_INFO_MIN_RECOV_MODE_EN = 1 << 1,
105
106 /*
107 * Read-only Config Enabled: It indicates HW protection to CSE RO region is enabled.
108 * The option is relevant only if the BP_INFO_MIN_RECOV_MODE_EN flag is enabled.
109 */
110 BP_INFO_READ_ONLY_CFG = 1 << 2,
111};
112
113/* Boot Partition FW Version */
114struct fw_version {
115 uint16_t major;
116 uint16_t minor;
117 uint16_t hotfix;
118 uint16_t build;
119} __packed;
120
121/* CSE boot partition entry info */
122struct cse_bp_entry {
123 /* Boot partition version */
124 struct fw_version fw_ver;
125
126 /* Boot partition status */
127 uint32_t status;
128
129 /* Starting offset of the partition within CSE region */
130 uint32_t start_offset;
131
132 /* Ending offset of the partition within CSE region */
133 uint32_t end_offset;
134 uint8_t reserved[12];
135} __packed;
136
137/* CSE boot partition info */
138struct cse_bp_info {
139 /* Number of boot partitions */
140 uint8_t total_number_of_bp;
141
142 /* Current boot partition */
143 uint8_t current_bp;
144
145 /* Next boot partition */
146 uint8_t next_bp;
147
148 /* Boot Partition Info Flags */
149 uint8_t flags;
150
151 /* Boot Partition Entry Info */
152 struct cse_bp_entry bp_entries[CSE_MAX_BOOT_PARTITIONS];
153} __packed;
154
155struct get_bp_info_rsp {
156 struct mkhi_hdr hdr;
157 struct cse_bp_info bp_info;
158} __packed;
159
Sridhar Siricilla33aa1152020-06-26 14:29:40 +0530160static void cse_log_status_registers(void)
161{
162 printk(BIOS_DEBUG, "cse_lite: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
163 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
164 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
165}
166
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530167static void cse_trigger_recovery(uint8_t rec_sub_code)
168{
Sridhar Siricilla33aa1152020-06-26 14:29:40 +0530169 /* Log CSE Firmware Status Registers to help debugging */
170 cse_log_status_registers();
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530171 if (CONFIG(VBOOT)) {
Subrata Banik754de4d2020-09-15 15:16:42 +0530172 struct vb2_context *ctx = vboot_get_context();
173 if (ctx == NULL)
174 goto failure;
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530175 vb2api_fail(ctx, VB2_RECOVERY_INTEL_CSE_LITE_SKU, rec_sub_code);
176 vboot_save_data(ctx);
177 vboot_reboot();
178 }
Subrata Banik754de4d2020-09-15 15:16:42 +0530179failure:
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530180 die("cse_lite: Failed to trigger recovery mode(recovery subcode:%d)\n", rec_sub_code);
181}
182
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530183static uint8_t cse_get_current_bp(const struct cse_bp_info *cse_bp_info)
184{
185 return cse_bp_info->current_bp;
186}
187
188static const struct cse_bp_entry *cse_get_bp_entry(enum boot_partition_id bp,
189 const struct cse_bp_info *cse_bp_info)
190{
191 return &cse_bp_info->bp_entries[bp];
192}
193
194static void cse_print_boot_partition_info(const struct cse_bp_info *cse_bp_info)
195{
196 const struct cse_bp_entry *cse_bp;
197
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530198 printk(BIOS_DEBUG, "cse_lite: Number of partitions = %d\n",
199 cse_bp_info->total_number_of_bp);
200 printk(BIOS_DEBUG, "cse_lite: Current partition = %s\n",
201 GET_BP_STR(cse_bp_info->current_bp));
202 printk(BIOS_DEBUG, "cse_lite: Next partition = %s\n", GET_BP_STR(cse_bp_info->next_bp));
203 printk(BIOS_DEBUG, "cse_lite: Flags = 0x%x\n", cse_bp_info->flags);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530204
205 /* Log version info of RO & RW partitions */
206 cse_bp = cse_get_bp_entry(RO, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530207 printk(BIOS_DEBUG, "cse_lite: %s version = %d.%d.%d.%d (Status=0x%x, Start=0x%x, End=0x%x)\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530208 GET_BP_STR(RO), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
209 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
210 cse_bp->status, cse_bp->start_offset,
211 cse_bp->end_offset);
212
213 cse_bp = cse_get_bp_entry(RW, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530214 printk(BIOS_DEBUG, "cse_lite: %s version = %d.%d.%d.%d (Status=0x%x, Start=0x%x, End=0x%x)\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530215 GET_BP_STR(RW), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
216 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
217 cse_bp->status, cse_bp->start_offset,
218 cse_bp->end_offset);
219}
220
221/*
222 * Checks prerequisites for MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO and
223 * MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO HECI commands.
224 * It allows execution of the Boot Partition commands in below scenarios:
225 * - When CSE boots from RW partition (COM: Normal and CWS: Normal)
226 * - When CSE boots from RO partition (COM: Soft Temp Disable and CWS: Normal)
227 * - After HMRFPO_ENABLE command is issued to CSE (COM: SECOVER_MEI_MSG and CWS: Normal)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530228 * The prerequisite check should be handled in cse_get_bp_info() and
229 * cse_set_next_boot_partition() since the CSE's current operation mode is changed between these
230 * cmd handler calls.
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530231 */
232static bool cse_is_bp_cmd_info_possible(void)
233{
234 if (cse_is_hfs1_cws_normal()) {
235 if (cse_is_hfs1_com_normal())
236 return true;
237 if (cse_is_hfs1_com_secover_mei_msg())
238 return true;
239 if (cse_is_hfs1_com_soft_temp_disable())
240 return true;
241 }
242 return false;
243}
244
245static bool cse_get_bp_info(struct get_bp_info_rsp *bp_info_rsp)
246{
247 struct get_bp_info_req {
248 struct mkhi_hdr hdr;
249 uint8_t reserved[4];
250 } __packed;
251
252 struct get_bp_info_req info_req = {
253 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
254 .hdr.command = MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO,
255 .reserved = {0},
256 };
257
258 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530259 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530260 return false;
261 }
262
263 size_t resp_size = sizeof(struct get_bp_info_rsp);
264
265 if (!heci_send_receive(&info_req, sizeof(info_req), bp_info_rsp, &resp_size)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530266 printk(BIOS_ERR, "cse_lite: Could not get partition info\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530267 return false;
268 }
269
270 if (bp_info_rsp->hdr.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530271 printk(BIOS_ERR, "cse_lite: Get partition info resp failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530272 bp_info_rsp->hdr.result);
273 return false;
274 }
275
276 cse_print_boot_partition_info(&bp_info_rsp->bp_info);
277
278 return true;
279}
280/*
281 * It sends HECI command to notify CSE about its next boot partition. When coreboot wants
282 * CSE to boot from certain partition (BP1 <RO> or BP2 <RW>), then this command can be used.
283 * The CSE's valid bootable partitions are BP1(RO) and BP2(RW).
284 * This function must be used before EOP.
285 * Returns false on failure and true on success.
286 */
287static bool cse_set_next_boot_partition(enum boot_partition_id bp)
288{
289 struct set_boot_partition_info_req {
290 struct mkhi_hdr hdr;
291 uint8_t next_bp;
292 uint8_t reserved[3];
293 } __packed;
294
295 struct set_boot_partition_info_req switch_req = {
296 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
297 .hdr.command = MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO,
298 .next_bp = bp,
299 .reserved = {0},
300 };
301
302 if (bp != RO && bp != RW) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530303 printk(BIOS_ERR, "cse_lite: Incorrect partition id(%d) is provided", bp);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530304 return false;
305 }
306
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530307 printk(BIOS_INFO, "cse_lite: Set Boot Partition Info Command (%s)\n", GET_BP_STR(bp));
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530308
309 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530310 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530311 return false;
312 }
313
314 struct mkhi_hdr switch_resp;
315 size_t sw_resp_sz = sizeof(struct mkhi_hdr);
316
317 if (!heci_send_receive(&switch_req, sizeof(switch_req), &switch_resp, &sw_resp_sz))
318 return false;
319
320 if (switch_resp.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530321 printk(BIOS_ERR, "cse_lite: Set Boot Partition Info Response Failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530322 switch_resp.result);
323 return false;
324 }
325
326 return true;
327}
328
V Sowmyaf9905522020-11-12 20:19:04 +0530329static bool cse_data_clear_request(const struct cse_bp_info *cse_bp_info)
330{
331 struct data_clr_request {
332 struct mkhi_hdr hdr;
333 uint8_t reserved[4];
334 } __packed;
335
336 struct data_clr_request data_clr_rq = {
337 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
338 .hdr.command = MKHI_BUP_COMMON_DATA_CLEAR,
339 .reserved = {0},
340 };
341
342 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_soft_temp_disable() ||
343 cse_get_current_bp(cse_bp_info) != RO) {
344 printk(BIOS_ERR, "cse_lite: CSE doesn't meet DATA CLEAR cmd prerequisites\n");
345 return false;
346 }
347
348 printk(BIOS_DEBUG, "cse_lite: Sending DATA CLEAR HECI command\n");
349
350 struct mkhi_hdr data_clr_rsp;
351 size_t data_clr_rsp_sz = sizeof(data_clr_rsp);
352
353 if (!heci_send_receive(&data_clr_rq, sizeof(data_clr_rq), &data_clr_rsp,
354 &data_clr_rsp_sz)) {
355 return false;
356 }
357
358 if (data_clr_rsp.result) {
359 printk(BIOS_ERR, "cse_lite: CSE DATA CLEAR command response failed: %d\n",
360 data_clr_rsp.result);
361 return false;
362 }
363
364 return true;
365}
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600366__weak void cse_board_reset(void)
367{
368 /* Default weak implementation, does nothing. */
369}
370
Rizwan Qureshiec321092019-09-06 20:28:43 +0530371/* Set the CSE's next boot partition and issues system reset */
372static bool cse_set_and_boot_from_next_bp(enum boot_partition_id bp)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530373{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530374 if (!cse_set_next_boot_partition(bp))
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530375 return false;
376
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600377 /* Allow the board to perform a reset for CSE RO<->RW jump */
378 cse_board_reset();
379
380 /* If board does not perform the reset, then perform global_reset */
Furquan Shaikhb13bd1e2020-09-21 22:44:27 +0000381 do_global_reset();
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530382
Rizwan Qureshiec321092019-09-06 20:28:43 +0530383 die("cse_lite: Failed to reset the system\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530384
385 /* Control never reaches here */
386 return false;
387}
388
Rizwan Qureshiec321092019-09-06 20:28:43 +0530389static bool cse_boot_to_rw(const struct cse_bp_info *cse_bp_info)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530390{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530391 if (cse_get_current_bp(cse_bp_info) == RW)
392 return true;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530393
Rizwan Qureshiec321092019-09-06 20:28:43 +0530394 return cse_set_and_boot_from_next_bp(RW);
395}
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530396
V Sowmyaf9905522020-11-12 20:19:04 +0530397/* Check if CSE RW data partition is valid or not */
398static bool cse_is_rw_dp_valid(const struct cse_bp_info *cse_bp_info)
399{
400 const struct cse_bp_entry *rw_bp;
401
402 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
403 return rw_bp->status != BP_STATUS_DATA_FAILURE;
404}
405
406/*
407 * It returns true if RW partition doesn't indicate BP_STATUS_DATA_FAILURE
408 * otherwise false if any operation fails.
409 */
410static bool cse_fix_data_failure_err(const struct cse_bp_info *cse_bp_info)
411{
412 /*
413 * If RW partition status indicates BP_STATUS_DATA_FAILURE,
414 * - Send DATA CLEAR HECI command to CSE
415 * - Send SET BOOT PARTITION INFO(RW) command to set CSE's next partition
416 * - Issue GLOBAL RESET HECI command.
417 */
418 if (cse_is_rw_dp_valid(cse_bp_info))
419 return true;
420
421 if (!cse_data_clear_request(cse_bp_info))
422 return false;
423
424 return cse_boot_to_rw(cse_bp_info);
425}
426
427#if CONFIG(SOC_INTEL_CSE_RW_UPDATE)
428static const struct fw_version *cse_get_bp_entry_version(enum boot_partition_id bp,
429 const struct cse_bp_info *bp_info)
430{
431 const struct cse_bp_entry *cse_bp;
432
433 cse_bp = cse_get_bp_entry(bp, bp_info);
434 return &cse_bp->fw_ver;
435}
436
437static const struct fw_version *cse_get_rw_version(const struct cse_bp_info *cse_bp_info)
438{
439 return cse_get_bp_entry_version(RW, cse_bp_info);
440}
441
442static void cse_get_bp_entry_range(const struct cse_bp_info *cse_bp_info,
443 enum boot_partition_id bp, uint32_t *start_offset, uint32_t *end_offset)
444{
445 const struct cse_bp_entry *cse_bp;
446
447 cse_bp = cse_get_bp_entry(bp, cse_bp_info);
448
449 if (start_offset)
450 *start_offset = cse_bp->start_offset;
451
452 if (end_offset)
453 *end_offset = cse_bp->end_offset;
454
455}
456
457static bool cse_is_rw_bp_status_valid(const struct cse_bp_info *cse_bp_info)
458{
459 const struct cse_bp_entry *rw_bp;
460
461 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
462
463 if (rw_bp->status == BP_STATUS_PARTITION_NOT_PRESENT ||
464 rw_bp->status == BP_STATUS_GENERAL_FAILURE) {
465 printk(BIOS_ERR, "cse_lite: RW BP (status:%u) is not valid\n", rw_bp->status);
466 return false;
467 }
468 return true;
469}
470
Rizwan Qureshiec321092019-09-06 20:28:43 +0530471static bool cse_boot_to_ro(const struct cse_bp_info *cse_bp_info)
472{
473 if (cse_get_current_bp(cse_bp_info) == RO)
474 return true;
475
476 return cse_set_and_boot_from_next_bp(RO);
477}
478
479static bool cse_get_rw_rdev(struct region_device *rdev)
480{
481 if (fmap_locate_area_as_rdev_rw(CONFIG_SOC_INTEL_CSE_FMAP_NAME, rdev) < 0) {
482 printk(BIOS_ERR, "cse_lite: Failed to locate %s in FMAP\n",
483 CONFIG_SOC_INTEL_CSE_FMAP_NAME);
484 return false;
485 }
486
487 return true;
488}
489
490static bool cse_get_cbfs_rdev(struct region_device *source_rdev)
491{
492 struct cbfsf file_desc;
493
494 if (cbfs_boot_locate(&file_desc, CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, NULL) < 0)
495 return false;
496
497 cbfs_file_data(source_rdev, &file_desc);
498 return true;
499}
500
501static bool cse_is_rw_bp_sign_valid(const struct region_device *target_rdev)
502{
503 uint32_t cse_bp_sign;
504
505 if (rdev_readat(target_rdev, &cse_bp_sign, 0, CSE_RW_SIGN_SIZE) != CSE_RW_SIGN_SIZE) {
506 printk(BIOS_ERR, "cse_lite: Failed to read RW boot partition signature\n");
507 return false;
508 }
509
510 return cse_bp_sign == CSE_RW_SIGNATURE;
511}
512
513static bool cse_get_target_rdev(const struct cse_bp_info *cse_bp_info,
514 struct region_device *target_rdev)
515{
516 struct region_device cse_region_rdev;
517 size_t size;
518 uint32_t start_offset;
519 uint32_t end_offset;
520
521 if (!cse_get_rw_rdev(&cse_region_rdev))
522 return false;
523
524 cse_get_bp_entry_range(cse_bp_info, RW, &start_offset, &end_offset);
525 size = end_offset + 1 - start_offset;
526
527 if (rdev_chain(target_rdev, &cse_region_rdev, start_offset, size))
528 return false;
529
530 printk(BIOS_DEBUG, "cse_lite: CSE RW partition: offset = 0x%x, size = 0x%x\n",
531 (uint32_t)start_offset, (uint32_t) size);
532
533 return true;
534}
535
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530536
Rizwan Qureshiec321092019-09-06 20:28:43 +0530537static bool cse_get_cbfs_rw_version(const struct region_device *source_rdev,
538 void *cse_cbfs_rw_ver)
539{
540
541 if (rdev_readat(source_rdev, (void *) cse_cbfs_rw_ver, 0, sizeof(struct fw_version))
542 != sizeof(struct fw_version)) {
543 printk(BIOS_ERR, "cse_lite: Failed to read CSE CBFW RW version\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530544 return false;
545 }
546 return true;
547}
548
Rizwan Qureshiec321092019-09-06 20:28:43 +0530549/*
550 * Compare versions of CSE CBFS RW and CSE RW partition
551 * If ver_cmp_status = 0, no update is required
552 * If ver_cmp_status < 0, coreboot downgrades CSE RW region
553 * If ver_cmp_status > 0, coreboot upgrades CSE RW region
554 */
555static int cse_check_version_mismatch(const struct cse_bp_info *cse_bp_info,
556 const struct region_device *source_rdev)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530557{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530558 struct fw_version cse_cbfs_rw_ver;
559 const struct fw_version *cse_rw_ver;
560
561 if (!cse_get_cbfs_rw_version(source_rdev, &cse_cbfs_rw_ver))
562 return false;
563
564 printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n",
565 cse_cbfs_rw_ver.major,
566 cse_cbfs_rw_ver.minor,
567 cse_cbfs_rw_ver.hotfix,
568 cse_cbfs_rw_ver.build);
569
570 cse_rw_ver = cse_get_rw_version(cse_bp_info);
571
572 if (cse_cbfs_rw_ver.major != cse_rw_ver->major)
573 return cse_cbfs_rw_ver.major - cse_rw_ver->major;
574 else if (cse_cbfs_rw_ver.minor != cse_rw_ver->minor)
575 return cse_cbfs_rw_ver.minor - cse_rw_ver->minor;
576 else if (cse_cbfs_rw_ver.hotfix != cse_rw_ver->hotfix)
577 return cse_cbfs_rw_ver.hotfix - cse_rw_ver->hotfix;
578 else
579 return cse_cbfs_rw_ver.build - cse_rw_ver->build;
580}
581
582static bool cse_erase_rw_region(const struct region_device *target_rdev)
583{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530584 if (rdev_eraseat(target_rdev, 0, region_device_sz(target_rdev)) < 0) {
585 printk(BIOS_ERR, "cse_lite: CSE RW partition could not be erased\n");
586 return false;
587 }
588 return true;
589}
590
591static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf, size_t offset,
592 size_t size)
593{
594 if (rdev_writeat(target_rdev, buf, offset, size) < 0) {
595 printk(BIOS_ERR, "cse_lite: Failed to update CSE firmware\n");
596 return false;
597 }
598
599 return true;
600}
601
602static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info,
603 const struct region_device *source_rdev)
604{
605 return !cse_check_version_mismatch(cse_bp_info, source_rdev);
606}
607
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530608static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info,
609 const struct region_device *source_rdev)
610{
611 return cse_check_version_mismatch(cse_bp_info, source_rdev) < 0;
612}
613
Rizwan Qureshiec321092019-09-06 20:28:43 +0530614static bool cse_is_update_required(const struct cse_bp_info *cse_bp_info,
615 const struct region_device *source_rdev, struct region_device *target_rdev)
616{
617 return (!cse_is_rw_bp_sign_valid(target_rdev) ||
618 !cse_is_rw_version_latest(cse_bp_info, source_rdev));
619}
620
621static bool cse_write_rw_region(const struct region_device *target_rdev,
622 const struct region_device *source_rdev)
623{
624 void *cse_cbfs_rw = rdev_mmap(source_rdev, CSE_RW_VERSION_SZ,
625 region_device_sz(source_rdev) - CSE_RW_VERSION_SZ);
626
627 /* Points to CSE CBFS RW image after boot partition signature */
628 uint8_t *cse_cbfs_rw_wo_sign = (uint8_t *)cse_cbfs_rw + CSE_RW_SIGN_SIZE;
629
630 /* Size of CSE CBFS RW image without boot partition signature */
631 uint32_t cse_cbfs_rw_wo_sign_sz = region_device_sz(source_rdev) -
632 (CSE_RW_VERSION_SZ + CSE_RW_SIGN_SIZE);
633
634 /* Update except CSE RW signature */
635 if (!cse_copy_rw(target_rdev, cse_cbfs_rw_wo_sign, CSE_RW_SIGN_SIZE,
636 cse_cbfs_rw_wo_sign_sz))
637 goto exit_rw_update;
638
639 /* Update CSE RW signature to indicate update is complete */
640 if (!cse_copy_rw(target_rdev, (void *)cse_cbfs_rw, 0, CSE_RW_SIGN_SIZE))
641 goto exit_rw_update;
642
643 rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign);
644 return true;
645
646exit_rw_update:
647 rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign);
648 return false;
649}
650
651static bool cse_update_rw(const struct cse_bp_info *cse_bp_info,
652 const struct region_device *source_rdev, struct region_device *target_rdev)
653{
654 if (!cse_erase_rw_region(target_rdev))
655 return false;
656
657 if (!cse_write_rw_region(target_rdev, source_rdev))
658 return false;
659
660 printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n");
661 return true;
662}
663
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530664static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info,
665 const struct region_device *source_rdev)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530666{
667 /*
668 * To set CSE's operation mode to HMRFPO mode:
669 * 1. Ensure CSE to boot from RO(BP1)
670 * 2. Send HMRFPO_ENABLE command to CSE
671 */
672 if (!cse_boot_to_ro(cse_bp_info))
673 return false;
674
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530675 if (cse_is_downgrade_instance(cse_bp_info, source_rdev) &&
676 !cse_data_clear_request(cse_bp_info)) {
677 printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n");
678 return false;
679 }
680
Rizwan Qureshiec321092019-09-06 20:28:43 +0530681 return cse_hmrfpo_enable();
682}
683
684static uint8_t cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info,
685 const struct region_device *source_rdev, struct region_device *target_rdev)
686{
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530687 if (!cse_prep_for_rw_update(cse_bp_info, source_rdev))
Rizwan Qureshiec321092019-09-06 20:28:43 +0530688 return CSE_LITE_SKU_COMMUNICATION_ERROR;
689
690 if (!cse_update_rw(cse_bp_info, source_rdev, target_rdev))
691 return CSE_LITE_SKU_FW_UPDATE_ERROR;
692
693 return 0;
694}
695
696static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info,
697 const struct region_device *source_rdev)
698{
699 struct region_device target_rdev;
700
701 if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) {
702 printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n");
703 return CSE_LITE_SKU_RW_ACCESS_ERROR;
704 }
705
706 if (cse_is_update_required(cse_bp_info, source_rdev, &target_rdev)) {
707 printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
708 return cse_trigger_fw_update(cse_bp_info, source_rdev, &target_rdev);
709 }
710
711 if (!cse_is_rw_bp_status_valid(cse_bp_info))
712 return CSE_LITE_SKU_RW_JUMP_ERROR;
713
714 return 0;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530715}
V Sowmyaf9905522020-11-12 20:19:04 +0530716#endif
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530717
718void cse_fw_sync(void *unused)
719{
720 static struct get_bp_info_rsp cse_bp_info;
721
722 if (vboot_recovery_mode_enabled()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530723 printk(BIOS_DEBUG, "cse_lite: Skip switching to RW in the recovery path\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530724 return;
725 }
726
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530727 /* If CSE SKU type is not Lite, skip enabling CSE Lite SKU */
728 if (!cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530729 printk(BIOS_ERR, "cse_lite: Not a CSE Lite SKU\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530730 return;
731 }
732
733 if (!cse_get_bp_info(&cse_bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530734 printk(BIOS_ERR, "cse_lite: Failed to get CSE boot partition info\n");
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530735 cse_trigger_recovery(CSE_LITE_SKU_COMMUNICATION_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530736 }
737
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530738 if (!cse_fix_data_failure_err(&cse_bp_info.bp_info))
739 cse_trigger_recovery(CSE_LITE_SKU_DATA_WIPE_ERROR);
740
Rizwan Qureshiec321092019-09-06 20:28:43 +0530741 /* If RW blob is present in CBFS, then trigger CSE firmware update */
V Sowmyaf9905522020-11-12 20:19:04 +0530742#if CONFIG(SOC_INTEL_CSE_RW_UPDATE)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530743 uint8_t rv;
744 struct region_device source_rdev;
745 if (cse_get_cbfs_rdev(&source_rdev)) {
746 rv = cse_fw_update(&cse_bp_info.bp_info, &source_rdev);
747 if (rv)
748 cse_trigger_recovery(rv);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530749 }
V Sowmyaf9905522020-11-12 20:19:04 +0530750#endif
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530751
752 if (!cse_boot_to_rw(&cse_bp_info.bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530753 printk(BIOS_ERR, "cse_lite: Failed to switch to RW\n");
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530754 cse_trigger_recovery(CSE_LITE_SKU_RW_SWITCH_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530755 }
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530756}
757
Karthikeyan Ramasubramaniancc05e312020-09-18 01:34:27 -0600758#if CONFIG(SOC_INTEL_TIGERLAKE) || CONFIG(SOC_INTEL_JASPERLAKE)
Caveh Jalali9bc04112020-07-23 17:09:22 -0700759/*
760 * This needs to happen after the MRC cache write to avoid a 2nd
761 * memory training sequence.
762 */
763BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_ENTRY, cse_fw_sync, NULL);
Jamie Ryubd8e7612020-06-24 18:29:06 -0700764#else
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530765BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, cse_fw_sync, NULL);
Jamie Ryubd8e7612020-06-24 18:29:06 -0700766#endif