1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <console/console.h>
7 #include <ec/google/chromeec/ec.h>
9 #include <security/vboot/misc.h>
10 #include <security/vboot/vbnv.h>
11 #include <security/vboot/vboot_common.h>
13 #include <timestamp.h>
16 #define _EC_FILENAME(select, suffix) \
17 (select == VB_SELECT_FIRMWARE_READONLY ? "ecro" suffix : "ecrw" suffix)
18 #define EC_IMAGE_FILENAME(select) _EC_FILENAME(select, "")
19 #define EC_HASH_FILENAME(select) _EC_FILENAME(select, ".hash")
21 /* Wait 10 ms between attempts to check if EC's hash is ready */
22 #define CROS_EC_HASH_CHECK_DELAY_MS 10
23 /* Give the EC 2 seconds to finish calculating its hash */
24 #define CROS_EC_HASH_TIMEOUT_MS 2000
26 /* Wait 3 seconds after software sync for EC to clear the limit power flag. */
27 #define LIMIT_POWER_WAIT_TIMEOUT_MS 3000
28 /* Check the limit power flag every 10 ms while waiting. */
29 #define LIMIT_POWER_POLL_SLEEP_MS 10
31 /* Wait 3 seconds for EC to sysjump to RW */
32 #define CROS_EC_SYSJUMP_TIMEOUT_MS 3000
35 * The external API for EC software sync. This function calls into
36 * vboot, which kicks off the process. Vboot runs the verified boot
37 * logic, and requires the client program to provide callbacks which
40 void vboot_sync_ec(void)
42 vb2_error_t retval
= VB2_SUCCESS
;
43 struct vb2_context
*ctx
;
45 timestamp_add_now(TS_EC_SYNC_START
);
47 ctx
= vboot_get_context();
48 ctx
->flags
|= VB2_CONTEXT_EC_SYNC_SUPPORTED
;
50 retval
= vb2api_ec_sync(ctx
);
57 case VB2_REQUEST_REBOOT_EC_TO_RO
:
58 printk(BIOS_INFO
, "EC Reboot requested. Doing cold reboot\n");
59 if (google_chromeec_reboot(EC_REBOOT_COLD
, 0))
60 printk(BIOS_EMERG
, "Failed to get EC to cold reboot\n");
66 case VB2_REQUEST_REBOOT_EC_SWITCH_RW
:
67 printk(BIOS_INFO
, "Switch EC slot requested. Doing cold reboot\n");
68 if (google_chromeec_reboot(EC_REBOOT_COLD
,
69 EC_REBOOT_FLAG_SWITCH_RW_SLOT
))
70 printk(BIOS_EMERG
, "Failed to get EC to cold reboot\n");
75 case VB2_REQUEST_REBOOT
:
76 printk(BIOS_INFO
, "Reboot requested. Doing warm reboot\n");
81 printk(BIOS_ERR
, "EC software sync failed (%#x),"
82 " rebooting\n", retval
);
87 timestamp_add_now(TS_EC_SYNC_END
);
90 /* Convert firmware image type into a flash offset */
91 static uint32_t get_vboot_hash_offset(enum vb2_firmware_selection select
)
94 case VB_SELECT_FIRMWARE_READONLY
:
95 return EC_VBOOT_HASH_OFFSET_RO
;
96 case VB_SELECT_FIRMWARE_EC_UPDATE
:
97 return EC_VBOOT_HASH_OFFSET_UPDATE
;
99 return EC_VBOOT_HASH_OFFSET_ACTIVE
;
104 * Asks the EC to calculate a hash of the specified firmware image, and
105 * returns the information in **hash and *hash_size.
107 static vb2_error_t
ec_hash_image(enum vb2_firmware_selection select
,
108 const uint8_t **hash
, int *hash_size
)
110 static struct ec_response_vboot_hash resp
;
111 uint32_t hash_offset
;
112 int recalc_requested
= 0;
115 hash_offset
= get_vboot_hash_offset(select
);
117 stopwatch_init_msecs_expire(&sw
, CROS_EC_HASH_TIMEOUT_MS
);
119 if (google_chromeec_get_vboot_hash(hash_offset
, &resp
))
120 return VB2_ERROR_UNKNOWN
;
122 switch (resp
.status
) {
123 case EC_VBOOT_HASH_STATUS_NONE
:
125 * There is no hash available right now.
126 * Request a recalc if it hasn't been done yet.
128 if (recalc_requested
)
132 "%s: No valid hash (status=%d size=%d). "
133 "Computing...\n", __func__
, resp
.status
,
136 if (google_chromeec_start_vboot_hash(
137 EC_VBOOT_HASH_TYPE_SHA256
, hash_offset
, &resp
))
138 return VB2_ERROR_UNKNOWN
;
140 recalc_requested
= 1;
143 * Expect status to be busy since we just sent
146 resp
.status
= EC_VBOOT_HASH_STATUS_BUSY
;
148 /* Hash just started calculating, let it go for a bit */
149 mdelay(CROS_EC_HASH_CHECK_DELAY_MS
);
152 case EC_VBOOT_HASH_STATUS_BUSY
:
153 /* Hash is still calculating. */
154 mdelay(CROS_EC_HASH_CHECK_DELAY_MS
);
157 case EC_VBOOT_HASH_STATUS_DONE
: /* intentional fallthrough */
162 } while (resp
.status
== EC_VBOOT_HASH_STATUS_BUSY
&&
163 !stopwatch_expired(&sw
));
165 timestamp_add_now(TS_EC_HASH_READY
);
167 if (resp
.status
!= EC_VBOOT_HASH_STATUS_DONE
) {
168 printk(BIOS_ERR
, "%s: Hash status not done: %d\n", __func__
,
170 return VB2_ERROR_UNKNOWN
;
172 if (resp
.hash_type
!= EC_VBOOT_HASH_TYPE_SHA256
) {
173 printk(BIOS_ERR
, "EC hash was the wrong type.\n");
174 return VB2_ERROR_UNKNOWN
;
177 printk(BIOS_INFO
, "EC took %lldus to calculate image hash\n",
178 stopwatch_duration_usecs(&sw
));
180 *hash
= resp
.hash_digest
;
181 *hash_size
= resp
.digest_size
;
187 * Asks the EC to protect or unprotect the specified flash region.
189 static vb2_error_t
ec_protect_flash(int enable
)
191 struct ec_response_flash_protect resp
;
192 uint32_t protected_region
= EC_FLASH_PROTECT_ALL_NOW
;
193 const uint32_t mask
= EC_FLASH_PROTECT_ALL_NOW
| EC_FLASH_PROTECT_ALL_AT_BOOT
;
195 if (google_chromeec_flash_protect(mask
, enable
? mask
: 0, &resp
) != 0)
196 return VB2_ERROR_UNKNOWN
;
199 /* If protection is still enabled, need reboot */
200 if (resp
.flags
& protected_region
)
201 return VB2_REQUEST_REBOOT_EC_TO_RO
;
207 * If write protect and ro-at-boot aren't both asserted, don't expect
208 * protection enabled.
210 if ((~resp
.flags
) & (EC_FLASH_PROTECT_GPIO_ASSERTED
|
211 EC_FLASH_PROTECT_RO_AT_BOOT
))
214 /* If flash is protected now, success */
215 if (resp
.flags
& EC_FLASH_PROTECT_ALL_NOW
)
218 /* If RW will be protected at boot but not now, need a reboot */
219 if (resp
.flags
& EC_FLASH_PROTECT_ALL_AT_BOOT
)
220 return VB2_REQUEST_REBOOT_EC_TO_RO
;
222 /* Otherwise, it's an error */
223 return VB2_ERROR_UNKNOWN
;
226 /* Convert a firmware image type to an EC flash region */
227 static enum ec_flash_region
vboot_to_ec_region(enum vb2_firmware_selection select
)
230 case VB_SELECT_FIRMWARE_READONLY
:
231 return EC_FLASH_REGION_WP_RO
;
232 case VB_SELECT_FIRMWARE_EC_UPDATE
:
233 return EC_FLASH_REGION_UPDATE
;
235 return EC_FLASH_REGION_ACTIVE
;
240 * Send an image to the EC in burst-sized chunks.
242 static vb2_error_t
ec_flash_write(void *image
, uint32_t region_offset
,
245 struct ec_response_get_protocol_info resp_proto
;
246 struct ec_response_flash_info resp_flash
;
247 ssize_t pdata_max_size
;
250 struct ec_params_flash_write
*params
;
254 * Get EC's protocol information, so that we can figure out how much
255 * data can be sent in one message.
257 if (google_chromeec_get_protocol_info(&resp_proto
)) {
258 printk(BIOS_ERR
, "Failed to get EC protocol information; "
259 "skipping flash write\n");
260 return VB2_ERROR_UNKNOWN
;
264 * Determine burst size. This must be a multiple of the write block
265 * size, and must also fit into the host parameter buffer.
267 if (google_chromeec_flash_info(&resp_flash
)) {
268 printk(BIOS_ERR
, "Failed to get EC flash information; "
269 "skipping flash write\n");
270 return VB2_ERROR_UNKNOWN
;
273 /* Limit the potential buffer stack allocation to 1K */
274 pdata_max_size
= MIN(1024, resp_proto
.max_request_packet_size
-
275 sizeof(struct ec_host_request
));
277 /* Round burst to a multiple of the flash write block size */
278 burst
= pdata_max_size
- sizeof(*params
);
279 burst
= (burst
/ resp_flash
.write_block_size
) *
280 resp_flash
.write_block_size
;
282 /* Buffer too small */
284 printk(BIOS_ERR
, "Flash write buffer too small! skipping "
286 return VB2_ERROR_UNKNOWN
;
289 /* Allocate buffer on the stack */
290 params
= alloca(burst
+ sizeof(*params
));
292 /* Fill up the buffer */
293 end
= region_offset
+ image_size
;
295 for (off
= region_offset
; off
< end
; off
+= burst
) {
296 uint32_t todo
= MIN(end
- off
, burst
);
297 uint32_t xfer_size
= todo
+ sizeof(*params
);
299 params
->offset
= off
;
302 /* Read todo bytes into the buffer */
303 memcpy(params
+ 1, file_buf
, todo
);
305 /* Make sure to add back in the size of the parameters */
306 if (google_chromeec_flash_write_block(
307 (const uint8_t *)params
, xfer_size
)) {
308 printk(BIOS_ERR
, "EC failed flash write command, "
309 "relative offset %u!\n", off
- region_offset
);
310 return VB2_ERROR_UNKNOWN
;
320 * The logic for updating an EC firmware image.
322 static vb2_error_t
ec_update_image(enum vb2_firmware_selection select
)
324 uint32_t region_offset
, region_size
;
325 enum ec_flash_region region
;
330 /* Un-protect the flash region */
331 rv
= ec_protect_flash(0);
332 if (rv
!= VB2_SUCCESS
)
335 /* Convert vboot region into an EC region */
336 region
= vboot_to_ec_region(select
);
338 /* Get information about the flash region */
339 if (google_chromeec_flash_region_info(region
, ®ion_offset
,
341 return VB2_ERROR_UNKNOWN
;
343 /* Map the CBFS file */
344 image
= cbfs_map(EC_IMAGE_FILENAME(select
), &image_size
);
346 return VB2_ERROR_UNKNOWN
;
348 rv
= VB2_ERROR_UNKNOWN
;
350 /* Bail if the image is too large */
351 if (image_size
> region_size
)
354 /* Erase the region */
355 if (google_chromeec_flash_erase(region_offset
, region_size
))
358 /* Write the image into the region */
359 if (ec_flash_write(image
, region_offset
, image_size
))
362 /* Verify the image */
363 if (google_chromeec_efs_verify(region
))
373 static vb2_error_t
ec_get_expected_hash(enum vb2_firmware_selection select
,
374 const uint8_t **hash
,
378 const char *filename
= EC_HASH_FILENAME(select
);
380 /* vboot has no API to return this memory, so must permanently leak a mapping here. */
381 const uint8_t *file
= cbfs_map(filename
, &size
);
384 return VB2_ERROR_UNKNOWN
;
387 *hash_size
= (int)size
;
392 /***********************************************************************
394 ***********************************************************************/
397 * Write opaque data into NV storage region.
399 vb2_error_t
vb2ex_commit_data(struct vb2_context
*ctx
)
401 save_vbnv(ctx
->nvdata
);
406 * Report whether the EC is in RW or not.
408 vb2_error_t
vb2ex_ec_running_rw(int *in_rw
)
410 *in_rw
= !google_ec_running_ro();
415 * Callback for when Vboot is finished.
417 vb2_error_t
vb2ex_ec_vboot_done(struct vb2_context
*ctx
)
420 bool message_printed
= false;
422 int in_recovery
= !!(ctx
->flags
& VB2_CONTEXT_RECOVERY_MODE
);
425 * Do not wait for the limit power flag to be cleared in
426 * recovery mode since we didn't just sysjump.
431 timestamp_add_now(TS_EC_POWER_LIMIT_WAIT
);
433 stopwatch_init_msecs_expire(&sw
, LIMIT_POWER_WAIT_TIMEOUT_MS
);
435 /* Ensure we have enough power to continue booting. */
437 if (google_chromeec_read_limit_power_request(&limit_power
)) {
438 printk(BIOS_ERR
, "Failed to check EC limit power"
440 return VB2_ERROR_UNKNOWN
;
443 if (!limit_power
|| stopwatch_expired(&sw
))
446 if (!message_printed
) {
448 "Waiting for EC to clear limit power flag.\n");
449 message_printed
= true;
452 mdelay(LIMIT_POWER_POLL_SLEEP_MS
);
457 "EC requests limited power usage. Request shutdown.\n");
458 return VB2_REQUEST_SHUTDOWN
;
460 printk(BIOS_INFO
, "Waited %lldus to clear limit power flag.\n",
461 stopwatch_duration_usecs(&sw
));
468 * Support battery cutoff if required.
470 vb2_error_t
vb2ex_ec_battery_cutoff(void)
472 if (google_chromeec_battery_cutoff(EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN
))
473 return VB2_ERROR_UNKNOWN
;
479 * Vboot callback for calculating an EC image's hash.
481 vb2_error_t
vb2ex_ec_hash_image(enum vb2_firmware_selection select
,
482 const uint8_t **hash
, int *hash_size
)
484 return ec_hash_image(select
, hash
, hash_size
);
488 * Vboot callback for EC flash protection.
490 vb2_error_t
vb2ex_ec_protect(void)
492 return ec_protect_flash(1);
496 * Get hash for image.
498 vb2_error_t
vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select
,
499 const uint8_t **hash
,
502 return ec_get_expected_hash(select
, hash
, hash_size
);
506 * Disable further sysjumps (i.e., stay in RW until next reboot)
508 vb2_error_t
vb2ex_ec_disable_jump(void)
510 if (google_chromeec_reboot(EC_REBOOT_DISABLE_JUMP
, 0))
511 return VB2_ERROR_UNKNOWN
;
519 vb2_error_t
vb2ex_ec_update_image(enum vb2_firmware_selection select
)
521 return ec_update_image(select
);
525 * Vboot callback for commanding EC to sysjump to RW.
527 vb2_error_t
vb2ex_ec_jump_to_rw(void)
531 if (google_chromeec_reboot(EC_REBOOT_JUMP_RW
, 0))
532 return VB2_ERROR_UNKNOWN
;
534 /* Give the EC 3 seconds to sysjump */
535 stopwatch_init_msecs_expire(&sw
, CROS_EC_SYSJUMP_TIMEOUT_MS
);
537 /* Default delay to wait after EC reboot */
539 while (google_chromeec_hello()) {
540 if (stopwatch_expired(&sw
)) {
541 printk(BIOS_ERR
, "EC did not return from reboot after %lldus\n",
542 stopwatch_duration_usecs(&sw
));
543 return VB2_ERROR_UNKNOWN
;
549 printk(BIOS_INFO
, "\nEC returned from reboot after %lldus\n",
550 stopwatch_duration_usecs(&sw
));