summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2016-10-27 11:20:34 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-12-20 21:56:56 -0800
commit2603675460d75e3941070c44cfe90ba09a40d0ce (patch)
tree716e1a10aca4242cfa17ab27a60459c341ffcc7f
parente5500a319bd34abfd8b13851a4e758fad154f5d4 (diff)
downloadvboot-2603675460d75e3941070c44cfe90ba09a40d0ce.tar.gz
vboot: Split ec software sync to its own file
This was previously done inside vboot_api_kernel. But it has nothing to do with kernel verification; that's just the only place where we could easily put it given that vboot (currently) owns the firmware UI. No outwardly-visible functionality changes. BUG=chromium:611535 BRANCH=none TEST=make runtests; emerge-kevin coreboot depthcharge Change-Id: I8a434eb4449a5a86b129ecac61ad81d0ad55549c Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/404920
-rw-r--r--Makefile5
-rw-r--r--firmware/lib/ec_sync.c387
-rw-r--r--firmware/lib/include/vboot_kernel.h7
-rw-r--r--firmware/lib/vboot_api_kernel.c380
-rw-r--r--tests/ec_sync_tests.c (renamed from tests/vboot_api_kernel3_tests.c)23
-rw-r--r--tests/vboot_api_kernel4_tests.c3
6 files changed, 419 insertions, 386 deletions
diff --git a/Makefile b/Makefile
index d93ad08e..dab004ef 100644
--- a/Makefile
+++ b/Makefile
@@ -331,6 +331,7 @@ VBSLK_SRCS = \
firmware/lib/cgptlib/cgptlib.c \
firmware/lib/cgptlib/cgptlib_internal.c \
firmware/lib/cgptlib/crc32.c \
+ firmware/lib/ec_sync.c \
firmware/lib/gpt_misc.c \
firmware/lib/utility_string.c \
firmware/lib/vboot_api_kernel.c \
@@ -711,6 +712,7 @@ TEST_OBJS += ${TESTLIB_OBJS}
# And some compiled tests.
TEST_NAMES = \
tests/cgptlib_test \
+ tests/ec_sync_tests \
tests/rollback_index3_tests \
tests/sha_benchmark \
tests/utility_string_tests \
@@ -718,7 +720,6 @@ TEST_NAMES = \
tests/vboot_api_devmode_tests \
tests/vboot_api_kernel_tests \
tests/vboot_api_kernel2_tests \
- tests/vboot_api_kernel3_tests \
tests/vboot_api_kernel4_tests \
tests/vboot_api_kernel5_tests \
tests/vboot_api_kernel6_tests \
@@ -1401,6 +1402,7 @@ runtestscripts: test_setup genfuzztestcases
.PHONY: runmisctests
runmisctests: test_setup
+ ${RUNTEST} ${BUILD_RUN}/tests/ec_sync_tests
ifeq (${TPM2_MODE},)
${RUNTEST} ${BUILD_RUN}/tests/tlcl_tests
${RUNTEST} ${BUILD_RUN}/tests/rollback_index2_tests
@@ -1411,7 +1413,6 @@ endif
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_devmode_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel2_tests
- ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel3_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel4_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel5_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel6_tests
diff --git a/firmware/lib/ec_sync.c b/firmware/lib/ec_sync.c
new file mode 100644
index 00000000..e989bbda
--- /dev/null
+++ b/firmware/lib/ec_sync.c
@@ -0,0 +1,387 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * EC software sync routines for vboot
+ */
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "sysincludes.h"
+#include "utility.h"
+#include "vb2_common.h"
+#include "vboot_api.h"
+#include "vboot_common.h"
+#include "vboot_display.h"
+#include "vboot_kernel.h"
+#include "vboot_nvstorage.h"
+
+static void request_recovery(VbNvContext *vnc, uint32_t recovery_request)
+{
+ VB2_DEBUG("request_recovery(%d)\n", (int)recovery_request);
+
+ VbNvSet(vnc, VBNV_RECOVERY_REQUEST, recovery_request);
+}
+
+/**
+ * Wrapper around VbExEcProtect() which sets recovery reason on error.
+ */
+static VbError_t EcProtect(int devidx, enum VbSelectFirmware_t select,
+ VbNvContext *vnc)
+{
+ int rv = VbExEcProtect(devidx, select);
+
+ if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
+ VBDEBUG(("VbExEcProtect() needs reboot\n"));
+ } else if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbExEcProtect() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_PROTECT);
+ }
+ return rv;
+}
+
+static VbError_t EcUpdateImage(int devidx, VbCommonParams *cparams,
+ enum VbSelectFirmware_t select,
+ int *need_update, int in_rw, VbNvContext *vnc)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ int rv;
+ int hash_size;
+ int ec_hash_size;
+ const uint8_t *hash = NULL;
+ const uint8_t *expected = NULL;
+ const uint8_t *ec_hash = NULL;
+ int expected_size;
+ int i;
+ int rw_request = select != VB_SELECT_FIRMWARE_READONLY;
+
+ *need_update = 0;
+ VBDEBUG(("EcUpdateImage() - "
+ "Check for %s update\n", rw_request ? "RW" : "RO"));
+
+ /* Get current EC hash. */
+ rv = VbExEcHashImage(devidx, select, &ec_hash, &ec_hash_size);
+ if (rv) {
+ VBDEBUG(("EcUpdateImage() - "
+ "VbExEcHashImage() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_HASH_FAILED);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ VBDEBUG(("EC-%s hash: ", rw_request ? "RW" : "RO"));
+ for (i = 0; i < ec_hash_size; i++)
+ VBDEBUG(("%02x",ec_hash[i]));
+ VBDEBUG(("\n"));
+
+ /* Get expected EC hash. */
+ rv = VbExEcGetExpectedImageHash(devidx, select, &hash, &hash_size);
+ if (rv) {
+ VBDEBUG(("EcUpdateImage() - "
+ "VbExEcGetExpectedImageHash() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_EXPECTED_HASH);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ if (ec_hash_size != hash_size) {
+ VBDEBUG(("EcUpdateImage() - "
+ "EC uses %d-byte hash, but AP-RW contains %d bytes\n",
+ ec_hash_size, hash_size));
+ request_recovery(vnc, VBNV_RECOVERY_EC_HASH_SIZE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("Expected hash: "));
+ for (i = 0; i < hash_size; i++)
+ VBDEBUG(("%02x", hash[i]));
+ VBDEBUG(("\n"));
+ *need_update = vb2_safe_memcmp(ec_hash, hash, hash_size);
+
+ if (!*need_update)
+ return VBERROR_SUCCESS;
+
+ /* Get expected EC image */
+ rv = VbExEcGetExpectedImage(devidx, select, &expected, &expected_size);
+ if (rv) {
+ VBDEBUG(("EcUpdateImage() - "
+ "VbExEcGetExpectedImage() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_EXPECTED_IMAGE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ VBDEBUG(("EcUpdateImage() - image len = %d\n", expected_size));
+
+ if (in_rw && rw_request) {
+ /*
+ * Check if BIOS should also load VGA Option ROM when
+ * rebooting to save another reboot if possible.
+ */
+ if ((shared->flags & VBSD_EC_SLOW_UPDATE) &&
+ (shared->flags & VBSD_OPROM_MATTERS) &&
+ !(shared->flags & VBSD_OPROM_LOADED)) {
+ VBDEBUG(("EcUpdateImage() - Reboot to "
+ "load VGA Option ROM\n"));
+ VbNvSet(vnc, VBNV_OPROM_NEEDED, 1);
+ }
+
+ /*
+ * EC is running the wrong RW image. Reboot the EC to
+ * RO so we can update it on the next boot.
+ */
+ VBDEBUG(("EcUpdateImage() - "
+ "in RW, need to update RW, so reboot\n"));
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("EcUpdateImage() updating EC-%s...\n",
+ rw_request ? "RW" : "RO"));
+
+ if (shared->flags & VBSD_EC_SLOW_UPDATE) {
+ VBDEBUG(("EcUpdateImage() - EC is slow. Show WAIT screen.\n"));
+
+ /* Ensure the VGA Option ROM is loaded */
+ if ((shared->flags & VBSD_OPROM_MATTERS) &&
+ !(shared->flags & VBSD_OPROM_LOADED)) {
+ VBDEBUG(("EcUpdateImage() - Reboot to "
+ "load VGA Option ROM\n"));
+ VbNvSet(vnc, VBNV_OPROM_NEEDED, 1);
+ return VBERROR_VGA_OPROM_MISMATCH;
+ }
+
+ VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, vnc);
+ }
+
+ rv = VbExEcUpdateImage(devidx, select, expected, expected_size);
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("EcUpdateImage() - "
+ "VbExEcUpdateImage() returned %d\n", rv));
+
+ /*
+ * The EC may know it needs a reboot. It may need to
+ * unprotect the region before updating, or may need to
+ * reboot after updating. Either way, it's not an error
+ * requiring recovery mode.
+ *
+ * If we fail for any other reason, trigger recovery
+ * mode.
+ */
+ if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
+ request_recovery(vnc, VBNV_RECOVERY_EC_UPDATE);
+
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /* Verify the EC was updated properly */
+ rv = VbExEcHashImage(devidx, select, &ec_hash, &ec_hash_size);
+ if (rv) {
+ VBDEBUG(("EcUpdateImage() - "
+ "VbExEcHashImage() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_HASH_FAILED);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ if (hash_size != ec_hash_size) {
+ VBDEBUG(("EcUpdateImage() - "
+ "VbExEcHashImage() says size %d, not %d\n",
+ ec_hash_size, hash_size));
+ request_recovery(vnc, VBNV_RECOVERY_EC_HASH_SIZE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ VBDEBUG(("Updated EC-%s hash: ", rw_request ? "RW" : "RO"));
+ for (i = 0; i < ec_hash_size; i++)
+ VBDEBUG(("%02x",ec_hash[i]));
+ VBDEBUG(("\n"));
+
+ if (vb2_safe_memcmp(ec_hash, hash, hash_size)){
+ VBDEBUG(("EcUpdateImage() - "
+ "Failed to update EC-%s\n", rw_request ?
+ "RW" : "RO"));
+ request_recovery(vnc, VBNV_RECOVERY_EC_UPDATE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams,
+ VbNvContext *vnc)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ enum VbSelectFirmware_t select_rw =
+ shared->firmware_index ? VB_SELECT_FIRMWARE_B :
+ VB_SELECT_FIRMWARE_A;
+ enum VbSelectFirmware_t select_ro = VB_SELECT_FIRMWARE_READONLY;
+ int in_rw = 0;
+ int ro_try_count = 2;
+ int num_tries = 0;
+ uint32_t try_ro_sync, recovery_request;
+ int rv, updated_rw, updated_ro;
+
+ VBDEBUG(("VbEcSoftwareSync(devidx=%d)\n", devidx));
+
+ /* Determine whether the EC is in RO or RW */
+ rv = VbExEcRunningRW(devidx, &in_rw);
+
+ if (shared->recovery_reason) {
+ /* Recovery mode; just verify the EC is in RO code */
+ if (rv == VBERROR_SUCCESS && in_rw == 1) {
+ /*
+ * EC is definitely in RW firmware. We want it in
+ * read-only code, so preserve the current recovery
+ * reason and reboot.
+ *
+ * We don't reboot on error or unknown EC code, because
+ * we could end up in an endless reboot loop. If we
+ * had some way to track that we'd already rebooted for
+ * this reason, we could retry only once.
+ */
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "want recovery but got EC-RW\n"));
+ request_recovery(vnc, shared->recovery_reason);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
+ return VBERROR_SUCCESS;
+ }
+
+ /*
+ * Not in recovery. If we couldn't determine where the EC was,
+ * reboot to recovery.
+ */
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcRunningRW() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /* If AP is read-only normal, EC should be in its RO code also. */
+ if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
+ /* If EC is in RW code, request reboot back to RO */
+ if (in_rw == 1) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "want RO-normal but got EC-RW\n"));
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /* Protect the RW flash and stay in EC-RO */
+ rv = EcProtect(devidx, select_rw, vnc);
+ if (rv != VBERROR_SUCCESS)
+ return rv;
+
+ rv = VbExEcDisableJump(devidx);
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcDisableJump() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_SOFTWARE_SYNC);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
+ return VBERROR_SUCCESS;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() check for RW update.\n"));
+
+ /* Update the RW Image. */
+ rv = EcUpdateImage(devidx, cparams, select_rw, &updated_rw, in_rw, vnc);
+
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "EcUpdateImage() returned %d\n", rv));
+ return rv;
+ }
+
+ /* Tell EC to jump to its RW image */
+ if (!in_rw) {
+ VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
+ rv = VbExEcJumpToRW(devidx);
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcJumpToRW() returned %x\n", rv));
+
+ /*
+ * If the EC booted RO-normal and a previous AP boot
+ * has called VbExEcStayInRO(), we need to reboot the EC
+ * to unlock the ability to jump to the RW firmware.
+ *
+ * All other errors trigger recovery mode.
+ */
+ if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
+ request_recovery(vnc, VBNV_RECOVERY_EC_JUMP_RW);
+
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ }
+
+ VbNvGet(vnc, VBNV_TRY_RO_SYNC, &try_ro_sync);
+
+ if (!devidx && try_ro_sync &&
+ !(shared->flags & VBSD_BOOT_FIRMWARE_WP_ENABLED)) {
+ /* Reset RO Software Sync NV flag */
+ VbNvSet(vnc, VBNV_TRY_RO_SYNC, 0);
+
+ VbNvGet(vnc, VBNV_RECOVERY_REQUEST, &recovery_request);
+
+ /* Update the RO Image. */
+ while (num_tries < ro_try_count) {
+ VBDEBUG(("VbEcSoftwareSync() RO Software Sync\n"));
+
+ /* Get expected EC-RO Image. */
+ rv = EcUpdateImage(devidx, cparams, select_ro,
+ &updated_ro, in_rw, vnc);
+ if (rv == VBERROR_SUCCESS) {
+ /*
+ * If the RO update had failed, reset the
+ * recovery request.
+ */
+ if (num_tries)
+ request_recovery(vnc, recovery_request);
+ break;
+ } else
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "EcUpdateImage() returned %d\n", rv));
+
+ num_tries++;
+ }
+ }
+ if (rv != VBERROR_SUCCESS)
+ return rv;
+
+ /* Protect RO flash */
+ rv = EcProtect(devidx, select_ro, vnc);
+ if (rv != VBERROR_SUCCESS)
+ return rv;
+
+ /* Protect RW flash */
+ rv = EcProtect(devidx, select_rw, vnc);
+ if (rv != VBERROR_SUCCESS)
+ return rv;
+
+ rv = VbExEcDisableJump(devidx);
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcDisableJump() returned %d\n", rv));
+ request_recovery(vnc, VBNV_RECOVERY_EC_SOFTWARE_SYNC);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /*
+ * Reboot to unload VGA Option ROM if:
+ * - RW update was done
+ * - the system is NOT in developer mode
+ * - the system has slow EC update flag set
+ * - the VGA Option ROM was needed and loaded
+ */
+ if (updated_rw &&
+ !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
+ (shared->flags & VBSD_EC_SLOW_UPDATE) &&
+ (shared->flags & VBSD_OPROM_MATTERS) &&
+ (shared->flags & VBSD_OPROM_LOADED)) {
+ VBDEBUG(("VbEcSoftwareSync() - Reboot to "
+ "unload VGA Option ROM\n"));
+ VbNvSet(vnc, VBNV_OPROM_NEEDED, 0);
+ return VBERROR_VGA_OPROM_MISMATCH;
+ }
+
+
+ return rv;
+}
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h
index 2c69f969..c7134af3 100644
--- a/firmware/lib/include/vboot_kernel.h
+++ b/firmware/lib/include/vboot_kernel.h
@@ -67,7 +67,12 @@ VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p);
/**
* Sync EC device <devidx> firmware to expected version.
+ *
+ * @param devidx EC device index to sync
+ * @param cparams Common vboot params
+ * @param vnc NV storage context
*/
-VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams);
+VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams,
+ VbNvContext *vnc);
#endif /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index e465fc31..7cf8d8a4 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -57,6 +57,12 @@ static void VbSetRecoverySubcode(uint32_t recovery_request)
VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE, recovery_request);
}
+static void VbNvLoad(void)
+{
+ VbExNvStorageRead(vnc.raw);
+ VbNvSetup(&vnc);
+}
+
static void VbNvCommit(void)
{
VbNvTeardown(&vnc);
@@ -694,367 +700,6 @@ VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p)
return VBERROR_SUCCESS;
}
-/**
- * Wrapper around VbExEcProtect() which sets recovery reason on error.
- */
-static VbError_t EcProtect(int devidx, enum VbSelectFirmware_t select)
-{
- int rv = VbExEcProtect(devidx, select);
-
- if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
- VBDEBUG(("VbExEcProtect() needs reboot\n"));
- } else if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbExEcProtect() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_PROTECT);
- }
- return rv;
-}
-
-static VbError_t EcUpdateImage(int devidx, VbCommonParams *cparams,
- enum VbSelectFirmware_t select,
- int *need_update, int in_rw)
-{
- VbSharedDataHeader *shared =
- (VbSharedDataHeader *)cparams->shared_data_blob;
- int rv;
- int hash_size;
- int ec_hash_size;
- const uint8_t *hash = NULL;
- const uint8_t *expected = NULL;
- const uint8_t *ec_hash = NULL;
- int expected_size;
- int i;
- int rw_request = select != VB_SELECT_FIRMWARE_READONLY;
-
- *need_update = 0;
- VBDEBUG(("EcUpdateImage() - "
- "Check for %s update\n", rw_request ? "RW" : "RO"));
-
- /* Get current EC hash. */
- rv = VbExEcHashImage(devidx, select, &ec_hash, &ec_hash_size);
- if (rv) {
- VBDEBUG(("EcUpdateImage() - "
- "VbExEcHashImage() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- VBDEBUG(("EC-%s hash: ", rw_request ? "RW" : "RO"));
- for (i = 0; i < ec_hash_size; i++)
- VBDEBUG(("%02x",ec_hash[i]));
- VBDEBUG(("\n"));
-
- /* Get expected EC hash. */
- rv = VbExEcGetExpectedImageHash(devidx, select, &hash, &hash_size);
- if (rv) {
- VBDEBUG(("EcUpdateImage() - "
- "VbExEcGetExpectedImageHash() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- if (ec_hash_size != hash_size) {
- VBDEBUG(("EcUpdateImage() - "
- "EC uses %d-byte hash, but AP-RW contains %d bytes\n",
- ec_hash_size, hash_size));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("Expected hash: "));
- for (i = 0; i < hash_size; i++)
- VBDEBUG(("%02x", hash[i]));
- VBDEBUG(("\n"));
- *need_update = vb2_safe_memcmp(ec_hash, hash, hash_size);
-
- if (!*need_update)
- return VBERROR_SUCCESS;
-
- /* Get expected EC image */
- rv = VbExEcGetExpectedImage(devidx, select, &expected, &expected_size);
- if (rv) {
- VBDEBUG(("EcUpdateImage() - "
- "VbExEcGetExpectedImage() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- VBDEBUG(("EcUpdateImage() - image len = %d\n", expected_size));
-
- if (in_rw && rw_request) {
- /*
- * Check if BIOS should also load VGA Option ROM when
- * rebooting to save another reboot if possible.
- */
- if ((shared->flags & VBSD_EC_SLOW_UPDATE) &&
- (shared->flags & VBSD_OPROM_MATTERS) &&
- !(shared->flags & VBSD_OPROM_LOADED)) {
- VBDEBUG(("EcUpdateImage() - Reboot to "
- "load VGA Option ROM\n"));
- VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
- }
-
- /*
- * EC is running the wrong RW image. Reboot the EC to
- * RO so we can update it on the next boot.
- */
- VBDEBUG(("EcUpdateImage() - "
- "in RW, need to update RW, so reboot\n"));
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("EcUpdateImage() updating EC-%s...\n",
- rw_request ? "RW" : "RO"));
-
- if (shared->flags & VBSD_EC_SLOW_UPDATE) {
- VBDEBUG(("EcUpdateImage() - EC is slow. Show WAIT screen.\n"));
-
- /* Ensure the VGA Option ROM is loaded */
- if ((shared->flags & VBSD_OPROM_MATTERS) &&
- !(shared->flags & VBSD_OPROM_LOADED)) {
- VBDEBUG(("EcUpdateImage() - Reboot to "
- "load VGA Option ROM\n"));
- VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
- return VBERROR_VGA_OPROM_MISMATCH;
- }
-
- VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
- }
-
- rv = VbExEcUpdateImage(devidx, select, expected, expected_size);
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("EcUpdateImage() - "
- "VbExEcUpdateImage() returned %d\n", rv));
-
- /*
- * The EC may know it needs a reboot. It may need to
- * unprotect the region before updating, or may need to
- * reboot after updating. Either way, it's not an error
- * requiring recovery mode.
- *
- * If we fail for any other reason, trigger recovery
- * mode.
- */
- if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
-
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /* Verify the EC was updated properly */
- rv = VbExEcHashImage(devidx, select, &ec_hash, &ec_hash_size);
- if (rv) {
- VBDEBUG(("EcUpdateImage() - "
- "VbExEcHashImage() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- if (hash_size != ec_hash_size) {
- VBDEBUG(("EcUpdateImage() - "
- "VbExEcHashImage() says size %d, not %d\n",
- ec_hash_size, hash_size));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- VBDEBUG(("Updated EC-%s hash: ", rw_request ? "RW" : "RO"));
- for (i = 0; i < ec_hash_size; i++)
- VBDEBUG(("%02x",ec_hash[i]));
- VBDEBUG(("\n"));
-
- if (vb2_safe_memcmp(ec_hash, hash, hash_size)){
- VBDEBUG(("EcUpdateImage() - "
- "Failed to update EC-%s\n", rw_request ?
- "RW" : "RO"));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- return VBERROR_SUCCESS;
-}
-
-VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams)
-{
- VbSharedDataHeader *shared =
- (VbSharedDataHeader *)cparams->shared_data_blob;
- enum VbSelectFirmware_t select_rw =
- shared->firmware_index ? VB_SELECT_FIRMWARE_B :
- VB_SELECT_FIRMWARE_A;
- enum VbSelectFirmware_t select_ro = VB_SELECT_FIRMWARE_READONLY;
- int in_rw = 0;
- int ro_try_count = 2;
- int num_tries = 0;
- uint32_t try_ro_sync, recovery_request;
- int rv, updated_rw, updated_ro;
-
- VBDEBUG(("VbEcSoftwareSync(devidx=%d)\n", devidx));
-
- /* Determine whether the EC is in RO or RW */
- rv = VbExEcRunningRW(devidx, &in_rw);
-
- if (shared->recovery_reason) {
- /* Recovery mode; just verify the EC is in RO code */
- if (rv == VBERROR_SUCCESS && in_rw == 1) {
- /*
- * EC is definitely in RW firmware. We want it in
- * read-only code, so preserve the current recovery
- * reason and reboot.
- *
- * We don't reboot on error or unknown EC code, because
- * we could end up in an endless reboot loop. If we
- * had some way to track that we'd already rebooted for
- * this reason, we could retry only once.
- */
- VBDEBUG(("VbEcSoftwareSync() - "
- "want recovery but got EC-RW\n"));
- VbSetRecoveryRequest(shared->recovery_reason);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
- return VBERROR_SUCCESS;
- }
-
- /*
- * Not in recovery. If we couldn't determine where the EC was,
- * reboot to recovery.
- */
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - "
- "VbExEcRunningRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /* If AP is read-only normal, EC should be in its RO code also. */
- if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
- /* If EC is in RW code, request reboot back to RO */
- if (in_rw == 1) {
- VBDEBUG(("VbEcSoftwareSync() - "
- "want RO-normal but got EC-RW\n"));
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /* Protect the RW flash and stay in EC-RO */
- rv = EcProtect(devidx, select_rw);
- if (rv != VBERROR_SUCCESS)
- return rv;
-
- rv = VbExEcDisableJump(devidx);
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - "
- "VbExEcDisableJump() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
- return VBERROR_SUCCESS;
- }
-
- VBDEBUG(("VbEcSoftwareSync() check for RW update.\n"));
-
- /* Update the RW Image. */
- rv = EcUpdateImage(devidx, cparams, select_rw, &updated_rw, in_rw);
-
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - "
- "EcUpdateImage() returned %d\n", rv));
- return rv;
- }
-
- /* Tell EC to jump to its RW image */
- if (!in_rw) {
- VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
- rv = VbExEcJumpToRW(devidx);
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - "
- "VbExEcJumpToRW() returned %x\n", rv));
-
- /*
- * If the EC booted RO-normal and a previous AP boot
- * has called VbExEcStayInRO(), we need to reboot the EC
- * to unlock the ability to jump to the RW firmware.
- *
- * All other errors trigger recovery mode.
- */
- if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
-
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- }
-
- VbNvGet(&vnc, VBNV_TRY_RO_SYNC, &try_ro_sync);
-
- if (!devidx && try_ro_sync &&
- !(shared->flags & VBSD_BOOT_FIRMWARE_WP_ENABLED)) {
- /* Reset RO Software Sync NV flag */
- VbNvSet(&vnc, VBNV_TRY_RO_SYNC, 0);
-
- VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery_request);
-
- /* Update the RO Image. */
- while (num_tries < ro_try_count) {
- VBDEBUG(("VbEcSoftwareSync() RO Software Sync\n"));
-
- /* Get expected EC-RO Image. */
- rv = EcUpdateImage(devidx, cparams, select_ro,
- &updated_ro, in_rw);
- if (rv == VBERROR_SUCCESS) {
- /*
- * If the RO update had failed, reset the
- * recovery request.
- */
- if (num_tries)
- VbSetRecoveryRequest(recovery_request);
- break;
- } else
- VBDEBUG(("VbEcSoftwareSync() - "
- "EcUpdateImage() returned %d\n", rv));
-
- num_tries++;
- }
- }
- if (rv != VBERROR_SUCCESS)
- return rv;
-
- /* Protect RO flash */
- rv = EcProtect(devidx, select_ro);
- if (rv != VBERROR_SUCCESS)
- return rv;
-
- /* Protect RW flash */
- rv = EcProtect(devidx, select_rw);
- if (rv != VBERROR_SUCCESS)
- return rv;
-
- rv = VbExEcDisableJump(devidx);
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - "
- "VbExEcDisableJump() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /*
- * Reboot to unload VGA Option ROM if:
- * - RW update was done
- * - the system is NOT in developer mode
- * - the system has slow EC update flag set
- * - the VGA Option ROM was needed and loaded
- */
- if (updated_rw &&
- !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
- (shared->flags & VBSD_EC_SLOW_UPDATE) &&
- (shared->flags & VBSD_OPROM_MATTERS) &&
- (shared->flags & VBSD_OPROM_LOADED)) {
- VBDEBUG(("VbEcSoftwareSync() - Reboot to "
- "unload VGA Option ROM\n"));
- VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
- return VBERROR_VGA_OPROM_MISMATCH;
- }
-
-
- return rv;
-}
-
/* This function is also used by tests */
void VbApiKernelFree(VbCommonParams *cparams)
{
@@ -1082,8 +727,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
/* Start timer */
shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
- VbExNvStorageRead(vnc.raw);
- VbNvSetup(&vnc);
+ VbNvLoad();
/* Fill in params for calls to LoadKernel() */
memset(&p, 0, sizeof(p));
@@ -1118,7 +762,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
!(cparams->gbb->flags & GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)) {
int oprom_mismatch = 0;
- retval = VbEcSoftwareSync(0, cparams);
+ retval = VbEcSoftwareSync(0, cparams, &vnc);
/* Save reboot requested until after possible PD sync */
if (retval == VBERROR_VGA_OPROM_MISMATCH)
oprom_mismatch = 1;
@@ -1128,7 +772,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
#ifdef PD_SYNC
if (!(cparams->gbb->flags &
GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) {
- retval = VbEcSoftwareSync(1, cparams);
+ retval = VbEcSoftwareSync(1, cparams, &vnc);
if (retval == VBERROR_VGA_OPROM_MISMATCH)
oprom_mismatch = 1;
else if (retval != VBERROR_SUCCESS)
@@ -1380,8 +1024,7 @@ VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams,
*/
dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON;
- VbExNvStorageRead(vnc.raw);
- VbNvSetup(&vnc);
+ VbNvLoad();
VbNvGet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP,
&allow_fastboot_full_cap);
@@ -1519,8 +1162,7 @@ VbError_t VbUnlockDevice(void)
VbError_t VbLockDevice(void)
{
- VbExNvStorageRead(vnc.raw);
- VbNvSetup(&vnc);
+ VbNvLoad();
VBDEBUG(("%s() - Storing request to leave dev-mode.\n",
__func__));
diff --git a/tests/vboot_api_kernel3_tests.c b/tests/ec_sync_tests.c
index 3eddb739..28a6a143 100644
--- a/tests/vboot_api_kernel3_tests.c
+++ b/tests/ec_sync_tests.c
@@ -47,6 +47,7 @@ static int mock_ec_rw_hash_size;
static uint8_t want_ec_hash[32];
static uint8_t update_hash;
static int want_ec_hash_size;
+static VbNvContext mock_vnc;
static uint32_t screens_displayed[8];
static uint32_t screens_count = 0;
@@ -64,13 +65,9 @@ static void ResetMocks(void)
gbb.minor_version = GBB_MINOR_VER;
gbb.flags = 0;
- /*
- * Only the outermost vboot_api_kernel call sets vboot_api_kernel's
- * vnc. So clear it here too.
- */
- memset(VbApiKernelGetVnc(), 0, sizeof(VbNvContext));
- VbNvSetup(VbApiKernelGetVnc());
- VbNvTeardown(VbApiKernelGetVnc()); /* So CRC gets generated */
+ memset(&mock_vnc, 0, sizeof(VbNvContext));
+ VbNvSetup(&mock_vnc);
+ VbNvTeardown(&mock_vnc); /* So CRC gets generated */
memset(&shared_data, 0, sizeof(shared_data));
VbSharedDataInit(shared, sizeof(shared_data));
@@ -207,8 +204,8 @@ static void test_ssync(VbError_t retval, int recovery_reason, const char *desc)
{
uint32_t u;
- TEST_EQ(VbEcSoftwareSync(0, &cparams), retval, desc);
- VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(VbEcSoftwareSync(0, &cparams, &mock_vnc), retval, desc);
+ VbNvGet(&mock_vnc, VBNV_RECOVERY_REQUEST, &u);
TEST_EQ(u, recovery_reason, " recovery reason");
}
@@ -300,7 +297,7 @@ static void VbSoftwareSyncTest(void)
ResetMocks();
mock_ec_rw_hash[0]++;
- VbNvSet(VbApiKernelGetVnc(), VBNV_TRY_RO_SYNC, 1);
+ VbNvSet(&mock_vnc, VBNV_TRY_RO_SYNC, 1);
test_ssync(0, 0, "Update rw without reboot");
TEST_EQ(ec_rw_protected, 1, " ec rw protected");
TEST_EQ(ec_run_image, 1, " ec run image");
@@ -311,7 +308,7 @@ static void VbSoftwareSyncTest(void)
ResetMocks();
mock_ec_rw_hash[0]++;
mock_ec_ro_hash[0]++;
- VbNvSet(VbApiKernelGetVnc(), VBNV_TRY_RO_SYNC, 1);
+ VbNvSet(&mock_vnc, VBNV_TRY_RO_SYNC, 1);
test_ssync(0, 0, "Update rw and ro images without reboot");
TEST_EQ(ec_rw_protected, 1, " ec rw protected");
TEST_EQ(ec_run_image, 1, " ec run image");
@@ -321,7 +318,7 @@ static void VbSoftwareSyncTest(void)
ResetMocks();
shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
- VbNvSet(VbApiKernelGetVnc(), VBNV_TRY_RO_SYNC, 1);
+ VbNvSet(&mock_vnc, VBNV_TRY_RO_SYNC, 1);
mock_ec_rw_hash[0]++;
mock_ec_ro_hash[0]++;
test_ssync(0, 0, "WP enabled");
@@ -332,7 +329,7 @@ static void VbSoftwareSyncTest(void)
TEST_EQ(ec_ro_updated, 0, " ec ro updated");
ResetMocks();
- VbNvSet(VbApiKernelGetVnc(), VBNV_TRY_RO_SYNC, 1);
+ VbNvSet(&mock_vnc, VBNV_TRY_RO_SYNC, 1);
mock_ec_ro_hash[0]++;
test_ssync(0, 0, "rw update not needed");
TEST_EQ(ec_rw_protected, 1, " ec rw protected");
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
index 401c61d5..7e4b47dd 100644
--- a/tests/vboot_api_kernel4_tests.c
+++ b/tests/vboot_api_kernel4_tests.c
@@ -81,7 +81,8 @@ VbError_t VbExNvStorageWrite(const uint8_t *buf)
return VBERROR_SUCCESS;
}
-VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams)
+VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams,
+ VbNvContext *vnc)
{
return ecsync_retval;
}