xref: /aosp_15_r20/external/vboot_reference/firmware/2lib/2ec_sync.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2013 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * EC software sync routines for vboot
6  */
7 
8 #include "2api.h"
9 #include "2common.h"
10 #include "2misc.h"
11 #include "2nvstorage.h"
12 #include "2secdata.h"
13 #include "2sysincludes.h"
14 
15 #define SYNC_FLAG(select)					\
16 	((select) == VB_SELECT_FIRMWARE_READONLY ?		\
17 	 VB2_SD_FLAG_ECSYNC_EC_RO : VB2_SD_FLAG_ECSYNC_EC_RW)
18 
19 /**
20  * Print a hash to debug output
21  *
22  * @param hash		Pointer to the hash
23  * @param hash_size	Size of the hash in bytes
24  * @param desc		Description of what's being hashed
25  */
print_hash(const uint8_t * hash,uint32_t hash_size)26 static void print_hash(const uint8_t *hash, uint32_t hash_size)
27 {
28 	int i;
29 	for (i = 0; i < hash_size; i++)
30 		VB2_DEBUG_RAW("%02x", hash[i]);
31 	VB2_DEBUG_RAW("\n");
32 }
33 
image_name_to_string(enum vb2_firmware_selection select)34 static const char *image_name_to_string(enum vb2_firmware_selection select)
35 {
36 	switch (select) {
37 	case VB_SELECT_FIRMWARE_READONLY:
38 		return "RO";
39 	case VB_SELECT_FIRMWARE_EC_ACTIVE:
40 		return "RW(active)";
41 	case VB_SELECT_FIRMWARE_EC_UPDATE:
42 		return "RW(update)";
43 	default:
44 		return "UNKNOWN";
45 	}
46 }
47 
48 /**
49  * Check if the hash of the EC code matches the expected hash.
50  *
51  * @param ctx		Vboot2 context
52  * @param select	Which firmware image to check
53  * @return VB2_SUCCESS, or non-zero error code.
54  */
check_ec_hash(struct vb2_context * ctx,enum vb2_firmware_selection select)55 static vb2_error_t check_ec_hash(struct vb2_context *ctx,
56 				 enum vb2_firmware_selection select)
57 {
58 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
59 	const uint8_t *hexp = NULL;
60 	const uint8_t *hmir = NULL;
61 	const uint8_t *heff = NULL;
62 	int hexp_len, heff_len;
63 	const int hmir_len = VB2_SHA256_DIGEST_SIZE;
64 	vb2_error_t rv;
65 
66 	/*
67 	 * Get expected EC hash and length.
68 	 */
69 	VB2_TRY(vb2ex_ec_get_expected_image_hash(select, &hexp, &hexp_len),
70 		ctx, VB2_RECOVERY_EC_EXPECTED_HASH);
71 	VB2_DEBUG("Hexp %10s: ", image_name_to_string(select));
72 	print_hash(hexp, hexp_len);
73 
74 	/*
75 	 * Get mirrored EC hash. This returns NULL on old systems. On new
76 	 * systems without EFS2, Hmir will be updated but unused.
77 	 *
78 	 * If it's called from update_ec, Hmir and Hexp are already synced.
79 	 */
80 	hmir = vb2_secdata_kernel_get_ec_hash(ctx);
81 	if (hmir && select == VB_SELECT_FIRMWARE_EC_ACTIVE) {
82 		VB2_DEBUG("     %10s: ", "Hmir");
83 		print_hash(hmir, hmir_len);
84 		if (hmir_len != hexp_len) {
85 			VB2_DEBUG("Hmir size (%d) != Hexp size (%d)\n",
86 				  hmir_len, hexp_len);
87 			rv = VB2_ERROR_EC_HASH_SIZE;
88 			vb2api_fail(ctx, VB2_RECOVERY_EC_HASH_SIZE, rv);
89 			return rv;
90 		}
91 		if (vb2_safe_memcmp(hmir, hexp, hexp_len)) {
92 			VB2_DEBUG("Hmir != Hexp. Update Hmir.\n");
93 			vb2_secdata_kernel_set_ec_hash(ctx, hexp);
94 			sd->flags |= VB2_SD_FLAG_ECSYNC_HMIR_UPDATED;
95 		}
96 	}
97 
98 	/*
99 	 * Get effective EC hash and length.
100 	 */
101 	VB2_TRY(vb2ex_ec_hash_image(select, &heff, &heff_len),
102 		ctx, VB2_RECOVERY_EC_HASH_FAILED);
103 	VB2_DEBUG("Heff %10s: ", image_name_to_string(select));
104 	print_hash(heff, heff_len);
105 
106 	/* Lengths should match. */
107 	if (heff_len != hexp_len) {
108 		VB2_DEBUG("EC uses %d-byte hash but AP-RW contains %d bytes\n",
109 			  heff_len, hexp_len);
110 		rv = VB2_ERROR_EC_HASH_SIZE;
111 		vb2api_fail(ctx, VB2_RECOVERY_EC_HASH_SIZE, rv);
112 		return rv;
113 	}
114 
115 	if (vb2_safe_memcmp(heff, hexp, hexp_len)) {
116 		VB2_DEBUG("Heff != Hexp. Schedule update\n");
117 		sd->flags |= SYNC_FLAG(select);
118 	}
119 
120 	return VB2_SUCCESS;
121 }
122 
123 /**
124  * Update the specified EC and verify the update succeeded
125  *
126  * @param ctx		Vboot2 context
127  * @param select	Which firmware image to check
128  * @return VB2_SUCCESS, or non-zero error code.
129  */
update_ec(struct vb2_context * ctx,enum vb2_firmware_selection select)130 static vb2_error_t update_ec(struct vb2_context *ctx,
131 			     enum vb2_firmware_selection select)
132 {
133 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
134 
135 	VB2_DEBUG("Updating %s...\n", image_name_to_string(select));
136 	VB2_TRY(vb2ex_ec_update_image(select), ctx, VB2_RECOVERY_EC_UPDATE);
137 
138 	/* Verify the EC was updated properly */
139 	sd->flags &= ~SYNC_FLAG(select);
140 	VB2_TRY(check_ec_hash(ctx, select));
141 	if (sd->flags & SYNC_FLAG(select)) {
142 		VB2_DEBUG("Failed to update\n");
143 		vb2api_fail(ctx, VB2_RECOVERY_EC_UPDATE, 0);
144 		return VB2_REQUEST_REBOOT_EC_TO_RO;
145 	}
146 
147 	VB2_DEBUG("Updated %s successfully\n", image_name_to_string(select));
148 
149 	return VB2_SUCCESS;
150 }
151 
152 /**
153  * Set VB2_SD_FLAG_ECSYNC_EC_IN_RW flag for the EC
154  *
155  * @param ctx		Vboot2 context
156  * @return VB2_SUCCESS, or non-zero if error.
157  */
check_ec_active(struct vb2_context * ctx)158 static vb2_error_t check_ec_active(struct vb2_context *ctx)
159 {
160 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
161 	int in_rw = 0;
162 	/*
163 	 * We don't use VB2_CONTEXT_EC_TRUSTED, which checks if not EC_IN_RW.
164 	 * It is controlled by GSC but on some platforms, GSC can't know when
165 	 * a EC resets. So, we trust what EC-RW says. If it lies it's in RO,
166 	 * we'll flash RW while it's in RW.
167 	 */
168 	/* If we couldn't determine where the EC was, reboot to recovery. */
169 	VB2_TRY(vb2ex_ec_running_rw(&in_rw),
170 		ctx, VB2_RECOVERY_EC_UNKNOWN_IMAGE);
171 
172 	if (in_rw)
173 		sd->flags |= VB2_SD_FLAG_ECSYNC_EC_IN_RW;
174 
175 	return VB2_SUCCESS;
176 }
177 
178 /**
179  * Sync, jump, and protect EC device
180  *
181  * @param ctx		Vboot2 context
182  * @return VB2_SUCCESS, or non-zero if error.
183  */
sync_ec(struct vb2_context * ctx)184 static vb2_error_t sync_ec(struct vb2_context *ctx)
185 {
186 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
187 
188 	const enum vb2_firmware_selection select_rw = EC_EFS ?
189 		VB_SELECT_FIRMWARE_EC_UPDATE :
190 		VB_SELECT_FIRMWARE_EC_ACTIVE;
191 	VB2_DEBUG("select_rw=%s\n", image_name_to_string(select_rw));
192 
193 	/* Update the RW Image */
194 	if (sd->flags & SYNC_FLAG(select_rw)) {
195 		VB2_TRY(update_ec(ctx, select_rw), ctx, VB2_RECOVERY_EC_UPDATE);
196 		/* Updated successfully. Cold reboot to switch to the new RW. */
197 		if (ctx->flags & VB2_CONTEXT_NO_BOOT) {
198 			VB2_DEBUG("Rebooting to jump to new EC-RW\n");
199 			return VB2_REQUEST_REBOOT_EC_TO_RO;
200 		} else if (EC_EFS) {
201 			VB2_DEBUG("Rebooting to switch to new EC-RW\n");
202 			return VB2_REQUEST_REBOOT_EC_SWITCH_RW;
203 		}
204 	}
205 
206 	if (sd->flags & VB2_SD_FLAG_ECSYNC_HMIR_UPDATED) {
207 		/*
208 		 * After Hmir is updated, EFS needs to be retried since the
209 		 * verification result is revoked.
210 		 */
211 		VB2_DEBUG("Reset EC after Hmir update\n");
212 		return VB2_REQUEST_REBOOT_EC_TO_RO;
213 	}
214 
215 	/* We no longer trust the EC once it is already in RW or tries to jump
216 	   to RW. */
217 	ctx->flags &= ~VB2_CONTEXT_EC_TRUSTED;
218 
219 	/* Tell EC to jump to RW. It should already be in RW for EFS2. */
220 	if (!(sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW)) {
221 		VB2_DEBUG("jumping to EC-RW\n");
222 		VB2_TRY(vb2ex_ec_jump_to_rw(), ctx, VB2_RECOVERY_EC_JUMP_RW);
223 	}
224 
225 	/* Might need to update EC-RO */
226 	if (sd->flags & VB2_SD_FLAG_ECSYNC_EC_RO) {
227 		VB2_DEBUG("RO Software Sync\n");
228 
229 		/* Reset RO Software Sync NV flag */
230 		vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 0);
231 
232 		/* Update the RO Image */
233 		VB2_TRY(update_ec(ctx, VB_SELECT_FIRMWARE_READONLY),
234 			ctx, VB2_RECOVERY_EC_UPDATE);
235 	}
236 
237 	/* Protect RW flash */
238 	VB2_TRY(vb2ex_ec_protect(), ctx, VB2_RECOVERY_EC_PROTECT);
239 
240 	/* Disable further sysjumps */
241 	VB2_TRY(vb2ex_ec_disable_jump(), ctx, VB2_RECOVERY_EC_SOFTWARE_SYNC);
242 
243 	return VB2_SUCCESS;
244 }
245 
246 /**
247  * EC sync, phase 1
248  *
249  * This checks whether the EC is running the correct image to do EC sync, and
250  * whether any updates are necessary.
251  *
252  * @param ctx		Vboot2 context
253  * @return VB2_SUCCESS, VB2_REQUEST_REBOOT_EC_TO_RO if the EC must reboot back
254  * to its RO code to continue EC sync, or other non-zero error code.
255  */
ec_sync_phase1(struct vb2_context * ctx)256 static vb2_error_t ec_sync_phase1(struct vb2_context *ctx)
257 {
258 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
259 	struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
260 
261 	/* Reasons not to do sync at all */
262 	if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED))
263 		return VB2_SUCCESS;
264 	if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)
265 		return VB2_SUCCESS;
266 
267 	/* Set VB2_SD_FLAG_ECSYNC_EC_IN_RW flag */
268 	if (check_ec_active(ctx))
269 		return VB2_REQUEST_REBOOT_EC_TO_RO;
270 
271 	/* Check if we need to update RW. Failures trigger recovery mode. */
272 	if (check_ec_hash(ctx, VB_SELECT_FIRMWARE_EC_ACTIVE))
273 		return VB2_REQUEST_REBOOT_EC_TO_RO;
274 
275 	/* See if we need to update EC-RO. */
276 	if (vb2_nv_get(ctx, VB2_NV_TRY_RO_SYNC) &&
277 	    check_ec_hash(ctx, VB_SELECT_FIRMWARE_READONLY)) {
278 		return VB2_REQUEST_REBOOT_EC_TO_RO;
279 	}
280 
281 	/*
282 	 * If we're in RW, we need to reboot back to RO because RW can't be
283 	 * updated while we're running it.
284 	 *
285 	 * If EC supports RW-A/B slots, we can proceed but we need
286 	 * to jump to the new RW version later.
287 	 */
288 	if ((sd->flags & SYNC_FLAG(VB_SELECT_FIRMWARE_EC_ACTIVE)) &&
289 	    (sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW) && !EC_EFS) {
290 		if (ctx->flags & VB2_CONTEXT_EC_SYNC_SLOW) {
291 			/* Ignore the return value. */
292 			vb2api_need_reboot_for_display(ctx);
293 		}
294 		return VB2_REQUEST_REBOOT_EC_TO_RO;
295 	}
296 
297 	return VB2_SUCCESS;
298 }
299 
300 /**
301  * determine if we can update the EC
302  *
303  * @param ctx		Vboot2 context
304  * @return boolean (true iff we can update the EC)
305  */
306 
ec_sync_allowed(struct vb2_context * ctx)307 static int ec_sync_allowed(struct vb2_context *ctx)
308 {
309 	struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
310 
311 	/* Reasons not to do sync at all */
312 	if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED))
313 		return 0;
314 	if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)
315 		return 0;
316 	if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
317 		return 0;
318 	return 1;
319 }
320 
321 /**
322  * EC sync, phase 2
323  *
324  * This updates the EC if necessary, makes sure it has protected its image(s),
325  * and makes sure it has jumped to the correct image.
326  *
327  * @param ctx		Vboot2 context
328  * @return VB2_SUCCESS, VB2_REQUEST_REBOOT_EC_TO_RO if the EC must
329  * reboot back to its RO code to continue EC sync, or other non-zero error
330  * code.
331  */
ec_sync_phase2(struct vb2_context * ctx)332 static vb2_error_t ec_sync_phase2(struct vb2_context *ctx)
333 {
334 	if (!ec_sync_allowed(ctx))
335 		return VB2_SUCCESS;
336 
337 	/* Handle updates and jumps for EC */
338 	return sync_ec(ctx);
339 }
340 
341 test_mockable
vb2api_ec_sync(struct vb2_context * ctx)342 vb2_error_t vb2api_ec_sync(struct vb2_context *ctx)
343 {
344 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
345 
346 	/*
347 	 * If the status indicates that the EC has already gone through
348 	 * software sync this boot, then don't do it again.
349 	 */
350 	if (sd->status & VB2_SD_STATUS_EC_SYNC_COMPLETE) {
351 		VB2_DEBUG("EC software sync already performed this boot, skipping\n");
352 		return VB2_SUCCESS;
353 	}
354 
355 	/*
356 	 * If the device is in recovery mode, then EC sync should
357 	 * not be performed.
358 	 */
359 	if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
360 		VB2_DEBUG("In recovery mode, skipping EC sync\n");
361 		return VB2_SUCCESS;
362 	}
363 
364 	/* Phase 1; this determines if we need an update */
365 	VB2_TRY(ec_sync_phase1(ctx));
366 
367 	/* Phase 2; Applies update and/or jumps to the correct EC image */
368 	VB2_TRY(ec_sync_phase2(ctx));
369 
370 	/* Phase 3; Let the platform know that EC software sync is now done */
371 	VB2_TRY(vb2ex_ec_vboot_done(ctx));
372 
373 	/* Establish that EC software sync is complete and successful */
374 	sd->status |= VB2_SD_STATUS_EC_SYNC_COMPLETE;
375 
376 	return VB2_SUCCESS;
377 }
378