summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-02-04 15:00:09 -0800
committerChromeBot <chrome-bot@google.com>2013-02-06 17:38:03 -0800
commit5ca4ea087a3d67c2a639e8b9254f51f076bf85fa (patch)
treebd5de84d148b867c9cb342815bb2cf858c45557b
parent9a8e79cc2642381b24078b5ebb2dff7558f10c62 (diff)
downloadvboot-5ca4ea087a3d67c2a639e8b9254f51f076bf85fa.tar.gz
EC software sync uses precomputed hash if available
This removes the need to load the EC code at all when the precomputed hash matches. BUG=chrome-os-partner:17606 BRANCH=spring TEST=wouldn't that be nice Change-Id: If4438b9db8b1449b8fd4d90ef3acb3bbec5e09a0 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/42567
-rw-r--r--firmware/include/vboot_nvstorage.h4
-rw-r--r--firmware/lib/vboot_api_kernel.c98
-rw-r--r--firmware/lib/vboot_display.c6
-rw-r--r--firmware/stub/vboot_api_stub.c13
4 files changed, 102 insertions, 19 deletions
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h
index 890af4b6..943a5664 100644
--- a/firmware/include/vboot_nvstorage.h
+++ b/firmware/include/vboot_nvstorage.h
@@ -142,6 +142,10 @@ typedef enum VbNvParam {
#define VBNV_RECOVERY_EC_JUMP_RW 0x27
/* EC software sync - unable to protect / unprotect EC-RW */
#define VBNV_RECOVERY_EC_PROTECT 0x28
+/* EC software sync - error obtaining expected EC hash */
+#define VBNV_RECOVERY_EC_EXPECTED_HASH 0x29
+/* EC software sync - expected EC image doesn't match hash */
+#define VBNV_RECOVERY_EC_HASH_MISMATCH 0x2A
/* Unspecified/unknown error in read-only firmware */
#define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F
/*
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 3a385d2d..c7213ede 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -555,12 +555,14 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams)
(VbSharedDataHeader *)cparams->shared_data_blob;
int in_rw = 0;
int rv;
- const uint8_t *ec_hash;
+ const uint8_t *ec_hash = NULL;
int ec_hash_size;
- const uint8_t *expected;
+ const uint8_t *rw_hash = NULL;
+ int rw_hash_size;
+ const uint8_t *expected = NULL;
int expected_size;
uint8_t expected_hash[SHA256_DIGEST_SIZE];
- int need_update;
+ int need_update = 0;
int i;
/* Determine whether the EC is in RO or RW */
@@ -660,29 +662,87 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams)
VBDEBUG(("\n"));
/*
- * Get expected EC-RW code. Note that we've already checked for
+ * Get expected EC-RW hash. Note that we've already checked for
* RO_NORMAL, so we know that the BIOS must be RW-A or RW-B, and
* therefore the EC must match.
*/
- rv = VbExEcGetExpectedRW(shared->firmware_index ?
+ rv = VbExEcGetExpectedRWHash(shared->firmware_index ?
VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
- &expected, &expected_size);
- if (rv) {
+ &rw_hash, &rw_hash_size);
+
+ if (rv == VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE) {
+ /*
+ * BIOS has verified EC image but doesn't have a precomputed
+ * hash for it, so we must compute the hash ourselves.
+ */
+ rw_hash = NULL;
+ } else if (rv) {
VBDEBUG(("VbEcSoftwareSync() - "
- "VbExEcGetExpectedRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
+ "VbExEcGetExpectedRWHash() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ } else if (rw_hash_size != SHA256_DIGEST_SIZE) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRWHash() says size %d, not %d\n",
+ rw_hash_size, SHA256_DIGEST_SIZE));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ } else {
+ VBDEBUG(("Expected hash:"));
+ for (i = 0; i < SHA256_DIGEST_SIZE; i++)
+ VBDEBUG(("%02x", rw_hash[i]));
+ VBDEBUG(("\n"));
+
+ need_update = SafeMemcmp(ec_hash, rw_hash, SHA256_DIGEST_SIZE);
}
- VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n", expected_size));
- /* Hash expected code */
- internal_SHA256(expected, expected_size, expected_hash);
- VBDEBUG(("Expected hash:"));
- for (i = 0; i < SHA256_DIGEST_SIZE; i++)
- VBDEBUG(("%02x", expected_hash[i]));
- VBDEBUG(("\n"));
+ /*
+ * Get expected EC-RW image if we're sure we need to update (because the
+ * expected hash didn't match the EC) or we still don't know (because
+ * there was no expected hash and we need the image to compute one
+ * ourselves).
+ */
+ if (need_update || !rw_hash) {
+ /* Get expected EC-RW image */
+ rv = VbExEcGetExpectedRW(shared->firmware_index ?
+ VB_SELECT_FIRMWARE_B :
+ VB_SELECT_FIRMWARE_A,
+ &expected, &expected_size);
+ if (rv) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n",
+ expected_size));
+
+ /* Hash expected image */
+ internal_SHA256(expected, expected_size, expected_hash);
+ VBDEBUG(("Computed hash of expected image:"));
+ for (i = 0; i < SHA256_DIGEST_SIZE; i++)
+ VBDEBUG(("%02x", expected_hash[i]));
+ VBDEBUG(("\n"));
+ }
- need_update = SafeMemcmp(ec_hash, expected_hash, SHA256_DIGEST_SIZE);
+ if (!rw_hash) {
+ /*
+ * BIOS didn't have expected EC hash, so check if we need
+ * update by comparing EC hash to the one we just computed.
+ */
+ need_update = SafeMemcmp(ec_hash, expected_hash,
+ SHA256_DIGEST_SIZE);
+ } else if (need_update &&
+ SafeMemcmp(rw_hash, expected_hash, SHA256_DIGEST_SIZE)) {
+ /*
+ * We need to update, but the expected EC image doesn't match
+ * the expected EC hash we were given.
+ */
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_MISMATCH);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
/*
* TODO: GBB flag to override whether we need update; needed for EC
@@ -692,7 +752,7 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams)
if (in_rw) {
if (need_update) {
/*
- * EC is running the wrong RW code. Reboot the EC to
+ * EC is running the wrong RW image. Reboot the EC to
* RO so we can update it on the next boot.
*/
VBDEBUG(("VbEcSoftwareSync() - "
@@ -747,7 +807,7 @@ VbError_t VbEcSoftwareSync(VbCommonParams *cparams)
if (rv != VBERROR_SUCCESS)
return rv;
- /* Tell EC to jump to its RW code */
+ /* Tell EC to jump to its RW image */
VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
rv = VbExEcJumpToRW();
if (rv != VBERROR_SUCCESS) {
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index b5488486..bd86d654 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -497,6 +497,12 @@ const char *RecoveryReasonString(uint8_t code)
case VBNV_RECOVERY_EC_EXPECTED_IMAGE:
return "EC software sync error "
"obtaining expected EC image from BIOS";
+ case VBNV_RECOVERY_EC_EXPECTED_HASH:
+ return "EC software sync error "
+ "obtaining expected EC hash from BIOS";
+ case VBNV_RECOVERY_EC_HASH_MISMATCH:
+ return "EC software sync error "
+ "comparing expected EC hash and image";
case VBNV_RECOVERY_EC_UPDATE:
return "EC software sync error updating EC";
case VBNV_RECOVERY_EC_JUMP_RW:
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c
index 8521db0e..dd0d5d4b 100644
--- a/firmware/stub/vboot_api_stub.c
+++ b/firmware/stub/vboot_api_stub.c
@@ -181,6 +181,19 @@ VbError_t VbExEcGetExpectedRW(enum VbSelectFirmware_t select,
return VBERROR_SUCCESS;
}
+/**
+ * Read the SHA-256 hash of the expected contents of the EC image associated
+ * with the main firmware specified by the "select" argument.
+ */
+VbError_t VbExEcGetExpectedRWHash(enum VbSelectFirmware_t select,
+ const uint8_t **hash, int *hash_size) {
+ static const uint8_t fake_hash[32] = {1, 2, 3, 4};
+
+ *hash = fake_hash;
+ *hash_size = sizeof(fake_hash);
+ return VBERROR_SUCCESS;
+}
+
VbError_t VbExEcUpdateRW(const uint8_t *image, int image_size) {
return VBERROR_SUCCESS;
}