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 * Display functions used in kernel selection. 6 */ 7 8 #include "sysincludes.h" 9 10 #include "bmpblk_font.h" 11 #include "gbb_access.h" 12 #include "gbb_header.h" 13 #include "region.h" 14 #include "utility.h" 15 #include "vboot_api.h" 16 #include "vboot_common.h" 17 #include "vboot_display.h" 18 #include "vboot_nvstorage.h" 19 20 static uint32_t disp_current_screen = VB_SCREEN_BLANK; 21 static uint32_t disp_width = 0, disp_height = 0; 22 23 VbError_t VbGetLocalizationCount(VbCommonParams *cparams, uint32_t *count) 24 { 25 BmpBlockHeader hdr; 26 VbError_t ret; 27 28 /* Default to 0 on error */ 29 *count = 0; 30 31 ret = VbGbbReadBmpHeader(cparams, &hdr); 32 if (ret) 33 return ret; 34 35 *count = hdr.number_of_localizations; 36 return VBERROR_SUCCESS; 37 } 38 39 /* 40 * TODO: We could cache the font info to speed things up, by making the 41 * in-memory font structure distinct from the in-flash version. We'll do that 42 * Real Soon Now. Until then, we just repeat the same linear search every time. 43 */ 44 45 VbFont_t *VbInternalizeFontData(FontArrayHeader *fonthdr) 46 { 47 /* Just return the raw data pointer for now. */ 48 return (VbFont_t *)fonthdr; 49 } 50 51 void VbDoneWithFontForNow(VbFont_t *ptr) 52 { 53 /* Nothing. */ 54 } 55 56 ImageInfo *VbFindFontGlyph(VbFont_t *font, uint32_t ascii, 57 void **bufferptr, uint32_t *buffersize) 58 { 59 uint8_t *ptr, *firstptr; 60 uint32_t max; 61 uint32_t i; 62 FontArrayEntryHeader *entry; 63 64 ptr = (uint8_t *)font; 65 max = ((FontArrayHeader *)ptr)->num_entries; 66 ptr += sizeof(FontArrayHeader); 67 firstptr = ptr; 68 69 /* 70 * Simple linear search. 71 * 72 * Note: We're assuming glpyhs are uncompressed. That's true because 73 * the bmpblk_font tool doesn't compress anything. The bmpblk_utility 74 * does, but it compresses the entire font blob at once, and we've 75 * already uncompressed that before we got here. 76 */ 77 for(i=0; i<max; i++) { 78 entry = (FontArrayEntryHeader *)ptr; 79 if (entry->ascii == ascii) { 80 *bufferptr = ptr + sizeof(FontArrayEntryHeader); 81 *buffersize = entry->info.original_size; 82 return &(entry->info); 83 } 84 ptr += sizeof(FontArrayEntryHeader)+entry->info.compressed_size; 85 } 86 87 /* 88 * We must return something valid. We'll just use the first glyph in 89 * the font structure (so it should be something distinct). 90 */ 91 entry = (FontArrayEntryHeader *)firstptr; 92 *bufferptr = firstptr + sizeof(FontArrayEntryHeader); 93 *buffersize = entry->info.original_size; 94 return &(entry->info); 95 } 96 97 void VbRenderTextAtPos(const char *text, int right_to_left, 98 uint32_t x, uint32_t y, VbFont_t *font) 99 { 100 int i; 101 ImageInfo *image_info = 0; 102 void *buffer; 103 uint32_t buffersize; 104 uint32_t cur_x = x, cur_y = y; 105 106 if (!text || !font) { 107 VBDEBUG((" VbRenderTextAtPos: invalid args\n")); 108 return; 109 } 110 111 for (i=0; text[i]; i++) { 112 113 if (text[i] == '\n') { 114 if (!image_info) 115 image_info = VbFindFontGlyph(font, text[i], 116 &buffer, 117 &buffersize); 118 cur_x = x; 119 cur_y += image_info->height; 120 continue; 121 } 122 123 image_info = VbFindFontGlyph(font, text[i], &buffer, 124 &buffersize); 125 126 if (right_to_left) 127 cur_x -= image_info->width; 128 129 if (VBERROR_SUCCESS != VbExDisplayImage(cur_x, cur_y, buffer, 130 buffersize)) { 131 VBDEBUG((" VbRenderTextAtPos: " 132 "can't display ascii 0x%x\n", text[i])); 133 } 134 135 if (!right_to_left) 136 cur_x += image_info->width; 137 } 138 } 139 140 VbError_t VbDisplayScreenFromGBB(VbCommonParams *cparams, uint32_t screen, 141 VbNvContext *vncptr) 142 { 143 char *fullimage = NULL; 144 BmpBlockHeader hdr; 145 uint32_t screen_index; 146 uint32_t localization = 0; 147 VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven ok */ 148 uint32_t inoutsize; 149 uint32_t i; 150 VbFont_t *font; 151 const char *text_to_show; 152 int rtol = 0; 153 VbError_t ret; 154 155 ret = VbGbbReadBmpHeader(cparams, &hdr); 156 if (ret) 157 return ret; 158 159 /* 160 * Translate screen ID into index. Note that not all screens are in 161 * the GBB. 162 * 163 * TODO: ensure screen IDs match indices? Having this translation here 164 * is awful. 165 */ 166 switch (screen) { 167 case VB_SCREEN_DEVELOPER_WARNING: 168 screen_index = SCREEN_DEVELOPER_WARNING; 169 break; 170 case VB_SCREEN_RECOVERY_REMOVE: 171 screen_index = SCREEN_RECOVERY_REMOVE; 172 break; 173 case VB_SCREEN_RECOVERY_NO_GOOD: 174 screen_index = SCREEN_RECOVERY_NO_GOOD; 175 break; 176 case VB_SCREEN_RECOVERY_INSERT: 177 screen_index = SCREEN_RECOVERY_INSERT; 178 break; 179 case VB_SCREEN_RECOVERY_TO_DEV: 180 screen_index = SCREEN_RECOVERY_TO_DEV; 181 break; 182 case VB_SCREEN_DEVELOPER_TO_NORM: 183 screen_index = SCREEN_DEVELOPER_TO_NORM; 184 break; 185 case VB_SCREEN_WAIT: 186 screen_index = SCREEN_WAIT; 187 break; 188 case VB_SCREEN_TO_NORM_CONFIRMED: 189 screen_index = SCREEN_TO_NORM_CONFIRMED; 190 break; 191 case VB_SCREEN_BLANK: 192 case VB_SCREEN_DEVELOPER_EGG: 193 default: 194 /* Screens which aren't in the GBB */ 195 VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n", 196 (int)screen)); 197 retval = VBERROR_INVALID_SCREEN_INDEX; 198 goto VbDisplayScreenFromGBB_exit; 199 } 200 201 if (screen_index >= hdr.number_of_screenlayouts) { 202 VBDEBUG(("VbDisplayScreenFromGBB(): " 203 "screen %d index %d not in the GBB\n", 204 (int)screen, (int)screen_index)); 205 retval = VBERROR_INVALID_SCREEN_INDEX; 206 goto VbDisplayScreenFromGBB_exit; 207 } 208 209 /* Clip localization to number of localizations present in the GBB */ 210 VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &localization); 211 if (localization >= hdr.number_of_localizations) { 212 localization = 0; 213 VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, localization); 214 VbNvSet(vncptr, VBNV_BACKUP_NVRAM_REQUEST, 1); 215 } 216 217 /* Display all bitmaps for the image */ 218 for (i = 0; i < MAX_IMAGE_IN_LAYOUT; i++) { 219 ScreenLayout layout; 220 ImageInfo image_info; 221 char hwid[256]; 222 223 ret = VbGbbReadImage(cparams, localization, screen_index, 224 i, &layout, &image_info, 225 &fullimage, &inoutsize); 226 if (ret == VBERROR_NO_IMAGE_PRESENT) { 227 continue; 228 } else if (ret) { 229 retval = ret; 230 goto VbDisplayScreenFromGBB_exit; 231 } 232 233 switch(image_info.format) { 234 case FORMAT_BMP: 235 if (i == 0) { 236 /** 237 * In current version GBB bitmaps, first image 238 * is always the background. 239 */ 240 ret = VbExDisplaySetDimension( 241 image_info.width, 242 image_info.height); 243 if (ret) { 244 VBDEBUG(("VbExDisplaySetDimension" 245 "(%d,%d): failed (%#x).\n", 246 image_info.width, 247 image_info.height, ret)); 248 } 249 } 250 251 retval = VbExDisplayImage(layout.images[i].x, 252 layout.images[i].y, 253 fullimage, inoutsize); 254 break; 255 256 case FORMAT_FONT: 257 /* 258 * The uncompressed blob is our font structure. Cache 259 * it as needed. 260 */ 261 font = VbInternalizeFontData( 262 (FontArrayHeader *)fullimage); 263 264 /* TODO: handle text in general here */ 265 if (TAG_HWID == image_info.tag || 266 TAG_HWID_RTOL == image_info.tag) { 267 VbRegionReadHWID(cparams, hwid, sizeof(hwid)); 268 text_to_show = hwid; 269 rtol = (TAG_HWID_RTOL == image_info.tag); 270 } else { 271 text_to_show = ""; 272 rtol = 0; 273 } 274 275 VbRenderTextAtPos(text_to_show, rtol, 276 layout.images[i].x, 277 layout.images[i].y, font); 278 279 VbDoneWithFontForNow(font); 280 break; 281 282 default: 283 VBDEBUG(("VbDisplayScreenFromGBB(): " 284 "unsupported ImageFormat %d\n", 285 image_info.format)); 286 retval = VBERROR_INVALID_GBB; 287 } 288 289 VbExFree(fullimage); 290 291 if (VBERROR_SUCCESS != retval) 292 goto VbDisplayScreenFromGBB_exit; 293 } 294 295 /* Successful if all bitmaps displayed */ 296 retval = VBERROR_SUCCESS; 297 298 VbRegionCheckVersion(cparams); 299 300 VbDisplayScreenFromGBB_exit: 301 VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval)); 302 return retval; 303 } 304 305 VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, 306 int force, VbNvContext *vncptr) 307 { 308 VbError_t retval; 309 310 /* Initialize display if necessary */ 311 if (!disp_width) { 312 retval = VbExDisplayInit(&disp_width, &disp_height); 313 if (VBERROR_SUCCESS != retval) 314 return retval; 315 } 316 317 /* If requested screen is the same as the current one, we're done. */ 318 if (disp_current_screen == screen && 0 == force) 319 return VBERROR_SUCCESS; 320 321 /* If the screen is blank, turn off the backlight; else turn it on. */ 322 VbExDisplayBacklight(VB_SCREEN_BLANK == screen ? 0 : 1); 323 324 /* Request the screen */ 325 disp_current_screen = screen; 326 327 /* Look in the GBB first */ 328 if (VBERROR_SUCCESS == VbDisplayScreenFromGBB(cparams, screen, 329 vncptr)) 330 return VBERROR_SUCCESS; 331 332 /* If screen wasn't in the GBB bitmaps, fall back to a default */ 333 return VbExDisplayScreen(screen); 334 } 335 336 static void Uint8ToString(char *buf, uint8_t val) 337 { 338 const char *trans = "0123456789abcdef"; 339 *buf++ = trans[val >> 4]; 340 *buf = trans[val & 0xF]; 341 } 342 343 static void FillInSha1Sum(char *outbuf, VbPublicKey *key) 344 { 345 uint8_t *buf = ((uint8_t *)key) + key->key_offset; 346 uint64_t buflen = key->key_size; 347 uint8_t *digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM); 348 int i; 349 for (i = 0; i < SHA1_DIGEST_SIZE; i++) { 350 Uint8ToString(outbuf, digest[i]); 351 outbuf += 2; 352 } 353 *outbuf = '\0'; 354 VbExFree(digest); 355 } 356 357 const char *RecoveryReasonString(uint8_t code) 358 { 359 switch(code) { 360 case VBNV_RECOVERY_NOT_REQUESTED: 361 return "Recovery not requested"; 362 case VBNV_RECOVERY_LEGACY: 363 return "Recovery requested from legacy utility"; 364 case VBNV_RECOVERY_RO_MANUAL: 365 return "recovery button pressed"; 366 case VBNV_RECOVERY_RO_INVALID_RW: 367 return "RW firmware failed signature check"; 368 case VBNV_RECOVERY_RO_S3_RESUME: 369 return "S3 resume failed"; 370 case VBNV_RECOVERY_DEP_RO_TPM_ERROR: 371 return "TPM error in read-only firmware"; 372 case VBNV_RECOVERY_RO_SHARED_DATA: 373 return "Shared data error in read-only firmware"; 374 case VBNV_RECOVERY_RO_TEST_S3: 375 return "Test error from S3Resume()"; 376 case VBNV_RECOVERY_RO_TEST_LFS: 377 return "Test error from LoadFirmwareSetup()"; 378 case VBNV_RECOVERY_RO_TEST_LF: 379 return "Test error from LoadFirmware()"; 380 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_NOT_DONE: 381 return "RW firmware check not done"; 382 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_DEV_MISMATCH: 383 return "RW firmware developer flag mismatch"; 384 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_REC_MISMATCH: 385 return "RW firmware recovery flag mismatch"; 386 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + 387 VBSD_LF_CHECK_VERIFY_KEYBLOCK: 388 return "RW firmware unable to verify key block"; 389 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_KEY_ROLLBACK: 390 return "RW firmware key version rollback detected"; 391 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + 392 VBSD_LF_CHECK_DATA_KEY_PARSE: 393 return "RW firmware unable to parse data key"; 394 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + 395 VBSD_LF_CHECK_VERIFY_PREAMBLE: 396 return "RW firmware unable to verify preamble"; 397 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_FW_ROLLBACK: 398 return "RW firmware version rollback detected"; 399 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_GET_FW_BODY: 400 return "RW firmware unable to get firmware body"; 401 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + 402 VBSD_LF_CHECK_HASH_WRONG_SIZE: 403 return "RW firmware hash is wrong size"; 404 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_VERIFY_BODY: 405 return "RW firmware unable to verify firmware body"; 406 case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_NO_RO_NORMAL: 407 return "RW firmware read-only normal path is not supported"; 408 case VBNV_RECOVERY_RO_FIRMWARE: 409 return "Firmware problem outside of verified boot"; 410 case VBNV_RECOVERY_RO_TPM_REBOOT: 411 return "TPM requires a system reboot (should be transient)"; 412 case VBNV_RECOVERY_EC_SOFTWARE_SYNC: 413 return "EC software sync error"; 414 case VBNV_RECOVERY_EC_UNKNOWN_IMAGE: 415 return "EC software sync unable to determine active EC image"; 416 case VBNV_RECOVERY_DEP_EC_HASH: 417 return "EC software sync error obtaining EC image hash"; 418 case VBNV_RECOVERY_EC_EXPECTED_IMAGE: 419 return "EC software sync error " 420 "obtaining expected EC image from BIOS"; 421 case VBNV_RECOVERY_EC_EXPECTED_HASH: 422 return "EC software sync error " 423 "obtaining expected EC hash from BIOS"; 424 case VBNV_RECOVERY_EC_HASH_MISMATCH: 425 return "EC software sync error " 426 "comparing expected EC hash and image"; 427 case VBNV_RECOVERY_EC_UPDATE: 428 return "EC software sync error updating EC"; 429 case VBNV_RECOVERY_EC_JUMP_RW: 430 return "EC software sync unable to jump to EC-RW"; 431 case VBNV_RECOVERY_EC_PROTECT: 432 return "EC software sync protection error"; 433 case VBNV_RECOVERY_VB2_SECDATA_INIT: 434 return "Secure NVRAM (TPM) initialization error"; 435 case VBNV_RECOVERY_VB2_GBB_HEADER: 436 return "Error parsing GBB header"; 437 case VBNV_RECOVERY_VB2_TPM_CLEAR_OWNER: 438 return "Error trying to clear TPM owner"; 439 case VBNV_RECOVERY_VB2_DEV_SWITCH: 440 return "Error reading or updating developer switch"; 441 case VBNV_RECOVERY_VB2_FW_SLOT: 442 return "Error selecting RW firmware slot"; 443 case VBNV_RECOVERY_RO_UNSPECIFIED: 444 return "Unspecified/unknown error in RO firmware"; 445 case VBNV_RECOVERY_RW_DEV_SCREEN: 446 return "User requested recovery from dev-mode warning screen"; 447 case VBNV_RECOVERY_RW_NO_OS: 448 return "No OS kernel detected (or kernel rollback attempt?)"; 449 case VBNV_RECOVERY_RW_INVALID_OS: 450 return "OS kernel failed signature check"; 451 case VBNV_RECOVERY_DEP_RW_TPM_ERROR: 452 return "TPM error in rewritable firmware"; 453 case VBNV_RECOVERY_RW_DEV_MISMATCH: 454 return "RW firmware in dev mode, but dev switch is off"; 455 case VBNV_RECOVERY_RW_SHARED_DATA: 456 return "Shared data error in rewritable firmware"; 457 case VBNV_RECOVERY_RW_TEST_LK: 458 return "Test error from LoadKernel()"; 459 case VBNV_RECOVERY_DEP_RW_NO_DISK: 460 return "No bootable disk found"; 461 case VBNV_RECOVERY_TPM_E_FAIL: 462 return "TPM error that was not fixed by reboot"; 463 case VBNV_RECOVERY_RO_TPM_S_ERROR: 464 return "TPM setup error in read-only firmware"; 465 case VBNV_RECOVERY_RO_TPM_W_ERROR: 466 return "TPM write error in read-only firmware"; 467 case VBNV_RECOVERY_RO_TPM_L_ERROR: 468 return "TPM lock error in read-only firmware"; 469 case VBNV_RECOVERY_RO_TPM_U_ERROR: 470 return "TPM update error in read-only firmware"; 471 case VBNV_RECOVERY_RW_TPM_R_ERROR: 472 return "TPM read error in rewritable firmware"; 473 case VBNV_RECOVERY_RW_TPM_W_ERROR: 474 return "TPM write error in rewritable firmware"; 475 case VBNV_RECOVERY_RW_TPM_L_ERROR: 476 return "TPM lock error in rewritable firmware"; 477 case VBNV_RECOVERY_EC_HASH_FAILED: 478 return "EC software sync unable to get EC image hash"; 479 case VBNV_RECOVERY_EC_HASH_SIZE: 480 return "EC software sync invalid image hash size"; 481 case VBNV_RECOVERY_LK_UNSPECIFIED: 482 return "Unspecified error while trying to load kernel"; 483 case VBNV_RECOVERY_RW_NO_DISK: 484 return "No bootable storage device in system"; 485 case VBNV_RECOVERY_RW_NO_KERNEL: 486 return "No bootable kernel found on disk"; 487 case VBNV_RECOVERY_RW_UNSPECIFIED: 488 return "Unspecified/unknown error in RW firmware"; 489 case VBNV_RECOVERY_KE_DM_VERITY: 490 return "DM-verity error"; 491 case VBNV_RECOVERY_KE_UNSPECIFIED: 492 return "Unspecified/unknown error in kernel"; 493 case VBNV_RECOVERY_US_TEST: 494 return "Recovery mode test from user-mode"; 495 case VBNV_RECOVERY_US_UNSPECIFIED: 496 return "Unspecified/unknown error in user-mode"; 497 } 498 return "We have no idea what this means"; 499 } 500 501 #define DEBUG_INFO_SIZE 512 502 503 VbError_t VbDisplayDebugInfo(VbCommonParams *cparams, VbNvContext *vncptr) 504 { 505 VbSharedDataHeader *shared = 506 (VbSharedDataHeader *)cparams->shared_data_blob; 507 GoogleBinaryBlockHeader *gbb = cparams->gbb; 508 char buf[DEBUG_INFO_SIZE] = ""; 509 char sha1sum[SHA1_DIGEST_SIZE * 2 + 1]; 510 char hwid[256]; 511 uint32_t used = 0; 512 VbPublicKey *key; 513 VbError_t ret; 514 uint32_t i; 515 516 /* Redisplay current screen to overwrite any previous debug output */ 517 VbDisplayScreen(cparams, disp_current_screen, 1, vncptr); 518 519 /* Add hardware ID */ 520 VbRegionReadHWID(cparams, hwid, sizeof(hwid)); 521 used += StrnAppend(buf + used, "HWID: ", DEBUG_INFO_SIZE - used); 522 used += StrnAppend(buf + used, hwid, DEBUG_INFO_SIZE - used); 523 524 /* Add recovery reason and subcode */ 525 VbNvGet(vncptr, VBNV_RECOVERY_SUBCODE, &i); 526 used += StrnAppend(buf + used, 527 "\nrecovery_reason: 0x", DEBUG_INFO_SIZE - used); 528 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, 529 shared->recovery_reason, 16, 2); 530 used += StrnAppend(buf + used, " / 0x", DEBUG_INFO_SIZE - used); 531 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 16, 2); 532 used += StrnAppend(buf + used, " ", DEBUG_INFO_SIZE - used); 533 used += StrnAppend(buf + used, 534 RecoveryReasonString(shared->recovery_reason), 535 DEBUG_INFO_SIZE - used); 536 537 /* Add VbSharedData flags */ 538 used += StrnAppend(buf + used, "\nVbSD.flags: 0x", DEBUG_INFO_SIZE - used); 539 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, 540 shared->flags, 16, 8); 541 542 /* Add raw contents of VbNvStorage */ 543 used += StrnAppend(buf + used, "\nVbNv.raw:", DEBUG_INFO_SIZE - used); 544 for (i = 0; i < VBNV_BLOCK_SIZE; i++) { 545 used += StrnAppend(buf + used, " ", DEBUG_INFO_SIZE - used); 546 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, 547 vncptr->raw[i], 16, 2); 548 } 549 550 /* Add dev_boot_usb flag */ 551 VbNvGet(vncptr, VBNV_DEV_BOOT_USB, &i); 552 used += StrnAppend(buf + used, "\ndev_boot_usb: ", DEBUG_INFO_SIZE - used); 553 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0); 554 555 /* Add dev_boot_legacy flag */ 556 VbNvGet(vncptr, VBNV_DEV_BOOT_LEGACY, &i); 557 used += StrnAppend(buf + used, 558 "\ndev_boot_legacy: ", DEBUG_INFO_SIZE - used); 559 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0); 560 561 /* Add dev_boot_signed_only flag */ 562 VbNvGet(vncptr, VBNV_DEV_BOOT_SIGNED_ONLY, &i); 563 used += StrnAppend(buf + used, "\ndev_boot_signed_only: ", 564 DEBUG_INFO_SIZE - used); 565 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0); 566 567 /* Add TPM versions */ 568 used += StrnAppend(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used); 569 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, 570 shared->fw_version_tpm, 16, 8); 571 used += StrnAppend(buf + used, " kernver=0x", DEBUG_INFO_SIZE - used); 572 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, 573 shared->kernel_version_tpm, 16, 8); 574 575 /* Add GBB flags */ 576 used += StrnAppend(buf + used, "\ngbb.flags: 0x", DEBUG_INFO_SIZE - used); 577 if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1) { 578 used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, 579 gbb->flags, 16, 8); 580 } else { 581 used += StrnAppend(buf + used, 582 "0 (default)", DEBUG_INFO_SIZE - used); 583 } 584 585 /* Add sha1sum for Root & Recovery keys */ 586 ret = VbGbbReadRootKey(cparams, &key); 587 if (!ret) { 588 FillInSha1Sum(sha1sum, key); 589 VbExFree(key); 590 used += StrnAppend(buf + used, "\ngbb.rootkey: ", 591 DEBUG_INFO_SIZE - used); 592 used += StrnAppend(buf + used, sha1sum, 593 DEBUG_INFO_SIZE - used); 594 } 595 596 ret = VbGbbReadRecoveryKey(cparams, &key); 597 if (!ret) { 598 FillInSha1Sum(sha1sum, key); 599 VbExFree(key); 600 used += StrnAppend(buf + used, "\ngbb.recovery_key: ", 601 DEBUG_INFO_SIZE - used); 602 used += StrnAppend(buf + used, sha1sum, 603 DEBUG_INFO_SIZE - used); 604 } 605 606 /* If we're in dev-mode, show the kernel subkey that we expect, too. */ 607 if (0 == shared->recovery_reason) { 608 FillInSha1Sum(sha1sum, &shared->kernel_subkey); 609 used += StrnAppend(buf + used, 610 "\nkernel_subkey: ", DEBUG_INFO_SIZE - used); 611 used += StrnAppend(buf + used, sha1sum, DEBUG_INFO_SIZE - used); 612 } 613 614 /* Make sure we finish with a newline */ 615 used += StrnAppend(buf + used, "\n", DEBUG_INFO_SIZE - used); 616 617 /* TODO: add more interesting data: 618 * - Information on current disks */ 619 620 buf[DEBUG_INFO_SIZE - 1] = '\0'; 621 return VbExDisplayDebugInfo(buf); 622 } 623 624 #define MAGIC_WORD_LEN 5 625 #define MAGIC_WORD "xyzzy" 626 static uint8_t MagicBuffer[MAGIC_WORD_LEN]; 627 628 VbError_t VbCheckDisplayKey(VbCommonParams *cparams, uint32_t key, 629 VbNvContext *vncptr) 630 { 631 int i; 632 633 /* Update key buffer */ 634 for(i = 1; i < MAGIC_WORD_LEN; i++) 635 MagicBuffer[i - 1] = MagicBuffer[i]; 636 /* Save as lower-case ASCII */ 637 MagicBuffer[MAGIC_WORD_LEN - 1] = (key | 0x20) & 0xFF; 638 639 if ('\t' == key) { 640 /* Tab = display debug info */ 641 return VbDisplayDebugInfo(cparams, vncptr); 642 } else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key || 643 VB_KEY_DOWN == key || VB_KEY_UP == key) { 644 /* Arrow keys = change localization */ 645 uint32_t loc = 0; 646 uint32_t count = 0; 647 648 VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &loc); 649 if (VBERROR_SUCCESS != VbGetLocalizationCount(cparams, &count)) 650 loc = 0; /* No localization count (bad GBB?) */ 651 else if (VB_KEY_RIGHT == key || VB_KEY_UP == key) 652 loc = (loc < count - 1 ? loc + 1 : 0); 653 else 654 loc = (loc > 0 ? loc - 1 : count - 1); 655 VBDEBUG(("VbCheckDisplayKey() - change localization to %d\n", 656 (int)loc)); 657 VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, loc); 658 VbNvSet(vncptr, VBNV_BACKUP_NVRAM_REQUEST, 1); 659 660 #ifdef SAVE_LOCALE_IMMEDIATELY 661 VbNvTeardown(vncptr); /* really only computes checksum */ 662 if (vncptr->raw_changed) 663 VbExNvStorageWrite(vncptr->raw); 664 #endif 665 666 /* Force redraw of current screen */ 667 return VbDisplayScreen(cparams, disp_current_screen, 1, vncptr); 668 } 669 670 if (0 == Memcmp(MagicBuffer, MAGIC_WORD, MAGIC_WORD_LEN)) { 671 if (VBEASTEREGG) 672 (void)VbDisplayScreen(cparams, disp_current_screen, 673 1, vncptr); 674 } 675 676 return VBERROR_SUCCESS; 677 } 678