Vboot wrapper - add recovery reason, refactor timing

Pressing Tab at a firmware screen now displays real data, including
the recovery reason, HWID, and contents of VbNvStorage.

Entry point start/end time tracking in VbSharedData now refers to the
new wrapper APIs.

Added capability for calling firmware to request recovery mode (for
example, if it's unable to initialize RAM, can't find the SSD, etc.).
Previously, calling firmware had no (good) way to do this other than
faking the recovery button being pressed.

BUG=chromium-os:17018
TEST=emerge on x86 and tegra2_seaboard

Change-Id: I7d377f279842b30a10d945d13571c41c464633f1
Reviewed-on: http://gerrit.chromium.org/gerrit/3814
Reviewed-by: Simon Glass <sjg@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Randall Spangler
2011-07-08 14:01:54 -07:00
parent 1b1998dff0
commit 9619112a57
10 changed files with 175 additions and 180 deletions

View File

@@ -95,7 +95,11 @@ typedef struct VbCommonParams {
#define VB_INIT_FLAG_WP_ENABLED 0x00000004 #define VB_INIT_FLAG_WP_ENABLED 0x00000004
/* This is a S3 resume, not a normal boot. */ /* This is a S3 resume, not a normal boot. */
#define VB_INIT_FLAG_S3_RESUME 0x00000008 #define VB_INIT_FLAG_S3_RESUME 0x00000008
/* Previous boot attempt failed for reasons external to verified boot (RAM
* init failure, SSD missing, etc.). */
/* TODO: add a field to VbInitParams which holds a reason code, and report
* that via VbSharedData. */
#define VB_INIT_FLAG_PREVIOUS_BOOT_FAIL 0x00000010
/* Output flags for VbInitParams.out_flags. Used to indicate /* Output flags for VbInitParams.out_flags. Used to indicate
* potential boot paths and configuration to the calling firmware * potential boot paths and configuration to the calling firmware
@@ -210,14 +214,6 @@ void VbUpdateFirmwareBodyHash(VbCommonParams* cparams,
VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
VbSelectAndLoadKernelParams* kparams); VbSelectAndLoadKernelParams* kparams);
/* S3 resume handler. This only needs to be called if the hardware
* does not maintain power to the TPM when in S3 (suspend-to-RAM).
*
* Returns VBERROR_SUCCESS if success, non-zero if error; on error,
* caller should reboot. */
VbError_t VbS3Resume(void);
/*****************************************************************************/ /*****************************************************************************/
/* Debug output (from utility.h) */ /* Debug output (from utility.h) */

View File

@@ -86,6 +86,9 @@ typedef enum VbNvParam {
* vboot_struct.h. */ * vboot_struct.h. */
#define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN 0x10 #define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN 0x10
#define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX 0x1F #define VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX 0x1F
/* Firmware boot failure outside of verified boot (RAM init, missing SSD,
* etc.). */
#define VBNV_RECOVERY_RO_FIRMWARE 0x20
/* Unspecified/unknown error in read-only firmware */ /* Unspecified/unknown error in read-only firmware */
#define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F #define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F
/* User manually requested recovery by pressing a key at developer /* User manually requested recovery by pressing a key at developer

View File

@@ -280,14 +280,17 @@ typedef struct VbSharedDataHeader {
uint64_t kernel_subkey_data_size; /* Size of kernel subkey data */ uint64_t kernel_subkey_data_size; /* Size of kernel subkey data */
/* Timer values from VbExGetTimer(). Unused values are set to 0. /* Timer values from VbExGetTimer(). Unused values are set to 0.
* If a function is called mutiple times, these are the times from * Note that these are now the enter/exit times for the wrapper API entry
* the most recent call. See crosbug.com/17018. */ * points; see crosbug.com/17018. */
uint64_t timer_load_firmware_start_enter; /* VbInit() - enter */ /* VbInit() enter/exit */
uint64_t timer_load_firmware_start_exit; /* VbInit() - exit */ uint64_t timer_vb_init_enter;
uint64_t timer_load_firmware_enter; /* LoadFirmware() - enter */ uint64_t timer_vb_init_exit;
uint64_t timer_load_firmware_exit; /* LoadFirmware() - exit */ /* VbSelectFirmware() enter/exit */
uint64_t timer_load_kernel_enter; /* LoadKernel() - enter */ uint64_t timer_vb_select_firmware_enter;
uint64_t timer_load_kernel_exit; /* LoadKernel() - exit */ uint64_t timer_vb_select_firmware_exit;
/* VbSelectAndLoadKernel() enter/exit */
uint64_t timer_vb_select_and_load_kernel_enter;
uint64_t timer_vb_select_and_load_kernel_exit;
/* Information stored in TPM, as retrieved by firmware */ /* Information stored in TPM, as retrieved by firmware */
uint32_t fw_version_tpm; /* Current firmware version in TPM */ uint32_t fw_version_tpm; /* Current firmware version in TPM */

View File

@@ -20,11 +20,15 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams,
VbNvContext vnc; VbNvContext vnc;
int rv; int rv;
/* Start timer */
shared->timer_vb_select_firmware_enter = VbExGetTimer();
/* If recovery is requested, go straight to recovery without checking the /* If recovery is requested, go straight to recovery without checking the
* RW firmware. */ * RW firmware. */
if (VBNV_RECOVERY_NOT_REQUESTED != shared->recovery_reason) { if (VBNV_RECOVERY_NOT_REQUESTED != shared->recovery_reason) {
VBDEBUG(("VbSelectFirmware() detected recovery request, reason=%d.\n", VBDEBUG(("VbSelectFirmware() detected recovery request, reason=%d.\n",
(int)shared->recovery_reason)); (int)shared->recovery_reason));
shared->timer_vb_select_firmware_exit = VbExGetTimer();
fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY; fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
return VBERROR_SUCCESS; return VBERROR_SUCCESS;
} }
@@ -66,6 +70,9 @@ VbError_t VbSelectFirmware(VbCommonParams* cparams,
/* Copy amount of used shared data back to the wrapper API struct */ /* Copy amount of used shared data back to the wrapper API struct */
cparams->shared_data_size = (uint32_t)p.shared_data_size; cparams->shared_data_size = (uint32_t)p.shared_data_size;
/* Stop timer */
shared->timer_vb_select_firmware_exit = VbExGetTimer();
/* Translate return codes */ /* Translate return codes */
if (LOAD_FIRMWARE_SUCCESS == rv) { if (LOAD_FIRMWARE_SUCCESS == rv) {
/* Found good firmware in either A or B */ /* Found good firmware in either A or B */

View File

@@ -17,6 +17,7 @@
VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
VbNvContext vnc; VbNvContext vnc;
VbError_t retval = VBERROR_SUCCESS;
uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED; uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
int is_s3_resume = 0; int is_s3_resume = 0;
uint32_t s3_debug_boot = 0; uint32_t s3_debug_boot = 0;
@@ -36,7 +37,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
return 1; return 1;
} }
shared->timer_load_firmware_start_enter = VbExGetTimer(); shared->timer_vb_init_enter = VbExGetTimer();
/* Copy boot switch flags */ /* Copy boot switch flags */
shared->flags = 0; shared->flags = 0;
@@ -74,6 +75,15 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED); VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED);
} }
/* If the previous boot failed in the firmware somewhere outside of verified
* boot, and recovery is not requested for our own reasons, request recovery
* mode. This gives the calling firmware a way to request recovery if it
* finds something terribly wrong. */
if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
recovery = VBNV_RECOVERY_RO_FIRMWARE;
}
/* If recovery button is pressed, override recovery reason. Note that we /* If recovery button is pressed, override recovery reason. Note that we
* do this in the S3 resume path also. */ * do this in the S3 resume path also. */
if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
@@ -97,11 +107,15 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
/* Copy current recovery reason to shared data */ /* Copy current recovery reason to shared data */
shared->recovery_reason = (uint8_t)recovery; shared->recovery_reason = (uint8_t)recovery;
/* Clear the recovery request, so we won't get stuck in recovery mode */ /* If this is a S3 resume, resume the TPM */
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED); if (is_s3_resume) {
if (TPM_SUCCESS != RollbackS3Resume()) {
// TODO: Handle S3 resume path ourselves, if VB_INIT_FLAG_S3_RESUME /* If we can't resume, just do a full reboot. No need to go to recovery
// (I believe we can do this now...) * mode here, since if the TPM is really broken we'll catch it on the
* next boot. */
retval = 1;
}
}
/* Tear down NV storage */ /* Tear down NV storage */
VbNvTeardown(&vnc); VbNvTeardown(&vnc);
@@ -110,24 +124,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags)); VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
shared->timer_load_firmware_start_exit = VbExGetTimer(); shared->timer_vb_init_exit = VbExGetTimer();
return VBERROR_SUCCESS; return retval;
}
VbError_t VbS3Resume(void) {
/* TODO: handle test errors (requires passing in VbNvContext) */
/* Resume the TPM */
uint32_t status = RollbackS3Resume();
/* 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. */
if (status == TPM_SUCCESS)
return VBERROR_SUCCESS;
else
return 1;
} }

