Refactor TPM calls into vboot wrapper

Try #2, now that ARM has the fix from http://gerrit.chromium.org/gerrit/4667

This cleans up the TPM calls inside vboot_reference.
* TPM calls share mode code between boot modes.
* Better handling for TPM_E_MUST_REBOOT, particularly in recovery mode.
* TAB screen shows current TPM versions.

No changes required to the wrapper API; these changes are internal to vboot.

BUG=chromium-os:18084
TEST=make && make runtests; built for both alex and tegra2-seaboard

Original-Change-Id: I2a52066f2889210af83409872b10f9d6380470af
(cherry picked from commit da55560cddcf7a1aa8a881cdf52792a21a01e766)

Change-Id: I120797145772116f09b8125b9e56fdbb11dc16b3
Reviewed-on: http://gerrit.chromium.org/gerrit/4671
Tested-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Randall Spangler
2011-07-22 14:06:51 -07:00
parent e11860ea47
commit 22e7bb2b8e
11 changed files with 257 additions and 339 deletions

View File

@@ -7,6 +7,7 @@
#include "gbb_header.h"
#include "load_kernel_fw.h"
#include "rollback_index.h"
#include "utility.h"
#include "vboot_api.h"
#include "vboot_common.h"
@@ -268,14 +269,18 @@ static VbError_t VbDisplayDebugInfo(VbCommonParams* cparams) {
used += Strncat(buf + used, "\ndev_boot_usb: ", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
/* Add TPM versions */
used += Strncat(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
shared->fw_version_tpm, 16, 8);
used += Strncat(buf + used, " kernver=0x", DEBUG_INFO_SIZE - used);
used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
shared->kernel_version_tpm, 16, 8);
/* Make sure we finish with a newline */
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
@@ -322,12 +327,11 @@ static VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key) {
}
/* Return codes fof VbTryLoadKernel, in addition to VBERROR_SUCCESS */
/* 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,
/* Need to reboot to same mode/recovery reason as this boot */
VBERROR_TRY_LOAD_REBOOT = 2,
/* Some other error; go to recovery mode if this was the only hope to boot */
VBERROR_TRY_LOAD_RECOVERY = 3,
};
@@ -338,7 +342,6 @@ enum VbTryLoadKernelError_t {
* VBERROR_TRY_LOAD_* for additional return codes. */
uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
uint32_t get_info_flags) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
int retval = VBERROR_TRY_LOAD_NO_DISKS;
VbDiskInfo* disk_info = NULL;
uint32_t disk_count = 0;
@@ -369,10 +372,10 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
retval = LoadKernel(p);
VBDEBUG(("VbTryLoadKernel() LoadKernel() returned %d\n", retval));
/* Stop now if we found a kernel or we need to reboot */
/* 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 || LOAD_KERNEL_REBOOT == retval)
if (LOAD_KERNEL_SUCCESS == retval)
break;
}
@@ -386,10 +389,6 @@ uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
switch (retval) {
case LOAD_KERNEL_SUCCESS:
return VBERROR_SUCCESS;
case LOAD_KERNEL_REBOOT:
/* Reboot to same mode, so reuse the current recovery reason */
VbSetRecoveryRequest(shared->recovery_reason);
return VBERROR_TRY_LOAD_REBOOT;
case LOAD_KERNEL_NOT_FOUND:
VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_OS);
return VBERROR_TRY_LOAD_RECOVERY;
@@ -554,8 +553,6 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
if (VBERROR_SUCCESS == retval)
break; /* Found a recovery kernel */
else if (VBERROR_TRY_LOAD_REBOOT == retval)
return 1; /* Must reboot (back into recovery mode) */
VbDisplayScreen(cparams, VBERROR_TRY_LOAD_NO_DISKS == retval ?
VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD, 0);
@@ -579,6 +576,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
VbError_t retval = VBERROR_SUCCESS;
LoadKernelParams p;
uint32_t tpm_status = 0;
VBDEBUG(("VbSelectAndLoadKernel() start\n"));
@@ -595,6 +593,18 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
kparams->bootloader_size = 0;
Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
/* Read the kernel version from the TPM. Ignore errors in recovery mode. */
tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
if (0 != tpm_status) {
VBDEBUG(("Unable to get kernel versions from TPM\n"));
if (!shared->recovery_reason) {
VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_ERROR);
retval = 1;
goto VbSelectAndLoadKernel_exit;
}
}
shared->kernel_version_tpm_start = shared->kernel_version_tpm;
/* Fill in params for calls to LoadKernel() */
Memset(&p, 0, sizeof(p));
p.shared_data_blob = cparams->shared_data_blob;
@@ -620,6 +630,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
VBDEBUG(("Developer firmware called with dev switch off!\n"));
VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH);
retval = 1;
goto VbSelectAndLoadKernel_exit;
}
#else
/* Recovery firmware, or merged normal+developer firmware. No
@@ -627,32 +638,63 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
#endif
/* Select boot path */
if (VBERROR_SUCCESS != retval) {
/* Failure during setup; don't attempt booting a kernel */
} else if (shared->recovery_reason) {
if (shared->recovery_reason) {
/* Recovery boot */
p.boot_flags |= BOOT_FLAG_RECOVERY;
retval = VbBootRecovery(cparams, &p);
VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0);
} else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
/* Developer boot */
retval = VbBootDeveloper(cparams, &p);
VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0);
} else {
/* Normal boot */
retval = VbBootNormal(cparams, &p);
/* See if we need to update the TPM. */
if (!((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED))) {
/* We don't advance the TPM if we're trying a new firmware B, because
* that firmware may have a key change and roll forward the TPM too
* soon. */
VBDEBUG(("Checking if TPM kernel version needs advancing\n"));
if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) {
tpm_status = RollbackKernelWrite(shared->kernel_version_tpm);
if (0 != tpm_status) {
VBDEBUG(("Error writing kernel versions to TPM.\n"));
VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_ERROR);
retval = 1;
goto VbSelectAndLoadKernel_exit;
}
}
}
}
if (VBERROR_SUCCESS == retval) {
/* Save disk parameters */
kparams->disk_handle = p.disk_handle;
kparams->partition_number = (uint32_t)p.partition_number;
kparams->bootloader_address = p.bootloader_address;
kparams->bootloader_size = (uint32_t)p.bootloader_size;
Memcpy(kparams->partition_guid, p.partition_guid,
sizeof(kparams->partition_guid));
if (VBERROR_SUCCESS != retval)
goto VbSelectAndLoadKernel_exit;
/* Save disk parameters */
kparams->disk_handle = p.disk_handle;
kparams->partition_number = (uint32_t)p.partition_number;
kparams->bootloader_address = p.bootloader_address;
kparams->bootloader_size = (uint32_t)p.bootloader_size;
Memcpy(kparams->partition_guid, p.partition_guid,
sizeof(kparams->partition_guid));
/* Lock the kernel versions. Ignore errors in recovery mode. */
tpm_status = RollbackKernelLock();
if (0 != tpm_status) {
VBDEBUG(("Error locking kernel versions.\n"));
if (!shared->recovery_reason) {
VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_ERROR);
retval = 1;
goto VbSelectAndLoadKernel_exit;
}
}
VbSelectAndLoadKernel_exit:
if (vnc.raw_changed)
VbExNvStorageWrite(vnc.raw);