blob: b2e70e675224b4b7e89def16bee710e5c47ac021 [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>
5#include <commonlib/cbfs.h>
6#include <commonlib/region.h>
7#include <fmap.h>
Sridhar Siricillaf87ff332019-09-12 17:18:20 +05308#include <intelblocks/cse.h>
9#include <security/vboot/vboot_common.h>
Sridhar Siricilla87e36c42020-05-03 19:08:18 +053010#include <security/vboot/misc.h>
Rizwan Qureshiec321092019-09-06 20:28:43 +053011#include <soc/intel/common/reset.h>
12
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053013/* Converts bp index to boot partition string */
14#define GET_BP_STR(bp_index) (bp_index ? "RW" : "RO")
15
Rizwan Qureshiec321092019-09-06 20:28:43 +053016/* CSE RW boot partition signature */
17#define CSE_RW_SIGNATURE 0x000055aa
18
19/* CSE RW boot partition signature size */
20#define CSE_RW_SIGN_SIZE sizeof(uint32_t)
21
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053022/*
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053023 * CSE Firmware supports 3 boot partitions. For CSE Lite SKU, only 2 boot partitions are
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053024 * used and 3rd boot partition is set to BP_STATUS_PARTITION_NOT_PRESENT.
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053025 * CSE Lite SKU Image Layout:
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053026 * ------------- ------------------- ---------------------
27 * |CSE REGION | => | RO | RW | DATA | => | BP1 | BP2 | DATA |
28 * ------------- ------------------- ---------------------
29 */
30#define CSE_MAX_BOOT_PARTITIONS 3
31
Sridhar Siricilla99dbca32020-05-12 21:05:04 +053032/* CSE Lite SKU's valid bootable partition identifiers */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053033enum boot_partition_id {
Rizwan Qureshiec321092019-09-06 20:28:43 +053034 /* RO(BP1) contains recovery/minimal boot firmware */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053035 RO = 0,
36
Rizwan Qureshiec321092019-09-06 20:28:43 +053037 /* RW(BP2) contains fully functional CSE firmware */
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053038 RW = 1
39};
40
41/*
42 * Boot partition status.
43 * The status is returned in response to MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO cmd.
44 */
45enum bp_status {
46 /* This value is returned when a partition has no errors */
47 BP_STATUS_SUCCESS = 0,
48
49 /*
50 * This value is returned when a partition should be present based on layout, but it is
51 * not valid.
52 */
53 BP_STATUS_GENERAL_FAILURE = 1,
54
55 /* This value is returned when a partition is not present per initial image layout */
56 BP_STATUS_PARTITION_NOT_PRESENT = 2,
57
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +053058 /*
59 * This value is returned when unexpected issues are detected in CSE Data area
60 * and CSE TCB-SVN downgrade scenario.
61 */
62 BP_STATUS_DATA_FAILURE = 3,
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053063};
64
65/*
66 * Boot Partition Info Flags
67 * The flags are returned in response to MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO cmd.
68 */
69enum bp_info_flags {
70
71 /* Redundancy Enabled: It indicates CSE supports RO(BP1) and RW(BP2) regions */
72 BP_INFO_REDUNDANCY_EN = 1 << 0,
73
74 /* It indicates RO(BP1) supports Minimal Recovery Mode */
75 BP_INFO_MIN_RECOV_MODE_EN = 1 << 1,
76
77 /*
78 * Read-only Config Enabled: It indicates HW protection to CSE RO region is enabled.
79 * The option is relevant only if the BP_INFO_MIN_RECOV_MODE_EN flag is enabled.
80 */
81 BP_INFO_READ_ONLY_CFG = 1 << 2,
82};
83
Sridhar Siricillaf87ff332019-09-12 17:18:20 +053084/* CSE boot partition entry info */
85struct cse_bp_entry {
86 /* Boot partition version */
87 struct fw_version fw_ver;
88
89 /* Boot partition status */
90 uint32_t status;
91
92 /* Starting offset of the partition within CSE region */
93 uint32_t start_offset;
94
95 /* Ending offset of the partition within CSE region */
96 uint32_t end_offset;
97 uint8_t reserved[12];
98} __packed;
99
100/* CSE boot partition info */
101struct cse_bp_info {
102 /* Number of boot partitions */
103 uint8_t total_number_of_bp;
104
105 /* Current boot partition */
106 uint8_t current_bp;
107
108 /* Next boot partition */
109 uint8_t next_bp;
110
111 /* Boot Partition Info Flags */
112 uint8_t flags;
113
114 /* Boot Partition Entry Info */
115 struct cse_bp_entry bp_entries[CSE_MAX_BOOT_PARTITIONS];
116} __packed;
117
118struct get_bp_info_rsp {
119 struct mkhi_hdr hdr;
120 struct cse_bp_info bp_info;
121} __packed;
122
Sridhar Siricilla33aa1152020-06-26 14:29:40 +0530123static void cse_log_status_registers(void)
124{
125 printk(BIOS_DEBUG, "cse_lite: CSE status registers: HFSTS1: 0x%x, HFSTS2: 0x%x "
126 "HFSTS3: 0x%x\n", me_read_config32(PCI_ME_HFSTS1),
127 me_read_config32(PCI_ME_HFSTS2), me_read_config32(PCI_ME_HFSTS3));
128}
129
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530130static void cse_trigger_recovery(uint8_t rec_sub_code)
131{
Sridhar Siricilla33aa1152020-06-26 14:29:40 +0530132 /* Log CSE Firmware Status Registers to help debugging */
133 cse_log_status_registers();
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530134 if (CONFIG(VBOOT)) {
Subrata Banik754de4d2020-09-15 15:16:42 +0530135 struct vb2_context *ctx = vboot_get_context();
136 if (ctx == NULL)
137 goto failure;
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530138 vb2api_fail(ctx, VB2_RECOVERY_INTEL_CSE_LITE_SKU, rec_sub_code);
139 vboot_save_data(ctx);
140 vboot_reboot();
141 }
Subrata Banik754de4d2020-09-15 15:16:42 +0530142failure:
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530143 die("cse_lite: Failed to trigger recovery mode(recovery subcode:%d)\n", rec_sub_code);
144}
145
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530146static uint8_t cse_get_current_bp(const struct cse_bp_info *cse_bp_info)
147{
148 return cse_bp_info->current_bp;
149}
150
151static const struct cse_bp_entry *cse_get_bp_entry(enum boot_partition_id bp,
152 const struct cse_bp_info *cse_bp_info)
153{
154 return &cse_bp_info->bp_entries[bp];
155}
156
157static void cse_print_boot_partition_info(const struct cse_bp_info *cse_bp_info)
158{
159 const struct cse_bp_entry *cse_bp;
160
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530161 printk(BIOS_DEBUG, "cse_lite: Number of partitions = %d\n",
162 cse_bp_info->total_number_of_bp);
163 printk(BIOS_DEBUG, "cse_lite: Current partition = %s\n",
164 GET_BP_STR(cse_bp_info->current_bp));
165 printk(BIOS_DEBUG, "cse_lite: Next partition = %s\n", GET_BP_STR(cse_bp_info->next_bp));
166 printk(BIOS_DEBUG, "cse_lite: Flags = 0x%x\n", cse_bp_info->flags);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530167
168 /* Log version info of RO & RW partitions */
169 cse_bp = cse_get_bp_entry(RO, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530170 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 +0530171 GET_BP_STR(RO), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
172 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
173 cse_bp->status, cse_bp->start_offset,
174 cse_bp->end_offset);
175
176 cse_bp = cse_get_bp_entry(RW, cse_bp_info);
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530177 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 +0530178 GET_BP_STR(RW), cse_bp->fw_ver.major, cse_bp->fw_ver.minor,
179 cse_bp->fw_ver.hotfix, cse_bp->fw_ver.build,
180 cse_bp->status, cse_bp->start_offset,
181 cse_bp->end_offset);
182}
183
184/*
185 * Checks prerequisites for MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO and
186 * MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO HECI commands.
187 * It allows execution of the Boot Partition commands in below scenarios:
188 * - When CSE boots from RW partition (COM: Normal and CWS: Normal)
189 * - When CSE boots from RO partition (COM: Soft Temp Disable and CWS: Normal)
190 * - After HMRFPO_ENABLE command is issued to CSE (COM: SECOVER_MEI_MSG and CWS: Normal)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530191 * The prerequisite check should be handled in cse_get_bp_info() and
192 * cse_set_next_boot_partition() since the CSE's current operation mode is changed between these
193 * cmd handler calls.
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530194 */
195static bool cse_is_bp_cmd_info_possible(void)
196{
197 if (cse_is_hfs1_cws_normal()) {
198 if (cse_is_hfs1_com_normal())
199 return true;
200 if (cse_is_hfs1_com_secover_mei_msg())
201 return true;
202 if (cse_is_hfs1_com_soft_temp_disable())
203 return true;
204 }
205 return false;
206}
207
208static bool cse_get_bp_info(struct get_bp_info_rsp *bp_info_rsp)
209{
210 struct get_bp_info_req {
211 struct mkhi_hdr hdr;
212 uint8_t reserved[4];
213 } __packed;
214
215 struct get_bp_info_req info_req = {
216 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
217 .hdr.command = MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO,
218 .reserved = {0},
219 };
220
221 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530222 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530223 return false;
224 }
225
226 size_t resp_size = sizeof(struct get_bp_info_rsp);
227
228 if (!heci_send_receive(&info_req, sizeof(info_req), bp_info_rsp, &resp_size)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530229 printk(BIOS_ERR, "cse_lite: Could not get partition info\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530230 return false;
231 }
232
233 if (bp_info_rsp->hdr.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530234 printk(BIOS_ERR, "cse_lite: Get partition info resp failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530235 bp_info_rsp->hdr.result);
236 return false;
237 }
238
239 cse_print_boot_partition_info(&bp_info_rsp->bp_info);
240
241 return true;
242}
243/*
244 * It sends HECI command to notify CSE about its next boot partition. When coreboot wants
245 * CSE to boot from certain partition (BP1 <RO> or BP2 <RW>), then this command can be used.
246 * The CSE's valid bootable partitions are BP1(RO) and BP2(RW).
247 * This function must be used before EOP.
248 * Returns false on failure and true on success.
249 */
250static bool cse_set_next_boot_partition(enum boot_partition_id bp)
251{
252 struct set_boot_partition_info_req {
253 struct mkhi_hdr hdr;
254 uint8_t next_bp;
255 uint8_t reserved[3];
256 } __packed;
257
258 struct set_boot_partition_info_req switch_req = {
259 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
260 .hdr.command = MKHI_BUP_COMMON_SET_BOOT_PARTITION_INFO,
261 .next_bp = bp,
262 .reserved = {0},
263 };
264
265 if (bp != RO && bp != RW) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530266 printk(BIOS_ERR, "cse_lite: Incorrect partition id(%d) is provided", bp);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530267 return false;
268 }
269
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530270 printk(BIOS_INFO, "cse_lite: Set Boot Partition Info Command (%s)\n", GET_BP_STR(bp));
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530271
272 if (!cse_is_bp_cmd_info_possible()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530273 printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530274 return false;
275 }
276
277 struct mkhi_hdr switch_resp;
278 size_t sw_resp_sz = sizeof(struct mkhi_hdr);
279
280 if (!heci_send_receive(&switch_req, sizeof(switch_req), &switch_resp, &sw_resp_sz))
281 return false;
282
283 if (switch_resp.result) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530284 printk(BIOS_ERR, "cse_lite: Set Boot Partition Info Response Failed: %d\n",
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530285 switch_resp.result);
286 return false;
287 }
288
289 return true;
290}
291
V Sowmyaf9905522020-11-12 20:19:04 +0530292static bool cse_data_clear_request(const struct cse_bp_info *cse_bp_info)
293{
294 struct data_clr_request {
295 struct mkhi_hdr hdr;
296 uint8_t reserved[4];
297 } __packed;
298
299 struct data_clr_request data_clr_rq = {
300 .hdr.group_id = MKHI_GROUP_ID_BUP_COMMON,
301 .hdr.command = MKHI_BUP_COMMON_DATA_CLEAR,
302 .reserved = {0},
303 };
304
305 if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_soft_temp_disable() ||
306 cse_get_current_bp(cse_bp_info) != RO) {
307 printk(BIOS_ERR, "cse_lite: CSE doesn't meet DATA CLEAR cmd prerequisites\n");
308 return false;
309 }
310
311 printk(BIOS_DEBUG, "cse_lite: Sending DATA CLEAR HECI command\n");
312
313 struct mkhi_hdr data_clr_rsp;
314 size_t data_clr_rsp_sz = sizeof(data_clr_rsp);
315
316 if (!heci_send_receive(&data_clr_rq, sizeof(data_clr_rq), &data_clr_rsp,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530317 &data_clr_rsp_sz)) {
V Sowmyaf9905522020-11-12 20:19:04 +0530318 return false;
319 }
320
321 if (data_clr_rsp.result) {
322 printk(BIOS_ERR, "cse_lite: CSE DATA CLEAR command response failed: %d\n",
323 data_clr_rsp.result);
324 return false;
325 }
326
327 return true;
328}
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530329
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600330__weak void cse_board_reset(void)
331{
332 /* Default weak implementation, does nothing. */
333}
334
Rizwan Qureshiec321092019-09-06 20:28:43 +0530335/* Set the CSE's next boot partition and issues system reset */
336static bool cse_set_and_boot_from_next_bp(enum boot_partition_id bp)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530337{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530338 if (!cse_set_next_boot_partition(bp))
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530339 return false;
340
Karthikeyan Ramasubramanianf9cc6372020-08-04 16:38:58 -0600341 /* Allow the board to perform a reset for CSE RO<->RW jump */
342 cse_board_reset();
343
344 /* If board does not perform the reset, then perform global_reset */
Furquan Shaikhb13bd1e2020-09-21 22:44:27 +0000345 do_global_reset();
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530346
Rizwan Qureshiec321092019-09-06 20:28:43 +0530347 die("cse_lite: Failed to reset the system\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530348
349 /* Control never reaches here */
350 return false;
351}
352
Rizwan Qureshiec321092019-09-06 20:28:43 +0530353static bool cse_boot_to_rw(const struct cse_bp_info *cse_bp_info)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530354{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530355 if (cse_get_current_bp(cse_bp_info) == RW)
356 return true;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530357
Rizwan Qureshiec321092019-09-06 20:28:43 +0530358 return cse_set_and_boot_from_next_bp(RW);
359}
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530360
V Sowmyaf9905522020-11-12 20:19:04 +0530361/* Check if CSE RW data partition is valid or not */
362static bool cse_is_rw_dp_valid(const struct cse_bp_info *cse_bp_info)
363{
364 const struct cse_bp_entry *rw_bp;
365
366 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
367 return rw_bp->status != BP_STATUS_DATA_FAILURE;
368}
369
370/*
371 * It returns true if RW partition doesn't indicate BP_STATUS_DATA_FAILURE
372 * otherwise false if any operation fails.
373 */
374static bool cse_fix_data_failure_err(const struct cse_bp_info *cse_bp_info)
375{
376 /*
377 * If RW partition status indicates BP_STATUS_DATA_FAILURE,
378 * - Send DATA CLEAR HECI command to CSE
379 * - Send SET BOOT PARTITION INFO(RW) command to set CSE's next partition
380 * - Issue GLOBAL RESET HECI command.
381 */
382 if (cse_is_rw_dp_valid(cse_bp_info))
383 return true;
384
385 if (!cse_data_clear_request(cse_bp_info))
386 return false;
387
388 return cse_boot_to_rw(cse_bp_info);
389}
390
V Sowmyaf9905522020-11-12 20:19:04 +0530391static const struct fw_version *cse_get_bp_entry_version(enum boot_partition_id bp,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530392 const struct cse_bp_info *bp_info)
V Sowmyaf9905522020-11-12 20:19:04 +0530393{
394 const struct cse_bp_entry *cse_bp;
395
396 cse_bp = cse_get_bp_entry(bp, bp_info);
397 return &cse_bp->fw_ver;
398}
399
400static const struct fw_version *cse_get_rw_version(const struct cse_bp_info *cse_bp_info)
401{
402 return cse_get_bp_entry_version(RW, cse_bp_info);
403}
404
405static void cse_get_bp_entry_range(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530406 enum boot_partition_id bp, uint32_t *start_offset, uint32_t *end_offset)
V Sowmyaf9905522020-11-12 20:19:04 +0530407{
408 const struct cse_bp_entry *cse_bp;
409
410 cse_bp = cse_get_bp_entry(bp, cse_bp_info);
411
412 if (start_offset)
413 *start_offset = cse_bp->start_offset;
414
415 if (end_offset)
416 *end_offset = cse_bp->end_offset;
417
418}
419
420static bool cse_is_rw_bp_status_valid(const struct cse_bp_info *cse_bp_info)
421{
422 const struct cse_bp_entry *rw_bp;
423
424 rw_bp = cse_get_bp_entry(RW, cse_bp_info);
425
426 if (rw_bp->status == BP_STATUS_PARTITION_NOT_PRESENT ||
427 rw_bp->status == BP_STATUS_GENERAL_FAILURE) {
428 printk(BIOS_ERR, "cse_lite: RW BP (status:%u) is not valid\n", rw_bp->status);
429 return false;
430 }
431 return true;
432}
433
Rizwan Qureshiec321092019-09-06 20:28:43 +0530434static bool cse_boot_to_ro(const struct cse_bp_info *cse_bp_info)
435{
436 if (cse_get_current_bp(cse_bp_info) == RO)
437 return true;
438
439 return cse_set_and_boot_from_next_bp(RO);
440}
441
442static bool cse_get_rw_rdev(struct region_device *rdev)
443{
444 if (fmap_locate_area_as_rdev_rw(CONFIG_SOC_INTEL_CSE_FMAP_NAME, rdev) < 0) {
445 printk(BIOS_ERR, "cse_lite: Failed to locate %s in FMAP\n",
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530446 CONFIG_SOC_INTEL_CSE_FMAP_NAME);
Rizwan Qureshiec321092019-09-06 20:28:43 +0530447 return false;
448 }
449
450 return true;
451}
452
Rizwan Qureshiec321092019-09-06 20:28:43 +0530453static bool cse_is_rw_bp_sign_valid(const struct region_device *target_rdev)
454{
455 uint32_t cse_bp_sign;
456
457 if (rdev_readat(target_rdev, &cse_bp_sign, 0, CSE_RW_SIGN_SIZE) != CSE_RW_SIGN_SIZE) {
458 printk(BIOS_ERR, "cse_lite: Failed to read RW boot partition signature\n");
459 return false;
460 }
461
462 return cse_bp_sign == CSE_RW_SIGNATURE;
463}
464
465static bool cse_get_target_rdev(const struct cse_bp_info *cse_bp_info,
466 struct region_device *target_rdev)
467{
468 struct region_device cse_region_rdev;
469 size_t size;
470 uint32_t start_offset;
471 uint32_t end_offset;
472
473 if (!cse_get_rw_rdev(&cse_region_rdev))
474 return false;
475
476 cse_get_bp_entry_range(cse_bp_info, RW, &start_offset, &end_offset);
477 size = end_offset + 1 - start_offset;
478
479 if (rdev_chain(target_rdev, &cse_region_rdev, start_offset, size))
480 return false;
481
482 printk(BIOS_DEBUG, "cse_lite: CSE RW partition: offset = 0x%x, size = 0x%x\n",
483 (uint32_t)start_offset, (uint32_t) size);
484
485 return true;
486}
487
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530488static const char *cse_get_source_rdev_fmap(void)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530489{
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530490 struct vb2_context *ctx = vboot_get_context();
491 if (ctx == NULL)
492 return NULL;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530493
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530494 if (vboot_is_firmware_slot_a(ctx))
495 return CONFIG_SOC_INTEL_CSE_RW_A_FMAP_NAME;
496
497 return CONFIG_SOC_INTEL_CSE_RW_B_FMAP_NAME;
498}
499
500static bool cse_get_source_rdev(struct region_device *rdev)
501{
502 const char *reg_name;
503 uint32_t cbfs_type = CBFS_TYPE_RAW;
504 struct cbfsf fh;
505
506 reg_name = cse_get_source_rdev_fmap();
507
508 if (reg_name == NULL)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530509 return false;
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530510
511 if (cbfs_locate_file_in_region(&fh, reg_name, CONFIG_SOC_INTEL_CSE_RW_CBFS_NAME,
512 &cbfs_type) < 0)
513 return false;
514
515 cbfs_file_data(rdev, &fh);
516
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530517 return true;
518}
519
Rizwan Qureshiec321092019-09-06 20:28:43 +0530520/*
521 * Compare versions of CSE CBFS RW and CSE RW partition
522 * If ver_cmp_status = 0, no update is required
523 * If ver_cmp_status < 0, coreboot downgrades CSE RW region
524 * If ver_cmp_status > 0, coreboot upgrades CSE RW region
525 */
526static int cse_check_version_mismatch(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530527 const struct cse_rw_metadata *source_metadata)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530528{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530529 const struct fw_version *cse_rw_ver;
530
Rizwan Qureshiec321092019-09-06 20:28:43 +0530531 printk(BIOS_DEBUG, "cse_lite: CSE CBFS RW version : %d.%d.%d.%d\n",
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530532 source_metadata->version.major,
533 source_metadata->version.minor,
534 source_metadata->version.hotfix,
535 source_metadata->version.build);
Rizwan Qureshiec321092019-09-06 20:28:43 +0530536
537 cse_rw_ver = cse_get_rw_version(cse_bp_info);
538
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530539 if (source_metadata->version.major != cse_rw_ver->major)
540 return source_metadata->version.major - cse_rw_ver->major;
541 else if (source_metadata->version.minor != cse_rw_ver->minor)
542 return source_metadata->version.minor - cse_rw_ver->minor;
543 else if (source_metadata->version.hotfix != cse_rw_ver->hotfix)
544 return source_metadata->version.hotfix - cse_rw_ver->hotfix;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530545 else
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530546 return source_metadata->version.build - cse_rw_ver->build;
547}
548
549/* The function calculates SHA-256 of CSE RW blob and compares it with the provided SHA value */
550static bool cse_verify_cbfs_rw_sha256(const uint8_t *expected_rw_blob_sha,
551 const void *rw_blob, const size_t rw_blob_sz)
552
553{
554 uint8_t rw_comp_sha[VB2_SHA256_DIGEST_SIZE];
555
556 if (vb2_digest_buffer(rw_blob, rw_blob_sz, VB2_HASH_SHA256, rw_comp_sha,
557 VB2_SHA256_DIGEST_SIZE)) {
558 printk(BIOS_ERR, "cse_lite: CSE CBFS RW's SHA-256 calculation has failed\n");
559 return false;
560 }
561
562 if (memcmp(expected_rw_blob_sha, rw_comp_sha, VB2_SHA256_DIGEST_SIZE)) {
563 printk(BIOS_ERR, "cse_lite: Computed CBFS RW's SHA-256 does not match with"
564 "the provided SHA in the metadata\n");
565 return false;
566 }
567 printk(BIOS_SPEW, "cse_lite: Computed SHA of CSE CBFS RW Image matches the"
568 " provided hash in the metadata\n");
569 return true;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530570}
571
572static bool cse_erase_rw_region(const struct region_device *target_rdev)
573{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530574 if (rdev_eraseat(target_rdev, 0, region_device_sz(target_rdev)) < 0) {
575 printk(BIOS_ERR, "cse_lite: CSE RW partition could not be erased\n");
576 return false;
577 }
578 return true;
579}
580
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530581static bool cse_copy_rw(const struct region_device *target_rdev, const void *buf,
582 size_t offset, size_t size)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530583{
584 if (rdev_writeat(target_rdev, buf, offset, size) < 0) {
585 printk(BIOS_ERR, "cse_lite: Failed to update CSE firmware\n");
586 return false;
587 }
588
589 return true;
590}
591
592static bool cse_is_rw_version_latest(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530593 const struct cse_rw_metadata *source_metadata)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530594{
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530595 return !cse_check_version_mismatch(cse_bp_info, source_metadata);
Rizwan Qureshiec321092019-09-06 20:28:43 +0530596}
597
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530598static bool cse_is_downgrade_instance(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530599 const struct cse_rw_metadata *source_metadata)
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530600{
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530601 return cse_check_version_mismatch(cse_bp_info, source_metadata) < 0;
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530602}
603
Rizwan Qureshiec321092019-09-06 20:28:43 +0530604static bool cse_is_update_required(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530605 const struct cse_rw_metadata *source_metadata,
606 struct region_device *target_rdev)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530607{
608 return (!cse_is_rw_bp_sign_valid(target_rdev) ||
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530609 !cse_is_rw_version_latest(cse_bp_info, source_metadata));
Rizwan Qureshiec321092019-09-06 20:28:43 +0530610}
611
612static bool cse_write_rw_region(const struct region_device *target_rdev,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530613 const void *cse_cbfs_rw, const size_t cse_cbfs_rw_sz)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530614{
Rizwan Qureshiec321092019-09-06 20:28:43 +0530615 /* Points to CSE CBFS RW image after boot partition signature */
616 uint8_t *cse_cbfs_rw_wo_sign = (uint8_t *)cse_cbfs_rw + CSE_RW_SIGN_SIZE;
617
618 /* Size of CSE CBFS RW image without boot partition signature */
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530619 uint32_t cse_cbfs_rw_wo_sign_sz = cse_cbfs_rw_sz - CSE_RW_SIGN_SIZE;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530620
621 /* Update except CSE RW signature */
622 if (!cse_copy_rw(target_rdev, cse_cbfs_rw_wo_sign, CSE_RW_SIGN_SIZE,
623 cse_cbfs_rw_wo_sign_sz))
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530624 return false;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530625
626 /* Update CSE RW signature to indicate update is complete */
627 if (!cse_copy_rw(target_rdev, (void *)cse_cbfs_rw, 0, CSE_RW_SIGN_SIZE))
Rizwan Qureshiec321092019-09-06 20:28:43 +0530628 return false;
629
630 printk(BIOS_INFO, "cse_lite: CSE RW Update Successful\n");
631 return true;
632}
633
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530634static enum csme_failure_reason cse_update_rw(const struct cse_bp_info *cse_bp_info,
635 const void *cse_cbfs_rw, const size_t cse_blob_sz,
636 struct region_device *target_rdev)
637{
Sridhar Siricillaabeb6882020-12-07 15:55:10 +0530638 if (region_device_sz(target_rdev) < cse_blob_sz) {
639 printk(BIOS_ERR, "RW update does not fit. CSE RW flash region size: %zx, Update blob size:%zx\n",
640 region_device_sz(target_rdev), cse_blob_sz);
641 return CSE_LITE_SKU_LAYOUT_MISMATCH_ERROR;
642 }
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530643
644 if (!cse_erase_rw_region(target_rdev))
645 return CSE_LITE_SKU_FW_UPDATE_ERROR;
646
647 if (!cse_write_rw_region(target_rdev, cse_cbfs_rw, cse_blob_sz))
648 return CSE_LITE_SKU_FW_UPDATE_ERROR;
649
Tim Wawrzynczake380a432021-06-18 09:54:55 -0600650 return CSE_NO_ERROR;
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530651}
652
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530653static bool cse_prep_for_rw_update(const struct cse_bp_info *cse_bp_info,
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530654 const struct cse_rw_metadata *source_metadata)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530655{
656 /*
657 * To set CSE's operation mode to HMRFPO mode:
658 * 1. Ensure CSE to boot from RO(BP1)
659 * 2. Send HMRFPO_ENABLE command to CSE
660 */
661 if (!cse_boot_to_ro(cse_bp_info))
662 return false;
663
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530664 if (cse_is_downgrade_instance(cse_bp_info, source_metadata) &&
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530665 !cse_data_clear_request(cse_bp_info)) {
666 printk(BIOS_ERR, "cse_lite: CSE FW downgrade is aborted\n");
667 return false;
668 }
669
Rizwan Qureshiec321092019-09-06 20:28:43 +0530670 return cse_hmrfpo_enable();
671}
672
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530673static enum csme_failure_reason cse_trigger_fw_update(const struct cse_bp_info *cse_bp_info,
674 const struct cse_rw_metadata *source_metadata,
675 struct region_device *target_rdev)
Rizwan Qureshiec321092019-09-06 20:28:43 +0530676{
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530677 struct region_device source_rdev;
678 enum csme_failure_reason rv;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530679
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530680 if (!cse_get_source_rdev(&source_rdev))
681 return CSE_LITE_SKU_RW_BLOB_NOT_FOUND;
Rizwan Qureshiec321092019-09-06 20:28:43 +0530682
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530683 void *cse_cbfs_rw = rdev_mmap_full(&source_rdev);
684
685 if (!cse_cbfs_rw) {
686 printk(BIOS_ERR, "cse_lite: CSE CBFS RW blob could not be mapped\n");
687 return CSE_LITE_SKU_RW_BLOB_NOT_FOUND;
688 }
689
690 if (!cse_verify_cbfs_rw_sha256(source_metadata->sha256, cse_cbfs_rw,
691 region_device_sz(&source_rdev))) {
692 rv = CSE_LITE_SKU_RW_BLOB_SHA256_MISMATCH;
693 goto error_exit;
694 }
695
696 if (!cse_prep_for_rw_update(cse_bp_info, source_metadata)) {
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
701 rv = cse_update_rw(cse_bp_info, cse_cbfs_rw, region_device_sz(&source_rdev),
702 target_rdev);
703
704error_exit:
705 rdev_munmap(&source_rdev, cse_cbfs_rw);
706 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;
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530712 struct cse_rw_metadata source_metadata;
713
714 /* Read CSE CBFS RW metadata */
V Sowmya13695162020-12-04 09:40:12 +0530715 if (cbfs_load(CONFIG_SOC_INTEL_CSE_RW_METADATA_CBFS_NAME, &source_metadata,
716 sizeof(source_metadata)) != sizeof(source_metadata)) {
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530717 printk(BIOS_ERR, "cse_lite: Failed to get CSE CBFS RW metadata\n");
718 return CSE_LITE_SKU_RW_METADATA_NOT_FOUND;
719 }
Rizwan Qureshiec321092019-09-06 20:28:43 +0530720
721 if (!cse_get_target_rdev(cse_bp_info, &target_rdev)) {
722 printk(BIOS_ERR, "cse_lite: Failed to get CSE RW Partition\n");
723 return CSE_LITE_SKU_RW_ACCESS_ERROR;
724 }
725
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530726 if (cse_is_update_required(cse_bp_info, &source_metadata, &target_rdev)) {
Rizwan Qureshiec321092019-09-06 20:28:43 +0530727 printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530728 return cse_trigger_fw_update(cse_bp_info, &source_metadata, &target_rdev);
Rizwan Qureshiec321092019-09-06 20:28:43 +0530729 }
730
Rizwan Qureshiec321092019-09-06 20:28:43 +0530731 return 0;
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530732}
733
Sridhar Siricilla1a2b7022020-12-04 02:22:28 +0530734void cse_fw_sync(void)
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530735{
736 static struct get_bp_info_rsp cse_bp_info;
737
738 if (vboot_recovery_mode_enabled()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530739 printk(BIOS_DEBUG, "cse_lite: Skip switching to RW in the recovery path\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530740 return;
741 }
742
Sridhar Siricilla99dbca32020-05-12 21:05:04 +0530743 /* If CSE SKU type is not Lite, skip enabling CSE Lite SKU */
744 if (!cse_is_hfs3_fw_sku_lite()) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530745 printk(BIOS_ERR, "cse_lite: Not a CSE Lite SKU\n");
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530746 return;
747 }
748
749 if (!cse_get_bp_info(&cse_bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530750 printk(BIOS_ERR, "cse_lite: Failed to get CSE boot partition info\n");
Tim Wawrzynczake380a432021-06-18 09:54:55 -0600751 cse_trigger_recovery(CSE_COMMUNICATION_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530752 }
753
Sridhar Siricilla2f6d5552020-04-19 23:39:02 +0530754 if (!cse_fix_data_failure_err(&cse_bp_info.bp_info))
755 cse_trigger_recovery(CSE_LITE_SKU_DATA_WIPE_ERROR);
756
Sridhar Siricilla361e3642020-10-18 20:14:07 +0530757 /*
758 * If SOC_INTEL_CSE_RW_UPDATE is defined , then trigger CSE firmware update. The driver
759 * triggers recovery if CSE CBFS RW metadata or CSE CBFS RW blob is not available.
760 */
Sridhar Siricilla4c2890d2020-12-09 00:28:30 +0530761 if (CONFIG(SOC_INTEL_CSE_RW_UPDATE)) {
762 uint8_t rv;
763 rv = cse_fw_update(&cse_bp_info.bp_info);
764 if (rv)
765 cse_trigger_recovery(rv);
766 }
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530767
Sridahr Siricilla54b03562021-06-18 10:59:30 +0530768 if (!cse_is_rw_bp_status_valid(&cse_bp_info.bp_info))
769 cse_trigger_recovery(CSE_LITE_SKU_RW_JUMP_ERROR);
770
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530771 if (!cse_boot_to_rw(&cse_bp_info.bp_info)) {
Sridhar Siricilla9f71b172020-06-01 14:50:52 +0530772 printk(BIOS_ERR, "cse_lite: Failed to switch to RW\n");
Sridhar Siricilla87e36c42020-05-03 19:08:18 +0530773 cse_trigger_recovery(CSE_LITE_SKU_RW_SWITCH_ERROR);
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530774 }
Sridhar Siricillaf87ff332019-09-12 17:18:20 +0530775}