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