View File

@@ -219,24 +219,67 @@ static VbError_t VbDisplayScreen(VbCommonParams* cparams, uint32_t screen,
return VbExDisplayScreen(screen); return VbExDisplayScreen(screen);
} }
#define DEBUG_INFO_SIZE 512
static VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key) { static VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
if ('\t' == key) { if ('\t' == key) {
/* Tab = display debug info */ /* Tab = display debug info */
char buf[DEBUG_INFO_SIZE] = "";
uint32_t used = 0;
uint32_t i;
/* Redisplay the current screen, to overwrite any previous debug output */ /* Redisplay the current screen, to overwrite any previous debug output */
VbDisplayScreen(cparams, disp_current_screen, 1); VbDisplayScreen(cparams, disp_current_screen, 1);
/* TODO: add real data: /* Add hardware ID */
* - HWID used += Strncat(buf + used, "HWID: ", DEBUG_INFO_SIZE - used);
* - Current recovery request if (0 == gbb->hwid_size ||
* - Boot flags gbb->hwid_offset > cparams->gbb_size ||
gbb->hwid_offset + gbb->hwid_size > cparams->gbb_size) {
VBDEBUG(("VbCheckDisplayKey(): invalid hwid offset/size\n"));
used += Strncat(buf + used, "(INVALID)", DEBUG_INFO_SIZE - used);
} else {
used += Strncat(buf + used, (char*)((uint8_t*)gbb + gbb->hwid_offset),
DEBUG_INFO_SIZE - used);
}
/* Add recovery request */
used += Strncat(buf + used, "\nrecovery_request: 0x",
DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
shared->recovery_reason, 16, 2);
/* Add VbSharedData flags */
used += Strncat(buf + used, "\nVbSD.flags: 0x", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
shared->flags, 16, 8);
/* Add raw contents of VbNvStorage */
used += Strncat(buf + used, "\nVbNv.raw:", DEBUG_INFO_SIZE - used);
for (i = 0; i < VBNV_BLOCK_SIZE; i++) {
used += Strncat(buf + used, " ", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
vnc.raw[i], 16, 2);
}
used += Strncat(buf + used, "\n", DEBUG_INFO_SIZE - used);
/* TODO: add more interesting data:
* - TPM firmware and kernel versions. In the current code, they're
* only filled into VbSharedData by LoadFirmware() and LoadKernel(), and
* since neither of those is called in the recovery path this isn't
* feasible yet.
* - SHA1 of kernel subkey (assuming we always set it in VbSelectFirmware,
* even in recovery mode, where we just copy it from the root key)
* - Information on current disks * - Information on current disks
* - Anything else interesting from cparams and/or nvram * - Anything else interesting from VbNvStorage */
*
* TODO: Add a VbExSnprintf() function for this? */ buf[DEBUG_INFO_SIZE - 1] = '\0';
return VbExDisplayDebugInfo("Testing 1 2 3\nTesting 4 5 6\n"); VBDEBUG(("VbCheckDisplayKey() wants to show '%s'\n", buf));
return VbExDisplayDebugInfo(buf);
} else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key) { } else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key) {
/* Arrow keys = change localization */ /* Arrow keys = change localization */
@@ -505,6 +548,9 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
VBDEBUG(("VbSelectAndLoadKernel() start\n")); VBDEBUG(("VbSelectAndLoadKernel() start\n"));
/* Start timer */
shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
VbExNvStorageRead(vnc.raw); VbExNvStorageRead(vnc.raw);
vnc.raw_changed = 0; vnc.raw_changed = 0;
@@ -563,6 +609,9 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
if (vnc.raw_changed) if (vnc.raw_changed)
VbExNvStorageWrite(vnc.raw); VbExNvStorageWrite(vnc.raw);
/* Stop timer */
shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval)); VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
/* Pass through return value from boot path */ /* Pass through return value from boot path */

