1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * High-level firmware wrapper API - entry points for kernel selection
6 */
7
8#include "sysincludes.h"
9
10#include "gbb_access.h"
11#include "gbb_header.h"
12#include "load_kernel_fw.h"
13#include "region.h"
14#include "rollback_index.h"
15#include "utility.h"
16#include "vboot_api.h"
17#include "vboot_audio.h"
18#include "vboot_common.h"
19#include "vboot_display.h"
20#include "vboot_kernel.h"
21#include "vboot_nvstorage.h"
22
23/* Global variables */
24static VbNvContext vnc;
25
26#ifdef CHROMEOS_ENVIRONMENT
27/* Global variable accessor for unit tests */
28
29VbNvContext *VbApiKernelGetVnc(void)
30{
31	return &vnc;
32}
33#endif
34
35/**
36 * Set recovery request (called from vboot_api_kernel.c functions only)
37 */
38static void VbSetRecoveryRequest(uint32_t recovery_request)
39{
40	VBDEBUG(("VbSetRecoveryRequest(%d)\n", (int)recovery_request));
41	VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request);
42}
43
44/**
45 * Checks GBB flags against VbExIsShutdownRequested() shutdown request to
46 * determine if a shutdown is required.
47 *
48 * Returns true if a shutdown is required and false if no shutdown is required.
49 */
50static int VbWantShutdown(uint32_t gbb_flags)
51{
52	uint32_t shutdown_request = VbExIsShutdownRequested();
53
54	/* If desired, ignore shutdown request due to lid closure. */
55	if (gbb_flags & GBB_FLAG_DISABLE_LID_SHUTDOWN)
56		shutdown_request &= ~VB_SHUTDOWN_REQUEST_LID_CLOSED;
57
58	return !!shutdown_request;
59}
60
61/**
62 * Attempt loading a kernel from the specified type(s) of disks.
63 *
64 * If successful, sets p->disk_handle to the disk for the kernel and returns
65 * VBERROR_SUCCESS.
66 *
67 * Returns VBERROR_NO_DISK_FOUND if no disks of the specified type were found.
68 *
69 * May return other VBERROR_ codes for other failures.
70 */
71uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
72                         uint32_t get_info_flags)
73{
74	VbError_t retval = VBERROR_UNKNOWN;
75	VbDiskInfo* disk_info = NULL;
76	uint32_t disk_count = 0;
77	uint32_t i;
78
79	VBDEBUG(("VbTryLoadKernel() start, get_info_flags=0x%x\n",
80		 (unsigned)get_info_flags));
81
82	p->disk_handle = NULL;
83
84	/* Find disks */
85	if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
86					       get_info_flags))
87		disk_count = 0;
88
89	VBDEBUG(("VbTryLoadKernel() found %d disks\n", (int)disk_count));
90	if (0 == disk_count) {
91		VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK);
92		return VBERROR_NO_DISK_FOUND;
93	}
94
95	/* Loop over disks */
96	for (i = 0; i < disk_count; i++) {
97		VBDEBUG(("VbTryLoadKernel() trying disk %d\n", (int)i));
98		/*
99		 * Sanity-check what we can. FWIW, VbTryLoadKernel() is always
100		 * called with only a single bit set in get_info_flags.
101		 *
102		 * Ensure 512-byte sectors and non-trivially sized disk (for
103		 * cgptlib) and that we got a partition with only the flags we
104		 * asked for.
105		 */
106		if (512 != disk_info[i].bytes_per_lba ||
107		    16 > disk_info[i].lba_count ||
108		    get_info_flags != (disk_info[i].flags & ~VB_DISK_FLAG_EXTERNAL_GPT)) {
109			VBDEBUG(("  skipping: bytes_per_lba=%" PRIu64
110				 " lba_count=%" PRIu64 " flags=0x%x\n",
111				 disk_info[i].bytes_per_lba,
112				 disk_info[i].lba_count,
113				 disk_info[i].flags));
114			continue;
115		}
116		p->disk_handle = disk_info[i].handle;
117		p->bytes_per_lba = disk_info[i].bytes_per_lba;
118		p->gpt_lba_count = disk_info[i].lba_count;
119		p->streaming_lba_count = disk_info[i].streaming_lba_count
120						?: p->gpt_lba_count;
121		p->boot_flags |= disk_info[i].flags & VB_DISK_FLAG_EXTERNAL_GPT
122				? BOOT_FLAG_EXTERNAL_GPT : 0;
123		retval = LoadKernel(p, cparams);
124		VBDEBUG(("VbTryLoadKernel() LoadKernel() = %d\n", retval));
125
126		/*
127		 * Stop now if we found a kernel.
128		 *
129		 * TODO: If recovery requested, should track the farthest we
130		 * get, instead of just returning the value from the last disk
131		 * attempted.
132		 */
133		if (VBERROR_SUCCESS == retval)
134			break;
135	}
136
137	/* If we didn't find any good kernels, don't return a disk handle. */
138	if (VBERROR_SUCCESS != retval) {
139		VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_KERNEL);
140		p->disk_handle = NULL;
141	}
142
143	VbExDiskFreeInfo(disk_info, p->disk_handle);
144
145	/*
146	 * Pass through return code.  Recovery reason (if any) has already been
147	 * set by LoadKernel().
148	 */
149	return retval;
150}
151
152#define CONFIRM_KEY_DELAY 20  /* Check confirm screen keys every 20ms */
153
154int VbUserConfirms(VbCommonParams *cparams, uint32_t confirm_flags)
155{
156	VbSharedDataHeader *shared =
157           (VbSharedDataHeader *)cparams->shared_data_blob;
158	uint32_t key;
159	uint32_t key_flags;
160        uint32_t button;
161	int rec_button_was_pressed = 0;
162
163	VBDEBUG(("Entering %s(0x%x)\n", __func__, confirm_flags));
164
165	/* Await further instructions */
166	while (1) {
167		if (VbWantShutdown(cparams->gbb->flags))
168			return -1;
169		key = VbExKeyboardReadWithFlags(&key_flags);
170                button = VbExGetSwitches(VB_INIT_FLAG_REC_BUTTON_PRESSED);
171		switch (key) {
172		case '\r':
173			/* If we require a trusted keyboard for confirmation,
174			 * but the keyboard may be faked (for instance, a USB
175			 * device), beep and keep waiting.
176			 */
177			if (confirm_flags & VB_CONFIRM_MUST_TRUST_KEYBOARD &&
178			    !(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD)) {
179				VbExBeep(120, 400);
180				break;
181                        }
182
183			VBDEBUG(("%s() - Yes (1)\n", __func__));
184			return 1;
185			break;
186		case ' ':
187			VBDEBUG(("%s() - Space (%d)\n", __func__,
188				 confirm_flags & VB_CONFIRM_SPACE_MEANS_NO));
189			if (confirm_flags & VB_CONFIRM_SPACE_MEANS_NO)
190				return 0;
191			break;
192		case 0x1b:
193			VBDEBUG(("%s() - No (0)\n", __func__));
194			return 0;
195			break;
196		default:
197			/* If the recovery button is physical, and is pressed,
198			 * this is also a YES, but must wait for release.
199			 */
200			if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL)) {
201				if (button) {
202					VBDEBUG(("%s() - Rec button pressed\n",
203						 __func__));
204	                                rec_button_was_pressed = 1;
205				} else if (rec_button_was_pressed) {
206					VBDEBUG(("%s() - Rec button (1)\n",
207					 __func__));
208					return 1;
209				}
210			}
211			VbCheckDisplayKey(cparams, key, &vnc);
212		}
213		VbExSleepMs(CONFIRM_KEY_DELAY);
214	}
215
216	/* Not reached, but compiler will complain without it */
217	return -1;
218}
219
220VbError_t VbBootNormal(VbCommonParams *cparams, LoadKernelParams *p)
221{
222	/* Boot from fixed disk only */
223	VBDEBUG(("Entering %s()\n", __func__));
224	return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
225}
226
227VbError_t VbBootDeveloper(VbCommonParams *cparams, LoadKernelParams *p)
228{
229	GoogleBinaryBlockHeader *gbb = cparams->gbb;
230	VbSharedDataHeader *shared =
231		(VbSharedDataHeader *)cparams->shared_data_blob;
232	uint32_t allow_usb = 0, allow_legacy = 0, ctrl_d_pressed = 0;
233	VbAudioContext *audio = 0;
234
235	VBDEBUG(("Entering %s()\n", __func__));
236
237	/* Check if USB booting is allowed */
238	VbNvGet(&vnc, VBNV_DEV_BOOT_USB, &allow_usb);
239	VbNvGet(&vnc, VBNV_DEV_BOOT_LEGACY, &allow_legacy);
240
241	/* Handle GBB flag override */
242	if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
243		allow_usb = 1;
244	if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
245		allow_legacy = 1;
246
247	/* Show the dev mode warning screen */
248	VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
249
250	/* Get audio/delay context */
251	audio = VbAudioOpen(cparams);
252
253	/* We'll loop until we finish the delay or are interrupted */
254	do {
255		uint32_t key;
256
257		if (VbWantShutdown(gbb->flags)) {
258			VBDEBUG(("VbBootDeveloper() - shutdown requested!\n"));
259			VbAudioClose(audio);
260			return VBERROR_SHUTDOWN_REQUESTED;
261		}
262
263		key = VbExKeyboardRead();
264		switch (key) {
265		case 0:
266			/* nothing pressed */
267			break;
268		case '\r':
269			/* Only disable virtual dev switch if allowed by GBB */
270			if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
271				break;
272		case ' ':
273			/* See if we should disable virtual dev-mode switch. */
274			VBDEBUG(("%s shared->flags=0x%x\n",
275				 __func__, shared->flags));
276			if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
277			    shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
278				/* Stop the countdown while we go ask... */
279				VbAudioClose(audio);
280				if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
281					/*
282					 * TONORM won't work (only for
283					 * non-shipping devices).
284					 */
285					VBDEBUG(("%s() - TONORM rejected by "
286						 "FORCE_DEV_SWITCH_ON\n",
287						 __func__));
288					VbExDisplayDebugInfo(
289						"WARNING: TONORM prohibited by "
290						"GBB FORCE_DEV_SWITCH_ON.\n\n");
291					VbExBeep(120, 400);
292					break;
293				}
294				VbDisplayScreen(cparams,
295						VB_SCREEN_DEVELOPER_TO_NORM,
296						0, &vnc);
297				/* Ignore space in VbUserConfirms()... */
298				switch (VbUserConfirms(cparams, 0)) {
299				case 1:
300					VBDEBUG(("%s() - leaving dev-mode.\n",
301						 __func__));
302					VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST,
303						1);
304					VbDisplayScreen(
305						cparams,
306						VB_SCREEN_TO_NORM_CONFIRMED,
307						0, &vnc);
308					VbExSleepMs(5000);
309					return VBERROR_TPM_REBOOT_REQUIRED;
310				case -1:
311					VBDEBUG(("%s() - shutdown requested\n",
312						 __func__));
313					return VBERROR_SHUTDOWN_REQUESTED;
314				default:
315					/* Stay in dev-mode */
316					VBDEBUG(("%s() - stay in dev-mode\n",
317						 __func__));
318					VbDisplayScreen(
319						cparams,
320						VB_SCREEN_DEVELOPER_WARNING,
321						0, &vnc);
322					/* Start new countdown */
323					audio = VbAudioOpen(cparams);
324				}
325			} else {
326				/*
327				 * No virtual dev-mode switch, so go directly
328				 * to recovery mode.
329				 */
330				VBDEBUG(("%s() - going to recovery\n",
331					 __func__));
332				VbSetRecoveryRequest(
333					VBNV_RECOVERY_RW_DEV_SCREEN);
334				VbAudioClose(audio);
335				return VBERROR_LOAD_KERNEL_RECOVERY;
336			}
337			break;
338		case 0x04:
339			/* Ctrl+D = dismiss warning; advance to timeout */
340			VBDEBUG(("VbBootDeveloper() - "
341				 "user pressed Ctrl+D; skip delay\n"));
342			ctrl_d_pressed = 1;
343			goto fallout;
344			break;
345		case 0x0c:
346			VBDEBUG(("VbBootDeveloper() - "
347				 "user pressed Ctrl+L; Try legacy boot\n"));
348			/*
349			 * If VbExLegacy() succeeds, it will never return.  If
350			 * it returns, beep.
351			 */
352			if (allow_legacy)
353				VbExLegacy();
354			else
355				VBDEBUG(("VbBootDeveloper() - "
356					 "Legacy boot is disabled\n"));
357
358			VbExBeep(120, 400);
359			VbExSleepMs(120);
360			VbExBeep(120, 400);
361			break;
362
363		case VB_KEY_CTRL_ENTER:
364			/*
365			 * The Ctrl-Enter is special for Lumpy test purpose;
366			 * fall through to Ctrl+U handler.
367			 */
368		case 0x15:
369			/* Ctrl+U = try USB boot, or beep if failure */
370			VBDEBUG(("VbBootDeveloper() - "
371				 "user pressed Ctrl+U; try USB\n"));
372			if (!allow_usb) {
373				VBDEBUG(("VbBootDeveloper() - "
374					 "USB booting is disabled\n"));
375				VbExDisplayDebugInfo(
376					"WARNING: Booting from external media "
377					"(USB/SD) has not been enabled. Refer "
378					"to the developer-mode documentation "
379					"for details.\n");
380				VbExBeep(120, 400);
381				VbExSleepMs(120);
382				VbExBeep(120, 400);
383			} else {
384				/*
385				 * Clear the screen to show we get the Ctrl+U
386				 * key press.
387				 */
388				VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0,
389						&vnc);
390				if (VBERROR_SUCCESS ==
391				    VbTryLoadKernel(cparams, p,
392						    VB_DISK_FLAG_REMOVABLE)) {
393					VBDEBUG(("VbBootDeveloper() - "
394						 "booting USB\n"));
395					VbAudioClose(audio);
396					return VBERROR_SUCCESS;
397				} else {
398					VBDEBUG(("VbBootDeveloper() - "
399						 "no kernel found on USB\n"));
400					VbExBeep(250, 200);
401					VbExSleepMs(120);
402					/*
403					 * Clear recovery requests from failed
404					 * kernel loading, so that powering off
405					 * at this point doesn't put us into
406					 * recovery mode.
407					 */
408					VbSetRecoveryRequest(
409						VBNV_RECOVERY_NOT_REQUESTED);
410					/* Show dev mode warning screen again */
411					VbDisplayScreen(
412						cparams,
413						VB_SCREEN_DEVELOPER_WARNING,
414						0, &vnc);
415				}
416			}
417			break;
418		default:
419			VBDEBUG(("VbBootDeveloper() - pressed key %d\n", key));
420			VbCheckDisplayKey(cparams, key, &vnc);
421			break;
422		}
423	} while(VbAudioLooping(audio));
424
425 fallout:
426
427	/* If defaulting to legacy boot, try that unless Ctrl+D was pressed */
428	if ((gbb->flags & GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY) &&
429	    !ctrl_d_pressed) {
430		VBDEBUG(("VbBootDeveloper() - defaulting to legacy\n"));
431		VbExLegacy();
432
433		/* If that fails, beep and fall through to fixed disk */
434		VbExBeep(120, 400);
435		VbExSleepMs(120);
436		VbExBeep(120, 400);
437	}
438
439	/* Timeout or Ctrl+D; attempt loading from fixed disk */
440	VBDEBUG(("VbBootDeveloper() - trying fixed disk\n"));
441	VbAudioClose(audio);
442	return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
443}
444
445/* Delay in recovery mode */
446#define REC_DISK_DELAY       1000     /* Check disks every 1s */
447#define REC_KEY_DELAY        20       /* Check keys every 20ms */
448#define REC_MEDIA_INIT_DELAY 500      /* Check removable media every 500ms */
449
450VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p)
451{
452	VbSharedDataHeader *shared =
453		(VbSharedDataHeader *)cparams->shared_data_blob;
454	uint32_t retval;
455	uint32_t key;
456	int i;
457
458	VBDEBUG(("VbBootRecovery() start\n"));
459
460	/*
461	 * If the dev-mode switch is off and the user didn't press the recovery
462	 * button, require removal of all external media.
463	 */
464	if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
465	    !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
466		VbDiskInfo *disk_info = NULL;
467		uint32_t disk_count = 0;
468
469		VBDEBUG(("VbBootRecovery() forcing device removal\n"));
470
471		/* If no media is detected initially, delay and make one extra
472		 * attempt, in case devices appear later than expected. */
473		if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
474						       VB_DISK_FLAG_REMOVABLE))
475			disk_count = 0;
476
477		VbExDiskFreeInfo(disk_info, NULL);
478		if (0 == disk_count)
479			VbExSleepMs(REC_MEDIA_INIT_DELAY);
480
481		while (1) {
482			disk_info = NULL;
483			disk_count = 0;
484			if (VBERROR_SUCCESS !=
485			    VbExDiskGetInfo(&disk_info, &disk_count,
486					    VB_DISK_FLAG_REMOVABLE))
487				disk_count = 0;
488
489			VbExDiskFreeInfo(disk_info, NULL);
490
491			if (0 == disk_count) {
492				VbDisplayScreen(cparams, VB_SCREEN_BLANK,
493						0, &vnc);
494				break;
495			}
496
497			VBDEBUG(("VbBootRecovery() "
498				 "waiting for %d disks to be removed\n",
499				 (int)disk_count));
500
501			VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_REMOVE,
502					0, &vnc);
503
504			/*
505			 * Scan keyboard more frequently than media, since x86
506			 * platforms don't like to scan USB too rapidly.
507			 */
508			for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
509				VbCheckDisplayKey(cparams, VbExKeyboardRead(),
510						  &vnc);
511				if (VbWantShutdown(cparams->gbb->flags))
512					return VBERROR_SHUTDOWN_REQUESTED;
513				VbExSleepMs(REC_KEY_DELAY);
514			}
515		}
516	}
517
518	/* Loop and wait for a recovery image */
519	while (1) {
520		VBDEBUG(("VbBootRecovery() attempting to load kernel2\n"));
521		retval = VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE);
522
523		/*
524		 * Clear recovery requests from failed kernel loading, since
525		 * we're already in recovery mode.  Do this now, so that
526		 * powering off after inserting an invalid disk doesn't leave
527		 * us stuck in recovery mode.
528		 */
529		VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
530
531		if (VBERROR_SUCCESS == retval)
532			break; /* Found a recovery kernel */
533
534		VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ?
535				VB_SCREEN_RECOVERY_INSERT :
536				VB_SCREEN_RECOVERY_NO_GOOD,
537				0, &vnc);
538
539		/*
540		 * Scan keyboard more frequently than media, since x86
541		 * platforms don't like to scan USB too rapidly.
542		 */
543		for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
544			key = VbExKeyboardRead();
545			/*
546			 * We might want to enter dev-mode from the Insert
547			 * screen if all of the following are true:
548			 *   - user pressed Ctrl-D
549			 *   - we can honor the virtual dev switch
550			 *   - not already in dev mode
551			 *   - user forced recovery mode
552			 *   - EC isn't pwned
553			 */
554			if (key == 0x04 &&
555			    shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
556			    !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
557			    (shared->flags & VBSD_BOOT_REC_SWITCH_ON) &&
558			    VbExTrustEC(0)) {
559                                if (!(shared->flags &
560				      VBSD_BOOT_REC_SWITCH_VIRTUAL) &&
561				    VbExGetSwitches(
562					     VB_INIT_FLAG_REC_BUTTON_PRESSED)) {
563					/*
564					 * Is the recovery button stuck?  In
565					 * any case we don't like this.  Beep
566					 * and ignore.
567					 */
568					VBDEBUG(("%s() - ^D but rec switch "
569						 "is pressed\n", __func__));
570					VbExBeep(120, 400);
571					continue;
572				}
573
574				/* Ask the user to confirm entering dev-mode */
575				VbDisplayScreen(cparams,
576						VB_SCREEN_RECOVERY_TO_DEV,
577						0, &vnc);
578				/* SPACE means no... */
579				uint32_t vbc_flags =
580					VB_CONFIRM_SPACE_MEANS_NO |
581					VB_CONFIRM_MUST_TRUST_KEYBOARD;
582				switch (VbUserConfirms(cparams, vbc_flags)) {
583				case 1:
584					VBDEBUG(("%s() Enabling dev-mode...\n",
585						 __func__));
586					if (TPM_SUCCESS != SetVirtualDevMode(1))
587						return VBERROR_TPM_SET_BOOT_MODE_STATE;
588					VBDEBUG(("%s() Reboot so it will take "
589						 "effect\n", __func__));
590					return VBERROR_TPM_REBOOT_REQUIRED;
591				case -1:
592					VBDEBUG(("%s() - Shutdown requested\n",
593						 __func__));
594					return VBERROR_SHUTDOWN_REQUESTED;
595				default: /* zero, actually */
596					VBDEBUG(("%s() - Not enabling "
597						 "dev-mode\n", __func__));
598					/*
599					 * Jump out of the outer loop to
600					 * refresh the display quickly.
601					 */
602					i = 4;
603					break;
604				}
605			} else {
606				VbCheckDisplayKey(cparams, key, &vnc);
607			}
608			if (VbWantShutdown(cparams->gbb->flags))
609				return VBERROR_SHUTDOWN_REQUESTED;
610			VbExSleepMs(REC_KEY_DELAY);
611		}
612	}
613
614	return VBERROR_SUCCESS;
615}
616
617/**
618 * Wrapper around VbExEcProtectRW() which sets recovery reason on error.
619 */
620static VbError_t EcProtectRW(int devidx)
621{
622	int rv = VbExEcProtectRW(devidx);
623
624	if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
625		VBDEBUG(("VbExEcProtectRW() needs reboot\n"));
626	} else if (rv != VBERROR_SUCCESS) {
627		VBDEBUG(("VbExEcProtectRW() returned %d\n", rv));
628		VbSetRecoveryRequest(VBNV_RECOVERY_EC_PROTECT);
629	}
630	return rv;
631}
632
633VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams)
634{
635	VbSharedDataHeader *shared =
636		(VbSharedDataHeader *)cparams->shared_data_blob;
637	int in_rw = 0;
638	int rv;
639	const uint8_t *ec_hash = NULL;
640	int ec_hash_size;
641	const uint8_t *rw_hash = NULL;
642	int rw_hash_size;
643	const uint8_t *expected = NULL;
644	int expected_size;
645	uint8_t expected_hash[SHA256_DIGEST_SIZE];
646	int need_update = 0;
647	int i;
648
649	VBDEBUG(("VbEcSoftwareSync(devidx=%d)\n", devidx));
650
651	/* Determine whether the EC is in RO or RW */
652	rv = VbExEcRunningRW(devidx, &in_rw);
653
654	if (shared->recovery_reason) {
655		/* Recovery mode; just verify the EC is in RO code */
656		if (rv == VBERROR_SUCCESS && in_rw == 1) {
657			/*
658			 * EC is definitely in RW firmware.  We want it in
659			 * read-only code, so preserve the current recovery
660			 * reason and reboot.
661			 *
662			 * We don't reboot on error or unknown EC code, because
663			 * we could end up in an endless reboot loop.  If we
664			 * had some way to track that we'd already rebooted for
665			 * this reason, we could retry only once.
666			 */
667			VBDEBUG(("VbEcSoftwareSync() - "
668				 "want recovery but got EC-RW\n"));
669			VbSetRecoveryRequest(shared->recovery_reason);
670			return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
671		}
672
673		VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
674		return VBERROR_SUCCESS;
675	}
676
677	/*
678	 * Not in recovery.  If we couldn't determine where the EC was,
679	 * reboot to recovery.
680	 */
681	if (rv != VBERROR_SUCCESS) {
682		VBDEBUG(("VbEcSoftwareSync() - "
683			 "VbExEcRunningRW() returned %d\n", rv));
684		VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
685		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
686	}
687
688	/* If AP is read-only normal, EC should be in its RO code also. */
689	if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
690		/* If EC is in RW code, request reboot back to RO */
691		if (in_rw == 1) {
692			VBDEBUG(("VbEcSoftwareSync() - "
693				 "want RO-normal but got EC-RW\n"));
694			return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
695		}
696
697		/* Protect the RW flash and stay in EC-RO */
698		rv = EcProtectRW(devidx);
699		if (rv != VBERROR_SUCCESS)
700			return rv;
701
702		rv = VbExEcDisableJump(devidx);
703		if (rv != VBERROR_SUCCESS) {
704			VBDEBUG(("VbEcSoftwareSync() - "
705				 "VbExEcDisableJump() returned %d\n", rv));
706			VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
707			return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
708		}
709
710		VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
711		return VBERROR_SUCCESS;
712	}
713
714	/* Get hash of EC-RW */
715	rv = VbExEcHashRW(devidx, &ec_hash, &ec_hash_size);
716	if (rv) {
717		VBDEBUG(("VbEcSoftwareSync() - "
718			 "VbExEcHashRW() returned %d\n", rv));
719		VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
720		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
721	}
722	if (ec_hash_size != SHA256_DIGEST_SIZE) {
723		VBDEBUG(("VbEcSoftwareSync() - "
724			 "VbExEcHashRW() says size %d, not %d\n",
725			 ec_hash_size, SHA256_DIGEST_SIZE));
726		VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
727		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
728	}
729
730	VBDEBUG(("EC hash:"));
731	for (i = 0; i < SHA256_DIGEST_SIZE; i++)
732		VBDEBUG(("%02x", ec_hash[i]));
733	VBDEBUG(("\n"));
734
735	/*
736	 * Get expected EC-RW hash. Note that we've already checked for
737	 * RO_NORMAL, so we know that the BIOS must be RW-A or RW-B, and
738	 * therefore the EC must match.
739	 */
740	rv = VbExEcGetExpectedRWHash(devidx, shared->firmware_index ?
741				 VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
742				 &rw_hash, &rw_hash_size);
743
744	if (rv == VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE) {
745		/*
746		 * BIOS has verified EC image but doesn't have a precomputed
747		 * hash for it, so we must compute the hash ourselves.
748		 */
749		rw_hash = NULL;
750	} else if (rv) {
751		VBDEBUG(("VbEcSoftwareSync() - "
752			 "VbExEcGetExpectedRWHash() returned %d\n", rv));
753		VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
754		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
755	} else if (rw_hash_size != SHA256_DIGEST_SIZE) {
756		VBDEBUG(("VbEcSoftwareSync() - "
757			 "VbExEcGetExpectedRWHash() says size %d, not %d\n",
758			 rw_hash_size, SHA256_DIGEST_SIZE));
759		VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
760		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
761	} else {
762		VBDEBUG(("Expected hash:"));
763		for (i = 0; i < SHA256_DIGEST_SIZE; i++)
764			VBDEBUG(("%02x", rw_hash[i]));
765		VBDEBUG(("\n"));
766
767		need_update = SafeMemcmp(ec_hash, rw_hash, SHA256_DIGEST_SIZE);
768	}
769
770	/*
771	 * Get expected EC-RW image if we're sure we need to update (because the
772	 * expected hash didn't match the EC) or we still don't know (because
773	 * there was no expected hash and we need the image to compute one
774	 * ourselves).
775	 */
776	if (need_update || !rw_hash) {
777		/* Get expected EC-RW image */
778		rv = VbExEcGetExpectedRW(devidx, shared->firmware_index ?
779					 VB_SELECT_FIRMWARE_B :
780					 VB_SELECT_FIRMWARE_A,
781					 &expected, &expected_size);
782		if (rv) {
783			VBDEBUG(("VbEcSoftwareSync() - "
784				 "VbExEcGetExpectedRW() returned %d\n", rv));
785			VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
786			return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
787		}
788		VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n",
789			 expected_size));
790
791		/* Hash expected image */
792		internal_SHA256(expected, expected_size, expected_hash);
793		VBDEBUG(("Computed hash of expected image:"));
794		for (i = 0; i < SHA256_DIGEST_SIZE; i++)
795			VBDEBUG(("%02x", expected_hash[i]));
796		VBDEBUG(("\n"));
797	}
798
799	if (!rw_hash) {
800		/*
801		 * BIOS didn't have expected EC hash, so check if we need
802		 * update by comparing EC hash to the one we just computed.
803		 */
804		need_update = SafeMemcmp(ec_hash, expected_hash,
805					 SHA256_DIGEST_SIZE);
806	} else if (need_update &&
807		   SafeMemcmp(rw_hash, expected_hash, SHA256_DIGEST_SIZE)) {
808		/*
809		 * We need to update, but the expected EC image doesn't match
810		 * the expected EC hash we were given.
811		 */
812		VBDEBUG(("VbEcSoftwareSync() - "
813			 "VbExEcGetExpectedRW() returned %d\n", rv));
814		VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_MISMATCH);
815		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
816	}
817
818	/*
819	 * TODO: GBB flag to override whether we need update; needed for EC
820	 * development.
821	 */
822
823	if (in_rw) {
824		if (need_update) {
825			/*
826			 * Check if BIOS should also load VGA Option ROM when
827			 * rebooting to save another reboot if possible.
828			 */
829			if ((shared->flags & VBSD_EC_SLOW_UPDATE) &&
830			    (shared->flags & VBSD_OPROM_MATTERS) &&
831			    !(shared->flags & VBSD_OPROM_LOADED)) {
832				VBDEBUG(("VbEcSoftwareSync() - Reboot to "
833					 "load VGA Option ROM\n"));
834				VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
835			}
836
837			/*
838			 * EC is running the wrong RW image.  Reboot the EC to
839			 * RO so we can update it on the next boot.
840			 */
841			VBDEBUG(("VbEcSoftwareSync() - "
842				 "in RW, need to update RW, so reboot\n"));
843			return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
844		}
845
846		VBDEBUG(("VbEcSoftwareSync() in EC-RW and it matches\n"));
847		return VBERROR_SUCCESS;
848	}
849
850	/* Update EC if necessary */
851	if (need_update) {
852		VBDEBUG(("VbEcSoftwareSync() updating EC-RW...\n"));
853
854		if (shared->flags & VBSD_EC_SLOW_UPDATE) {
855			VBDEBUG(("VbEcSoftwareSync() - "
856				 "EC is slow. Show WAIT screen.\n"));
857
858			/* Ensure the VGA Option ROM is loaded */
859			if ((shared->flags & VBSD_OPROM_MATTERS) &&
860			    !(shared->flags & VBSD_OPROM_LOADED)) {
861				VBDEBUG(("VbEcSoftwareSync() - Reboot to "
862					 "load VGA Option ROM\n"));
863				VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
864				return VBERROR_VGA_OPROM_MISMATCH;
865			}
866
867			VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
868		}
869
870		rv = VbExEcUpdateRW(devidx, expected, expected_size);
871
872		if (rv != VBERROR_SUCCESS) {
873			VBDEBUG(("VbEcSoftwareSync() - "
874				 "VbExEcUpdateRW() returned %d\n", rv));
875
876			/*
877			 * The EC may know it needs a reboot.  It may need to
878			 * unprotect RW before updating, or may need to reboot
879			 * after RW updated.  Either way, it's not an error
880			 * requiring recovery mode.
881			 *
882			 * If we fail for any other reason, trigger recovery
883			 * mode.
884			 */
885			if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
886				VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
887
888			return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
889		}
890
891		/*
892		 * TODO: should ask EC to recompute its hash to verify it's
893		 * correct before continuing?
894		 */
895	}
896
897	/* Protect EC-RW flash */
898	rv = EcProtectRW(devidx);
899	if (rv != VBERROR_SUCCESS)
900		return rv;
901
902	/* Tell EC to jump to its RW image */
903	VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
904	rv = VbExEcJumpToRW(devidx);
905	if (rv != VBERROR_SUCCESS) {
906		VBDEBUG(("VbEcSoftwareSync() - "
907			 "VbExEcJumpToRW() returned %d\n", rv));
908
909		/*
910		 * If the EC booted RO-normal and a previous AP boot has called
911		 * VbExEcStayInRO(), we need to reboot the EC to unlock the
912		 * ability to jump to the RW firmware.
913		 *
914		 * All other errors trigger recovery mode.
915		 */
916		if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
917			VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
918
919		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
920	}
921
922	VBDEBUG(("VbEcSoftwareSync() jumped to EC-RW\n"));
923
924	rv = VbExEcDisableJump(devidx);
925	if (rv != VBERROR_SUCCESS) {
926		VBDEBUG(("VbEcSoftwareSync() - "
927			"VbExEcDisableJump() returned %d\n", rv));
928		VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
929		return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
930	}
931
932	/*
933	 * Reboot to unload VGA Option ROM if:
934	 * - RW update was done
935	 * - the system is NOT in developer mode
936	 * - the system has slow EC update flag set
937	 * - the VGA Option ROM was needed and loaded
938	 */
939	if (need_update &&
940	    !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
941	    (shared->flags & VBSD_EC_SLOW_UPDATE) &&
942	    (shared->flags & VBSD_OPROM_MATTERS) &&
943	    (shared->flags & VBSD_OPROM_LOADED)) {
944		VBDEBUG(("VbEcSoftwareSync() - Reboot to "
945			 "unload VGA Option ROM\n"));
946		return VBERROR_VGA_OPROM_MISMATCH;
947	}
948
949	VBDEBUG(("VbEcSoftwareSync() in RW; done\n"));
950	return VBERROR_SUCCESS;
951}
952
953/* This function is also used by tests */
954void VbApiKernelFree(VbCommonParams *cparams)
955{
956	/* VbSelectAndLoadKernel() always allocates this, tests don't */
957	if (cparams->gbb) {
958		VbExFree(cparams->gbb);
959		cparams->gbb = NULL;
960	}
961	if (cparams->bmp) {
962		VbExFree(cparams->bmp);
963		cparams->bmp = NULL;
964	}
965}
966
967VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
968                                VbSelectAndLoadKernelParams *kparams)
969{
970	VbSharedDataHeader *shared =
971		(VbSharedDataHeader *)cparams->shared_data_blob;
972	VbError_t retval = VBERROR_SUCCESS;
973	LoadKernelParams p;
974	uint32_t tpm_status = 0;
975
976	/* Start timer */
977	shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
978
979	VbExNvStorageRead(vnc.raw);
980	VbNvSetup(&vnc);
981
982	/* Clear output params in case we fail */
983	kparams->disk_handle = NULL;
984	kparams->partition_number = 0;
985	kparams->bootloader_address = 0;
986	kparams->bootloader_size = 0;
987	kparams->flags = 0;
988	Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
989
990	cparams->bmp = NULL;
991	cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
992	retval = VbGbbReadHeader_static(cparams, cparams->gbb);
993	if (VBERROR_SUCCESS != retval)
994		goto VbSelectAndLoadKernel_exit;
995
996	/* Do EC software sync if necessary */
997	if ((shared->flags & VBSD_EC_SOFTWARE_SYNC) &&
998	    !(cparams->gbb->flags & GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)) {
999		int oprom_mismatch = 0;
1000
1001		retval = VbEcSoftwareSync(0, cparams);
1002		/* Save reboot requested until after possible PD sync */
1003		if (retval == VBERROR_VGA_OPROM_MISMATCH)
1004			oprom_mismatch = 1;
1005		else if (retval != VBERROR_SUCCESS)
1006			goto VbSelectAndLoadKernel_exit;
1007
1008#ifdef PD_SYNC
1009		if (!(cparams->gbb->flags &
1010		      GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) {
1011			retval = VbEcSoftwareSync(1, cparams);
1012			if (retval == VBERROR_VGA_OPROM_MISMATCH)
1013				oprom_mismatch = 1;
1014			else if (retval != VBERROR_SUCCESS)
1015				goto VbSelectAndLoadKernel_exit;
1016		}
1017#endif
1018
1019		/* Request reboot to unload VGA Option ROM */
1020		if (oprom_mismatch) {
1021			retval = VBERROR_VGA_OPROM_MISMATCH;
1022			goto VbSelectAndLoadKernel_exit;
1023		}
1024	}
1025
1026	/* Read kernel version from the TPM.  Ignore errors in recovery mode. */
1027	tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
1028	if (0 != tpm_status) {
1029		VBDEBUG(("Unable to get kernel versions from TPM\n"));
1030		if (!shared->recovery_reason) {
1031			VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_R_ERROR);
1032			retval = VBERROR_TPM_READ_KERNEL;
1033			goto VbSelectAndLoadKernel_exit;
1034		}
1035	}
1036	shared->kernel_version_tpm_start = shared->kernel_version_tpm;
1037
1038	/* Fill in params for calls to LoadKernel() */
1039	Memset(&p, 0, sizeof(p));
1040	p.shared_data_blob = cparams->shared_data_blob;
1041	p.shared_data_size = cparams->shared_data_size;
1042	p.gbb_data = cparams->gbb_data;
1043	p.gbb_size = cparams->gbb_size;
1044
1045	/*
1046	 * This could be set to NULL, in which case the vboot header
1047	 * information about the load address and size will be used.
1048	 */
1049	p.kernel_buffer = kparams->kernel_buffer;
1050	p.kernel_buffer_size = kparams->kernel_buffer_size;
1051
1052	p.nv_context = &vnc;
1053	p.boot_flags = 0;
1054	if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON)
1055		p.boot_flags |= BOOT_FLAG_DEVELOPER;
1056
1057	/* Handle separate normal and developer firmware builds. */
1058#if defined(VBOOT_FIRMWARE_TYPE_NORMAL)
1059	/* Normal-type firmware always acts like the dev switch is off. */
1060	p.boot_flags &= ~BOOT_FLAG_DEVELOPER;
1061#elif defined(VBOOT_FIRMWARE_TYPE_DEVELOPER)
1062	/* Developer-type firmware fails if the dev switch is off. */
1063	if (!(p.boot_flags & BOOT_FLAG_DEVELOPER)) {
1064		/*
1065		 * Dev firmware should be signed with a key that only verifies
1066		 * when the dev switch is on, so we should never get here.
1067		 */
1068		VBDEBUG(("Developer firmware called with dev switch off!\n"));
1069		VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH);
1070		retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH;
1071		goto VbSelectAndLoadKernel_exit;
1072	}
1073#else
1074	/*
1075	 * Recovery firmware, or merged normal+developer firmware.  No need to
1076	 * override flags.
1077	 */
1078#endif
1079
1080	/* Select boot path */
1081	if (shared->recovery_reason) {
1082		/* Recovery boot */
1083		p.boot_flags |= BOOT_FLAG_RECOVERY;
1084		retval = VbBootRecovery(cparams, &p);
1085		VbExEcEnteringMode(0, VB_EC_RECOVERY);
1086		VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
1087
1088	} else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
1089		/* Developer boot */
1090		retval = VbBootDeveloper(cparams, &p);
1091		VbExEcEnteringMode(0, VB_EC_DEVELOPER);
1092		VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
1093
1094	} else {
1095		/* Normal boot */
1096		VbExEcEnteringMode(0, VB_EC_NORMAL);
1097		retval = VbBootNormal(cparams, &p);
1098
1099		if ((1 == shared->firmware_index) &&
1100		    (shared->flags & VBSD_FWB_TRIED)) {
1101			/*
1102			 * Special cases for when we're trying a new firmware
1103			 * B.  These are needed because firmware updates also
1104			 * usually change the kernel key, which means that the
1105			 * B firmware can only boot a new kernel, and the old
1106			 * firmware in A can only boot the previous kernel.
1107			 *
1108			 * Don't advance the TPM if we're trying a new firmware
1109			 * B, because we don't yet know if the new kernel will
1110			 * successfully boot.  We still want to be able to fall
1111			 * back to the previous firmware+kernel if the new
1112			 * firmware+kernel fails.
1113			 *
1114			 * If we found only invalid kernels, reboot and try
1115			 * again.  This allows us to fall back to the previous
1116			 * firmware+kernel instead of giving up and going to
1117			 * recovery mode right away.  We'll still go to
1118			 * recovery mode if we run out of tries and the old
1119			 * firmware can't find a kernel it likes.
1120			 */
1121			if (VBERROR_INVALID_KERNEL_FOUND == retval) {
1122				VBDEBUG(("Trying firmware B, "
1123					 "and only found invalid kernels.\n"));
1124				VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
1125				goto VbSelectAndLoadKernel_exit;
1126			}
1127		} else {
1128			/* Not trying a new firmware B. */
1129
1130			/* See if we need to update the TPM. */
1131			VBDEBUG(("Checking if TPM kernel version needs "
1132				 "advancing\n"));
1133			if (shared->kernel_version_tpm >
1134			    shared->kernel_version_tpm_start) {
1135				tpm_status = RollbackKernelWrite(
1136						shared->kernel_version_tpm);
1137				if (0 != tpm_status) {
1138					VBDEBUG(("Error writing kernel "
1139						 "versions to TPM.\n"));
1140					VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_W_ERROR);
1141					retval = VBERROR_TPM_WRITE_KERNEL;
1142					goto VbSelectAndLoadKernel_exit;
1143				}
1144			}
1145		}
1146	}
1147
1148	if (VBERROR_SUCCESS != retval)
1149		goto VbSelectAndLoadKernel_exit;
1150
1151	/* Save disk parameters */
1152	kparams->disk_handle = p.disk_handle;
1153	kparams->partition_number = (uint32_t)p.partition_number;
1154	kparams->bootloader_address = p.bootloader_address;
1155	kparams->bootloader_size = (uint32_t)p.bootloader_size;
1156	kparams->flags = p.flags;
1157	Memcpy(kparams->partition_guid, p.partition_guid,
1158	       sizeof(kparams->partition_guid));
1159
1160	/* Lock the kernel versions.  Ignore errors in recovery mode. */
1161	tpm_status = RollbackKernelLock(shared->recovery_reason);
1162	if (0 != tpm_status) {
1163		VBDEBUG(("Error locking kernel versions.\n"));
1164		if (!shared->recovery_reason) {
1165			VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_L_ERROR);
1166			retval = VBERROR_TPM_LOCK_KERNEL;
1167			goto VbSelectAndLoadKernel_exit;
1168		}
1169	}
1170
1171 VbSelectAndLoadKernel_exit:
1172
1173	VbApiKernelFree(cparams);
1174
1175	VbNvTeardown(&vnc);
1176	if (vnc.raw_changed)
1177		VbExNvStorageWrite(vnc.raw);
1178
1179	/* Stop timer */
1180	shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
1181
1182	kparams->kernel_buffer = p.kernel_buffer;
1183	kparams->kernel_buffer_size = p.kernel_buffer_size;
1184
1185	VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
1186
1187	/* Pass through return value from boot path */
1188	return retval;
1189}
1190