mb/google/nissa/var/rull: add ssd timing and modify ssd GPIO pins of rtd3
[coreboot2.git] / src / security / vboot / ec_sync.c
blobac65dbd189f45217e6845d10798df212f2ca9a56
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <cbfs.h>
5 #include <console/console.h>
6 #include <delay.h>
7 #include <ec/google/chromeec/ec.h>
8 #include <halt.h>
9 #include <security/vboot/misc.h>
10 #include <security/vboot/vbnv.h>
11 #include <security/vboot/vboot_common.h>
12 #include <timer.h>
13 #include <timestamp.h>
14 #include <vb2_api.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
38 * perform the work.
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);
51 vboot_save_data(ctx);
53 switch (retval) {
54 case VB2_SUCCESS:
55 break;
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");
62 halt();
63 break;
65 /* Only for EC-EFS */
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");
72 halt();
73 break;
75 case VB2_REQUEST_REBOOT:
76 printk(BIOS_INFO, "Reboot requested. Doing warm reboot\n");
77 vboot_reboot();
78 break;
80 default:
81 printk(BIOS_ERR, "EC software sync failed (%#x),"
82 " rebooting\n", retval);
83 vboot_reboot();
84 break;
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)
93 switch (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;
98 default:
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;
113 struct stopwatch sw;
115 hash_offset = get_vboot_hash_offset(select);
117 stopwatch_init_msecs_expire(&sw, CROS_EC_HASH_TIMEOUT_MS);
118 do {
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)
129 break;
131 printk(BIOS_WARNING,
132 "%s: No valid hash (status=%d size=%d). "
133 "Computing...\n", __func__, resp.status,
134 resp.size);
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
144 * a recalc request.
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);
150 break;
152 case EC_VBOOT_HASH_STATUS_BUSY:
153 /* Hash is still calculating. */
154 mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
155 break;
157 case EC_VBOOT_HASH_STATUS_DONE: /* intentional fallthrough */
158 default:
159 /* Hash is ready! */
160 break;
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__,
169 resp.status);
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;
183 return VB2_SUCCESS;
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;
198 if (!enable) {
199 /* If protection is still enabled, need reboot */
200 if (resp.flags & protected_region)
201 return VB2_REQUEST_REBOOT_EC_TO_RO;
203 return VB2_SUCCESS;
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))
212 return VB2_SUCCESS;
214 /* If flash is protected now, success */
215 if (resp.flags & EC_FLASH_PROTECT_ALL_NOW)
216 return VB2_SUCCESS;
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)
229 switch (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;
234 default:
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,
243 int image_size)
245 struct ec_response_get_protocol_info resp_proto;
246 struct ec_response_flash_info resp_flash;
247 ssize_t pdata_max_size;
248 ssize_t burst;
249 uint8_t *file_buf;
250 struct ec_params_flash_write *params;
251 uint32_t end, off;
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 */
283 if (burst <= 0) {
284 printk(BIOS_ERR, "Flash write buffer too small! skipping "
285 "flash write\n");
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;
294 file_buf = image;
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;
300 params->size = todo;
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;
313 file_buf += todo;
316 return VB2_SUCCESS;
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;
326 vb2_error_t rv;
327 void *image;
328 size_t image_size;
330 /* Un-protect the flash region */
331 rv = ec_protect_flash(0);
332 if (rv != VB2_SUCCESS)
333 return rv;
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, &region_offset,
340 &region_size))
341 return VB2_ERROR_UNKNOWN;
343 /* Map the CBFS file */
344 image = cbfs_map(EC_IMAGE_FILENAME(select), &image_size);
345 if (!image)
346 return VB2_ERROR_UNKNOWN;
348 rv = VB2_ERROR_UNKNOWN;
350 /* Bail if the image is too large */
351 if (image_size > region_size)
352 goto unmap;
354 /* Erase the region */
355 if (google_chromeec_flash_erase(region_offset, region_size))
356 goto unmap;
358 /* Write the image into the region */
359 if (ec_flash_write(image, region_offset, image_size))
360 goto unmap;
362 /* Verify the image */
363 if (google_chromeec_efs_verify(region))
364 goto unmap;
366 rv = VB2_SUCCESS;
368 unmap:
369 cbfs_unmap(image);
370 return rv;
373 static vb2_error_t ec_get_expected_hash(enum vb2_firmware_selection select,
374 const uint8_t **hash,
375 int *hash_size)
377 size_t size;
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);
383 if (!file)
384 return VB2_ERROR_UNKNOWN;
386 *hash = file;
387 *hash_size = (int)size;
389 return VB2_SUCCESS;
392 /***********************************************************************
393 * Vboot Callbacks
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);
402 return VB2_SUCCESS;
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();
411 return VB2_SUCCESS;
415 * Callback for when Vboot is finished.
417 vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *ctx)
419 int limit_power = 0;
420 bool message_printed = false;
421 struct stopwatch sw;
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.
428 if (in_recovery)
429 return VB2_SUCCESS;
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. */
436 while (1) {
437 if (google_chromeec_read_limit_power_request(&limit_power)) {
438 printk(BIOS_ERR, "Failed to check EC limit power"
439 "flag.\n");
440 return VB2_ERROR_UNKNOWN;
443 if (!limit_power || stopwatch_expired(&sw))
444 break;
446 if (!message_printed) {
447 printk(BIOS_SPEW,
448 "Waiting for EC to clear limit power flag.\n");
449 message_printed = true;
452 mdelay(LIMIT_POWER_POLL_SLEEP_MS);
455 if (limit_power) {
456 printk(BIOS_INFO,
457 "EC requests limited power usage. Request shutdown.\n");
458 return VB2_REQUEST_SHUTDOWN;
459 } else {
460 printk(BIOS_INFO, "Waited %lldus to clear limit power flag.\n",
461 stopwatch_duration_usecs(&sw));
464 return VB2_SUCCESS;
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;
475 return VB2_SUCCESS;
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,
500 int *hash_size)
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;
513 return VB2_SUCCESS;
517 * Update EC image.
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)
529 struct stopwatch sw;
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 */
538 mdelay(50);
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;
546 mdelay(5);
549 printk(BIOS_INFO, "\nEC returned from reboot after %lldus\n",
550 stopwatch_duration_usecs(&sw));
552 return VB2_SUCCESS;