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 * determine if we can update the EC
248 *
249 * @param ctx Vboot2 context
250 * @return boolean (true iff we can update the EC)
251 */
252
ec_sync_allowed(struct vb2_context * ctx)253 static int ec_sync_allowed(struct vb2_context *ctx)
254 {
255 struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
256
257 /* Reasons not to do sync at all */
258 if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED))
259 return 0;
260 if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)
261 return 0;
262
263 return 1;
264 }
265
266 /**
267 * EC sync, phase 1
268 *
269 * This checks whether the EC is running the correct image to do EC sync, and
270 * whether any updates are necessary.
271 *
272 * @param ctx Vboot2 context
273 * @return VB2_SUCCESS, VB2_REQUEST_REBOOT_EC_TO_RO if the EC must reboot back
274 * to its RO code to continue EC sync, or other non-zero error code.
275 */
ec_sync_phase1(struct vb2_context * ctx)276 static vb2_error_t ec_sync_phase1(struct vb2_context *ctx)
277 {
278 struct vb2_shared_data *sd = vb2_get_sd(ctx);
279
280 /* Reasons not to do sync at all */
281 if (!ec_sync_allowed(ctx))
282 return VB2_SUCCESS;
283
284 /* Set VB2_SD_FLAG_ECSYNC_EC_IN_RW flag */
285 if (check_ec_active(ctx))
286 return VB2_REQUEST_REBOOT_EC_TO_RO;
287
288 /* Check if we need to update RW. Failures trigger recovery mode. */
289 if (check_ec_hash(ctx, VB_SELECT_FIRMWARE_EC_ACTIVE))
290 return VB2_REQUEST_REBOOT_EC_TO_RO;
291
292 /* See if we need to update EC-RO. */
293 if (vb2_nv_get(ctx, VB2_NV_TRY_RO_SYNC) &&
294 check_ec_hash(ctx, VB_SELECT_FIRMWARE_READONLY)) {
295 return VB2_REQUEST_REBOOT_EC_TO_RO;
296 }
297
298 /*
299 * If we're in RW, we need to reboot back to RO because RW can't be
300 * updated while we're running it.
301 *
302 * If EC supports RW-A/B slots, we can proceed but we need
303 * to jump to the new RW version later.
304 */
305 if ((sd->flags & SYNC_FLAG(VB_SELECT_FIRMWARE_EC_ACTIVE)) &&
306 (sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW) && !EC_EFS) {
307 if (ctx->flags & VB2_CONTEXT_EC_SYNC_SLOW) {
308 /* Ignore the return value. */
309 vb2api_need_reboot_for_display(ctx);
310 }
311 return VB2_REQUEST_REBOOT_EC_TO_RO;
312 }
313
314 return VB2_SUCCESS;
315 }
316
317 /**
318 * EC sync, phase 2
319 *
320 * This updates the EC if necessary, makes sure it has protected its image(s),
321 * and makes sure it has jumped to the correct image.
322 *
323 * @param ctx Vboot2 context
324 * @return VB2_SUCCESS, VB2_REQUEST_REBOOT_EC_TO_RO if the EC must
325 * reboot back to its RO code to continue EC sync, or other non-zero error
326 * code.
327 */
ec_sync_phase2(struct vb2_context * ctx)328 static vb2_error_t ec_sync_phase2(struct vb2_context *ctx)
329 {
330 if (!ec_sync_allowed(ctx))
331 return VB2_SUCCESS;
332
333 /* Handle updates and jumps for EC */
334 return sync_ec(ctx);
335 }
336
337 test_mockable
vb2api_ec_sync(struct vb2_context * ctx)338 vb2_error_t vb2api_ec_sync(struct vb2_context *ctx)
339 {
340 struct vb2_shared_data *sd = vb2_get_sd(ctx);
341
342 /*
343 * If the status indicates that the EC has already gone through
344 * software sync this boot, then don't do it again.
345 */
346 if (sd->status & VB2_SD_STATUS_EC_SYNC_COMPLETE) {
347 VB2_DEBUG("EC software sync already performed this boot, skipping\n");
348 return VB2_SUCCESS;
349 }
350
351 /*
352 * If the device is in recovery mode, then EC sync should
353 * not be performed.
354 */
355 if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
356 VB2_DEBUG("In recovery mode, skipping EC sync\n");
357 return VB2_SUCCESS;
358 }
359
360 /* Phase 1; this determines if we need an update */
361 VB2_TRY(ec_sync_phase1(ctx));
362
363 /* Phase 2; Applies update and/or jumps to the correct EC image */
364 VB2_TRY(ec_sync_phase2(ctx));
365
366 /* Phase 3; Let the platform know that EC software sync is now done */
367 VB2_TRY(vb2ex_ec_vboot_done(ctx));
368
369 /* Establish that EC software sync is complete and successful */
370 sd->status |= VB2_SD_STATUS_EC_SYNC_COMPLETE;
371
372 return VB2_SUCCESS;
373 }
374