blob: c9e4e1f4708c50ae77cb9adfd5f8b29720525f1c [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
Rizwan Qureshiec321092019-09-06 20:28:43 +0530194static void cse_get_bp_entry_range(const struct cse_bp_info *cse_bp_info,
195 enum boot_partition_id bp, uint32_t *start_offset, uint32_t *end_offset)
196{
197 const struct cse_bp_entry *cse_bp;
198
199 cse_bp = cse_get_bp_entry(bp, cse_bp_info);
200
201 if (start_offset)
202 *start_offset = cse_bp->start_offset;
203
204 if (end_offset)
205 *end_offset = cse_bp->end_offset;
206
207}
208
209static const struct fw_version *cse_get_bp_entry_version(enum boot_partition_id bp,
210 const struct cse_bp_info *bp_info)
211{
212 const struct cse_bp_entry *cse_bp;
213
214 cse_bp = cse_get_bp_entry(bp, bp_info);
215 return &cse_bp->fw_ver;
216}
217
218static const struct fw_version *cse_get_rw_version(const struct cse_bp_info *cse_bp_info)
219{
220 return cse_get_bp_entry_version(RW, cse_bp_info);
221}
222
223static bool cse_is_rw_bp_status_valid(const struct cse_bp_info *cse_bp_info)
224{
225 const struct cse_bp_entry *rw_bp;
226
227 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
228
229 if (rw_bp->status == BP_STATUS_PARTITION_NOT_PRESENT ||
230 rw_bp->status == BP_STATUS_GENERAL_FAILURE) {
231 printk(BIOS_ERR, "cse_lite: RW BP (status:%u) is not valid\n", rw_bp->status);
232 return false;
233 }
234 return true;
235}
236
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530237static void cse_print_boot_partition_info(const struct cse_bp_info *cse_bp_info)
238{
239 const struct cse_bp_entry *cse_bp;
240
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530241 printk(BIOS_DEBUG, "cse_lite: Number of partitions = %d\n",
242 cse_bp_info->total_number_of_bp);
243 printk(BIOS_DEBUG, "cse_lite: Current partition = %s\n",
244 GET_BP_STR(cse_bp_info->current_bp));
245 printk(BIOS_DEBUG, "cse_lite: Next partition = %s\n", GET_BP_STR(cse_bp_info->next_bp));
246 printk(BIOS_DEBUG, "cse_lite: Flags = 0x%x\n", cse_bp_info->flags);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530247
248 /* Log version info of RO & RW partitions */
249 cse_bp = cse_get_bp_entry(RO, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530250 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 +0530251 GET_BP_STR(RO), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
252 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
253 cse_bp->status, cse_bp->start_offset,
254 cse_bp->end_offset);
255
256 cse_bp = cse_get_bp_entry(RW, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530257 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 +0530258 GET_BP_STR(RW), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
259 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
260 cse_bp->status, cse_bp->start_offset,
261 cse_bp->end_offset);
262}
263
264/*
265 * Checks prerequisites for MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO and
266 * MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO HECI commands.
267 * It allows execution of the Boot Partition commands in below scenarios:
268 * - When CSE boots from RW partition (COM: Normal and CWS: Normal)
269 * - When CSE boots from RO partition (COM: Soft Temp Disable and CWS: Normal)
270 * - After HMRFPO_ENABLE command is issued to CSE (COM: SECOVER_MEI_MSG and CWS: Normal)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530271 * The prerequisite check should be handled in cse_get_bp_info() and
272 * cse_set_next_boot_partition() since the CSE's current operation mode is changed between these
273 * cmd handler calls.
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530274 */
275static bool cse_is_bp_cmd_info_possible(void)
276{
277 if (cse_is_hfs1_cws_normal()) {
278 if (cse_is_hfs1_com_normal())
279 return true;
280 if (cse_is_hfs1_com_secover_mei_msg())
281 return true;
282 if (cse_is_hfs1_com_soft_temp_disable())
283 return true;
284 }
285 return false;
286}
287
288static bool cse_get_bp_info(struct get_bp_info_rsp *bp_info_rsp)
289{
290 struct get_bp_info_req {
291 struct mkhi_hdr hdr;
292 uint8_t reserved[4];
293 } __packed;
294
295 struct get_bp_info_req info_req = {
296 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
297 .hdr.command = MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO,
298 .reserved = {0},
299 };
300
301 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530302 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530303 return false;
304 }
305
306 size_t resp_size = sizeof(struct get_bp_info_rsp);
307
308 if (!heci_send_receive(&info_req, sizeof(info_req), bp_info_rsp, &resp_size)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530309 printk(BIOS_ERR, "cse_lite: Could not get partition info\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530310 return false;
311 }
312
313 if (bp_info_rsp->hdr.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530314 printk(BIOS_ERR, "cse_lite: Get partition info resp failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530315 bp_info_rsp->hdr.result);
316 return false;
317 }
318
319 cse_print_boot_partition_info(&bp_info_rsp->bp_info);
320
321 return true;
322}
323/*
324 * It sends HECI command to notify CSE about its next boot partition. When coreboot wants
325 * CSE to boot from certain partition (BP1 <RO> or BP2 <RW>), then this command can be used.
326 * The CSE's valid bootable partitions are BP1(RO) and BP2(RW).
327 * This function must be used before EOP.
328 * Returns false on failure and true on success.
329 */
330static bool cse_set_next_boot_partition(enum boot_partition_id bp)
331{
332 struct set_boot_partition_info_req {
333 struct mkhi_hdr hdr;
334 uint8_t next_bp;
335 uint8_t reserved[3];
336 } __packed;
337
338 struct set_boot_partition_info_req switch_req = {
339 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
340 .hdr.command = MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO,
341 .next_bp = bp,
342 .reserved = {0},
343 };
344
345 if (bp != RO && bp != RW) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530346 printk(BIOS_ERR, "cse_lite: Incorrect partition id(%d) is provided", bp);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530347 return false;
348 }
349
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530350 printk(BIOS_INFO, "cse_lite: Set Boot Partition Info Command (%s)\n", GET_BP_STR(bp));
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530351
352 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530353 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530354 return false;
355 }
356
357 struct mkhi_hdr switch_resp;
358 size_t sw_resp_sz = sizeof(struct mkhi_hdr);
359
360 if (!heci_send_receive(&switch_req, sizeof(switch_req), &switch_resp, &sw_resp_sz))
361 return false;
362
363 if (switch_resp.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530364 printk(BIOS_ERR, "cse_lite: Set Boot Partition Info Response Failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530365 switch_resp.result);
366 return false;
367 }
368
369 return true;
370}
371
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600372__weak void cse_board_reset(void)
373{
374 /* Default weak implementation, does nothing. */
375}
376
Rizwan Qureshiec321092019-09-06 20:28:43 +0530377/* Set the CSE's next boot partition and issues system reset */
378static bool cse_set_and_boot_from_next_bp(enum boot_partition_id bp)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530379{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530380 if (!cse_set_next_boot_partition(bp))
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530381 return false;
382
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600383 /* Allow the board to perform a reset for CSE RO<->RW jump */
384 cse_board_reset();
385
386 /* If board does not perform the reset, then perform global_reset */
Furquan Shaikhb13bd1e2020-09-21 22:44:27 +0000387 do_global_reset();
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530388
Rizwan Qureshiec321092019-09-06 20:28:43 +0530389 die("cse_lite: Failed to reset the system\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530390
391 /* Control never reaches here */
392 return false;
393}
394
Rizwan Qureshiec321092019-09-06 20:28:43 +0530395static bool cse_boot_to_rw(const struct cse_bp_info *cse_bp_info)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530396{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530397 if (cse_get_current_bp(cse_bp_info) == RW)
398 return true;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530399
Rizwan Qureshiec321092019-09-06 20:28:43 +0530400 return cse_set_and_boot_from_next_bp(RW);
401}
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530402
Rizwan Qureshiec321092019-09-06 20:28:43 +0530403static bool cse_boot_to_ro(const struct cse_bp_info *cse_bp_info)
404{
405 if (cse_get_current_bp(cse_bp_info) == RO)
406 return true;
407
408 return cse_set_and_boot_from_next_bp(RO);
409}
410
411static bool cse_get_rw_rdev(struct region_device *rdev)
412{
413 if (fmap_locate_area_as_rdev_rw(CONFIG_SOC_INTEL_CSE_FMAP_NAME, rdev) < 0) {
414 printk(BIOS_ERR, "cse_lite: Failed to locate %s in FMAP\n",
415 CONFIG_SOC_INTEL_CSE_FMAP_NAME);
416 return false;
417 }
418
419 return true;
420}
421
422static bool cse_get_cbfs_rdev(struct region_device *source_rdev)
423{
424 struct cbfsf file_desc;
425
426 if (cbfs_boot_locate(&file_desc, CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, NULL) < 0)
427 return false;
428
429 cbfs_file_data(source_rdev, &file_desc);
430 return true;
431}
432
433static bool cse_is_rw_bp_sign_valid(const struct region_device *target_rdev)
434{
435 uint32_t cse_bp_sign;
436
437 if (rdev_readat(target_rdev, &cse_bp_sign, 0, CSE_RW_SIGN_SIZE) != CSE_RW_SIGN_SIZE) {
438 printk(BIOS_ERR, "cse_lite: Failed to read RW boot partition signature\n");
439 return false;
440 }
441
442 return cse_bp_sign == CSE_RW_SIGNATURE;
443}
444
445static bool cse_get_target_rdev(const struct cse_bp_info *cse_bp_info,
446 struct region_device *target_rdev)
447{
448 struct region_device cse_region_rdev;
449 size_t size;
450 uint32_t start_offset;
451 uint32_t end_offset;
452
453 if (!cse_get_rw_rdev(&cse_region_rdev))
454 return false;
455
456 cse_get_bp_entry_range(cse_bp_info, RW, &start_offset, &end_offset);
457 size = end_offset + 1 - start_offset;
458
459 if (rdev_chain(target_rdev, &cse_region_rdev, start_offset, size))
460 return false;
461
462 printk(BIOS_DEBUG, "cse_lite: CSE RW partition: offset = 0x%x, size = 0x%x\n",
463 (uint32_t)start_offset, (uint32_t) size);
464
465 return true;
466}
467
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530468static bool cse_data_clear_request(const struct cse_bp_info *cse_bp_info)
469{
470 struct data_clr_request {
471 struct mkhi_hdr hdr;
472 uint8_t reserved[4];
473 } __packed;
474
475 struct data_clr_request data_clr_rq = {
476 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
477 .hdr.command = MKHI_BUP_COMMON_DATA_CLEAR,
478 .reserved = {0},
479 };
480
481 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_soft_temp_disable() ||
482 cse_get_current_bp(cse_bp_info) != RO) {
483 printk(BIOS_ERR, "cse_lite: CSE doesn't meet DATA CLEAR cmd prerequisites\n");
484 return false;
485 }
486
487 printk(BIOS_DEBUG, "cse_lite: Sending DATA CLEAR HECI command\n");
488
489 struct mkhi_hdr data_clr_rsp;
490 size_t data_clr_rsp_sz = sizeof(data_clr_rsp);
491
492 if (!heci_send_receive(&data_clr_rq, sizeof(data_clr_rq), &data_clr_rsp,
493 &data_clr_rsp_sz)) {
494 return false;
495 }
496
497 if (data_clr_rsp.result) {
498 printk(BIOS_ERR, "cse_lite: CSE DATA CLEAR command response failed: %d\n",
499 data_clr_rsp.result);
500 return false;
501 }
502
503 return true;
504}
505
Rizwan Qureshiec321092019-09-06 20:28:43 +0530506static bool cse_get_cbfs_rw_version(const struct region_device *source_rdev,
507 void *cse_cbfs_rw_ver)
508{
509
510 if (rdev_readat(source_rdev, (void *) cse_cbfs_rw_ver, 0, sizeof(struct fw_version))
511 != sizeof(struct fw_version)) {
512 printk(BIOS_ERR, "cse_lite: Failed to read CSE CBFW RW version\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530513 return false;
514 }
515 return true;
516}
517
Rizwan Qureshiec321092019-09-06 20:28:43 +0530518/*
519 * Compare versions of CSE CBFS RW and CSE RW partition
520 * If ver_cmp_status = 0, no update is required
521 * If ver_cmp_status < 0, coreboot downgrades CSE RW region
522 * If ver_cmp_status > 0, coreboot upgrades CSE RW region
523 */
524static int cse_check_version_mismatch(const struct cse_bp_info *cse_bp_info,
525 const struct region_device *source_rdev)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530526{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530527 struct fw_version cse_cbfs_rw_ver;
528 const struct fw_version *cse_rw_ver;
529
530 if (!cse_get_cbfs_rw_version(source_rdev, &cse_cbfs_rw_ver))
531 return false;
532
533 printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n",
534 cse_cbfs_rw_ver.major,
535 cse_cbfs_rw_ver.minor,
536 cse_cbfs_rw_ver.hotfix,
537 cse_cbfs_rw_ver.build);
538
539 cse_rw_ver = cse_get_rw_version(cse_bp_info);
540
541 if (cse_cbfs_rw_ver.major != cse_rw_ver->major)
542 return cse_cbfs_rw_ver.major - cse_rw_ver->major;
543 else if (cse_cbfs_rw_ver.minor != cse_rw_ver->minor)
544 return cse_cbfs_rw_ver.minor - cse_rw_ver->minor;
545 else if (cse_cbfs_rw_ver.hotfix != cse_rw_ver->hotfix)
546 return cse_cbfs_rw_ver.hotfix - cse_rw_ver->hotfix;
547 else
548 return cse_cbfs_rw_ver.build - cse_rw_ver->build;
549}
550
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530551/* Check if CSE RW data partition is valid or not */
552static bool cse_is_rw_dp_valid(const struct cse_bp_info *cse_bp_info)
553{
554 const struct cse_bp_entry *rw_bp;
555
556 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
557 return rw_bp->status != BP_STATUS_DATA_FAILURE;
558}
559
560/*
561 * It returns true if RW partition doesn't indicate BP_STATUS_DATA_FAILURE
562 * otherwise false if any operation fails.
563 */
564static bool cse_fix_data_failure_err(const struct cse_bp_info *cse_bp_info)
565{
566 /*
567 * If RW partition status indicates BP_STATUS_DATA_FAILURE,
568 * - Send DATA CLEAR HECI command to CSE
569 * - Send SET BOOT PARTITION INFO(RW) command to set CSE's next partition
570 * - Issue GLOBAL RESET HECI command.
571 */
572 if (cse_is_rw_dp_valid(cse_bp_info))
573 return true;
574
575 if (!cse_data_clear_request(cse_bp_info))
576 return false;
577
578 return cse_boot_to_rw(cse_bp_info);
579}
580
Rizwan Qureshiec321092019-09-06 20:28:43 +0530581static bool cse_erase_rw_region(const struct region_device *target_rdev)
582{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530583 if (rdev_eraseat(target_rdev, 0, region_device_sz(target_rdev)) < 0) {
584 printk(BIOS_ERR, "cse_lite: CSE RW partition could not be erased\n");
585 return false;
586 }
587 return true;
588}
589
590static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf, size_t offset,
591 size_t size)
592{
593 if (rdev_writeat(target_rdev, buf, offset, size) < 0) {
594 printk(BIOS_ERR, "cse_lite: Failed to update CSE firmware\n");
595 return false;
596 }
597
598 return true;
599}
600
601static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info,
602 const struct region_device *source_rdev)
603{
604 return !cse_check_version_mismatch(cse_bp_info, source_rdev);
605}
606
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530607static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info,
608 const struct region_device *source_rdev)
609{
610 return cse_check_version_mismatch(cse_bp_info, source_rdev) < 0;
611}
612
Rizwan Qureshiec321092019-09-06 20:28:43 +0530613static bool cse_is_update_required(const struct cse_bp_info *cse_bp_info,
614 const struct region_device *source_rdev, struct region_device *target_rdev)
615{
616 return (!cse_is_rw_bp_sign_valid(target_rdev) ||
617 !cse_is_rw_version_latest(cse_bp_info, source_rdev));
618}
619
620static bool cse_write_rw_region(const struct region_device *target_rdev,
621 const struct region_device *source_rdev)
622{
623 void *cse_cbfs_rw = rdev_mmap(source_rdev, CSE_RW_VERSION_SZ,
624 region_device_sz(source_rdev) - CSE_RW_VERSION_SZ);
625
626 /* Points to CSE CBFS RW image after boot partition signature */
627 uint8_t *cse_cbfs_rw_wo_sign = (uint8_t *)cse_cbfs_rw + CSE_RW_SIGN_SIZE;
628
629 /* Size of CSE CBFS RW image without boot partition signature */
630 uint32_t cse_cbfs_rw_wo_sign_sz = region_device_sz(source_rdev) -
631 (CSE_RW_VERSION_SZ + CSE_RW_SIGN_SIZE);
632
633 /* Update except CSE RW signature */
634 if (!cse_copy_rw(target_rdev, cse_cbfs_rw_wo_sign, CSE_RW_SIGN_SIZE,
635 cse_cbfs_rw_wo_sign_sz))
636 goto exit_rw_update;
637
638 /* Update CSE RW signature to indicate update is complete */
639 if (!cse_copy_rw(target_rdev, (void *)cse_cbfs_rw, 0, CSE_RW_SIGN_SIZE))
640 goto exit_rw_update;
641
642 rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign);
643 return true;
644
645exit_rw_update:
646 rdev_munmap(source_rdev, cse_cbfs_rw_wo_sign);
647 return false;
648}
649
650static bool cse_update_rw(const struct cse_bp_info *cse_bp_info,
651 const struct region_device *source_rdev, struct region_device *target_rdev)
652{
653 if (!cse_erase_rw_region(target_rdev))
654 return false;
655
656 if (!cse_write_rw_region(target_rdev, source_rdev))
657 return false;
658
659 printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n");
660 return true;
661}
662
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530663static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info,
664 const struct region_device *source_rdev)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530665{
666 /*
667 * To set CSE's operation mode to HMRFPO mode:
668 * 1. Ensure CSE to boot from RO(BP1)
669 * 2. Send HMRFPO_ENABLE command to CSE
670 */
671 if (!cse_boot_to_ro(cse_bp_info))
672 return false;
673
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530674 if (cse_is_downgrade_instance(cse_bp_info, source_rdev) &&
675 !cse_data_clear_request(cse_bp_info)) {
676 printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n");
677 return false;
678 }
679
Rizwan Qureshiec321092019-09-06 20:28:43 +0530680 return cse_hmrfpo_enable();
681}
682
683static uint8_t cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info,
684 const struct region_device *source_rdev, struct region_device *target_rdev)
685{
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530686 if (!cse_prep_for_rw_update(cse_bp_info, source_rdev))
Rizwan Qureshiec321092019-09-06 20:28:43 +0530687 return CSE_LITE_SKU_COMMUNICATION_ERROR;
688
689 if (!cse_update_rw(cse_bp_info, source_rdev, target_rdev))
690 return CSE_LITE_SKU_FW_UPDATE_ERROR;
691
692 return 0;
693}
694
695static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info,
696 const struct region_device *source_rdev)
697{
698 struct region_device target_rdev;
699
700 if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) {
701 printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n");
702 return CSE_LITE_SKU_RW_ACCESS_ERROR;
703 }
704
705 if (cse_is_update_required(cse_bp_info, source_rdev, &target_rdev)) {
706 printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
707 return cse_trigger_fw_update(cse_bp_info, source_rdev, &target_rdev);
708 }
709
710 if (!cse_is_rw_bp_status_valid(cse_bp_info))
711 return CSE_LITE_SKU_RW_JUMP_ERROR;
712
713 return 0;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530714}
715
716void cse_fw_sync(void *unused)
717{
718 static struct get_bp_info_rsp cse_bp_info;
719
720 if (vboot_recovery_mode_enabled()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530721 printk(BIOS_DEBUG, "cse_lite: Skip switching to RW in the recovery path\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530722 return;
723 }
724
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530725 /* If CSE SKU type is not Lite, skip enabling CSE Lite SKU */
726 if (!cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530727 printk(BIOS_ERR, "cse_lite: Not a CSE Lite SKU\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530728 return;
729 }
730
731 if (!cse_get_bp_info(&cse_bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530732 printk(BIOS_ERR, "cse_lite: Failed to get CSE boot partition info\n");
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530733 cse_trigger_recovery(CSE_LITE_SKU_COMMUNICATION_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530734 }
735
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530736 if (!cse_fix_data_failure_err(&cse_bp_info.bp_info))
737 cse_trigger_recovery(CSE_LITE_SKU_DATA_WIPE_ERROR);
738
Rizwan Qureshiec321092019-09-06 20:28:43 +0530739 /* If RW blob is present in CBFS, then trigger CSE firmware update */
740 uint8_t rv;
741 struct region_device source_rdev;
742 if (cse_get_cbfs_rdev(&source_rdev)) {
743 rv = cse_fw_update(&cse_bp_info.bp_info, &source_rdev);
744 if (rv)
745 cse_trigger_recovery(rv);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530746 }
747
748 if (!cse_boot_to_rw(&cse_bp_info.bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530749 printk(BIOS_ERR, "cse_lite: Failed to switch to RW\n");
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530750 cse_trigger_recovery(CSE_LITE_SKU_RW_SWITCH_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530751 }
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530752}
753
Karthikeyan Ramasubramaniancc05e312020-09-18 01:34:27 -0600754#if CONFIG(SOC_INTEL_TIGERLAKE) || CONFIG(SOC_INTEL_JASPERLAKE)
Caveh Jalali9bc04112020-07-23 17:09:22 -0700755/*
756 * This needs to happen after the MRC cache write to avoid a 2nd
757 * memory training sequence.
758 */
759BOOT_STATE_INIT_ENTRY(BS_DEV_RESOURCES, BS_ON_ENTRY, cse_fw_sync, NULL);
Jamie Ryubd8e7612020-06-24 18:29:06 -0700760#else
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530761BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, cse_fw_sync, NULL);
Jamie Ryubd8e7612020-06-24 18:29:06 -0700762#endif