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