View File

@@ -64,9 +64,6 @@ int LoadFirmware(LoadFirmwareParams* params) {
/* Setup NV storage */ /* Setup NV storage */
VbNvSetup(vnc); VbNvSetup(vnc);
/* Start timer */
shared->timer_load_firmware_enter = VbExGetTimer();
/* Handle test errors */ /* Handle test errors */
VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err);
if (VBNV_TEST_ERROR_LOAD_FIRMWARE == test_err) { if (VBNV_TEST_ERROR_LOAD_FIRMWARE == test_err) {
@@ -378,8 +375,6 @@ LoadFirmwareExit:
recovery : VBNV_RECOVERY_NOT_REQUESTED); recovery : VBNV_RECOVERY_NOT_REQUESTED);
VbNvTeardown(vnc); VbNvTeardown(vnc);
shared->timer_load_firmware_exit = VbExGetTimer();
/* Note that we don't reduce params->shared_data_size to shared->data_used, /* Note that we don't reduce params->shared_data_size to shared->data_used,
* since we want to leave space for LoadKernel() to add to the shared data * since we want to leave space for LoadKernel() to add to the shared data
* buffer. */ * buffer. */

View File

@@ -145,7 +145,6 @@ int LoadKernel(LoadKernelParams* params) {
int retval = LOAD_KERNEL_RECOVERY; int retval = LOAD_KERNEL_RECOVERY;
int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
uint64_t timer_enter = VbExGetTimer();
/* Setup NV storage */ /* Setup NV storage */
VbNvSetup(vnc); VbNvSetup(vnc);
@@ -178,19 +177,6 @@ int LoadKernel(LoadKernelParams* params) {
dev_switch = 0; /* Always do a fully verified boot */ dev_switch = 0; /* Always do a fully verified boot */
} }
if (kBootRecovery == boot_mode) {
/* Initialize the shared data structure, since LoadFirmware() didn't do it
* for us. */
if (0 != VbSharedDataInit(shared, params->shared_data_size)) {
/* Error initializing the shared data, but we can keep going. We just
* can't use the shared data. */
VBDEBUG(("Shared data init error\n"));
params->shared_data_size = 0;
shared = NULL;
}
}
if (shared) {
/* Set up tracking for this call. This wraps around if called many times, /* Set up tracking for this call. This wraps around if called many times,
* so we need to initialize the call entry each time. */ * so we need to initialize the call entry each time. */
shcall = shared->lk_calls + (shared->lk_call_count shcall = shared->lk_calls + (shared->lk_call_count
@@ -201,14 +187,12 @@ int LoadKernel(LoadKernelParams* params) {
shcall->sector_size = (uint32_t)params->bytes_per_lba; shcall->sector_size = (uint32_t)params->bytes_per_lba;
shcall->sector_count = params->ending_lba + 1; shcall->sector_count = params->ending_lba + 1;
shared->lk_call_count++; shared->lk_call_count++;
}
/* Handle test errors */ /* Handle test errors */
VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err); VbNvGet(vnc, VBNV_TEST_ERROR_FUNC, &test_err);
if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) { if (VBNV_TEST_ERROR_LOAD_KERNEL == test_err) {
/* Get error code */ /* Get error code */
VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err); VbNvGet(vnc, VBNV_TEST_ERROR_NUM, &test_err);
if (shcall)
shcall->test_error_num = (uint8_t)test_err; shcall->test_error_num = (uint8_t)test_err;
/* Clear test params so we don't repeat the error */ /* Clear test params so we don't repeat the error */
VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0); VbNvSet(vnc, VBNV_TEST_ERROR_FUNC, 0);
@@ -240,7 +224,6 @@ int LoadKernel(LoadKernelParams* params) {
/* Dev firmware should be signed such that it never boots with the dev /* Dev firmware should be signed such that it never boots with the dev
* switch is off; so something is terribly wrong. */ * switch is off; so something is terribly wrong. */
VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n")); VBDEBUG(("LoadKernel() called with dev firmware but dev switch off\n"));
if (shcall)
shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH; shcall->check_result = VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH;
recovery = VBNV_RECOVERY_RW_DEV_MISMATCH; recovery = VBNV_RECOVERY_RW_DEV_MISMATCH;
goto LoadKernelExit; goto LoadKernelExit;
@@ -253,17 +236,14 @@ int LoadKernel(LoadKernelParams* params) {
/* Let the TPM know if we're in recovery mode */ /* Let the TPM know if we're in recovery mode */
if (0 != RollbackKernelRecovery(dev_switch)) { if (0 != RollbackKernelRecovery(dev_switch)) {
VBDEBUG(("Error setting up TPM for recovery kernel\n")); VBDEBUG(("Error setting up TPM for recovery kernel\n"));
if (shcall)
shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR; shcall->flags |= VBSD_LK_FLAG_REC_TPM_INIT_ERROR;
/* Ignore return code, since we need to boot recovery mode to /* Ignore return code, since we need to boot recovery mode to
* fix the TPM. */ * fix the TPM. */
} }
/* Read the key indices from the TPM; ignore any errors */ /* Read the key indices from the TPM; ignore any errors */
if (shared) {
RollbackFirmwareRead(&shared->fw_version_tpm); RollbackFirmwareRead(&shared->fw_version_tpm);
RollbackKernelRead(&shared->kernel_version_tpm); RollbackKernelRead(&shared->kernel_version_tpm);
}
} else { } else {
/* Use the kernel subkey passed from LoadFirmware(). */ /* Use the kernel subkey passed from LoadFirmware(). */
kernel_subkey = &shared->kernel_subkey; kernel_subkey = &shared->kernel_subkey;
@@ -279,7 +259,6 @@ int LoadKernel(LoadKernelParams* params) {
recovery = VBNV_RECOVERY_RW_TPM_ERROR; recovery = VBNV_RECOVERY_RW_TPM_ERROR;
goto LoadKernelExit; goto LoadKernelExit;
} }
if (shared)
shared->kernel_version_tpm = tpm_version; shared->kernel_version_tpm = tpm_version;
} }
@@ -289,7 +268,6 @@ int LoadKernel(LoadKernelParams* params) {
gpt.drive_sectors = params->ending_lba + 1; gpt.drive_sectors = params->ending_lba + 1;
if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) { if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
VBDEBUG(("Unable to read GPT data\n")); VBDEBUG(("Unable to read GPT data\n"));
if (shcall)
shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR; shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
break; break;
} }
@@ -297,7 +275,6 @@ int LoadKernel(LoadKernelParams* params) {
/* Initialize GPT library */ /* Initialize GPT library */
if (GPT_SUCCESS != GptInit(&gpt)) { if (GPT_SUCCESS != GptInit(&gpt)) {
VBDEBUG(("Error parsing GPT\n")); VBDEBUG(("Error parsing GPT\n"));
if (shcall)
shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR; shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
break; break;
} }
@@ -323,7 +300,6 @@ int LoadKernel(LoadKernelParams* params) {
VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
part_start, part_size)); part_start, part_size));
if (shcall) {
/* Set up tracking for this partition. This wraps around if called /* Set up tracking for this partition. This wraps around if called
* many times, so initialize the partition entry each time. */ * many times, so initialize the partition entry each time. */
shpart = shcall->parts + (shcall->kernel_parts_found shpart = shcall->parts + (shcall->kernel_parts_found
@@ -335,7 +311,6 @@ int LoadKernel(LoadKernelParams* params) {
* Adjust here, until cgptlib is fixed. */ * Adjust here, until cgptlib is fixed. */
shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1); shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
shcall->kernel_parts_found++; shcall->kernel_parts_found++;
}
/* Found at least one kernel partition. */ /* Found at least one kernel partition. */
found_partitions++; found_partitions++;
@@ -343,7 +318,6 @@ int LoadKernel(LoadKernelParams* params) {
/* Read the first part of the kernel partition. */ /* Read the first part of the kernel partition. */
if (part_size < kbuf_sectors) { if (part_size < kbuf_sectors) {
VBDEBUG(("Partition too small to hold kernel.\n")); VBDEBUG(("Partition too small to hold kernel.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL; shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
goto bad_kernel; goto bad_kernel;
} }
@@ -351,7 +325,6 @@ int LoadKernel(LoadKernelParams* params) {
if (0 != VbExDiskRead(params->disk_handle, part_start, kbuf_sectors, if (0 != VbExDiskRead(params->disk_handle, part_start, kbuf_sectors,
kbuf)) { kbuf)) {
VBDEBUG(("Unable to read start of partition.\n")); VBDEBUG(("Unable to read start of partition.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_READ_START; shpart->check_result = VBSD_LKP_CHECK_READ_START;
goto bad_kernel; goto bad_kernel;
} }
@@ -360,7 +333,6 @@ int LoadKernel(LoadKernelParams* params) {
key_block = (VbKeyBlockHeader*)kbuf; key_block = (VbKeyBlockHeader*)kbuf;
if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) { if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) {
VBDEBUG(("Verifying key block signature failed.\n")); VBDEBUG(("Verifying key block signature failed.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG; shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
key_block_valid = 0; key_block_valid = 0;
@@ -373,7 +345,6 @@ int LoadKernel(LoadKernelParams* params) {
* block is valid. */ * block is valid. */
if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) { if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) {
VBDEBUG(("Verifying key block hash failed.\n")); VBDEBUG(("Verifying key block hash failed.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH; shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH;
goto bad_kernel; goto bad_kernel;
} }
@@ -384,7 +355,6 @@ int LoadKernel(LoadKernelParams* params) {
(dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
KEY_BLOCK_FLAG_DEVELOPER_0))) { KEY_BLOCK_FLAG_DEVELOPER_0))) {
VBDEBUG(("Key block developer flag mismatch.\n")); VBDEBUG(("Key block developer flag mismatch.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH; shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
key_block_valid = 0; key_block_valid = 0;
} }
@@ -392,7 +362,6 @@ int LoadKernel(LoadKernelParams* params) {
(rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 : (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
KEY_BLOCK_FLAG_RECOVERY_0))) { KEY_BLOCK_FLAG_RECOVERY_0))) {
VBDEBUG(("Key block recovery flag mismatch.\n")); VBDEBUG(("Key block recovery flag mismatch.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH; shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
key_block_valid = 0; key_block_valid = 0;
} }
@@ -402,7 +371,6 @@ int LoadKernel(LoadKernelParams* params) {
if (kBootRecovery != boot_mode) { if (kBootRecovery != boot_mode) {
if (key_version < (tpm_version >> 16)) { if (key_version < (tpm_version >> 16)) {
VBDEBUG(("Key version too old.\n")); VBDEBUG(("Key version too old.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK; shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
key_block_valid = 0; key_block_valid = 0;
} }
@@ -418,7 +386,6 @@ int LoadKernel(LoadKernelParams* params) {
data_key = PublicKeyToRSA(&key_block->data_key); data_key = PublicKeyToRSA(&key_block->data_key);
if (!data_key) { if (!data_key) {
VBDEBUG(("Data key bad.\n")); VBDEBUG(("Data key bad.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE; shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
goto bad_kernel; goto bad_kernel;
} }
@@ -429,7 +396,6 @@ int LoadKernel(LoadKernelParams* params) {
KBUF_SIZE - key_block->key_block_size, KBUF_SIZE - key_block->key_block_size,
data_key))) { data_key))) {
VBDEBUG(("Preamble verification failed.\n")); VBDEBUG(("Preamble verification failed.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE; shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
goto bad_kernel; goto bad_kernel;
} }
@@ -438,12 +404,10 @@ int LoadKernel(LoadKernelParams* params) {
* rollback of the kernel version. */ * rollback of the kernel version. */
combined_version = ((key_version << 16) | combined_version = ((key_version << 16) |
(preamble->kernel_version & 0xFFFF)); (preamble->kernel_version & 0xFFFF));
if (shpart)
shpart->combined_version = (uint32_t)combined_version; shpart->combined_version = (uint32_t)combined_version;
if (key_block_valid && kBootRecovery != boot_mode) { if (key_block_valid && kBootRecovery != boot_mode) {
if (combined_version < tpm_version) { if (combined_version < tpm_version) {
VBDEBUG(("Kernel version too low.\n")); VBDEBUG(("Kernel version too low.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK; shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK;
/* If we're not in developer mode, kernel version must be valid. */ /* If we're not in developer mode, kernel version must be valid. */
if (kBootDev != boot_mode) if (kBootDev != boot_mode)
@@ -452,7 +416,6 @@ int LoadKernel(LoadKernelParams* params) {
} }
VBDEBUG(("Kernel preamble is good.\n")); VBDEBUG(("Kernel preamble is good.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID; shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
/* Check for lowest version from a valid header. */ /* Check for lowest version from a valid header. */
@@ -473,7 +436,6 @@ int LoadKernel(LoadKernelParams* params) {
if ((preamble->body_load_address != (size_t)params->kernel_buffer) && if ((preamble->body_load_address != (size_t)params->kernel_buffer) &&
!(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) { !(params->boot_flags & BOOT_FLAG_SKIP_ADDR_CHECK)) {
VBDEBUG(("Wrong body load address.\n")); VBDEBUG(("Wrong body load address.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS; shpart->check_result = VBSD_LKP_CHECK_BODY_ADDRESS;
goto bad_kernel; goto bad_kernel;
} }
@@ -482,7 +444,6 @@ int LoadKernel(LoadKernelParams* params) {
body_offset = key_block->key_block_size + preamble->preamble_size; body_offset = key_block->key_block_size + preamble->preamble_size;
if (0 != body_offset % blba) { if (0 != body_offset % blba) {
VBDEBUG(("Kernel body not at multiple of sector size.\n")); VBDEBUG(("Kernel body not at multiple of sector size.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET; shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
goto bad_kernel; goto bad_kernel;
} }
@@ -492,7 +453,6 @@ int LoadKernel(LoadKernelParams* params) {
body_sectors = (preamble->body_signature.data_size + blba - 1) / blba; body_sectors = (preamble->body_signature.data_size + blba - 1) / blba;
if (body_sectors * blba > params->kernel_buffer_size) { if (body_sectors * blba > params->kernel_buffer_size) {
VBDEBUG(("Kernel body doesn't fit in memory.\n")); VBDEBUG(("Kernel body doesn't fit in memory.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM; shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
goto bad_kernel; goto bad_kernel;
} }
@@ -500,7 +460,6 @@ int LoadKernel(LoadKernelParams* params) {
/* Verify kernel body fits in the partition */ /* Verify kernel body fits in the partition */
if (body_offset_sectors + body_sectors > part_size) { if (body_offset_sectors + body_sectors > part_size) {
VBDEBUG(("Kernel body doesn't fit in partition.\n")); VBDEBUG(("Kernel body doesn't fit in partition.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART; shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
goto bad_kernel; goto bad_kernel;
} }
@@ -512,7 +471,6 @@ int LoadKernel(LoadKernelParams* params) {
body_sectors, params->kernel_buffer)) { body_sectors, params->kernel_buffer)) {
VBDEBUG(("Unable to read kernel data.\n")); VBDEBUG(("Unable to read kernel data.\n"));
VBPERFEND("VB_RKD"); VBPERFEND("VB_RKD");
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_READ_DATA; shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
goto bad_kernel; goto bad_kernel;
} }
@@ -523,7 +481,6 @@ int LoadKernel(LoadKernelParams* params) {
params->kernel_buffer_size, params->kernel_buffer_size,
&preamble->body_signature, data_key)) { &preamble->body_signature, data_key)) {
VBDEBUG(("Kernel data verification failed.\n")); VBDEBUG(("Kernel data verification failed.\n"));
if (shpart)
shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA; shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
goto bad_kernel; goto bad_kernel;
} }
@@ -535,11 +492,9 @@ int LoadKernel(LoadKernelParams* params) {
/* If we're still here, the kernel is valid. */ /* If we're still here, the kernel is valid. */
/* Save the first good partition we find; that's the one we'll boot */ /* Save the first good partition we find; that's the one we'll boot */
VBDEBUG(("Partition is good.\n")); VBDEBUG(("Partition is good.\n"));
if (shpart) {
shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD; shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
if (key_block_valid) if (key_block_valid)
shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID; shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
}
good_partition_key_block_valid = key_block_valid; good_partition_key_block_valid = key_block_valid;
/* TODO: GPT partitions start at 1, but cgptlib starts them at 0. /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
@@ -597,7 +552,6 @@ int LoadKernel(LoadKernelParams* params) {
/* Handle finding a good partition */ /* Handle finding a good partition */
if (good_partition >= 0) { if (good_partition >= 0) {
VBDEBUG(("Good_partition >= 0\n")); VBDEBUG(("Good_partition >= 0\n"));
if (shcall)
shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION; shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
/* See if we need to update the TPM */ /* See if we need to update the TPM */
@@ -619,7 +573,6 @@ int LoadKernel(LoadKernelParams* params) {
recovery = VBNV_RECOVERY_RW_TPM_ERROR; recovery = VBNV_RECOVERY_RW_TPM_ERROR;
goto LoadKernelExit; goto LoadKernelExit;
} }
if (shared)
shared->kernel_version_tpm = (uint32_t)lowest_version; shared->kernel_version_tpm = (uint32_t)lowest_version;
} }
} }
@@ -641,7 +594,6 @@ int LoadKernel(LoadKernelParams* params) {
/* Success! */ /* Success! */
retval = LOAD_KERNEL_SUCCESS; retval = LOAD_KERNEL_SUCCESS;
} else { } else {
if (shcall)
shcall->check_result = (found_partitions > 0 shcall->check_result = (found_partitions > 0
? VBSD_LKC_CHECK_INVALID_PARTITIONS ? VBSD_LKC_CHECK_INVALID_PARTITIONS
: VBSD_LKC_CHECK_NO_PARTITIONS); : VBSD_LKC_CHECK_NO_PARTITIONS);
@@ -659,20 +611,14 @@ LoadKernelExit:
recovery : VBNV_RECOVERY_NOT_REQUESTED); recovery : VBNV_RECOVERY_NOT_REQUESTED);
VbNvTeardown(vnc); VbNvTeardown(vnc);
if (shared) {
if (shcall)
shcall->return_code = (uint8_t)retval; shcall->return_code = (uint8_t)retval;
/* Save whether the good partition's key block was fully verified */ /* Save whether the good partition's key block was fully verified */
if (good_partition_key_block_valid) if (good_partition_key_block_valid)
shared->flags |= VBSD_KERNEL_KEY_VERIFIED; shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
/* Save timer values */
shared->timer_load_kernel_enter = timer_enter;
shared->timer_load_kernel_exit = VbExGetTimer();
/* Store how much shared data we used, if any */ /* Store how much shared data we used, if any */
params->shared_data_size = shared->data_used; params->shared_data_size = shared->data_used;
}
return retval; return retval;
} }

View File

@@ -1,4 +1,4 @@
/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
*/ */
@@ -65,7 +65,6 @@ int main(void)
TlclGetPermissions(0, 0); TlclGetPermissions(0, 0);
/* vboot_api.h - entry points INTO vboot_reference */ /* vboot_api.h - entry points INTO vboot_reference */
VbS3Resume();
VbInit(0, 0); VbInit(0, 0);
VbSelectFirmware(0, 0); VbSelectFirmware(0, 0);
VbUpdateFirmwareBodyHash(0, 0, 0); VbUpdateFirmwareBodyHash(0, 0, 0);

View File

@@ -277,12 +277,12 @@ char* GetVdatString(char* dest, int size, VdatStringField field)
"LFS=%" PRIu64 ",%" PRIu64 "LFS=%" PRIu64 ",%" PRIu64
" LF=%" PRIu64 ",%" PRIu64 " LF=%" PRIu64 ",%" PRIu64
" LK=%" PRIu64 ",%" PRIu64, " LK=%" PRIu64 ",%" PRIu64,
sh->timer_load_firmware_start_enter, sh->timer_vb_init_enter,
sh->timer_load_firmware_start_exit, sh->timer_vb_init_exit,
sh->timer_load_firmware_enter, sh->timer_vb_select_firmware_enter,
sh->timer_load_firmware_exit, sh->timer_vb_select_firmware_exit,
sh->timer_load_kernel_enter, sh->timer_vb_select_and_load_kernel_enter,
sh->timer_load_kernel_exit); sh->timer_vb_select_and_load_kernel_exit);
break; break;
case VDAT_STRING_LOAD_FIRMWARE_DEBUG: case VDAT_STRING_LOAD_FIRMWARE_DEBUG: