xref: /aosp_15_r20/external/coreboot/src/security/vboot/ec_sync.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
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>
15 
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")
20 
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
25 
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
30 
31 /* Wait 3 seconds for EC to sysjump to RW */
32 #define CROS_EC_SYSJUMP_TIMEOUT_MS 3000
33 
34 /*
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.
39  */
vboot_sync_ec(void)40 void vboot_sync_ec(void)
41 {
42 	vb2_error_t retval = VB2_SUCCESS;
43 	struct vb2_context *ctx;
44 
45 	timestamp_add_now(TS_EC_SYNC_START);
46 
47 	ctx = vboot_get_context();
48 	ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
49 
50 	retval = vb2api_ec_sync(ctx);
51 	vboot_save_data(ctx);
52 
53 	switch (retval) {
54 	case VB2_SUCCESS:
55 		break;
56 
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");
61 
62 		halt();
63 		break;
64 
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");
71 
72 		halt();
73 		break;
74 
75 	case VB2_REQUEST_REBOOT:
76 		printk(BIOS_INFO, "Reboot requested. Doing warm reboot\n");
77 		vboot_reboot();
78 		break;
79 
80 	default:
81 		printk(BIOS_ERR, "EC software sync failed (%#x),"
82 			" rebooting\n", retval);
83 		vboot_reboot();
84 		break;
85 	}
86 
87 	timestamp_add_now(TS_EC_SYNC_END);
88 }
89 
90 /* Convert firmware image type into a flash offset */
get_vboot_hash_offset(enum vb2_firmware_selection select)91 static uint32_t get_vboot_hash_offset(enum vb2_firmware_selection select)
92 {
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;
100 	}
101 }
102 
103 /*
104  * Asks the EC to calculate a hash of the specified firmware image, and
105  * returns the information in **hash and *hash_size.
106  */
ec_hash_image(enum vb2_firmware_selection select,const uint8_t ** hash,int * hash_size)107 static vb2_error_t ec_hash_image(enum vb2_firmware_selection select,
108 				 const uint8_t **hash, int *hash_size)
109 {
110 	static struct ec_response_vboot_hash resp;
111 	uint32_t hash_offset;
112 	int recalc_requested = 0;
113 	struct stopwatch sw;
114 
115 	hash_offset = get_vboot_hash_offset(select);
116 
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;
121 
122 		switch (resp.status) {
123 		case EC_VBOOT_HASH_STATUS_NONE:
124 			/*
125 			 * There is no hash available right now.
126 			 * Request a recalc if it hasn't been done yet.
127 			 */
128 			if (recalc_requested)
129 				break;
130 
131 			printk(BIOS_WARNING,
132 			       "%s: No valid hash (status=%d size=%d). "
133 			       "Computing...\n", __func__, resp.status,
134 			       resp.size);
135 
136 			if (google_chromeec_start_vboot_hash(
137 				    EC_VBOOT_HASH_TYPE_SHA256, hash_offset, &resp))
138 				return VB2_ERROR_UNKNOWN;
139 
140 			recalc_requested = 1;
141 
142 			/*
143 			 * Expect status to be busy since we just sent
144 			 * a recalc request.
145 			 */
146 			resp.status = EC_VBOOT_HASH_STATUS_BUSY;
147 
148 			/* Hash just started calculating, let it go for a bit */
149 			mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
150 			break;
151 
152 		case EC_VBOOT_HASH_STATUS_BUSY:
153 			/* Hash is still calculating. */
154 			mdelay(CROS_EC_HASH_CHECK_DELAY_MS);
155 			break;
156 
157 		case EC_VBOOT_HASH_STATUS_DONE: /* intentional fallthrough */
158 		default:
159 			/* Hash is ready! */
160 			break;
161 		}
162 	} while (resp.status == EC_VBOOT_HASH_STATUS_BUSY &&
163 		 !stopwatch_expired(&sw));
164 
165 	timestamp_add_now(TS_EC_HASH_READY);
166 
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;
171 	}
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;
175 	}
176 
177 	printk(BIOS_INFO, "EC took %lldus to calculate image hash\n",
178 		stopwatch_duration_usecs(&sw));
179 
180 	*hash = resp.hash_digest;
181 	*hash_size = resp.digest_size;
182 
183 	return VB2_SUCCESS;
184 }
185 
186 /*
187  * Asks the EC to protect or unprotect the specified flash region.
188  */
ec_protect_flash(int enable)189 static vb2_error_t ec_protect_flash(int enable)
190 {
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;
194 
195 	if (google_chromeec_flash_protect(mask, enable ? mask : 0, &resp) != 0)
196 		return VB2_ERROR_UNKNOWN;
197 
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;
202 
203 		return VB2_SUCCESS;
204 	}
205 
206 	/*
207 	 * If write protect and ro-at-boot aren't both asserted, don't expect
208 	 * protection enabled.
209 	 */
210 	if ((~resp.flags) & (EC_FLASH_PROTECT_GPIO_ASSERTED |
211 			     EC_FLASH_PROTECT_RO_AT_BOOT))
212 		return VB2_SUCCESS;
213 
214 	/* If flash is protected now, success */
215 	if (resp.flags & EC_FLASH_PROTECT_ALL_NOW)
216 		return VB2_SUCCESS;
217 
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;
221 
222 	/* Otherwise, it's an error */
223 	return VB2_ERROR_UNKNOWN;
224 }
225 
226 /* Convert a firmware image type to an EC flash region */
vboot_to_ec_region(enum vb2_firmware_selection select)227 static enum ec_flash_region vboot_to_ec_region(enum vb2_firmware_selection select)
228 {
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;
236 	}
237 }
238 
239 /*
240  * Send an image to the EC in burst-sized chunks.
241  */
ec_flash_write(void * image,uint32_t region_offset,int image_size)242 static vb2_error_t ec_flash_write(void *image, uint32_t region_offset,
243 				  int image_size)
244 {
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;
252 
253 	/*
254 	 * Get EC's protocol information, so that we can figure out how much
255 	 * data can be sent in one message.
256 	 */
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;
261 	}
262 
263 	/*
264 	 * Determine burst size.  This must be a multiple of the write block
265 	 * size, and must also fit into the host parameter buffer.
266 	 */
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;
271 	}
272 
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));
276 
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;
281 
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;
287 	}
288 
289 	/* Allocate buffer on the stack */
290 	params = alloca(burst + sizeof(*params));
291 
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);
298 
299 		params->offset = off;
300 		params->size = todo;
301 
302 		/* Read todo bytes into the buffer */
303 		memcpy(params + 1, file_buf, todo);
304 
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;
311 		}
312 
313 		file_buf += todo;
314 	}
315 
316 	return VB2_SUCCESS;
317 }
318 
319 /*
320  * The logic for updating an EC firmware image.
321  */
ec_update_image(enum vb2_firmware_selection select)322 static vb2_error_t ec_update_image(enum vb2_firmware_selection select)
323 {
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;
329 
330 	/* Un-protect the flash region */
331 	rv = ec_protect_flash(0);
332 	if (rv != VB2_SUCCESS)
333 		return rv;
334 
335 	/* Convert vboot region into an EC region */
336 	region = vboot_to_ec_region(select);
337 
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;
342 
343 	/* Map the CBFS file */
344 	image = cbfs_map(EC_IMAGE_FILENAME(select), &image_size);
345 	if (!image)
346 		return VB2_ERROR_UNKNOWN;
347 
348 	rv = VB2_ERROR_UNKNOWN;
349 
350 	/* Bail if the image is too large */
351 	if (image_size > region_size)
352 		goto unmap;
353 
354 	/* Erase the region */
355 	if (google_chromeec_flash_erase(region_offset, region_size))
356 		goto unmap;
357 
358 	/* Write the image into the region */
359 	if (ec_flash_write(image, region_offset, image_size))
360 		goto unmap;
361 
362 	/* Verify the image */
363 	if (google_chromeec_efs_verify(region))
364 		goto unmap;
365 
366 	rv = VB2_SUCCESS;
367 
368 unmap:
369 	cbfs_unmap(image);
370 	return rv;
371 }
372 
ec_get_expected_hash(enum vb2_firmware_selection select,const uint8_t ** hash,int * hash_size)373 static vb2_error_t ec_get_expected_hash(enum vb2_firmware_selection select,
374 					const uint8_t **hash,
375 					int *hash_size)
376 {
377 	size_t size;
378 	const char *filename = EC_HASH_FILENAME(select);
379 
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);
382 
383 	if (!file)
384 		return VB2_ERROR_UNKNOWN;
385 
386 	*hash = file;
387 	*hash_size = (int)size;
388 
389 	return VB2_SUCCESS;
390 }
391 
392 /***********************************************************************
393  * Vboot Callbacks
394  ***********************************************************************/
395 
396 /*
397  * Write opaque data into NV storage region.
398  */
vb2ex_commit_data(struct vb2_context * ctx)399 vb2_error_t vb2ex_commit_data(struct vb2_context *ctx)
400 {
401 	save_vbnv(ctx->nvdata);
402 	return VB2_SUCCESS;
403 }
404 
405 /*
406  * Report whether the EC is in RW or not.
407  */
vb2ex_ec_running_rw(int * in_rw)408 vb2_error_t vb2ex_ec_running_rw(int *in_rw)
409 {
410 	*in_rw = !google_ec_running_ro();
411 	return VB2_SUCCESS;
412 }
413 
414 /*
415  * Callback for when Vboot is finished.
416  */
vb2ex_ec_vboot_done(struct vb2_context * ctx)417 vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *ctx)
418 {
419 	int limit_power = 0;
420 	bool message_printed = false;
421 	struct stopwatch sw;
422 	int in_recovery = !!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE);
423 
424 	/*
425 	 * Do not wait for the limit power flag to be cleared in
426 	 * recovery mode since we didn't just sysjump.
427 	 */
428 	if (in_recovery)
429 		return VB2_SUCCESS;
430 
431 	timestamp_add_now(TS_EC_POWER_LIMIT_WAIT);
432 
433 	stopwatch_init_msecs_expire(&sw, LIMIT_POWER_WAIT_TIMEOUT_MS);
434 
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;
441 		}
442 
443 		if (!limit_power || stopwatch_expired(&sw))
444 			break;
445 
446 		if (!message_printed) {
447 			printk(BIOS_SPEW,
448 			       "Waiting for EC to clear limit power flag.\n");
449 			message_printed = true;
450 		}
451 
452 		mdelay(LIMIT_POWER_POLL_SLEEP_MS);
453 	}
454 
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));
462 	}
463 
464 	return VB2_SUCCESS;
465 }
466 
467 /*
468  * Support battery cutoff if required.
469  */
vb2ex_ec_battery_cutoff(void)470 vb2_error_t vb2ex_ec_battery_cutoff(void)
471 {
472 	if (google_chromeec_battery_cutoff(EC_BATTERY_CUTOFF_FLAG_AT_SHUTDOWN))
473 		return VB2_ERROR_UNKNOWN;
474 
475 	return VB2_SUCCESS;
476 }
477 
478 /*
479  * Vboot callback for calculating an EC image's hash.
480  */
vb2ex_ec_hash_image(enum vb2_firmware_selection select,const uint8_t ** hash,int * hash_size)481 vb2_error_t vb2ex_ec_hash_image(enum vb2_firmware_selection select,
482 				const uint8_t **hash, int *hash_size)
483 {
484 	return ec_hash_image(select, hash, hash_size);
485 }
486 
487 /*
488  * Vboot callback for EC flash protection.
489  */
vb2ex_ec_protect(void)490 vb2_error_t vb2ex_ec_protect(void)
491 {
492 	return ec_protect_flash(1);
493 }
494 
495 /*
496  * Get hash for image.
497  */
vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select,const uint8_t ** hash,int * hash_size)498 vb2_error_t vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select,
499 					     const uint8_t **hash,
500 					     int *hash_size)
501 {
502 	return ec_get_expected_hash(select, hash, hash_size);
503 }
504 
505 /*
506  * Disable further sysjumps (i.e., stay in RW until next reboot)
507  */
vb2ex_ec_disable_jump(void)508 vb2_error_t vb2ex_ec_disable_jump(void)
509 {
510 	if (google_chromeec_reboot(EC_REBOOT_DISABLE_JUMP, 0))
511 		return VB2_ERROR_UNKNOWN;
512 
513 	return VB2_SUCCESS;
514 }
515 
516 /*
517  * Update EC image.
518  */
vb2ex_ec_update_image(enum vb2_firmware_selection select)519 vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select)
520 {
521 	return ec_update_image(select);
522 }
523 
524 /*
525  * Vboot callback for commanding EC to sysjump to RW.
526  */
vb2ex_ec_jump_to_rw(void)527 vb2_error_t vb2ex_ec_jump_to_rw(void)
528 {
529 	struct stopwatch sw;
530 
531 	if (google_chromeec_reboot(EC_REBOOT_JUMP_RW, 0))
532 		return VB2_ERROR_UNKNOWN;
533 
534 	/* Give the EC 3 seconds to sysjump */
535 	stopwatch_init_msecs_expire(&sw, CROS_EC_SYSJUMP_TIMEOUT_MS);
536 
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;
544 		}
545 
546 		mdelay(5);
547 	}
548 
549 	printk(BIOS_INFO, "\nEC returned from reboot after %lldus\n",
550 	       stopwatch_duration_usecs(&sw));
551 
552 	return VB2_SUCCESS;
553 }
554