blob: bb644443e29e0d723e4772f665f5720af3f5713b [file] [log] [blame]
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05301/* SPDX-License-Identifier: GPL-2.0-only */
Elyes HAOUAS944da482021-02-01 21:30:13 +01002
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05303#include <console/console.h>
Rizwan Qureshiec321092019-09-06 20:28:43 +05304#include <cbfs.h>
Rizwan Qureshiec321092019-09-06 20:28:43 +05305#include <commonlib/region.h>
6#include <fmap.h>
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05307#include <intelblocks/cse.h>
8#include <security/vboot/vboot_common.h>
Sridhar Siricilla87e36c42020-05-03 19:08:18 +05309#include <security/vboot/misc.h>
Rizwan Qureshiec321092019-09-06 20:28:43 +053010#include <soc/intel/common/reset.h>
11
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053012/* Converts bp index to boot partition string */
13#define GET_BP_STR(bp_index) (bp_index ? "RW" : "RO")
14
Rizwan Qureshiec321092019-09-06 20:28:43 +053015/* CSE RW boot partition signature */
16#define CSE_RW_SIGNATURE 0x000055aa
17
18/* CSE RW boot partition signature size */
19#define CSE_RW_SIGN_SIZE sizeof(uint32_t)
20
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053021/*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053022 * CSE Firmware supports 3 boot partitions. For CSE Lite SKU, only 2 boot partitions are
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053023 * used and 3rd boot partition is set to BP_STATUS_PARTITION_NOT_PRESENT.
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053024 * CSE Lite SKU Image Layout:
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053025 * ------------- ------------------- ---------------------
26 * |CSE REGION | => | RO | RW | DATA | => | BP1 | BP2 | DATA |
27 * ------------- ------------------- ---------------------
28 */
29#define CSE_MAX_BOOT_PARTITIONS 3
30
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053031/* CSE Lite SKU's valid bootable partition identifiers */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053032enum boot_partition_id {
Rizwan Qureshiec321092019-09-06 20:28:43 +053033 /* RO(BP1) contains recovery/minimal boot firmware */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053034 RO = 0,
35
Rizwan Qureshiec321092019-09-06 20:28:43 +053036 /* RW(BP2) contains fully functional CSE firmware */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053037 RW = 1
38};
39
40/*
41 * Boot partition status.
42 * The status is returned in response to MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO cmd.
43 */
44enum bp_status {
45 /* This value is returned when a partition has no errors */
46 BP_STATUS_SUCCESS = 0,
47
48 /*
49 * This value is returned when a partition should be present based on layout, but it is
50 * not valid.
51 */
52 BP_STATUS_GENERAL_FAILURE = 1,
53
54 /* This value is returned when a partition is not present per initial image layout */
55 BP_STATUS_PARTITION_NOT_PRESENT = 2,
56
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +053057 /*
58 * This value is returned when unexpected issues are detected in CSE Data area
59 * and CSE TCB-SVN downgrade scenario.
60 */
61 BP_STATUS_DATA_FAILURE = 3,
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053062};
63
64/*
65 * Boot Partition Info Flags
66 * The flags are returned in response to MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO cmd.
67 */
68enum bp_info_flags {
69
70 /* Redundancy Enabled: It indicates CSE supports RO(BP1) and RW(BP2) regions */
71 BP_INFO_REDUNDANCY_EN = 1 << 0,
72
73 /* It indicates RO(BP1) supports Minimal Recovery Mode */
74 BP_INFO_MIN_RECOV_MODE_EN = 1 << 1,
75
76 /*
77 * Read-only Config Enabled: It indicates HW protection to CSE RO region is enabled.
78 * The option is relevant only if the BP_INFO_MIN_RECOV_MODE_EN flag is enabled.
79 */
80 BP_INFO_READ_ONLY_CFG = 1 << 2,
81};
82
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053083/* CSE boot partition entry info */
84struct cse_bp_entry {
85 /* Boot partition version */
86 struct fw_version fw_ver;
87
88 /* Boot partition status */
89 uint32_t status;
90
91 /* Starting offset of the partition within CSE region */
92 uint32_t start_offset;
93
94 /* Ending offset of the partition within CSE region */
95 uint32_t end_offset;
96 uint8_t reserved[12];
97} __packed;
98
99/* CSE boot partition info */
100struct cse_bp_info {
101 /* Number of boot partitions */
102 uint8_t total_number_of_bp;
103
104 /* Current boot partition */
105 uint8_t current_bp;
106
107 /* Next boot partition */
108 uint8_t next_bp;
109
110 /* Boot Partition Info Flags */
111 uint8_t flags;
112
113 /* Boot Partition Entry Info */
114 struct cse_bp_entry bp_entries[CSE_MAX_BOOT_PARTITIONS];
115} __packed;
116
117struct get_bp_info_rsp {
118 struct mkhi_hdr hdr;
119 struct cse_bp_info bp_info;
120} __packed;
121
122static uint8_t cse_get_current_bp(const struct cse_bp_info *cse_bp_info)
123{
124 return cse_bp_info->current_bp;
125}
126
127static const struct cse_bp_entry *cse_get_bp_entry(enum boot_partition_id bp,
128 const struct cse_bp_info *cse_bp_info)
129{
130 return &cse_bp_info->bp_entries[bp];
131}
132
133static void cse_print_boot_partition_info(const struct cse_bp_info *cse_bp_info)
134{
135 const struct cse_bp_entry *cse_bp;
136
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530137 printk(BIOS_DEBUG, "cse_lite: Number of partitions = %d\n",
138 cse_bp_info->total_number_of_bp);
139 printk(BIOS_DEBUG, "cse_lite: Current partition = %s\n",
140 GET_BP_STR(cse_bp_info->current_bp));
141 printk(BIOS_DEBUG, "cse_lite: Next partition = %s\n", GET_BP_STR(cse_bp_info->next_bp));
142 printk(BIOS_DEBUG, "cse_lite: Flags = 0x%x\n", cse_bp_info->flags);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530143
144 /* Log version info of RO & RW partitions */
145 cse_bp = cse_get_bp_entry(RO, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530146 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 +0530147 GET_BP_STR(RO), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
148 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
149 cse_bp->status, cse_bp->start_offset,
150 cse_bp->end_offset);
151
152 cse_bp = cse_get_bp_entry(RW, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530153 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 +0530154 GET_BP_STR(RW), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
155 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
156 cse_bp->status, cse_bp->start_offset,
157 cse_bp->end_offset);
158}
159
160/*
161 * Checks prerequisites for MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO and
162 * MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO HECI commands.
163 * It allows execution of the Boot Partition commands in below scenarios:
164 * - When CSE boots from RW partition (COM: Normal and CWS: Normal)
165 * - When CSE boots from RO partition (COM: Soft Temp Disable and CWS: Normal)
166 * - After HMRFPO_ENABLE command is issued to CSE (COM: SECOVER_MEI_MSG and CWS: Normal)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530167 * The prerequisite check should be handled in cse_get_bp_info() and
168 * cse_set_next_boot_partition() since the CSE's current operation mode is changed between these
169 * cmd handler calls.
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530170 */
171static bool cse_is_bp_cmd_info_possible(void)
172{
173 if (cse_is_hfs1_cws_normal()) {
174 if (cse_is_hfs1_com_normal())
175 return true;
176 if (cse_is_hfs1_com_secover_mei_msg())
177 return true;
178 if (cse_is_hfs1_com_soft_temp_disable())
179 return true;
180 }
181 return false;
182}
183
184static bool cse_get_bp_info(struct get_bp_info_rsp *bp_info_rsp)
185{
186 struct get_bp_info_req {
187 struct mkhi_hdr hdr;
188 uint8_t reserved[4];
189 } __packed;
190
191 struct get_bp_info_req info_req = {
192 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
193 .hdr.command = MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO,
194 .reserved = {0},
195 };
196
197 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530198 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530199 return false;
200 }
201
202 size_t resp_size = sizeof(struct get_bp_info_rsp);
203
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530204 if (!heci_send_receive(&info_req, sizeof(info_req), bp_info_rsp, &resp_size,
205 HECI_MKHI_ADDR)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530206 printk(BIOS_ERR, "cse_lite: Could not get partition info\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530207 return false;
208 }
209
210 if (bp_info_rsp->hdr.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530211 printk(BIOS_ERR, "cse_lite: Get partition info resp failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530212 bp_info_rsp->hdr.result);
213 return false;
214 }
215
216 cse_print_boot_partition_info(&bp_info_rsp->bp_info);
217
218 return true;
219}
220/*
221 * It sends HECI command to notify CSE about its next boot partition. When coreboot wants
222 * CSE to boot from certain partition (BP1 <RO> or BP2 <RW>), then this command can be used.
223 * The CSE's valid bootable partitions are BP1(RO) and BP2(RW).
224 * This function must be used before EOP.
225 * Returns false on failure and true on success.
226 */
227static bool cse_set_next_boot_partition(enum boot_partition_id bp)
228{
229 struct set_boot_partition_info_req {
230 struct mkhi_hdr hdr;
231 uint8_t next_bp;
232 uint8_t reserved[3];
233 } __packed;
234
235 struct set_boot_partition_info_req switch_req = {
236 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
237 .hdr.command = MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO,
238 .next_bp = bp,
239 .reserved = {0},
240 };
241
242 if (bp != RO && bp != RW) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530243 printk(BIOS_ERR, "cse_lite: Incorrect partition id(%d) is provided", bp);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530244 return false;
245 }
246
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530247 printk(BIOS_INFO, "cse_lite: Set Boot Partition Info Command (%s)\n", GET_BP_STR(bp));
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530248
249 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530250 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530251 return false;
252 }
253
254 struct mkhi_hdr switch_resp;
255 size_t sw_resp_sz = sizeof(struct mkhi_hdr);
256
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530257 if (!heci_send_receive(&switch_req, sizeof(switch_req), &switch_resp, &sw_resp_sz,
258 HECI_MKHI_ADDR))
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530259 return false;
260
261 if (switch_resp.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530262 printk(BIOS_ERR, "cse_lite: Set Boot Partition Info Response Failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530263 switch_resp.result);
264 return false;
265 }
266
267 return true;
268}
269
V Sowmyaf9905522020-11-12 20:19:04 +0530270static bool cse_data_clear_request(const struct cse_bp_info *cse_bp_info)
271{
272 struct data_clr_request {
273 struct mkhi_hdr hdr;
274 uint8_t reserved[4];
275 } __packed;
276
277 struct data_clr_request data_clr_rq = {
278 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
279 .hdr.command = MKHI_BUP_COMMON_DATA_CLEAR,
280 .reserved = {0},
281 };
282
283 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_soft_temp_disable() ||
284 cse_get_current_bp(cse_bp_info) != RO) {
285 printk(BIOS_ERR, "cse_lite: CSE doesn't meet DATA CLEAR cmd prerequisites\n");
286 return false;
287 }
288
289 printk(BIOS_DEBUG, "cse_lite: Sending DATA CLEAR HECI command\n");
290
291 struct mkhi_hdr data_clr_rsp;
292 size_t data_clr_rsp_sz = sizeof(data_clr_rsp);
293
294 if (!heci_send_receive(&data_clr_rq, sizeof(data_clr_rq), &data_clr_rsp,
Rizwan Qureshi957857d2021-08-30 16:43:57 +0530295 &data_clr_rsp_sz, HECI_MKHI_ADDR)) {
V Sowmyaf9905522020-11-12 20:19:04 +0530296 return false;
297 }
298
299 if (data_clr_rsp.result) {
300 printk(BIOS_ERR, "cse_lite: CSE DATA CLEAR command response failed: %d\n",
301 data_clr_rsp.result);
302 return false;
303 }
304
305 return true;
306}
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530307
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600308__weak void cse_board_reset(void)
309{
310 /* Default weak implementation, does nothing. */
311}
312
Rizwan Qureshiec321092019-09-06 20:28:43 +0530313/* Set the CSE's next boot partition and issues system reset */
314static bool cse_set_and_boot_from_next_bp(enum boot_partition_id bp)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530315{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530316 if (!cse_set_next_boot_partition(bp))
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530317 return false;
318
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600319 /* Allow the board to perform a reset for CSE RO<->RW jump */
320 cse_board_reset();
321
322 /* If board does not perform the reset, then perform global_reset */
Furquan Shaikhb13bd1e2020-09-21 22:44:27 +0000323 do_global_reset();
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530324
Rizwan Qureshiec321092019-09-06 20:28:43 +0530325 die("cse_lite: Failed to reset the system\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530326
327 /* Control never reaches here */
328 return false;
329}
330
Rizwan Qureshiec321092019-09-06 20:28:43 +0530331static bool cse_boot_to_rw(const struct cse_bp_info *cse_bp_info)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530332{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530333 if (cse_get_current_bp(cse_bp_info) == RW)
334 return true;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530335
Rizwan Qureshiec321092019-09-06 20:28:43 +0530336 return cse_set_and_boot_from_next_bp(RW);
337}
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530338
V Sowmyaf9905522020-11-12 20:19:04 +0530339/* Check if CSE RW data partition is valid or not */
340static bool cse_is_rw_dp_valid(const struct cse_bp_info *cse_bp_info)
341{
342 const struct cse_bp_entry *rw_bp;
343
344 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
345 return rw_bp->status != BP_STATUS_DATA_FAILURE;
346}
347
348/*
349 * It returns true if RW partition doesn't indicate BP_STATUS_DATA_FAILURE
350 * otherwise false if any operation fails.
351 */
352static bool cse_fix_data_failure_err(const struct cse_bp_info *cse_bp_info)
353{
354 /*
355 * If RW partition status indicates BP_STATUS_DATA_FAILURE,
356 * - Send DATA CLEAR HECI command to CSE
357 * - Send SET BOOT PARTITION INFO(RW) command to set CSE's next partition
358 * - Issue GLOBAL RESET HECI command.
359 */
360 if (cse_is_rw_dp_valid(cse_bp_info))
361 return true;
362
363 if (!cse_data_clear_request(cse_bp_info))
364 return false;
365
366 return cse_boot_to_rw(cse_bp_info);
367}
368
V Sowmyaf9905522020-11-12 20:19:04 +0530369static const struct fw_version *cse_get_bp_entry_version(enum boot_partition_id bp,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530370 const struct cse_bp_info *bp_info)
V Sowmyaf9905522020-11-12 20:19:04 +0530371{
372 const struct cse_bp_entry *cse_bp;
373
374 cse_bp = cse_get_bp_entry(bp, bp_info);
375 return &cse_bp->fw_ver;
376}
377
378static const struct fw_version *cse_get_rw_version(const struct cse_bp_info *cse_bp_info)
379{
380 return cse_get_bp_entry_version(RW, cse_bp_info);
381}
382
383static void cse_get_bp_entry_range(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530384 enum boot_partition_id bp, uint32_t *start_offset, uint32_t *end_offset)
V Sowmyaf9905522020-11-12 20:19:04 +0530385{
386 const struct cse_bp_entry *cse_bp;
387
388 cse_bp = cse_get_bp_entry(bp, cse_bp_info);
389
390 if (start_offset)
391 *start_offset = cse_bp->start_offset;
392
393 if (end_offset)
394 *end_offset = cse_bp->end_offset;
395
396}
397
398static bool cse_is_rw_bp_status_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
404 if (rw_bp->status == BP_STATUS_PARTITION_NOT_PRESENT ||
405 rw_bp->status == BP_STATUS_GENERAL_FAILURE) {
406 printk(BIOS_ERR, "cse_lite: RW BP (status:%u) is not valid\n", rw_bp->status);
407 return false;
408 }
409 return true;
410}
411
Rizwan Qureshiec321092019-09-06 20:28:43 +0530412static bool cse_boot_to_ro(const struct cse_bp_info *cse_bp_info)
413{
414 if (cse_get_current_bp(cse_bp_info) == RO)
415 return true;
416
417 return cse_set_and_boot_from_next_bp(RO);
418}
419
420static bool cse_get_rw_rdev(struct region_device *rdev)
421{
422 if (fmap_locate_area_as_rdev_rw(CONFIG_SOC_INTEL_CSE_FMAP_NAME, rdev) < 0) {
423 printk(BIOS_ERR, "cse_lite: Failed to locate %s in FMAP\n",
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530424 CONFIG_SOC_INTEL_CSE_FMAP_NAME);
Rizwan Qureshiec321092019-09-06 20:28:43 +0530425 return false;
426 }
427
428 return true;
429}
430
Rizwan Qureshiec321092019-09-06 20:28:43 +0530431static bool cse_is_rw_bp_sign_valid(const struct region_device *target_rdev)
432{
433 uint32_t cse_bp_sign;
434
435 if (rdev_readat(target_rdev, &cse_bp_sign, 0, CSE_RW_SIGN_SIZE) != CSE_RW_SIGN_SIZE) {
436 printk(BIOS_ERR, "cse_lite: Failed to read RW boot partition signature\n");
437 return false;
438 }
439
440 return cse_bp_sign == CSE_RW_SIGNATURE;
441}
442
443static bool cse_get_target_rdev(const struct cse_bp_info *cse_bp_info,
444 struct region_device *target_rdev)
445{
446 struct region_device cse_region_rdev;
447 size_t size;
448 uint32_t start_offset;
449 uint32_t end_offset;
450
451 if (!cse_get_rw_rdev(&cse_region_rdev))
452 return false;
453
454 cse_get_bp_entry_range(cse_bp_info, RW, &start_offset, &end_offset);
455 size = end_offset + 1 - start_offset;
456
457 if (rdev_chain(target_rdev, &cse_region_rdev, start_offset, size))
458 return false;
459
460 printk(BIOS_DEBUG, "cse_lite: CSE RW partition: offset = 0x%x, size = 0x%x\n",
461 (uint32_t)start_offset, (uint32_t) size);
462
463 return true;
464}
465
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530466static const char *cse_get_source_rdev_fmap(void)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530467{
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530468 struct vb2_context *ctx = vboot_get_context();
469 if (ctx == NULL)
470 return NULL;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530471
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530472 if (vboot_is_firmware_slot_a(ctx))
473 return CONFIG_SOC_INTEL_CSE_RW_A_FMAP_NAME;
474
475 return CONFIG_SOC_INTEL_CSE_RW_B_FMAP_NAME;
476}
477
Rizwan Qureshiec321092019-09-06 20:28:43 +0530478/*
479 * Compare versions of CSE CBFS RW and CSE RW partition
480 * If ver_cmp_status = 0, no update is required
481 * If ver_cmp_status < 0, coreboot downgrades CSE RW region
482 * If ver_cmp_status > 0, coreboot upgrades CSE RW region
483 */
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700484static int compare_cse_version(const struct fw_version *a, const struct fw_version *b)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530485{
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700486 if (a->major != b->major)
487 return a->major - b->major;
488 else if (a->minor != b->minor)
489 return a->minor - b->minor;
490 else if (a->hotfix != b->hotfix)
491 return a->hotfix - b->hotfix;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530492 else
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700493 return a->build - b->build;
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530494}
495
496/* The function calculates SHA-256 of CSE RW blob and compares it with the provided SHA value */
497static bool cse_verify_cbfs_rw_sha256(const uint8_t *expected_rw_blob_sha,
498 const void *rw_blob, const size_t rw_blob_sz)
499
500{
501 uint8_t rw_comp_sha[VB2_SHA256_DIGEST_SIZE];
502
503 if (vb2_digest_buffer(rw_blob, rw_blob_sz, VB2_HASH_SHA256, rw_comp_sha,
504 VB2_SHA256_DIGEST_SIZE)) {
505 printk(BIOS_ERR, "cse_lite: CSE CBFS RW's SHA-256 calculation has failed\n");
506 return false;
507 }
508
509 if (memcmp(expected_rw_blob_sha, rw_comp_sha, VB2_SHA256_DIGEST_SIZE)) {
510 printk(BIOS_ERR, "cse_lite: Computed CBFS RW's SHA-256 does not match with"
511 "the provided SHA in the metadata\n");
512 return false;
513 }
514 printk(BIOS_SPEW, "cse_lite: Computed SHA of CSE CBFS RW Image matches the"
515 " provided hash in the metadata\n");
516 return true;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530517}
518
519static bool cse_erase_rw_region(const struct region_device *target_rdev)
520{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530521 if (rdev_eraseat(target_rdev, 0, region_device_sz(target_rdev)) < 0) {
522 printk(BIOS_ERR, "cse_lite: CSE RW partition could not be erased\n");
523 return false;
524 }
525 return true;
526}
527
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530528static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf,
529 size_t offset, size_t size)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530530{
531 if (rdev_writeat(target_rdev, buf, offset, size) < 0) {
532 printk(BIOS_ERR, "cse_lite: Failed to update CSE firmware\n");
533 return false;
534 }
535
536 return true;
537}
538
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700539enum cse_update_status {
540 CSE_UPDATE_NOT_REQUIRED,
541 CSE_UPDATE_UPGRADE,
542 CSE_UPDATE_DOWNGRADE,
543 CSE_UPDATE_CORRUPTED,
544 CSE_UPDATE_METADATA_ERROR,
545};
Rizwan Qureshiec321092019-09-06 20:28:43 +0530546
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700547static bool read_ver_field(const char *start, char **curr, size_t size, uint16_t *ver_field)
548{
549 if ((*curr - start) >= size) {
550 printk(BIOS_ERR, "cse_lite: Version string read overflow!\n");
551 return false;
552 }
553
554 *ver_field = skip_atoi(curr);
555 (*curr)++;
556 return true;
557}
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530558
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700559static enum cse_update_status cse_check_update_status(const struct cse_bp_info *cse_bp_info,
560 struct region_device *target_rdev)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530561{
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700562 int ret;
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700563 struct fw_version cbfs_rw_version;
564 char *version_str, *ptr;
565 size_t size;
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700566
567 if (!cse_is_rw_bp_sign_valid(target_rdev))
568 return CSE_UPDATE_CORRUPTED;
569
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700570 ptr = version_str = cbfs_map(CONFIG_SOC_INTEL_CSE_RW_VERSION_CBFS_NAME, &size);
571 if (!version_str) {
572 printk(BIOS_ERR, "cse_lite: Failed to get %s\n",
573 CONFIG_SOC_INTEL_CSE_RW_VERSION_CBFS_NAME);
574 return CSE_UPDATE_METADATA_ERROR;
575 }
576
577 if (!read_ver_field(version_str, &ptr, size, &cbfs_rw_version.major) ||
578 !read_ver_field(version_str, &ptr, size, &cbfs_rw_version.minor) ||
579 !read_ver_field(version_str, &ptr, size, &cbfs_rw_version.hotfix) ||
580 !read_ver_field(version_str, &ptr, size, &cbfs_rw_version.build)) {
581 cbfs_unmap(version_str);
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700582 return CSE_UPDATE_METADATA_ERROR;
583 }
584
585 printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n",
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700586 cbfs_rw_version.major,
587 cbfs_rw_version.minor,
588 cbfs_rw_version.hotfix,
589 cbfs_rw_version.build);
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700590
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700591 cbfs_unmap(version_str);
592
593 ret = compare_cse_version(&cbfs_rw_version, cse_get_rw_version(cse_bp_info));
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700594 if (ret == 0)
595 return CSE_UPDATE_NOT_REQUIRED;
596 else if (ret < 0)
597 return CSE_UPDATE_DOWNGRADE;
598 else
599 return CSE_UPDATE_UPGRADE;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530600}
601
602static bool cse_write_rw_region(const struct region_device *target_rdev,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530603 const void *cse_cbfs_rw, const size_t cse_cbfs_rw_sz)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530604{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530605 /* Points to CSE CBFS RW image after boot partition signature */
606 uint8_t *cse_cbfs_rw_wo_sign = (uint8_t *)cse_cbfs_rw + CSE_RW_SIGN_SIZE;
607
608 /* Size of CSE CBFS RW image without boot partition signature */
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530609 uint32_t cse_cbfs_rw_wo_sign_sz = cse_cbfs_rw_sz - CSE_RW_SIGN_SIZE;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530610
611 /* Update except CSE RW signature */
612 if (!cse_copy_rw(target_rdev, cse_cbfs_rw_wo_sign, CSE_RW_SIGN_SIZE,
613 cse_cbfs_rw_wo_sign_sz))
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530614 return false;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530615
616 /* Update CSE RW signature to indicate update is complete */
617 if (!cse_copy_rw(target_rdev, (void *)cse_cbfs_rw, 0, CSE_RW_SIGN_SIZE))
Rizwan Qureshiec321092019-09-06 20:28:43 +0530618 return false;
619
620 printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n");
621 return true;
622}
623
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530624static enum csme_failure_reason cse_update_rw(const struct cse_bp_info *cse_bp_info,
625 const void *cse_cbfs_rw, const size_t cse_blob_sz,
626 struct region_device *target_rdev)
627{
Sridhar Siricillaabeb6882020-12-07 15:55:10 +0530628 if (region_device_sz(target_rdev) < cse_blob_sz) {
629 printk(BIOS_ERR, "RW update does not fit. CSE RW flash region size: %zx, Update blob size:%zx\n",
630 region_device_sz(target_rdev), cse_blob_sz);
631 return CSE_LITE_SKU_LAYOUT_MISMATCH_ERROR;
632 }
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530633
634 if (!cse_erase_rw_region(target_rdev))
635 return CSE_LITE_SKU_FW_UPDATE_ERROR;
636
637 if (!cse_write_rw_region(target_rdev, cse_cbfs_rw, cse_blob_sz))
638 return CSE_LITE_SKU_FW_UPDATE_ERROR;
639
Tim Wawrzynczake380a432021-06-18 09:54:55 -0600640 return CSE_NO_ERROR;
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530641}
642
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530643static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info,
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700644 enum cse_update_status status)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530645{
646 /*
647 * To set CSE's operation mode to HMRFPO mode:
648 * 1. Ensure CSE to boot from RO(BP1)
649 * 2. Send HMRFPO_ENABLE command to CSE
650 */
651 if (!cse_boot_to_ro(cse_bp_info))
652 return false;
653
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700654 if ((status == CSE_UPDATE_DOWNGRADE) || (status == CSE_UPDATE_CORRUPTED)) {
655 if (!cse_data_clear_request(cse_bp_info)) {
656 printk(BIOS_ERR, "cse_lite: CSE data clear failed!\n");
657 return false;
658 }
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530659 }
660
Rizwan Qureshiec321092019-09-06 20:28:43 +0530661 return cse_hmrfpo_enable();
662}
663
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530664static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info,
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700665 enum cse_update_status status,
666 struct region_device *target_rdev)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530667{
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530668 enum csme_failure_reason rv;
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700669 uint8_t *cbfs_rw_hash;
Julius Werner18881f992021-04-13 15:28:12 -0700670 size_t size;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530671
Julius Werner18881f992021-04-13 15:28:12 -0700672 const char *area_name = cse_get_source_rdev_fmap();
673 if (!area_name)
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530674 return CSE_LITE_SKU_RW_BLOB_NOT_FOUND;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530675
Julius Werner18881f992021-04-13 15:28:12 -0700676 void *cse_cbfs_rw = cbfs_unverified_area_map(area_name,
677 CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME, &size);
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530678 if (!cse_cbfs_rw) {
679 printk(BIOS_ERR, "cse_lite: CSE CBFS RW blob could not be mapped\n");
680 return CSE_LITE_SKU_RW_BLOB_NOT_FOUND;
681 }
682
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700683 cbfs_rw_hash = cbfs_map(CONFIG_SOC_INTEL_CSE_RW_HASH_CBFS_NAME, NULL);
684 if (!cbfs_rw_hash) {
685 printk(BIOS_ERR, "cse_lite: Failed to get %s\n",
686 CONFIG_SOC_INTEL_CSE_RW_HASH_CBFS_NAME);
687 rv = CSE_LITE_SKU_RW_METADATA_NOT_FOUND;
688 goto error_exit;
689 }
690
Julius Werner18881f992021-04-13 15:28:12 -0700691 if (!cse_verify_cbfs_rw_sha256(cbfs_rw_hash, cse_cbfs_rw, size)) {
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530692 rv = CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH;
693 goto error_exit;
694 }
695
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700696 if (!cse_prep_for_rw_update(cse_bp_info, status)) {
Tim Wawrzynczake380a432021-06-18 09:54:55 -0600697 rv = CSE_COMMUNICATION_ERROR;
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530698 goto error_exit;
699 }
700
Julius Werner18881f992021-04-13 15:28:12 -0700701 rv = cse_update_rw(cse_bp_info, cse_cbfs_rw, size, target_rdev);
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530702
703error_exit:
Furquan Shaikhd2da8702021-10-07 00:08:59 -0700704 cbfs_unmap(cbfs_rw_hash);
Julius Werner18881f992021-04-13 15:28:12 -0700705 cbfs_unmap(cse_cbfs_rw);
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530706 return rv;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530707}
708
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530709static uint8_t cse_fw_update(const struct cse_bp_info *cse_bp_info)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530710{
711 struct region_device target_rdev;
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700712 enum cse_update_status status;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530713
714 if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) {
715 printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n");
716 return CSE_LITE_SKU_RW_ACCESS_ERROR;
717 }
718
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700719 status = cse_check_update_status(cse_bp_info, &target_rdev);
720 if (status == CSE_UPDATE_NOT_REQUIRED)
721 return CSE_NO_ERROR;
722 if (status == CSE_UPDATE_METADATA_ERROR)
723 return CSE_LITE_SKU_RW_METADATA_NOT_FOUND;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530724
Furquan Shaikhc45e0be2021-10-06 23:28:03 -0700725 printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
726 return cse_trigger_fw_update(cse_bp_info, status, &target_rdev);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530727}
728
Sridhar Siricilla1a2b7022020-12-04 02:22:28 +0530729void cse_fw_sync(void)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530730{
731 static struct get_bp_info_rsp cse_bp_info;
732
733 if (vboot_recovery_mode_enabled()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530734 printk(BIOS_DEBUG, "cse_lite: Skip switching to RW in the recovery path\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530735 return;
736 }
737
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530738 /* If CSE SKU type is not Lite, skip enabling CSE Lite SKU */
739 if (!cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530740 printk(BIOS_ERR, "cse_lite: Not a CSE Lite SKU\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530741 return;
742 }
743
744 if (!cse_get_bp_info(&cse_bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530745 printk(BIOS_ERR, "cse_lite: Failed to get CSE boot partition info\n");
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600746 cse_trigger_vboot_recovery(CSE_COMMUNICATION_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530747 }
748
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530749 if (!cse_fix_data_failure_err(&cse_bp_info.bp_info))
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600750 cse_trigger_vboot_recovery(CSE_LITE_SKU_DATA_WIPE_ERROR);
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530751
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530752 /*
753 * If SOC_INTEL_CSE_RW_UPDATE is defined , then trigger CSE firmware update. The driver
754 * triggers recovery if CSE CBFS RW metadata or CSE CBFS RW blob is not available.
755 */
Sridhar Siricilla4c2890d2020-12-09 00:28:30 +0530756 if (CONFIG(SOC_INTEL_CSE_RW_UPDATE)) {
757 uint8_t rv;
758 rv = cse_fw_update(&cse_bp_info.bp_info);
759 if (rv)
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600760 cse_trigger_vboot_recovery(rv);
Sridhar Siricilla4c2890d2020-12-09 00:28:30 +0530761 }
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530762
Sridahr Siricilla54b03562021-06-18 10:59:30 +0530763 if (!cse_is_rw_bp_status_valid(&cse_bp_info.bp_info))
Tim Wawrzynczakf2801f42021-06-22 11:25:14 -0600764 cse_trigger_vboot_recovery(CSE_LITE_SKU_RW_JUMP_ERROR);
Sridahr Siricilla54b03562021-06-18 10:59:30 +0530765
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530766 if (!cse_boot_to_rw(&cse_bp_info.bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530767 printk(BIOS_ERR, "cse_lite: Failed to switch to RW\n");
Tim Wawrzynczak09635f42021-06-18 10:08:47 -0600768 cse_trigger_vboot_recovery(CSE_LITE_SKU_RW_SWITCH_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530769 }
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530770}