From 1cf77cda5ea2d7549caccb953079263d463feadb Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Mon, 25 Jul 2011 09:19:58 -0700 Subject: Return more meaningful error codes from vboot entry points This also fixes one place where TPM error codes were getting lost. BUG=chromium-os:18132 TEST=make && make runtests Change-Id: I83c74e1103805f166d1dc7448be7d67bd46d15b3 Reviewed-on: http://gerrit.chromium.org/gerrit/4659 Tested-by: Randall Spangler Reviewed-by: Randall Spangler --- firmware/include/vboot_api.h | 66 ++++++++++++++++++++++++++++++---- firmware/lib/vboot_api_firmware.c | 22 ++++++++---- firmware/lib/vboot_api_init.c | 4 +-- firmware/lib/vboot_api_kernel.c | 74 +++++++++++++++++++-------------------- 4 files changed, 114 insertions(+), 52 deletions(-) diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index 55a0332c..e61340ef 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -31,15 +31,67 @@ /* Error codes */ /* Functions which return an error all return this type. This is a -* 32-bit value rather than an int so it's consistent across UEFI, -* which is 32-bit during PEI and 64-bit during DXE/BDS. */ + * 32-bit value rather than an int so it's consistent across UEFI, + * which is 32-bit during PEI and 64-bit during DXE/BDS. */ typedef uint32_t VbError_t; -/* No error; function completed successfully. */ -#define VBERROR_SUCCESS 0 -/* Errors are non-zero, but differ between functions. For example, - * the TPM functions may pass through TPM error codes, some of which - * may be recoverable. */ +/* Predefined error numbers. */ +enum VbErrorPredefined_t { + /* No error; function completed successfully. */ + VBERROR_SUCCESS = 0, + + /* Errors are non-zero, but differ between functions. For example, + * the TPM functions may pass through TPM error codes, some of which + * may be recoverable. */ + + /* The verified boot entry points VbInit(), VbSelectFirmware(), + * VbSelectAndLoadKernel() may return the following errors. */ + + /* Unknown error */ + VBERROR_UNKNOWN = 0x10000, + /* Unable to initialize shared data */ + VBERROR_INIT_SHARED_DATA = 0x10001, + /* Error resuming TPM during a S3 resume */ + VBERROR_TPM_S3_RESUME = 0x10002, + /* LoadFirmware() failed to find a valid firmware */ + VBERROR_LOAD_FIRMWARE = 0x10003, + /* Unable to write firmware versions to TPM */ + VBERROR_TPM_WRITE_FIRMWARE = 0x10004, + /* Unable to lock firmware versions in TPM */ + VBERROR_TPM_LOCK_FIRMWARE = 0x10005, + /* Unable to set boot mode state in TPM */ + VBERROR_TPM_SET_BOOT_MODE_STATE = 0x10006, + /* TPM requires reboot */ + VBERROR_TPM_REBOOT_REQUIRED = 0x10007, + /* Unable to set up TPM */ + VBERROR_TPM_FIRMWARE_SETUP = 0x10008, + /* Unable to read kernel versions from TPM */ + VBERROR_TPM_READ_KERNEL = 0x10009, + /* Attempted to load developer-only firmware when developer switch was off */ + VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH = 0x1000A, + /* Unable to write kernel versions to TPM */ + VBERROR_TPM_WRITE_KERNEL = 0x1000B, + /* Unable to lock kernel versions in TPM */ + VBERROR_TPM_LOCK_KERNEL = 0x1000C, + /* Calling firmware requested shutdown via VbExIsShutdownRequested() */ + VBERROR_SHUTDOWN_REQUESTED = 0x1000D, + /* Unable to find a suitable boot device on which to look for a kernel */ + VBERROR_NO_DISK_FOUND = 0x1000E, + /* No OS kernel found on any boot device */ + VBERROR_NO_KERNEL_FOUND = 0x1000F, + /* All OS kernels found were invalid (corrupt, improperly signed, etc.) */ + VBERROR_INVALID_KERNEL_FOUND = 0x10010, + /* LoadKernel() requested recovery mode */ + VBERROR_LOAD_KERNEL_RECOVERY = 0x10011, + /* Other error inside LoadKernel() */ + VBERROR_LOAD_KERNEL = 0x10012, + /* Invalid Google binary block */ + VBERROR_INVALID_GBB = 0x10013, + /* Invalid bitmap volume */ + VBERROR_INVALID_BMPFV = 0x10014, + /* Invalid screen index */ + VBERROR_INVALID_SCREEN_INDEX = 0x10015 +}; /*****************************************************************************/ diff --git a/firmware/lib/vboot_api_firmware.c b/firmware/lib/vboot_api_firmware.c index 56c8e653..6ffca2d0 100644 --- a/firmware/lib/vboot_api_firmware.c +++ b/firmware/lib/vboot_api_firmware.c @@ -31,7 +31,7 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; LoadFirmwareParams p; VbNvContext vnc; - VbError_t retval = 1; /* Assume error until proven successful */ + VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven successful */ int is_rec = (shared->recovery_reason ? 1 : 0); int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0); uint32_t tpm_version = 0; @@ -57,17 +57,20 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VBDEBUG(("TPM requires a reboot.\n")); if (!is_rec) { /* Not recovery mode. Just reboot (not into recovery). */ + retval = VBERROR_TPM_REBOOT_REQUIRED; goto VbSelectFirmware_exit; } else if (VBNV_RECOVERY_RO_TPM_REBOOT != shared->recovery_reason) { /* In recovery mode now, and we haven't requested a TPM reboot yet, * so request one. */ VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_REBOOT); + retval = VBERROR_TPM_REBOOT_REQUIRED; goto VbSelectFirmware_exit; } } if (!is_rec) { VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + retval = VBERROR_TPM_FIRMWARE_SETUP; goto VbSelectFirmware_exit; } } @@ -114,8 +117,10 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, cparams->shared_data_size = (uint32_t)p.shared_data_size; /* Exit if we failed to find an acceptable firmware */ - if (LOAD_FIRMWARE_SUCCESS != rv) + if (LOAD_FIRMWARE_SUCCESS != rv) { + retval = VBERROR_LOAD_FIRMWARE; goto VbSelectFirmware_exit; + } /* Translate the selected firmware path */ if (shared->flags & VBSD_LF_USE_RO_NORMAL) { @@ -133,6 +138,8 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VBPERFEND("VB_TPMU"); if (0 != tpm_status) { VBDEBUG(("Unable to write firmware version to TPM.\n")); + VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + retval = VBERROR_TPM_WRITE_FIRMWARE; goto VbSelectFirmware_exit; } } @@ -143,10 +150,9 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VBPERFEND("VB_TPML"); if (0 != tpm_status) { VBDEBUG(("Unable to lock firmware version in TPM.\n")); - if (!is_rec) { - VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); - goto VbSelectFirmware_exit; - } + VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + retval = VBERROR_TPM_LOCK_FIRMWARE; + goto VbSelectFirmware_exit; } } @@ -157,6 +163,7 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams, VBDEBUG(("Unable to update the TPM with boot mode information.\n")); if (!is_rec) { VbSfRequestRecovery(&vnc, VBNV_RECOVERY_RO_TPM_ERROR); + retval = VBERROR_TPM_SET_BOOT_MODE_STATE; goto VbSelectFirmware_exit; } } @@ -169,6 +176,9 @@ VbSelectFirmware_exit: /* Stop timer */ shared->timer_vb_select_firmware_exit = VbExGetTimer(); + /* Should always have a known error code */ + VbAssert(VBERROR_UNKNOWN != retval); + return retval; } diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c index df831291..2a6b7d0b 100644 --- a/firmware/lib/vboot_api_init.c +++ b/firmware/lib/vboot_api_init.c @@ -34,7 +34,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { /* Initialize shared data structure */ if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) { VBDEBUG(("Shared data init error\n")); - return 1; + return VBERROR_INIT_SHARED_DATA; } shared->timer_vb_init_enter = VbExGetTimer(); @@ -115,7 +115,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { /* If we can't resume, just do a full reboot. No need to go to recovery * mode here, since if the TPM is really broken we'll catch it on the * next boot. */ - retval = 1; + retval = VBERROR_TPM_S3_RESUME; } } diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 038065f2..ca2928df 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -53,7 +53,7 @@ static VbError_t VbGetLocalizationCount(VbCommonParams* cparams, if (0 == gbb->bmpfv_size || gbb->bmpfv_offset > cparams->gbb_size || gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) { - return 1; + return VBERROR_INVALID_GBB; } /* Sanity-check the bitmap block header */ @@ -63,7 +63,7 @@ static VbError_t VbGetLocalizationCount(VbCommonParams* cparams, (hdr->major_version > BMPBLOCK_MAJOR_VERSION) || ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) && (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) { - return 1; + return VBERROR_INVALID_BMPFV; } *count = hdr->number_of_localizations; @@ -81,7 +81,8 @@ static VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, ImageInfo* image_info; uint32_t screen_index; uint32_t localization = 0; - VbError_t retval = 1; /* Assume error until proven successful */ + VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven + * successful */ uint32_t offset; uint32_t i; @@ -90,7 +91,7 @@ static VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, gbb->bmpfv_offset > cparams->gbb_size || gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) { VBDEBUG(("VbDisplayScreenFromGBB(): invalid bmpfv offset/size\n")); - return 1; + return VBERROR_INVALID_GBB; } /* Copy bitmap data from GBB into RAM for speed */ @@ -105,6 +106,7 @@ static VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) && (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) { VBDEBUG(("VbDisplayScreenFromGBB(): invalid/too new bitmap header\n")); + retval = VBERROR_INVALID_BMPFV; goto VbDisplayScreenFromGBB_exit; } @@ -131,11 +133,13 @@ static VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, /* Screens which aren't in the GBB */ VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n", (int)screen)); + retval = VBERROR_INVALID_SCREEN_INDEX; goto VbDisplayScreenFromGBB_exit; } if (screen_index >= hdr->number_of_screenlayouts) { VBDEBUG(("VbDisplayScreenFromGBB(): screen %d index %d not in the GBB\n", (int)screen, (int)screen_index)); + retval = VBERROR_INVALID_SCREEN_INDEX; goto VbDisplayScreenFromGBB_exit; } @@ -193,13 +197,15 @@ VbDisplayScreenFromGBB_exit: * redisplays the screen even if it's the same as the current screen. */ static VbError_t VbDisplayScreen(VbCommonParams* cparams, uint32_t screen, int force) { + VbError_t retval; VBDEBUG(("VbDisplayScreen(%d, %d)\n", (int)screen, force)); /* Initialize display if necessary */ if (!disp_width) { - if (VBERROR_SUCCESS != VbExDisplayInit(&disp_width, &disp_height)) - return 1; + retval = VbExDisplayInit(&disp_width, &disp_height); + if (VBERROR_SUCCESS != retval) + return retval; } /* If the requested screen is the same as the current one, we're done. */ @@ -327,22 +333,16 @@ static VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key) { } -/* Return codes for VbTryLoadKernel(), in addition to VBERROR_SUCCESS. Note - * that there are some gaps in the enum from obsoleted old error codes. */ -enum VbTryLoadKernelError_t { - /* No disks found */ - VBERROR_TRY_LOAD_NO_DISKS = 1, - /* Some other error; go to recovery mode if this was the only hope to boot */ - VBERROR_TRY_LOAD_RECOVERY = 3, -}; - - /* Attempt loading a kernel from the specified type(s) of disks. If - * successful, sets p->disk_handle to the disk for the kernel. See - * VBERROR_TRY_LOAD_* for additional return codes. */ + * successful, sets p->disk_handle to the disk for the kernel and returns + * VBERROR_SUCCESS. + * + * Returns VBERROR_NO_DISK_FOUND if no disks of the specified type were found. + * + * May return other VBERROR_ codes for other failures. */ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, uint32_t get_info_flags) { - int retval = VBERROR_TRY_LOAD_NO_DISKS; + int lk_retval = LOAD_KERNEL_RECOVERY; VbDiskInfo* disk_info = NULL; uint32_t disk_count = 0; uint32_t i; @@ -360,7 +360,7 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, VBDEBUG(("VbTryLoadKernel() found %d disks\n", (int)disk_count)); if (0 == disk_count) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK); - return VBERROR_TRY_LOAD_NO_DISKS; + return VBERROR_NO_DISK_FOUND; } /* Loop over disks */ @@ -369,37 +369,37 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, p->disk_handle = disk_info[i].handle; p->bytes_per_lba = disk_info[i].bytes_per_lba; p->ending_lba = disk_info[i].lba_count - 1; - retval = LoadKernel(p); - VBDEBUG(("VbTryLoadKernel() LoadKernel() returned %d\n", retval)); + lk_retval = LoadKernel(p); + VBDEBUG(("VbTryLoadKernel() LoadKernel() returned %d\n", lk_retval)); /* Stop now if we found a kernel */ /* TODO: If recovery requested, should track the farthest we get, instead * of just returning the value from the last disk attempted. */ - if (LOAD_KERNEL_SUCCESS == retval) + if (LOAD_KERNEL_SUCCESS == lk_retval) break; } /* If we didn't succeed, don't return a disk handle */ - if (LOAD_KERNEL_SUCCESS != retval) + if (LOAD_KERNEL_SUCCESS != lk_retval) p->disk_handle = NULL; VbExDiskFreeInfo(disk_info, p->disk_handle); /* Translate return codes */ - switch (retval) { + switch (lk_retval) { case LOAD_KERNEL_SUCCESS: return VBERROR_SUCCESS; case LOAD_KERNEL_NOT_FOUND: VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_OS); - return VBERROR_TRY_LOAD_RECOVERY; + return VBERROR_NO_KERNEL_FOUND; case LOAD_KERNEL_INVALID: VbSetRecoveryRequest(VBNV_RECOVERY_RW_INVALID_OS); - return VBERROR_TRY_LOAD_RECOVERY; + return VBERROR_INVALID_KERNEL_FOUND; case LOAD_KERNEL_RECOVERY: - return VBERROR_TRY_LOAD_RECOVERY; + return VBERROR_LOAD_KERNEL_RECOVERY; default: VbSetRecoveryRequest(VBNV_RECOVERY_RW_UNSPECIFIED); - return VBERROR_TRY_LOAD_RECOVERY; + return VBERROR_LOAD_KERNEL; } } @@ -440,7 +440,7 @@ VbError_t VbBootDeveloper(VbCommonParams* cparams, LoadKernelParams* p) { uint32_t key; if (VbExIsShutdownRequested()) - return 1; + return VBERROR_SHUTDOWN_REQUESTED; if (DEV_DELAY_BEEP1 == delay_time || DEV_DELAY_BEEP2 == delay_time) VbExBeep(DEV_DELAY_INCREMENT, 400); @@ -535,7 +535,7 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) { for (i = 0; i < 4; i++) { VbCheckDisplayKey(cparams, VbExKeyboardRead()); if (VbExIsShutdownRequested()) - return 1; + return VBERROR_SHUTDOWN_REQUESTED; VbExSleepMs(REC_DELAY_INCREMENT); } } @@ -554,7 +554,7 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) { if (VBERROR_SUCCESS == retval) break; /* Found a recovery kernel */ - VbDisplayScreen(cparams, VBERROR_TRY_LOAD_NO_DISKS == retval ? + VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ? VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD, 0); /* Scan keyboard more frequently than media, since x86 platforms don't like @@ -562,7 +562,7 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) { for (i = 0; i < 4; i++) { VbCheckDisplayKey(cparams, VbExKeyboardRead()); if (VbExIsShutdownRequested()) - return 1; + return VBERROR_SHUTDOWN_REQUESTED; VbExSleepMs(REC_DELAY_INCREMENT); } } @@ -599,7 +599,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, VBDEBUG(("Unable to get kernel versions from TPM\n")); if (!shared->recovery_reason) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_ERROR); - retval = 1; + retval = VBERROR_TPM_READ_KERNEL; goto VbSelectAndLoadKernel_exit; } } @@ -629,7 +629,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, * when the dev switch is on, so we should never get here. */ VBDEBUG(("Developer firmware called with dev switch off!\n")); VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH); - retval = 1; + retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH; goto VbSelectAndLoadKernel_exit; } #else @@ -664,7 +664,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, if (0 != tpm_status) { VBDEBUG(("Error writing kernel versions to TPM.\n")); VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_ERROR); - retval = 1; + retval = VBERROR_TPM_WRITE_KERNEL; goto VbSelectAndLoadKernel_exit; } } @@ -688,7 +688,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, VBDEBUG(("Error locking kernel versions.\n")); if (!shared->recovery_reason) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_ERROR); - retval = 1; + retval = VBERROR_TPM_LOCK_KERNEL; goto VbSelectAndLoadKernel_exit; } } -- cgit v1.2.1