2bf183b38771f47e73f992f48b503f310caed50a
[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 VbExEcProtectRW() which sets recovery reason on error.
643  */
644 static VbError_t EcProtectRW(int devidx)
645 {
646         int rv = VbExEcProtectRW(devidx);
647
648         if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
649                 VBDEBUG(("VbExEcProtectRW() needs reboot\n"));
650         } else if (rv != VBERROR_SUCCESS) {
651                 VBDEBUG(("VbExEcProtectRW() 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         int in_rw = 0;
662         int rv;
663         const uint8_t *ec_hash = NULL;
664         int ec_hash_size;
665         const uint8_t *rw_hash = NULL;
666         int rw_hash_size;
667         const uint8_t *expected = NULL;
668         int expected_size;
669         uint8_t expected_hash[SHA256_DIGEST_SIZE];
670         int need_update = 0;
671         int i;
672
673         VBDEBUG(("VbEcSoftwareSync(devidx=%d)\n", devidx));
674
675         /* Determine whether the EC is in RO or RW */
676         rv = VbExEcRunningRW(devidx, &in_rw);
677
678         if (shared->recovery_reason) {
679                 /* Recovery mode; just verify the EC is in RO code */
680                 if (rv == VBERROR_SUCCESS && in_rw == 1) {
681                         /*
682                          * EC is definitely in RW firmware.  We want it in
683                          * read-only code, so preserve the current recovery
684                          * reason and reboot.
685                          *
686                          * We don't reboot on error or unknown EC code, because
687                          * we could end up in an endless reboot loop.  If we
688                          * had some way to track that we'd already rebooted for
689                          * this reason, we could retry only once.
690                          */
691                         VBDEBUG(("VbEcSoftwareSync() - "
692                                  "want recovery but got EC-RW\n"));
693                         VbSetRecoveryRequest(shared->recovery_reason);
694                         return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
695                 }
696
697                 VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
698                 return VBERROR_SUCCESS;
699         }
700
701         /*
702          * Not in recovery.  If we couldn't determine where the EC was,
703          * reboot to recovery.
704          */
705         if (rv != VBERROR_SUCCESS) {
706                 VBDEBUG(("VbEcSoftwareSync() - "
707                          "VbExEcRunningRW() returned %d\n", rv));
708                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
709                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
710         }
711
712         /* If AP is read-only normal, EC should be in its RO code also. */
713         if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
714                 /* If EC is in RW code, request reboot back to RO */
715                 if (in_rw == 1) {
716                         VBDEBUG(("VbEcSoftwareSync() - "
717                                  "want RO-normal but got EC-RW\n"));
718                         return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
719                 }
720
721                 /* Protect the RW flash and stay in EC-RO */
722                 rv = EcProtectRW(devidx);
723                 if (rv != VBERROR_SUCCESS)
724                         return rv;
725
726                 rv = VbExEcDisableJump(devidx);
727                 if (rv != VBERROR_SUCCESS) {
728                         VBDEBUG(("VbEcSoftwareSync() - "
729                                  "VbExEcDisableJump() returned %d\n", rv));
730                         VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
731                         return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
732                 }
733
734                 VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
735                 return VBERROR_SUCCESS;
736         }
737
738         /* Get hash of EC-RW */
739         rv = VbExEcHashRW(devidx, &ec_hash, &ec_hash_size);
740         if (rv) {
741                 VBDEBUG(("VbEcSoftwareSync() - "
742                          "VbExEcHashRW() returned %d\n", rv));
743                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
744                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
745         }
746         if (ec_hash_size != SHA256_DIGEST_SIZE) {
747                 VBDEBUG(("VbEcSoftwareSync() - "
748                          "VbExEcHashRW() says size %d, not %d\n",
749                          ec_hash_size, SHA256_DIGEST_SIZE));
750                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
751                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
752         }
753
754         VBDEBUG(("EC hash:"));
755         for (i = 0; i < SHA256_DIGEST_SIZE; i++)
756                 VBDEBUG(("%02x", ec_hash[i]));
757         VBDEBUG(("\n"));
758
759         /*
760          * Get expected EC-RW hash. Note that we've already checked for
761          * RO_NORMAL, so we know that the BIOS must be RW-A or RW-B, and
762          * therefore the EC must match.
763          */
764         rv = VbExEcGetExpectedRWHash(devidx, shared->firmware_index ?
765                                  VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
766                                  &rw_hash, &rw_hash_size);
767
768         if (rv == VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE) {
769                 /*
770                  * BIOS has verified EC image but doesn't have a precomputed
771                  * hash for it, so we must compute the hash ourselves.
772                  */
773                 rw_hash = NULL;
774         } else if (rv) {
775                 VBDEBUG(("VbEcSoftwareSync() - "
776                          "VbExEcGetExpectedRWHash() returned %d\n", rv));
777                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
778                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
779         } else if (rw_hash_size != SHA256_DIGEST_SIZE) {
780                 VBDEBUG(("VbEcSoftwareSync() - "
781                          "VbExEcGetExpectedRWHash() says size %d, not %d\n",
782                          rw_hash_size, SHA256_DIGEST_SIZE));
783                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
784                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
785         } else {
786                 VBDEBUG(("Expected hash:"));
787                 for (i = 0; i < SHA256_DIGEST_SIZE; i++)
788                         VBDEBUG(("%02x", rw_hash[i]));
789                 VBDEBUG(("\n"));
790
791                 need_update = SafeMemcmp(ec_hash, rw_hash, SHA256_DIGEST_SIZE);
792         }
793
794         /*
795          * Get expected EC-RW image if we're sure we need to update (because the
796          * expected hash didn't match the EC) or we still don't know (because
797          * there was no expected hash and we need the image to compute one
798          * ourselves).
799          */
800         if (need_update || !rw_hash) {
801                 /* Get expected EC-RW image */
802                 rv = VbExEcGetExpectedRW(devidx, shared->firmware_index ?
803                                          VB_SELECT_FIRMWARE_B :
804                                          VB_SELECT_FIRMWARE_A,
805                                          &expected, &expected_size);
806                 if (rv) {
807                         VBDEBUG(("VbEcSoftwareSync() - "
808                                  "VbExEcGetExpectedRW() returned %d\n", rv));
809                         VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
810                         return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
811                 }
812                 VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n",
813                          expected_size));
814
815                 /* Hash expected image */
816                 internal_SHA256(expected, expected_size, expected_hash);
817                 VBDEBUG(("Computed hash of expected image:"));
818                 for (i = 0; i < SHA256_DIGEST_SIZE; i++)
819                         VBDEBUG(("%02x", expected_hash[i]));
820                 VBDEBUG(("\n"));
821         }
822
823         if (!rw_hash) {
824                 /*
825                  * BIOS didn't have expected EC hash, so check if we need
826                  * update by comparing EC hash to the one we just computed.
827                  */
828                 need_update = SafeMemcmp(ec_hash, expected_hash,
829                                          SHA256_DIGEST_SIZE);
830         } else if (need_update &&
831                    SafeMemcmp(rw_hash, expected_hash, SHA256_DIGEST_SIZE)) {
832                 /*
833                  * We need to update, but the expected EC image doesn't match
834                  * the expected EC hash we were given.
835                  */
836                 VBDEBUG(("VbEcSoftwareSync() - "
837                          "VbExEcGetExpectedRW() returned %d\n", rv));
838                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_MISMATCH);
839                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
840         }
841
842         /*
843          * TODO: GBB flag to override whether we need update; needed for EC
844          * development.
845          */
846
847         if (in_rw) {
848                 if (need_update) {
849                         /*
850                          * Check if BIOS should also load VGA Option ROM when
851                          * rebooting to save another reboot if possible.
852                          */
853                         if ((shared->flags & VBSD_EC_SLOW_UPDATE) &&
854                             (shared->flags & VBSD_OPROM_MATTERS) &&
855                             !(shared->flags & VBSD_OPROM_LOADED)) {
856                                 VBDEBUG(("VbEcSoftwareSync() - Reboot to "
857                                          "load VGA Option ROM\n"));
858                                 VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
859                         }
860
861                         /*
862                          * EC is running the wrong RW image.  Reboot the EC to
863                          * RO so we can update it on the next boot.
864                          */
865                         VBDEBUG(("VbEcSoftwareSync() - "
866                                  "in RW, need to update RW, so reboot\n"));
867                         return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
868                 }
869
870                 VBDEBUG(("VbEcSoftwareSync() in EC-RW and it matches\n"));
871                 return VBERROR_SUCCESS;
872         }
873
874         /* Update EC if necessary */
875         if (need_update) {
876                 VBDEBUG(("VbEcSoftwareSync() updating EC-RW...\n"));
877
878                 if (shared->flags & VBSD_EC_SLOW_UPDATE) {
879                         VBDEBUG(("VbEcSoftwareSync() - "
880                                  "EC is slow. Show WAIT screen.\n"));
881
882                         /* Ensure the VGA Option ROM is loaded */
883                         if ((shared->flags & VBSD_OPROM_MATTERS) &&
884                             !(shared->flags & VBSD_OPROM_LOADED)) {
885                                 VBDEBUG(("VbEcSoftwareSync() - Reboot to "
886                                          "load VGA Option ROM\n"));
887                                 VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
888                                 return VBERROR_VGA_OPROM_MISMATCH;
889                         }
890
891                         VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
892                 }
893
894                 rv = VbExEcUpdateRW(devidx, expected, expected_size);
895
896                 if (rv != VBERROR_SUCCESS) {
897                         VBDEBUG(("VbEcSoftwareSync() - "
898                                  "VbExEcUpdateRW() returned %d\n", rv));
899
900                         /*
901                          * The EC may know it needs a reboot.  It may need to
902                          * unprotect RW before updating, or may need to reboot
903                          * after RW updated.  Either way, it's not an error
904                          * requiring recovery mode.
905                          *
906                          * If we fail for any other reason, trigger recovery
907                          * mode.
908                          */
909                         if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
910                                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
911
912                         return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
913                 }
914
915                 /*
916                  * TODO: should ask EC to recompute its hash to verify it's
917                  * correct before continuing?
918                  */
919         }
920
921         /* Protect EC-RW flash */
922         rv = EcProtectRW(devidx);
923         if (rv != VBERROR_SUCCESS)
924                 return rv;
925
926         /* Tell EC to jump to its RW image */
927         VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
928         rv = VbExEcJumpToRW(devidx);
929         if (rv != VBERROR_SUCCESS) {
930                 VBDEBUG(("VbEcSoftwareSync() - "
931                          "VbExEcJumpToRW() returned %d\n", rv));
932
933                 /*
934                  * If the EC booted RO-normal and a previous AP boot has called
935                  * VbExEcStayInRO(), we need to reboot the EC to unlock the
936                  * ability to jump to the RW firmware.
937                  *
938                  * All other errors trigger recovery mode.
939                  */
940                 if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
941                         VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
942
943                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
944         }
945
946         VBDEBUG(("VbEcSoftwareSync() jumped to EC-RW\n"));
947
948         rv = VbExEcDisableJump(devidx);
949         if (rv != VBERROR_SUCCESS) {
950                 VBDEBUG(("VbEcSoftwareSync() - "
951                         "VbExEcDisableJump() returned %d\n", rv));
952                 VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
953                 return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
954         }
955
956         /*
957          * Reboot to unload VGA Option ROM if:
958          * - RW update was done
959          * - the system is NOT in developer mode
960          * - the system has slow EC update flag set
961          * - the VGA Option ROM was needed and loaded
962          */
963         if (need_update &&
964             !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
965             (shared->flags & VBSD_EC_SLOW_UPDATE) &&
966             (shared->flags & VBSD_OPROM_MATTERS) &&
967             (shared->flags & VBSD_OPROM_LOADED)) {
968                 VBDEBUG(("VbEcSoftwareSync() - Reboot to "
969                          "unload VGA Option ROM\n"));
970                 return VBERROR_VGA_OPROM_MISMATCH;
971         }
972
973         VBDEBUG(("VbEcSoftwareSync() in RW; done\n"));
974         return VBERROR_SUCCESS;
975 }
976
977 /* This function is also used by tests */
978 void VbApiKernelFree(VbCommonParams *cparams)
979 {
980         /* VbSelectAndLoadKernel() always allocates this, tests don't */
981         if (cparams->gbb) {
982                 VbExFree(cparams->gbb);
983                 cparams->gbb = NULL;
984         }
985         if (cparams->bmp) {
986                 VbExFree(cparams->bmp);
987                 cparams->bmp = NULL;
988         }
989 }
990
991 VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
992                                 VbSelectAndLoadKernelParams *kparams)
993 {
994         VbSharedDataHeader *shared =
995                 (VbSharedDataHeader *)cparams->shared_data_blob;
996         VbError_t retval = VBERROR_SUCCESS;
997         LoadKernelParams p;
998         uint32_t tpm_status = 0;
999
1000         /* Start timer */
1001         shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
1002
1003         VbExNvStorageRead(vnc.raw);
1004         VbNvSetup(&vnc);
1005
1006         /* Clear output params in case we fail */
1007         kparams->disk_handle = NULL;
1008         kparams->partition_number = 0;
1009         kparams->bootloader_address = 0;
1010         kparams->bootloader_size = 0;
1011         kparams->flags = 0;
1012         Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
1013
1014         cparams->bmp = NULL;
1015         cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
1016         retval = VbGbbReadHeader_static(cparams, cparams->gbb);
1017         if (VBERROR_SUCCESS != retval)
1018                 goto VbSelectAndLoadKernel_exit;
1019
1020         /* Do EC software sync if necessary */
1021         if ((shared->flags & VBSD_EC_SOFTWARE_SYNC) &&
1022             !(cparams->gbb->flags & GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)) {
1023                 int oprom_mismatch = 0;
1024
1025                 retval = VbEcSoftwareSync(0, cparams);
1026                 /* Save reboot requested until after possible PD sync */
1027                 if (retval == VBERROR_VGA_OPROM_MISMATCH)
1028                         oprom_mismatch = 1;
1029                 else if (retval != VBERROR_SUCCESS)
1030                         goto VbSelectAndLoadKernel_exit;
1031
1032 #ifdef PD_SYNC
1033                 if (!(cparams->gbb->flags &
1034                       GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) {
1035                         retval = VbEcSoftwareSync(1, cparams);
1036                         if (retval == VBERROR_VGA_OPROM_MISMATCH)
1037                                 oprom_mismatch = 1;
1038                         else if (retval != VBERROR_SUCCESS)
1039                                 goto VbSelectAndLoadKernel_exit;
1040                 }
1041 #endif
1042
1043                 /* Request reboot to unload VGA Option ROM */
1044                 if (oprom_mismatch) {
1045                         retval = VBERROR_VGA_OPROM_MISMATCH;
1046                         goto VbSelectAndLoadKernel_exit;
1047                 }
1048         }
1049
1050         /* EC verification (and possibily updating / jumping) is done */
1051         retval = VbExEcVbootDone(!!shared->recovery_reason);
1052         if (retval != VBERROR_SUCCESS)
1053                 goto VbSelectAndLoadKernel_exit;
1054
1055         /* Read kernel version from the TPM.  Ignore errors in recovery mode. */
1056         tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
1057         if (0 != tpm_status) {
1058                 VBDEBUG(("Unable to get kernel versions from TPM\n"));
1059                 if (!shared->recovery_reason) {
1060                         VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_R_ERROR);
1061                         retval = VBERROR_TPM_READ_KERNEL;
1062                         goto VbSelectAndLoadKernel_exit;
1063                 }
1064         }
1065         shared->kernel_version_tpm_start = shared->kernel_version_tpm;
1066
1067         /* Fill in params for calls to LoadKernel() */
1068         Memset(&p, 0, sizeof(p));
1069         p.shared_data_blob = cparams->shared_data_blob;
1070         p.shared_data_size = cparams->shared_data_size;
1071         p.gbb_data = cparams->gbb_data;
1072         p.gbb_size = cparams->gbb_size;
1073
1074         /*
1075          * This could be set to NULL, in which case the vboot header
1076          * information about the load address and size will be used.
1077          */
1078         p.kernel_buffer = kparams->kernel_buffer;
1079         p.kernel_buffer_size = kparams->kernel_buffer_size;
1080
1081         p.nv_context = &vnc;
1082         p.boot_flags = 0;
1083         if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON)
1084                 p.boot_flags |= BOOT_FLAG_DEVELOPER;
1085
1086         /* Handle separate normal and developer firmware builds. */
1087 #if defined(VBOOT_FIRMWARE_TYPE_NORMAL)
1088         /* Normal-type firmware always acts like the dev switch is off. */
1089         p.boot_flags &= ~BOOT_FLAG_DEVELOPER;
1090 #elif defined(VBOOT_FIRMWARE_TYPE_DEVELOPER)
1091         /* Developer-type firmware fails if the dev switch is off. */
1092         if (!(p.boot_flags & BOOT_FLAG_DEVELOPER)) {
1093                 /*
1094                  * Dev firmware should be signed with a key that only verifies
1095                  * when the dev switch is on, so we should never get here.
1096                  */
1097                 VBDEBUG(("Developer firmware called with dev switch off!\n"));
1098                 VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH);
1099                 retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH;
1100                 goto VbSelectAndLoadKernel_exit;
1101         }
1102 #else
1103         /*
1104          * Recovery firmware, or merged normal+developer firmware.  No need to
1105          * override flags.
1106          */
1107 #endif
1108
1109         /* Select boot path */
1110         if (shared->recovery_reason) {
1111                 /* Recovery boot */
1112                 p.boot_flags |= BOOT_FLAG_RECOVERY;
1113                 retval = VbBootRecovery(cparams, &p);
1114                 VbExEcEnteringMode(0, VB_EC_RECOVERY);
1115                 VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
1116
1117         } else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
1118                 /* Developer boot */
1119                 retval = VbBootDeveloper(cparams, &p);
1120                 VbExEcEnteringMode(0, VB_EC_DEVELOPER);
1121                 VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
1122
1123         } else {
1124                 /* Normal boot */
1125                 VbExEcEnteringMode(0, VB_EC_NORMAL);
1126                 retval = VbBootNormal(cparams, &p);
1127
1128                 if ((1 == shared->firmware_index) &&
1129                     (shared->flags & VBSD_FWB_TRIED)) {
1130                         /*
1131                          * Special cases for when we're trying a new firmware
1132                          * B.  These are needed because firmware updates also
1133                          * usually change the kernel key, which means that the
1134                          * B firmware can only boot a new kernel, and the old
1135                          * firmware in A can only boot the previous kernel.
1136                          *
1137                          * Don't advance the TPM if we're trying a new firmware
1138                          * B, because we don't yet know if the new kernel will
1139                          * successfully boot.  We still want to be able to fall
1140                          * back to the previous firmware+kernel if the new
1141                          * firmware+kernel fails.
1142                          *
1143                          * If we found only invalid kernels, reboot and try
1144                          * again.  This allows us to fall back to the previous
1145                          * firmware+kernel instead of giving up and going to
1146                          * recovery mode right away.  We'll still go to
1147                          * recovery mode if we run out of tries and the old
1148                          * firmware can't find a kernel it likes.
1149                          */
1150                         if (VBERROR_INVALID_KERNEL_FOUND == retval) {
1151                                 VBDEBUG(("Trying firmware B, "
1152                                          "and only found invalid kernels.\n"));
1153                                 VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
1154                                 goto VbSelectAndLoadKernel_exit;
1155                         }
1156                 } else {
1157                         /* Not trying a new firmware B. */
1158
1159                         /* See if we need to update the TPM. */
1160                         VBDEBUG(("Checking if TPM kernel version needs "
1161                                  "advancing\n"));
1162                         if (shared->kernel_version_tpm >
1163                             shared->kernel_version_tpm_start) {
1164                                 tpm_status = RollbackKernelWrite(
1165                                                 shared->kernel_version_tpm);
1166                                 if (0 != tpm_status) {
1167                                         VBDEBUG(("Error writing kernel "
1168                                                  "versions to TPM.\n"));
1169                                         VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_W_ERROR);
1170                                         retval = VBERROR_TPM_WRITE_KERNEL;
1171                                         goto VbSelectAndLoadKernel_exit;
1172                                 }
1173                         }
1174                 }
1175         }
1176
1177         if (VBERROR_SUCCESS != retval)
1178                 goto VbSelectAndLoadKernel_exit;
1179
1180         /* Save disk parameters */
1181         kparams->disk_handle = p.disk_handle;
1182         kparams->partition_number = (uint32_t)p.partition_number;
1183         kparams->bootloader_address = p.bootloader_address;
1184         kparams->bootloader_size = (uint32_t)p.bootloader_size;
1185         kparams->flags = p.flags;
1186         Memcpy(kparams->partition_guid, p.partition_guid,
1187                sizeof(kparams->partition_guid));
1188
1189         /* Lock the kernel versions.  Ignore errors in recovery mode. */
1190         tpm_status = RollbackKernelLock(shared->recovery_reason);
1191         if (0 != tpm_status) {
1192                 VBDEBUG(("Error locking kernel versions.\n"));
1193                 if (!shared->recovery_reason) {
1194                         VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_L_ERROR);
1195                         retval = VBERROR_TPM_LOCK_KERNEL;
1196                         goto VbSelectAndLoadKernel_exit;
1197                 }
1198         }
1199
1200  VbSelectAndLoadKernel_exit:
1201
1202         VbApiKernelFree(cparams);
1203
1204         VbNvCommit();
1205
1206         /* Stop timer */
1207         shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
1208
1209         kparams->kernel_buffer = p.kernel_buffer;
1210         kparams->kernel_buffer_size = p.kernel_buffer_size;
1211
1212         VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
1213
1214         /* Pass through return value from boot path */
1215         return retval;
1216 }
1217
1218 VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams,
1219                                   VbSelectAndLoadKernelParams *kparams,
1220                                   void *boot_image,
1221                                   size_t image_size)
1222 {
1223         VbError_t retval;
1224         VbPublicKey* kernel_subkey = NULL;
1225         uint8_t *kbuf;
1226         VbKeyBlockHeader *key_block;
1227         VbSharedDataHeader *shared =
1228                 (VbSharedDataHeader *)cparams->shared_data_blob;
1229         RSAPublicKey *data_key = NULL;
1230         VbKernelPreambleHeader *preamble;
1231         uint64_t body_offset;
1232         int hash_only = 0;
1233         int dev_switch;
1234         uint32_t allow_fastboot_full_cap = 0;
1235
1236         if ((boot_image == NULL) || (image_size == 0))
1237                 return VBERROR_INVALID_PARAMETER;
1238
1239         /* Clear output params in case we fail. */
1240         kparams->disk_handle = NULL;
1241         kparams->partition_number = 0;
1242         kparams->bootloader_address = 0;
1243         kparams->bootloader_size = 0;
1244         kparams->flags = 0;
1245         Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
1246
1247         kbuf = boot_image;
1248
1249         /* Read GBB Header */
1250         cparams->bmp = NULL;
1251         cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
1252         retval = VbGbbReadHeader_static(cparams, cparams->gbb);
1253         if (VBERROR_SUCCESS != retval) {
1254                 VBDEBUG(("Gbb read header failed.\n"));
1255                 return retval;
1256         }
1257
1258         /*
1259          * We don't care verifying the image if:
1260          * 1. dev-mode switch is on and
1261          * 2a. GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP is set, or
1262          * 2b. DEV_BOOT_FASTBOOT_FULL_CAP flag is set in NvStorage
1263          *
1264          * Check only the integrity of the image.
1265          */
1266         dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON;
1267
1268         VbExNvStorageRead(vnc.raw);
1269         VbNvSetup(&vnc);
1270         VbNvGet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP,
1271                 &allow_fastboot_full_cap);
1272
1273         if (0 == allow_fastboot_full_cap) {
1274                 allow_fastboot_full_cap = !!(cparams->gbb->flags &
1275                                 GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP);
1276         }
1277
1278         if (dev_switch && allow_fastboot_full_cap) {
1279                 VBDEBUG(("Only performing integrity-check.\n"));
1280                 hash_only = 1;
1281         } else {
1282                 /* Get recovery key. */
1283                 retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey);
1284                 if (VBERROR_SUCCESS != retval) {
1285                         VBDEBUG(("Gbb Read Recovery key failed.\n"));
1286                         return retval;
1287                 }
1288         }
1289
1290         /* If we fail at any step, retval returned would be invalid kernel. */
1291         retval = VBERROR_INVALID_KERNEL_FOUND;
1292
1293         /* Verify the key block. */
1294         key_block = (VbKeyBlockHeader *)kbuf;
1295         if (0 != KeyBlockVerify(key_block, image_size, kernel_subkey,
1296                                 hash_only)) {
1297                 VBDEBUG(("Verifying key block signature/hash failed.\n"));
1298                 goto fail;
1299         }
1300
1301         /* Check the key block flags against the current boot mode. */
1302         if (!(key_block->key_block_flags &
1303               (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
1304                KEY_BLOCK_FLAG_DEVELOPER_0))) {
1305                 VBDEBUG(("Key block developer flag mismatch.\n"));
1306                 if (hash_only == 0)
1307                         goto fail;
1308         }
1309
1310         if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)) {
1311                 VBDEBUG(("Key block recovery flag mismatch.\n"));
1312                 if (hash_only == 0)
1313                         goto fail;
1314         }
1315
1316         /* Get key for preamble/data verification from the key block. */
1317         data_key = PublicKeyToRSA(&key_block->data_key);
1318         if (!data_key) {
1319                 VBDEBUG(("Data key bad.\n"));
1320                 goto fail;
1321         }
1322
1323         /* Verify the preamble, which follows the key block */
1324         preamble = (VbKernelPreambleHeader *)(kbuf + key_block->key_block_size);
1325         if ((0 != VerifyKernelPreamble(preamble,
1326                                        image_size -
1327                                        key_block->key_block_size,
1328                                        data_key))) {
1329                 VBDEBUG(("Preamble verification failed.\n"));
1330                 goto fail;
1331         }
1332
1333         VBDEBUG(("Kernel preamble is good.\n"));
1334
1335         /* Verify kernel data */
1336         body_offset = key_block->key_block_size + preamble->preamble_size;
1337         if (0 != VerifyData((const uint8_t *)(kbuf + body_offset),
1338                             image_size - body_offset,
1339                             &preamble->body_signature, data_key)) {
1340                 VBDEBUG(("Kernel data verification failed.\n"));
1341                 goto fail;
1342         }
1343
1344         VBDEBUG(("Kernel is good.\n"));
1345
1346         /* Fill in output parameters. */
1347         kparams->kernel_buffer = kbuf + body_offset;
1348         kparams->kernel_buffer_size = image_size - body_offset;
1349         kparams->bootloader_address = preamble->bootloader_address;
1350         kparams->bootloader_size = preamble->bootloader_size;
1351         if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
1352                 kparams->flags = preamble->flags;
1353
1354         retval = VBERROR_SUCCESS;
1355
1356 fail:
1357         VbApiKernelFree(cparams);
1358         if (NULL != data_key)
1359                 RSAPublicKeyFree(data_key);
1360         if (NULL != kernel_subkey)
1361                 VbExFree(kernel_subkey);
1362         return retval;
1363 }
1364
1365 VbError_t VbUnlockDevice(void)
1366 {
1367         VBDEBUG(("%s() Enabling dev-mode...\n", __func__));
1368         if (TPM_SUCCESS != SetVirtualDevMode(1))
1369                 return VBERROR_TPM_SET_BOOT_MODE_STATE;
1370
1371         VBDEBUG(("%s() Mode change will take effect on next reboot.\n",
1372                  __func__));
1373         return VBERROR_SUCCESS;
1374 }
1375
1376 VbError_t VbLockDevice(void)
1377 {
1378         VbExNvStorageRead(vnc.raw);
1379         VbNvSetup(&vnc);
1380
1381         VBDEBUG(("%s() - Storing request to leave dev-mode.\n",
1382                  __func__));
1383         VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST,
1384                 1);
1385
1386         VbNvCommit();
1387
1388         VBDEBUG(("%s() Mode change will take effect on next reboot.\n",
1389                  __func__));
1390
1391         return VBERROR_SUCCESS;
1392 }