blob: 3a177b16e85ba5ba3d6bc00d18cd256d979ddf88 [file] [log] [blame]
Angel Pons986d50e2020-04-02 23:48:53 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -06003
4#include <assert.h>
5#include <cbfs.h>
6#include <console/console.h>
7#include <delay.h>
8#include <ec/google/chromeec/ec.h>
Tim Wawrzynczak14dd0732019-12-06 09:28:29 -07009#include <halt.h>
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060010#include <security/vboot/misc.h>
11#include <security/vboot/vbnv.h>
12#include <security/vboot/vboot_common.h>
13#include <timer.h>
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -060014#include <timestamp.h>
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060015#include <vb2_api.h>
Joel Kitchinga6531a32020-02-20 17:50:25 +080016#include <vboot_api.h> /* for VbExDisplayScreen() and VbScreenData */
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060017
18#define _EC_FILENAME(select, suffix) \
19 (select == VB_SELECT_FIRMWARE_READONLY ? "ecro" suffix : "ecrw" suffix)
20#define EC_IMAGE_FILENAME(select) _EC_FILENAME(select, "")
21#define EC_HASH_FILENAME(select) _EC_FILENAME(select, ".hash")
22
23/* Wait 10 ms between attempts to check if EC's hash is ready */
24#define CROS_EC_HASH_CHECK_DELAY_MS 10
25/* Give the EC 2 seconds to finish calculating its hash */
26#define CROS_EC_HASH_TIMEOUT_MS 2000
27
28/* Wait 3 seconds after software sync for EC to clear the limit power flag. */
29#define LIMIT_POWER_WAIT_TIMEOUT_MS 3000
30/* Check the limit power flag every 10 ms while waiting. */
31#define LIMIT_POWER_POLL_SLEEP_MS 10
32
33/* Wait 3 seconds for EC to sysjump to RW */
34#define CROS_EC_SYSJUMP_TIMEOUT_MS 3000
35
36/*
37 * The external API for EC software sync. This function calls into
38 * vboot, which kicks off the process. Vboot runs the verified boot
39 * logic, and requires the client program to provide callbacks which
40 * perform the work.
41 */
42void vboot_sync_ec(void)
43{
44 vb2_error_t retval = VB2_SUCCESS;
45 struct vb2_context *ctx;
46
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -060047 timestamp_add_now(TS_START_EC_SYNC);
48
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060049 ctx = vboot_get_context();
50 ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
51
52 retval = vb2api_ec_sync(ctx);
53 vboot_save_nvdata_only(ctx);
54
Tim Wawrzynczak14dd0732019-12-06 09:28:29 -070055 switch (retval) {
56 case VB2_SUCCESS:
57 break;
58
59 case VBERROR_EC_REBOOT_TO_RO_REQUIRED:
60 printk(BIOS_INFO, "EC Reboot requested. Doing cold reboot\n");
61 if (google_chromeec_reboot(0, EC_REBOOT_COLD, 0))
62 printk(BIOS_EMERG, "Failed to get EC to cold reboot\n");
63
64 halt();
65 break;
66
67 /* Only for EC-EFS */
68 case VBERROR_EC_REBOOT_TO_SWITCH_RW:
69 printk(BIOS_INFO, "Switch EC slot requested. Doing cold reboot\n");
70 if (google_chromeec_reboot(0, EC_REBOOT_COLD,
71 EC_REBOOT_FLAG_SWITCH_RW_SLOT))
72 printk(BIOS_EMERG, "Failed to get EC to cold reboot\n");
73
74 halt();
75 break;
76
77 case VBERROR_REBOOT_REQUIRED:
78 printk(BIOS_INFO, "Reboot requested. Doing warm reboot\n");
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060079 vboot_reboot();
Tim Wawrzynczak14dd0732019-12-06 09:28:29 -070080 break;
81
82 default:
83 printk(BIOS_ERR, "EC software sync failed (%#x),"
84 " rebooting\n", retval);
85 vboot_reboot();
86 break;
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060087 }
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -060088
89 timestamp_add_now(TS_END_EC_SYNC);
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -060090}
91
92/* Convert firmware image type into a flash offset */
93static uint32_t get_vboot_hash_offset(enum vb2_firmware_selection select)
94{
95 switch (select) {
96 case VB_SELECT_FIRMWARE_READONLY:
97 return EC_VBOOT_HASH_OFFSET_RO;
98 case VB_SELECT_FIRMWARE_EC_UPDATE:
99 return EC_VBOOT_HASH_OFFSET_UPDATE;
100 default:
101 return EC_VBOOT_HASH_OFFSET_ACTIVE;
102 }
103}
104
105/*
106 * Asks the EC to calculate a hash of the specified firmware image, and
107 * returns the information in **hash and *hash_size.
108 */
109static vb2_error_t ec_hash_image(enum vb2_firmware_selection select,
110 const uint8_t **hash, int *hash_size)
111{
112 static struct ec_response_vboot_hash resp;
113 uint32_t hash_offset;
114 int recalc_requested = 0;
115 struct stopwatch sw;
116
117 hash_offset = get_vboot_hash_offset(select);
118
119 stopwatch_init_msecs_expire(&sw, CROS_EC_HASH_TIMEOUT_MS);
120 do {
121 if (google_chromeec_get_vboot_hash(hash_offset, &resp))
122 return VB2_ERROR_UNKNOWN;
123
124 switch (resp.status) {
125 case EC_VBOOT_HASH_STATUS_NONE:
126 /*
127 * There is no hash available right now.
128 * Request a recalc if it hasn't been done yet.
129 */
130 if (recalc_requested)
131 break;
132
133 printk(BIOS_WARNING,
134 "%s: No valid hash (status=%d size=%d). "
135 "Computing...\n", __func__, resp.status,
136 resp.size);
137
138 if (google_chromeec_start_vboot_hash(
139 EC_VBOOT_HASH_TYPE_SHA256, hash_offset, &resp))
140 return VB2_ERROR_UNKNOWN;
141
142 recalc_requested = 1;
143
144 /*
145 * Expect status to be busy since we just sent
146 * a recalc request.
147 */
148 resp.status = EC_VBOOT_HASH_STATUS_BUSY;
149
150 /* Hash just started calculating, let it go for a bit */
151 mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
152 break;
153
154 case EC_VBOOT_HASH_STATUS_BUSY:
155 /* Hash is still calculating. */
156 mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
157 break;
158
159 case EC_VBOOT_HASH_STATUS_DONE: /* intentional fallthrough */
160 default:
161 /* Hash is ready! */
162 break;
163 }
164 } while (resp.status == EC_VBOOT_HASH_STATUS_BUSY &&
165 !stopwatch_expired(&sw));
166
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -0600167 timestamp_add_now(TS_EC_HASH_READY);
168
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600169 if (resp.status != EC_VBOOT_HASH_STATUS_DONE) {
170 printk(BIOS_ERR, "%s: Hash status not done: %d\n", __func__,
171 resp.status);
172 return VB2_ERROR_UNKNOWN;
173 }
174 if (resp.hash_type != EC_VBOOT_HASH_TYPE_SHA256) {
175 printk(BIOS_ERR, "EC hash was the wrong type.\n");
176 return VB2_ERROR_UNKNOWN;
177 }
178
179 printk(BIOS_INFO, "EC took %luus to calculate image hash\n",
180 stopwatch_duration_usecs(&sw));
181
182 *hash = resp.hash_digest;
183 *hash_size = resp.digest_size;
184
185 return VB2_SUCCESS;
186}
187
188/*
189 * Asks the EC to protect or unprotect the specified flash region.
190 */
191static vb2_error_t ec_protect_flash(enum vb2_firmware_selection select, int enable)
192{
193 struct ec_response_flash_protect resp;
194 uint32_t protected_region = EC_FLASH_PROTECT_ALL_NOW;
195 const uint32_t mask = EC_FLASH_PROTECT_ALL_NOW | EC_FLASH_PROTECT_ALL_AT_BOOT;
196
197 if (select == VB_SELECT_FIRMWARE_READONLY)
198 protected_region = EC_FLASH_PROTECT_RO_NOW;
199
200 if (google_chromeec_flash_protect(mask, enable ? mask : 0, &resp) != 0)
201 return VB2_ERROR_UNKNOWN;
202
203 if (!enable) {
204 /* If protection is still enabled, need reboot */
205 if (resp.flags & protected_region)
206 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
207
208 return VB2_SUCCESS;
209 }
210
211 /*
212 * If write protect and ro-at-boot aren't both asserted, don't expect
213 * protection enabled.
214 */
215 if ((~resp.flags) & (EC_FLASH_PROTECT_GPIO_ASSERTED |
216 EC_FLASH_PROTECT_RO_AT_BOOT))
217 return VB2_SUCCESS;
218
219 /* If flash is protected now, success */
220 if (resp.flags & EC_FLASH_PROTECT_ALL_NOW)
221 return VB2_SUCCESS;
222
223 /* If RW will be protected at boot but not now, need a reboot */
224 if (resp.flags & EC_FLASH_PROTECT_ALL_AT_BOOT)
225 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
226
227 /* Otherwise, it's an error */
228 return VB2_ERROR_UNKNOWN;
229}
230
231/* Convert a firmware image type to an EC flash region */
232static enum ec_flash_region vboot_to_ec_region(enum vb2_firmware_selection select)
233{
234 switch (select) {
235 case VB_SELECT_FIRMWARE_READONLY:
236 return EC_FLASH_REGION_WP_RO;
237 case VB_SELECT_FIRMWARE_EC_UPDATE:
238 return EC_FLASH_REGION_UPDATE;
239 default:
240 return EC_FLASH_REGION_ACTIVE;
241 }
242}
243
244/*
245 * Read the EC's burst size bytes at a time from CBFS, and then send
246 * the chunk to the EC for it to write into its flash.
247 */
248static vb2_error_t ec_flash_write(struct region_device *image_region,
249 uint32_t region_offset, int image_size)
250{
251 struct ec_response_get_protocol_info resp_proto;
252 struct ec_response_flash_info resp_flash;
253 ssize_t pdata_max_size;
254 ssize_t burst;
255 uint8_t *file_buf;
256 struct ec_params_flash_write *params;
257 uint32_t end, off;
258
259 /*
260 * Get EC's protocol information, so that we can figure out how much
261 * data can be sent in one message.
262 */
263 if (google_chromeec_get_protocol_info(&resp_proto)) {
264 printk(BIOS_ERR, "Failed to get EC protocol information; "
265 "skipping flash write\n");
266 return VB2_ERROR_UNKNOWN;
267 }
268
269 /*
270 * Determine burst size. This must be a multiple of the write block
271 * size, and must also fit into the host parameter buffer.
272 */
273 if (google_chromeec_flash_info(&resp_flash)) {
274 printk(BIOS_ERR, "Failed to get EC flash information; "
275 "skipping flash write\n");
276 return VB2_ERROR_UNKNOWN;
277 }
278
279 /* Limit the potential buffer stack allocation to 1K */
280 pdata_max_size = MIN(1024, resp_proto.max_request_packet_size -
281 sizeof(struct ec_host_request));
282
283 /* Round burst to a multiple of the flash write block size */
284 burst = pdata_max_size - sizeof(*params);
285 burst = (burst / resp_flash.write_block_size) *
286 resp_flash.write_block_size;
287
288 /* Buffer too small */
289 if (burst <= 0) {
290 printk(BIOS_ERR, "Flash write buffer too small! skipping "
291 "flash write\n");
292 return VB2_ERROR_UNKNOWN;
293 }
294
295 /* Allocate buffer on the stack */
296 params = alloca(burst + sizeof(*params));
297
298 /* Fill up the buffer */
299 end = region_offset + image_size;
300 for (off = region_offset; off < end; off += burst) {
301 uint32_t todo = MIN(end - off, burst);
302 uint32_t xfer_size = todo + sizeof(*params);
303
304 /* Map 'todo' bytes into memory */
305 file_buf = rdev_mmap(image_region, off - region_offset, todo);
306 if (file_buf == NULL)
307 return VB2_ERROR_UNKNOWN;
308
309 params->offset = off;
310 params->size = todo;
311
312 /* Read todo bytes into the buffer */
313 memcpy(params + 1, file_buf, todo);
314
315 if (rdev_munmap(image_region, file_buf))
316 return VB2_ERROR_UNKNOWN;
317
318 /* Make sure to add back in the size of the parameters */
319 if (google_chromeec_flash_write_block(
320 (const uint8_t *)params, xfer_size)) {
321 printk(BIOS_ERR, "EC failed flash write command, "
322 "relative offset %u!\n", off - region_offset);
323 return VB2_ERROR_UNKNOWN;
324 }
325 }
326
327 return VB2_SUCCESS;
328}
329
330/*
331 * The logic for updating an EC firmware image.
332 */
333static vb2_error_t ec_update_image(enum vb2_firmware_selection select)
334{
335 uint32_t region_offset, region_size;
336 enum ec_flash_region region;
337 vb2_error_t rv;
338 size_t image_size;
339 struct cbfsf fh;
340 const char *filename;
341 struct region_device image_region;
342
343 /* Un-protect the flash region */
344 rv = ec_protect_flash(select, 0);
345 if (rv != VB2_SUCCESS)
346 return rv;
347
348 /* Convert vboot region into an EC region */
349 region = vboot_to_ec_region(select);
350
351 /* Get information about the flash region */
352 if (google_chromeec_flash_region_info(region, &region_offset,
353 &region_size))
354 return VB2_ERROR_UNKNOWN;
355
356 /* Locate the CBFS file */
357 filename = EC_IMAGE_FILENAME(select);
358 if (cbfs_boot_locate(&fh, filename, NULL))
359 return VB2_ERROR_UNKNOWN;
360
361 /* Get the file size and the region struct */
362 image_size = region_device_sz(&fh.data);
363 cbfs_file_data(&image_region, &fh);
364
365 /* Bail if the image is too large */
366 if (image_size > region_size)
367 return VB2_ERROR_INVALID_PARAMETER;
368
369 /* Erase the region */
370 if (google_chromeec_flash_erase(region_offset, region_size))
371 return VB2_ERROR_UNKNOWN;
372
373 /* Write the image into the region */
374 if (ec_flash_write(&image_region, region_offset, image_size))
375 return VB2_ERROR_UNKNOWN;
376
377 /* Verify the image */
378 if (google_chromeec_efs_verify(region))
379 return VB2_ERROR_UNKNOWN;
380
381 return VB2_SUCCESS;
382}
383
384static vb2_error_t ec_get_expected_hash(enum vb2_firmware_selection select,
385 const uint8_t **hash,
386 int *hash_size)
387{
388 size_t size;
389 const char *filename = EC_HASH_FILENAME(select);
390 const uint8_t *file = cbfs_boot_map_with_leak(filename, CBFS_TYPE_RAW, &size);
391
392 if (file == NULL)
393 return VB2_ERROR_UNKNOWN;
394
395 *hash = file;
396 *hash_size = (int)size;
397
398 return VB2_SUCCESS;
399}
400
401/***********************************************************************
402 * Vboot Callbacks
403 ***********************************************************************/
404
405/*
406 * Unsupported.
407 *
408 * coreboot does not support the graphics initialization needed to
409 * display the vboot "wait" screens, etc., because the use case for
410 * supporting software sync early in the boot flow is to be able to
411 * quickly update the EC and/or sysjump to RW earlier so that USB-PD
412 * power (> 15 W) can be negotiated for earlier.
413 */
414vb2_error_t VbExDisplayScreen(uint32_t screen_type, uint32_t locale,
415 const VbScreenData *data)
416{
417 return VB2_ERROR_UNKNOWN;
418}
419
420/*
421 * Write opaque data into NV storage region.
422 */
Joel Kitching1debc0c2019-11-27 14:25:16 +0800423vb2_error_t vb2ex_commit_data(struct vb2_context *ctx)
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600424{
Joel Kitching1debc0c2019-11-27 14:25:16 +0800425 save_vbnv(ctx->nvdata);
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600426 return VB2_SUCCESS;
427}
428
429/*
430 * Report whether the EC is in RW or not.
431 */
432vb2_error_t vb2ex_ec_running_rw(int *in_rw)
433{
434 *in_rw = !google_ec_running_ro();
435 return VB2_SUCCESS;
436}
437
438/*
439 * Callback for when Vboot is finished.
440 */
441vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *ctx)
442{
443 int limit_power = 0;
444 bool message_printed = false;
445 struct stopwatch sw;
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600446 int in_recovery = !!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE);
447
448 /*
449 * Do not wait for the limit power flag to be cleared in
450 * recovery mode since we didn't just sysjump.
451 */
452 if (in_recovery)
453 return VB2_SUCCESS;
454
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -0600455 timestamp_add_now(TS_EC_POWER_LIMIT_WAIT);
456
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600457 stopwatch_init_msecs_expire(&sw, LIMIT_POWER_WAIT_TIMEOUT_MS);
458
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -0600459 /* Ensure we have enough power to continue booting. */
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600460 while (1) {
461 if (google_chromeec_read_limit_power_request(&limit_power)) {
462 printk(BIOS_ERR, "Failed to check EC limit power"
463 "flag.\n");
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -0600464 return VB2_ERROR_UNKNOWN;
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600465 }
466
467 if (!limit_power || stopwatch_expired(&sw))
468 break;
469
470 if (!message_printed) {
471 printk(BIOS_SPEW,
472 "Waiting for EC to clear limit power flag.\n");
473 message_printed = true;
474 }
475
476 mdelay(LIMIT_POWER_POLL_SLEEP_MS);
477 }
478
479 if (limit_power) {
480 printk(BIOS_INFO,
481 "EC requests limited power usage. Request shutdown.\n");
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -0600482 return VBERROR_SHUTDOWN_REQUESTED;
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600483 } else {
484 printk(BIOS_INFO, "Waited %luus to clear limit power flag.\n",
485 stopwatch_duration_usecs(&sw));
486 }
487
Tim Wawrzynczakf9e74992019-10-25 14:59:43 -0600488 return VB2_SUCCESS;
Tim Wawrzynczakd6fc5572019-10-25 14:58:15 -0600489}
490
491/*
492 * Support battery cutoff if required.
493 */
494vb2_error_t vb2ex_ec_battery_cutoff(void)
495{
496 if (google_chromeec_battery_cutoff(EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN))
497 return VB2_ERROR_UNKNOWN;
498
499 return VB2_SUCCESS;
500}
501
502/*
503 * Vboot callback for calculating an EC image's hash.
504 */
505vb2_error_t vb2ex_ec_hash_image(enum vb2_firmware_selection select,
506 const uint8_t **hash, int *hash_size)
507{
508 return ec_hash_image(select, hash, hash_size);
509}
510
511/*
512 * Vboot callback for EC flash protection.
513 */
514vb2_error_t vb2ex_ec_protect(enum vb2_firmware_selection select)
515{
516 return ec_protect_flash(select, 1);
517}
518
519/*
520 * Get hash for image.
521 */
522vb2_error_t vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select,
523 const uint8_t **hash,
524 int *hash_size)
525{
526 return ec_get_expected_hash(select, hash, hash_size);
527}
528
529/*
530 * Disable further sysjumps (i.e., stay in RW until next reboot)
531 */
532vb2_error_t vb2ex_ec_disable_jump(void)
533{
534 if (google_chromeec_reboot(0, EC_REBOOT_DISABLE_JUMP, 0))
535 return VB2_ERROR_UNKNOWN;
536
537 return VB2_SUCCESS;
538}
539
540/*
541 * Update EC image.
542 */
543vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select)
544{
545 return ec_update_image(select);
546}
547
548/*
549 * Vboot callback for commanding EC to sysjump to RW.
550 */
551vb2_error_t vb2ex_ec_jump_to_rw(void)
552{
553 struct stopwatch sw;
554
555 if (google_chromeec_reboot(0, EC_REBOOT_JUMP_RW, 0))
556 return VB2_ERROR_UNKNOWN;
557
558 /* Give the EC 3 seconds to sysjump */
559 stopwatch_init_msecs_expire(&sw, CROS_EC_SYSJUMP_TIMEOUT_MS);
560
561 /* Default delay to wait after EC reboot */
562 mdelay(50);
563 while (google_chromeec_hello()) {
564 if (stopwatch_expired(&sw)) {
565 printk(BIOS_ERR, "EC did not return from reboot after %luus\n",
566 stopwatch_duration_usecs(&sw));
567 return VB2_ERROR_UNKNOWN;
568 }
569
570 mdelay(5);
571 }
572
573 printk(BIOS_INFO, "\nEC returned from reboot after %luus\n",
574 stopwatch_duration_usecs(&sw));
575
576 return VB2_SUCCESS;
577}