From 9d683f60244f95caf8662d6545fae574fe134bce Mon Sep 17 00:00:00 2001 From: Joel Kitching Date: Tue, 22 Oct 2019 15:51:32 +0800 Subject: vboot: move ec_sync to vboot2 namespace Move ec_sync.c to vboot2 namespace. Keep its API in vboot_api.h for the time being. BUG=b:124141368, chromium:1016688, b:112198832, b:143094352 TEST=make clean && make runtests BRANCH=none Change-Id: Ia925e93ecdcdb1a2a2724336774f48dbe0439743 Signed-off-by: Joel Kitching Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1872254 Tested-by: Joel Kitching Commit-Queue: Sean Abraham Reviewed-by: Julius Werner Reviewed-by: Furquan Shaikh --- Makefile | 6 +- firmware/2lib/2ec_sync.c | 580 +++++++++++++++++++++++++++++++++++++++ firmware/2lib/include/2ec_sync.h | 93 +++++++ firmware/lib/ec_sync.c | 580 --------------------------------------- firmware/lib/include/ec_sync.h | 94 ------- firmware/lib/vboot_api_kernel.c | 2 +- firmware/lib/vboot_ui.c | 2 +- firmware/lib/vboot_ui_menu.c | 2 +- tests/ec_sync_tests.c | 508 ---------------------------------- tests/vb2_ec_sync_tests.c | 508 ++++++++++++++++++++++++++++++++++ tests/vboot_api_kernel4_tests.c | 2 +- 11 files changed, 1188 insertions(+), 1189 deletions(-) create mode 100644 firmware/2lib/2ec_sync.c create mode 100644 firmware/2lib/include/2ec_sync.h delete mode 100644 firmware/lib/ec_sync.c delete mode 100644 firmware/lib/include/ec_sync.h delete mode 100644 tests/ec_sync_tests.c create mode 100644 tests/vb2_ec_sync_tests.c diff --git a/Makefile b/Makefile index 9972f3da..1a483800 100644 --- a/Makefile +++ b/Makefile @@ -338,7 +338,6 @@ FWLIB_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 \ @@ -356,6 +355,7 @@ FWLIB2X_SRCS = \ firmware/2lib/2api.c \ firmware/2lib/2common.c \ firmware/2lib/2crc8.c \ + firmware/2lib/2ec_sync.c \ firmware/2lib/2gbb.c \ firmware/2lib/2misc.c \ firmware/2lib/2nvstorage.c \ @@ -678,7 +678,6 @@ TEST_OBJS += ${TESTLIB_OBJS} # And some compiled tests. TEST_NAMES = \ tests/cgptlib_test \ - tests/ec_sync_tests \ tests/sha_benchmark \ tests/utility_string_tests \ tests/vboot_api_devmode_tests \ @@ -709,6 +708,7 @@ TEST_NAMES += ${TEST_FUTIL_NAMES} TEST2X_NAMES = \ tests/vb2_api_tests \ tests/vb2_common_tests \ + tests/vb2_ec_sync_tests \ tests/vb2_gbb_tests \ tests/vb2_misc_tests \ tests/vb2_nvstorage_tests \ @@ -1246,7 +1246,6 @@ runtestscripts: test_setup genfuzztestcases .PHONY: runmisctests runmisctests: test_setup - ${RUNTEST} ${BUILD_RUN}/tests/ec_sync_tests ifeq (${TPM2_MODE}${MOCK_TPM},) # TODO(apronin): tests for TPM2 case? # secdata_tpm_tests and tlcl_tests only work when MOCK_TPM is disabled @@ -1267,6 +1266,7 @@ endif run2tests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/vb2_api_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_common_tests + ${RUNTEST} ${BUILD_RUN}/tests/vb2_ec_sync_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_gbb_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests diff --git a/firmware/2lib/2ec_sync.c b/firmware/2lib/2ec_sync.c new file mode 100644 index 00000000..5857fc87 --- /dev/null +++ b/firmware/2lib/2ec_sync.c @@ -0,0 +1,580 @@ +/* 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 "2common.h" +#include "2ec_sync.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "2sysincludes.h" +#include "vboot_api.h" +#include "vboot_common.h" +#include "vboot_display.h" +#include "vboot_kernel.h" + +#define VB2_SD_FLAG_ECSYNC_RW \ + (VB2_SD_FLAG_ECSYNC_EC_RW | VB2_SD_FLAG_ECSYNC_PD_RW) +#define VB2_SD_FLAG_ECSYNC_ANY \ + (VB2_SD_FLAG_ECSYNC_EC_RO | VB2_SD_FLAG_ECSYNC_RW) +#define VB2_SD_FLAG_ECSYNC_IN_RW \ + (VB2_SD_FLAG_ECSYNC_EC_IN_RW | VB2_SD_FLAG_ECSYNC_PD_IN_RW) + +#define IN_RW(devidx) \ + ((devidx) ? VB2_SD_FLAG_ECSYNC_PD_IN_RW : VB2_SD_FLAG_ECSYNC_EC_IN_RW) + +#define WHICH_EC(devidx, select) \ + ((select) == VB_SELECT_FIRMWARE_READONLY ? VB2_SD_FLAG_ECSYNC_EC_RO : \ + ((devidx) ? VB2_SD_FLAG_ECSYNC_PD_RW : VB2_SD_FLAG_ECSYNC_EC_RW)) + +/* PD doesn't support RW A/B */ +#define RW_AB(devidx) ((devidx) ? 0 : VB2_CONTEXT_EC_EFS) + +static void request_recovery(struct vb2_context *ctx, uint32_t recovery_request) +{ + VB2_DEBUG("request_recovery(%u)\n", recovery_request); + + vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, recovery_request); +} + +/** + * Wrapper around VbExEcProtect() which sets recovery reason on error. + */ +static vb2_error_t protect_ec(struct vb2_context *ctx, int devidx, + enum VbSelectFirmware_t select) +{ + vb2_error_t rv = VbExEcProtect(devidx, select); + + if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) { + VB2_DEBUG("VbExEcProtect() needs reboot\n"); + } else if (rv != VB2_SUCCESS) { + VB2_DEBUG("VbExEcProtect() returned %d\n", rv); + request_recovery(ctx, VB2_RECOVERY_EC_PROTECT); + } + return rv; +} + +/** + * Print a hash to debug output + * + * @param hash Pointer to the hash + * @param hash_size Size of the hash in bytes + * @param desc Description of what's being hashed + */ +static void print_hash(const uint8_t *hash, uint32_t hash_size, + const char *desc) +{ + int i; + + VB2_DEBUG("%s hash: ", desc); + for (i = 0; i < hash_size; i++) + VB2_DEBUG_RAW("%02x", hash[i]); + VB2_DEBUG_RAW("\n"); +} + +static const char *image_name_to_string(enum VbSelectFirmware_t select) +{ + switch (select) { + case VB_SELECT_FIRMWARE_READONLY: + return "RO"; + case VB_SELECT_FIRMWARE_EC_ACTIVE: + return "RW(active)"; + case VB_SELECT_FIRMWARE_EC_UPDATE: + return "RW(update)"; + default: + return "UNKNOWN"; + } +} + +/** + * Check if the hash of the EC code matches the expected hash. + * + * @param ctx Vboot2 context + * @param devidx Index of EC device to check + * @param select Which firmware image to check + * @return VB2_SUCCESS, or non-zero error code. + */ +static vb2_error_t check_ec_hash(struct vb2_context *ctx, int devidx, + enum VbSelectFirmware_t select) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + /* Get current EC hash. */ + const uint8_t *ec_hash = NULL; + int ec_hash_size; + vb2_error_t rv = VbExEcHashImage(devidx, select, &ec_hash, + &ec_hash_size); + if (rv) { + VB2_DEBUG("VbExEcHashImage() returned %d\n", rv); + request_recovery(ctx, VB2_RECOVERY_EC_HASH_FAILED); + return VB2_ERROR_EC_HASH_IMAGE; + } + print_hash(ec_hash, ec_hash_size, image_name_to_string(select)); + + /* Get expected EC hash. */ + const uint8_t *hash = NULL; + int hash_size; + rv = VbExEcGetExpectedImageHash(devidx, select, &hash, &hash_size); + if (rv) { + VB2_DEBUG("VbExEcGetExpectedImageHash() returned %d\n", rv); + request_recovery(ctx, VB2_RECOVERY_EC_EXPECTED_HASH); + return VB2_ERROR_EC_HASH_EXPECTED; + } + if (ec_hash_size != hash_size) { + VB2_DEBUG("EC uses %d-byte hash, but AP-RW contains %d bytes\n", + ec_hash_size, hash_size); + request_recovery(ctx, VB2_RECOVERY_EC_HASH_SIZE); + return VB2_ERROR_EC_HASH_SIZE; + } + + if (vb2_safe_memcmp(ec_hash, hash, hash_size)) { + print_hash(hash, hash_size, "Expected"); + sd->flags |= WHICH_EC(devidx, select); + } + + return VB2_SUCCESS; +} + +/** + * Update the specified EC and verify the update succeeded + * + * @param ctx Vboot2 context + * @param devidx Index of EC device to check + * @param select Which firmware image to check + * @return VB2_SUCCESS, or non-zero error code. + */ +static vb2_error_t update_ec(struct vb2_context *ctx, int devidx, + enum VbSelectFirmware_t select) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + VB2_DEBUG("Updating %s...\n", image_name_to_string(select)); + + /* Get expected EC image */ + const uint8_t *want = NULL; + int want_size; + vb2_error_t rv = VbExEcGetExpectedImage(devidx, select, &want, + &want_size); + if (rv) { + VB2_DEBUG("VbExEcGetExpectedImage() returned %d\n", rv); + request_recovery(ctx, VB2_RECOVERY_EC_EXPECTED_IMAGE); + return rv; + } + VB2_DEBUG("image len = %d\n", want_size); + + rv = VbExEcUpdateImage(devidx, select, want, want_size); + if (rv != VB2_SUCCESS) { + VB2_DEBUG("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(ctx, VB2_RECOVERY_EC_UPDATE); + + return rv; + } + + /* Verify the EC was updated properly */ + sd->flags &= ~WHICH_EC(devidx, select); + if (check_ec_hash(ctx, devidx, select) != VB2_SUCCESS) + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + if (sd->flags & WHICH_EC(devidx, select)) { + VB2_DEBUG("Failed to update\n"); + request_recovery(ctx, VB2_RECOVERY_EC_UPDATE); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + return VB2_SUCCESS; +} + +/** + * Set IN_RW flag for a EC + * + * @param ctx Vboot2 context + * @param devidx Which device (EC=0, PD=1) + */ +static vb2_error_t check_ec_active(struct vb2_context *ctx, int devidx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + int in_rw = 0; + /* + * We don't use VbExTrustEC, which checks EC_IN_RW. It is controlled by + * cr50 but on some platforms, cr50 can't know when a EC resets. So, we + * trust what EC-RW says. If it lies it's in RO, we'll flash RW while + * it's in RW. + */ + vb2_error_t rv = VbExEcRunningRW(devidx, &in_rw); + + /* If we couldn't determine where the EC was, reboot to recovery. */ + if (rv != VB2_SUCCESS) { + VB2_DEBUG("VbExEcRunningRW() returned %d\n", rv); + request_recovery(ctx, VB2_RECOVERY_EC_UNKNOWN_IMAGE); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + if (in_rw) + sd->flags |= IN_RW(devidx); + + return VB2_SUCCESS; +} + +#define RO_RETRIES 2 /* Maximum times to retry flashing RO */ + +/** + * Sync, jump, and protect one EC device + * + * @param ctx Vboot2 context + * @param devidx Which device (EC=0, PD=1) + * @return VB2_SUCCESS, or non-zero if error. + */ +static vb2_error_t sync_one_ec(struct vb2_context *ctx, int devidx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + int is_rw_ab = ctx->flags & RW_AB(devidx); + vb2_error_t rv; + + const enum VbSelectFirmware_t select_rw = is_rw_ab ? + VB_SELECT_FIRMWARE_EC_UPDATE : + VB_SELECT_FIRMWARE_EC_ACTIVE; + VB2_DEBUG("devidx=%d select_rw=%d\n", devidx, select_rw); + + /* Update the RW Image */ + if (sd->flags & WHICH_EC(devidx, select_rw)) { + if (VB2_SUCCESS != update_ec(ctx, devidx, select_rw)) + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + /* Updated successfully. Cold reboot to switch to the new RW. + * TODO: Switch slot and proceed if EC is still in RO. */ + if (is_rw_ab) { + VB2_DEBUG("Rebooting to jump to new EC-RW\n"); + return VBERROR_EC_REBOOT_TO_SWITCH_RW; + } + } + + /* Tell EC to jump to its RW image */ + if (!(sd->flags & IN_RW(devidx))) { + VB2_DEBUG("jumping to EC-RW\n"); + rv = VbExEcJumpToRW(devidx); + if (rv != VB2_SUCCESS) { + VB2_DEBUG("VbExEcJumpToRW() returned %x\n", rv); + + /* + * If 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(ctx, VB2_RECOVERY_EC_JUMP_RW); + + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + } + + /* Might need to update EC-RO (but not PD-RO) */ + if (sd->flags & VB2_SD_FLAG_ECSYNC_EC_RO) { + VB2_DEBUG("RO Software Sync\n"); + + /* Reset RO Software Sync NV flag */ + vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 0); + + /* + * Get the current recovery request (if any). This gets + * overwritten by a failed try. If a later try succeeds, we'll + * need to restore this request (or the lack of a request), or + * else we'll end up in recovery mode even though RO software + * sync did eventually succeed. + */ + uint32_t recovery_request = + vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST); + + /* Update the RO Image. */ + int num_tries; + for (num_tries = 0; num_tries < RO_RETRIES; num_tries++) { + if (VB2_SUCCESS == + update_ec(ctx, devidx, VB_SELECT_FIRMWARE_READONLY)) + break; + } + if (num_tries == RO_RETRIES) { + /* Ran out of tries */ + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } else if (num_tries) { + /* + * Update succeeded after a failure, so we've polluted + * the recovery request. Restore it. + */ + request_recovery(ctx, recovery_request); + } + } + + /* Protect RO flash */ + rv = protect_ec(ctx, devidx, VB_SELECT_FIRMWARE_READONLY); + if (rv != VB2_SUCCESS) + return rv; + + /* Protect RW flash */ + rv = protect_ec(ctx, devidx, select_rw); + if (rv != VB2_SUCCESS) + return rv; + + rv = VbExEcDisableJump(devidx); + if (rv != VB2_SUCCESS) { + VB2_DEBUG("VbExEcDisableJump() returned %d\n", rv); + request_recovery(ctx, VB2_RECOVERY_EC_SOFTWARE_SYNC); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + return rv; +} + +vb2_error_t ec_sync_phase1(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); + + /* Reasons not to do sync at all */ + if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED)) + return VB2_SUCCESS; + if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) + return VB2_SUCCESS; + +#ifdef PD_SYNC + const int do_pd_sync = !(gbb->flags & + VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC); +#else + const int do_pd_sync = 0; +#endif + + /* Set IN_RW flags */ + if (check_ec_active(ctx, 0)) + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + if (do_pd_sync && check_ec_active(ctx, 1)) + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + + /* Check if we need to update RW. Failures trigger recovery mode. */ + if (check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_EC_ACTIVE)) + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + if (do_pd_sync && check_ec_hash(ctx, 1, VB_SELECT_FIRMWARE_EC_ACTIVE)) + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + /* + * See if we need to update EC-RO (devidx=0). + * + * If we want to extend this in the future to update PD-RO, we'll use a + * different NV flag so we can track EC-RO and PD-RO updates + * separately. + */ + if (vb2_nv_get(ctx, VB2_NV_TRY_RO_SYNC) && + check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_READONLY)) { + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + /* + * If we're in RW, we need to reboot back to RO because RW can't be + * updated while we're running it. + * + * If EC supports RW-A/B slots, we can proceed but we need + * to jump to the new RW version later. + */ + if ((sd->flags & VB2_SD_FLAG_ECSYNC_RW) && + (sd->flags & VB2_SD_FLAG_ECSYNC_IN_RW) && + !(ctx->flags & VB2_CONTEXT_EC_EFS)) { + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + return VB2_SUCCESS; +} + +int ec_will_update_slowly(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + return ((sd->flags & VB2_SD_FLAG_ECSYNC_ANY) && + (ctx->flags & VB2_CONTEXT_EC_SYNC_SLOW)); +} + +/** + * determine if we can update the EC + * + * @param ctx Vboot2 context + * @return boolean (true iff we can update the EC) + */ + +static int ec_sync_allowed(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); + + /* Reasons not to do sync at all */ + if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED)) + return 0; + if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) + return 0; + if (sd->recovery_reason) + return 0; + return 1; +} + +vb2_error_t ec_sync_check_aux_fw(struct vb2_context *ctx, + VbAuxFwUpdateSeverity_t *severity) +{ + struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); + + /* If we're not updating the EC, skip aux fw syncs as well */ + if (!ec_sync_allowed(ctx) || + (gbb->flags & VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) { + *severity = VB_AUX_FW_NO_UPDATE; + return VB2_SUCCESS; + } + return VbExCheckAuxFw(severity); +} + +vb2_error_t ec_sync_update_aux_fw(struct vb2_context *ctx) +{ + vb2_error_t rv = VbExUpdateAuxFw(); + if (rv) { + if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) { + VB2_DEBUG("AUX firmware update requires RO reboot.\n"); + } else { + VB2_DEBUG("AUX firmware update/protect failed.\n"); + request_recovery(ctx, VB2_RECOVERY_AUX_FW_UPDATE); + } + } + return rv; +} + +vb2_error_t ec_sync_phase2(struct vb2_context *ctx) +{ + if (!ec_sync_allowed(ctx)) + return VB2_SUCCESS; + + /* Handle updates and jumps for EC */ + vb2_error_t retval = sync_one_ec(ctx, 0); + if (retval != VB2_SUCCESS) + return retval; + +#ifdef PD_SYNC + /* Handle updates and jumps for PD */ + struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); + if (!(gbb->flags & VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) { + retval = sync_one_ec(ctx, 1); + if (retval != VB2_SUCCESS) + return retval; + } +#endif + + return VB2_SUCCESS; +} + +vb2_error_t ec_sync_phase3(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + + /* EC verification (and possibly updating / jumping) is done */ + vb2_error_t rv = VbExEcVbootDone(!!sd->recovery_reason); + if (rv) + return rv; + + /* Check if we need to cut-off battery. This must be done after EC + * firmware updating and before kernel started. */ + if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) { + VB2_DEBUG("Request to cut-off battery\n"); + vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0); + /* May lose power immediately, so commit our update now. */ + vb2_nv_commit(ctx); + VbExEcBatteryCutOff(); + return VBERROR_SHUTDOWN_REQUESTED; + } + + return VB2_SUCCESS; +} + +static int check_reboot_for_display(struct vb2_context *ctx) +{ + if (!(vb2_get_sd(ctx)->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE)) { + VB2_DEBUG("Reboot to initialize display\n"); + vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1); + return 1; + } + return 0; +} + +static void display_wait_screen(struct vb2_context *ctx, const char *fw_name) +{ + VB2_DEBUG("%s update is slow. Show WAIT screen.\n", fw_name); + VbDisplayScreen(ctx, VB_SCREEN_WAIT, 0, NULL); +} + +vb2_error_t ec_sync_all(struct vb2_context *ctx) +{ + VbAuxFwUpdateSeverity_t fw_update = VB_AUX_FW_NO_UPDATE; + vb2_error_t rv; + + /* Phase 1; this determines if we need an update */ + vb2_error_t phase1_rv = ec_sync_phase1(ctx); + int need_wait_screen = ec_will_update_slowly(ctx); + + /* Check if EC SW Sync Phase1 needs reboot */ + if (phase1_rv) { + ec_sync_check_aux_fw(ctx, &fw_update); + /* It does -- speculatively check if we need display as well */ + if (need_wait_screen || fw_update == VB_AUX_FW_SLOW_UPDATE) + check_reboot_for_display(ctx); + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + /* Is EC already in RO and needs slow update? */ + if (need_wait_screen) { + /* Might still need display in that case */ + if (check_reboot_for_display(ctx)) + return VBERROR_REBOOT_REQUIRED; + /* Display is available, so pop up the wait screen */ + display_wait_screen(ctx, "EC FW"); + } + + /* Phase 2; Applies update and/or jumps to the correct EC image */ + rv = ec_sync_phase2(ctx); + if (rv) + return rv; + + /* EC in RW, now we can check the severity of the AUX FW update */ + rv = ec_sync_check_aux_fw(ctx, &fw_update); + if (rv) + return rv; + + /* If AUX FW update is slow display the wait screen */ + if (fw_update == VB_AUX_FW_SLOW_UPDATE) { + /* Display should be available, but better check again */ + if (check_reboot_for_display(ctx)) + return VBERROR_REBOOT_REQUIRED; + display_wait_screen(ctx, "AUX FW"); + } + + if (fw_update > VB_AUX_FW_NO_UPDATE) { + /* Do Aux FW software sync */ + rv = ec_sync_update_aux_fw(ctx); + if (rv) + return rv; + /* + * AUX FW Update is applied successfully. Request EC reboot to + * RO, so that the chips that had FW update gets reset to a + * clean state. + */ + return VBERROR_EC_REBOOT_TO_RO_REQUIRED; + } + + /* Phase 3; Completes sync and handles battery cutoff */ + rv = ec_sync_phase3(ctx); + if (rv) + return rv; + + return VB2_SUCCESS; +} diff --git a/firmware/2lib/include/2ec_sync.h b/firmware/2lib/include/2ec_sync.h new file mode 100644 index 00000000..ebefb9b6 --- /dev/null +++ b/firmware/2lib/include/2ec_sync.h @@ -0,0 +1,93 @@ +/* Copyright 2016 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 for verified boot + */ + +#ifndef VBOOT_REFERENCE_2EC_SYNC_H_ +#define VBOOT_REFERENCE_2EC_SYNC_H_ + +#include "2api.h" +#include "vboot_api.h" + +/** + * EC sync, phase 1 + * + * This checks whether the EC is running the correct image to do EC sync, and + * whether any updates are necessary. + * + * @param ctx Vboot2 context + * @return VB2_SUCCESS, VBERROR_EC_REBOOT_TO_RO_REQUIRED if the EC must + * reboot back to its RO code to continue EC sync, or other non-zero error + * code. + */ +vb2_error_t ec_sync_phase1(struct vb2_context *ctx); + +/** + * Returns non-zero if the EC will perform a slow update during phase 2. + * + * This is only valid after calling ec_sync_phase1(), before calling + * ec_sync_phase2(). + * + * @param ctx Vboot2 context + * @return non-zero if a slow update will be done; zero if no update or a + * fast update. + */ +int ec_will_update_slowly(struct vb2_context *ctx); + +/** + * Check if auxiliary firmware blobs need to be updated. + * + * @param ctx Vboot2 context + * @param severity VB_AUX_FW_{NO,FAST,SLOW}_UPDATE + * @return VB2_SUCCESS or non-zero error code. + */ +vb2_error_t ec_sync_check_aux_fw(struct vb2_context *ctx, + VbAuxFwUpdateSeverity_t *severity); + +/** + * Update and protect auxiliary firmware. + * + * @param ctx Vboot2 context + * @return VB2_SUCCESS or non-zero error code. + */ +vb2_error_t ec_sync_update_aux_fw(struct vb2_context *ctx); + +/** + * EC sync, phase 2 + * + * This updates the EC if necessary, makes sure it has protected its image(s), + * and makes sure it has jumped to the correct image. + * + * If ec_will_update_slowly(), it is suggested that the caller display a + * warning screen before calling phase 2. + * + * @param ctx Vboot2 context + * @return VB2_SUCCESS, VBERROR_EC_REBOOT_TO_RO_REQUIRED if the EC must + * reboot back to its RO code to continue EC sync, or other non-zero error + * code. + */ +vb2_error_t ec_sync_phase2(struct vb2_context *ctx); + +/** + * EC sync, phase 3 + * + * This completes EC sync and handles battery cutoff if needed. + * + * @param ctx Vboot2 context + * @return VB2_SUCCESS or non-zero error code. + */ +vb2_error_t ec_sync_phase3(struct vb2_context *ctx); + +/** + * Sync all EC devices to expected versions. + * + * This is a high-level function which calls the functions above. + * + * @param ctx Vboot context + * @return VB2_SUCCESS, or non-zero if error. + */ +vb2_error_t ec_sync_all(struct vb2_context *ctx); + +#endif /* VBOOT_REFERENCE_2EC_SYNC_H_ */ diff --git a/firmware/lib/ec_sync.c b/firmware/lib/ec_sync.c deleted file mode 100644 index c83b0005..00000000 --- a/firmware/lib/ec_sync.c +++ /dev/null @@ -1,580 +0,0 @@ -/* 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 "2common.h" -#include "2misc.h" -#include "2nvstorage.h" -#include "2sysincludes.h" -#include "ec_sync.h" -#include "vboot_api.h" -#include "vboot_common.h" -#include "vboot_display.h" -#include "vboot_kernel.h" - -#define VB2_SD_FLAG_ECSYNC_RW \ - (VB2_SD_FLAG_ECSYNC_EC_RW | VB2_SD_FLAG_ECSYNC_PD_RW) -#define VB2_SD_FLAG_ECSYNC_ANY \ - (VB2_SD_FLAG_ECSYNC_EC_RO | VB2_SD_FLAG_ECSYNC_RW) -#define VB2_SD_FLAG_ECSYNC_IN_RW \ - (VB2_SD_FLAG_ECSYNC_EC_IN_RW | VB2_SD_FLAG_ECSYNC_PD_IN_RW) - -#define IN_RW(devidx) \ - ((devidx) ? VB2_SD_FLAG_ECSYNC_PD_IN_RW : VB2_SD_FLAG_ECSYNC_EC_IN_RW) - -#define WHICH_EC(devidx, select) \ - ((select) == VB_SELECT_FIRMWARE_READONLY ? VB2_SD_FLAG_ECSYNC_EC_RO : \ - ((devidx) ? VB2_SD_FLAG_ECSYNC_PD_RW : VB2_SD_FLAG_ECSYNC_EC_RW)) - -/* PD doesn't support RW A/B */ -#define RW_AB(devidx) ((devidx) ? 0 : VB2_CONTEXT_EC_EFS) - -static void request_recovery(struct vb2_context *ctx, uint32_t recovery_request) -{ - VB2_DEBUG("request_recovery(%u)\n", recovery_request); - - vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, recovery_request); -} - -/** - * Wrapper around VbExEcProtect() which sets recovery reason on error. - */ -static vb2_error_t protect_ec(struct vb2_context *ctx, int devidx, - enum VbSelectFirmware_t select) -{ - vb2_error_t rv = VbExEcProtect(devidx, select); - - if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) { - VB2_DEBUG("VbExEcProtect() needs reboot\n"); - } else if (rv != VB2_SUCCESS) { - VB2_DEBUG("VbExEcProtect() returned %d\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_PROTECT); - } - return rv; -} - -/** - * Print a hash to debug output - * - * @param hash Pointer to the hash - * @param hash_size Size of the hash in bytes - * @param desc Description of what's being hashed - */ -static void print_hash(const uint8_t *hash, uint32_t hash_size, - const char *desc) -{ - int i; - - VB2_DEBUG("%s hash: ", desc); - for (i = 0; i < hash_size; i++) - VB2_DEBUG_RAW("%02x", hash[i]); - VB2_DEBUG_RAW("\n"); -} - -static const char *image_name_to_string(enum VbSelectFirmware_t select) -{ - switch (select) { - case VB_SELECT_FIRMWARE_READONLY: - return "RO"; - case VB_SELECT_FIRMWARE_EC_ACTIVE: - return "RW(active)"; - case VB_SELECT_FIRMWARE_EC_UPDATE: - return "RW(update)"; - default: - return "UNKNOWN"; - } -} - -/** - * Check if the hash of the EC code matches the expected hash. - * - * @param ctx Vboot2 context - * @param devidx Index of EC device to check - * @param select Which firmware image to check - * @return VB2_SUCCESS, or non-zero error code. - */ -static vb2_error_t check_ec_hash(struct vb2_context *ctx, int devidx, - enum VbSelectFirmware_t select) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - - /* Get current EC hash. */ - const uint8_t *ec_hash = NULL; - int ec_hash_size; - vb2_error_t rv = VbExEcHashImage(devidx, select, &ec_hash, - &ec_hash_size); - if (rv) { - VB2_DEBUG("VbExEcHashImage() returned %d\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_HASH_FAILED); - return VB2_ERROR_EC_HASH_IMAGE; - } - print_hash(ec_hash, ec_hash_size, image_name_to_string(select)); - - /* Get expected EC hash. */ - const uint8_t *hash = NULL; - int hash_size; - rv = VbExEcGetExpectedImageHash(devidx, select, &hash, &hash_size); - if (rv) { - VB2_DEBUG("VbExEcGetExpectedImageHash() returned %d\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_EXPECTED_HASH); - return VB2_ERROR_EC_HASH_EXPECTED; - } - if (ec_hash_size != hash_size) { - VB2_DEBUG("EC uses %d-byte hash, but AP-RW contains %d bytes\n", - ec_hash_size, hash_size); - request_recovery(ctx, VB2_RECOVERY_EC_HASH_SIZE); - return VB2_ERROR_EC_HASH_SIZE; - } - - if (vb2_safe_memcmp(ec_hash, hash, hash_size)) { - print_hash(hash, hash_size, "Expected"); - sd->flags |= WHICH_EC(devidx, select); - } - - return VB2_SUCCESS; -} - -/** - * Update the specified EC and verify the update succeeded - * - * @param ctx Vboot2 context - * @param devidx Index of EC device to check - * @param select Which firmware image to check - * @return VB2_SUCCESS, or non-zero error code. - */ -static vb2_error_t update_ec(struct vb2_context *ctx, int devidx, - enum VbSelectFirmware_t select) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - - VB2_DEBUG("Updating %s...\n", image_name_to_string(select)); - - /* Get expected EC image */ - const uint8_t *want = NULL; - int want_size; - vb2_error_t rv = VbExEcGetExpectedImage(devidx, select, &want, - &want_size); - if (rv) { - VB2_DEBUG("VbExEcGetExpectedImage() returned %d\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_EXPECTED_IMAGE); - return rv; - } - VB2_DEBUG("image len = %d\n", want_size); - - rv = VbExEcUpdateImage(devidx, select, want, want_size); - if (rv != VB2_SUCCESS) { - VB2_DEBUG("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(ctx, VB2_RECOVERY_EC_UPDATE); - - return rv; - } - - /* Verify the EC was updated properly */ - sd->flags &= ~WHICH_EC(devidx, select); - if (check_ec_hash(ctx, devidx, select) != VB2_SUCCESS) - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - if (sd->flags & WHICH_EC(devidx, select)) { - VB2_DEBUG("Failed to update\n"); - request_recovery(ctx, VB2_RECOVERY_EC_UPDATE); - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - return VB2_SUCCESS; -} - -/** - * Set IN_RW flag for a EC - * - * @param ctx Vboot2 context - * @param devidx Which device (EC=0, PD=1) - */ -static vb2_error_t check_ec_active(struct vb2_context *ctx, int devidx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - int in_rw = 0; - /* - * We don't use VbExTrustEC, which checks EC_IN_RW. It is controlled by - * cr50 but on some platforms, cr50 can't know when a EC resets. So, we - * trust what EC-RW says. If it lies it's in RO, we'll flash RW while - * it's in RW. - */ - vb2_error_t rv = VbExEcRunningRW(devidx, &in_rw); - - /* If we couldn't determine where the EC was, reboot to recovery. */ - if (rv != VB2_SUCCESS) { - VB2_DEBUG("VbExEcRunningRW() returned %d\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_UNKNOWN_IMAGE); - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - if (in_rw) - sd->flags |= IN_RW(devidx); - - return VB2_SUCCESS; -} - -#define RO_RETRIES 2 /* Maximum times to retry flashing RO */ - -/** - * Sync, jump, and protect one EC device - * - * @param ctx Vboot2 context - * @param devidx Which device (EC=0, PD=1) - * @return VB2_SUCCESS, or non-zero if error. - */ -static vb2_error_t sync_one_ec(struct vb2_context *ctx, int devidx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - int is_rw_ab = ctx->flags & RW_AB(devidx); - vb2_error_t rv; - - const enum VbSelectFirmware_t select_rw = is_rw_ab ? - VB_SELECT_FIRMWARE_EC_UPDATE : - VB_SELECT_FIRMWARE_EC_ACTIVE; - VB2_DEBUG("devidx=%d select_rw=%d\n", devidx, select_rw); - - /* Update the RW Image */ - if (sd->flags & WHICH_EC(devidx, select_rw)) { - if (VB2_SUCCESS != update_ec(ctx, devidx, select_rw)) - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - /* Updated successfully. Cold reboot to switch to the new RW. - * TODO: Switch slot and proceed if EC is still in RO. */ - if (is_rw_ab) { - VB2_DEBUG("Rebooting to jump to new EC-RW\n"); - return VBERROR_EC_REBOOT_TO_SWITCH_RW; - } - } - - /* Tell EC to jump to its RW image */ - if (!(sd->flags & IN_RW(devidx))) { - VB2_DEBUG("jumping to EC-RW\n"); - rv = VbExEcJumpToRW(devidx); - if (rv != VB2_SUCCESS) { - VB2_DEBUG("VbExEcJumpToRW() returned %x\n", rv); - - /* - * If 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(ctx, VB2_RECOVERY_EC_JUMP_RW); - - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - } - - /* Might need to update EC-RO (but not PD-RO) */ - if (sd->flags & VB2_SD_FLAG_ECSYNC_EC_RO) { - VB2_DEBUG("RO Software Sync\n"); - - /* Reset RO Software Sync NV flag */ - vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 0); - - /* - * Get the current recovery request (if any). This gets - * overwritten by a failed try. If a later try succeeds, we'll - * need to restore this request (or the lack of a request), or - * else we'll end up in recovery mode even though RO software - * sync did eventually succeed. - */ - uint32_t recovery_request = - vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST); - - /* Update the RO Image. */ - int num_tries; - for (num_tries = 0; num_tries < RO_RETRIES; num_tries++) { - if (VB2_SUCCESS == - update_ec(ctx, devidx, VB_SELECT_FIRMWARE_READONLY)) - break; - } - if (num_tries == RO_RETRIES) { - /* Ran out of tries */ - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } else if (num_tries) { - /* - * Update succeeded after a failure, so we've polluted - * the recovery request. Restore it. - */ - request_recovery(ctx, recovery_request); - } - } - - /* Protect RO flash */ - rv = protect_ec(ctx, devidx, VB_SELECT_FIRMWARE_READONLY); - if (rv != VB2_SUCCESS) - return rv; - - /* Protect RW flash */ - rv = protect_ec(ctx, devidx, select_rw); - if (rv != VB2_SUCCESS) - return rv; - - rv = VbExEcDisableJump(devidx); - if (rv != VB2_SUCCESS) { - VB2_DEBUG("VbExEcDisableJump() returned %d\n", rv); - request_recovery(ctx, VB2_RECOVERY_EC_SOFTWARE_SYNC); - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - return rv; -} - -vb2_error_t ec_sync_phase1(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); - - /* Reasons not to do sync at all */ - if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED)) - return VB2_SUCCESS; - if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) - return VB2_SUCCESS; - -#ifdef PD_SYNC - const int do_pd_sync = !(gbb->flags & - VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC); -#else - const int do_pd_sync = 0; -#endif - - /* Set IN_RW flags */ - if (check_ec_active(ctx, 0)) - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - if (do_pd_sync && check_ec_active(ctx, 1)) - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - - /* Check if we need to update RW. Failures trigger recovery mode. */ - if (check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_EC_ACTIVE)) - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - if (do_pd_sync && check_ec_hash(ctx, 1, VB_SELECT_FIRMWARE_EC_ACTIVE)) - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - /* - * See if we need to update EC-RO (devidx=0). - * - * If we want to extend this in the future to update PD-RO, we'll use a - * different NV flag so we can track EC-RO and PD-RO updates - * separately. - */ - if (vb2_nv_get(ctx, VB2_NV_TRY_RO_SYNC) && - check_ec_hash(ctx, 0, VB_SELECT_FIRMWARE_READONLY)) { - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - /* - * If we're in RW, we need to reboot back to RO because RW can't be - * updated while we're running it. - * - * If EC supports RW-A/B slots, we can proceed but we need - * to jump to the new RW version later. - */ - if ((sd->flags & VB2_SD_FLAG_ECSYNC_RW) && - (sd->flags & VB2_SD_FLAG_ECSYNC_IN_RW) && - !(ctx->flags & VB2_CONTEXT_EC_EFS)) { - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - return VB2_SUCCESS; -} - -int ec_will_update_slowly(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - - return ((sd->flags & VB2_SD_FLAG_ECSYNC_ANY) && - (ctx->flags & VB2_CONTEXT_EC_SYNC_SLOW)); -} - -/** - * determine if we can update the EC - * - * @param ctx Vboot2 context - * @return boolean (true iff we can update the EC) - */ - -static int ec_sync_allowed(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); - - /* Reasons not to do sync at all */ - if (!(ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED)) - return 0; - if (gbb->flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC) - return 0; - if (sd->recovery_reason) - return 0; - return 1; -} - -vb2_error_t ec_sync_check_aux_fw(struct vb2_context *ctx, - VbAuxFwUpdateSeverity_t *severity) -{ - struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); - - /* If we're not updating the EC, skip aux fw syncs as well */ - if (!ec_sync_allowed(ctx) || - (gbb->flags & VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) { - *severity = VB_AUX_FW_NO_UPDATE; - return VB2_SUCCESS; - } - return VbExCheckAuxFw(severity); -} - -vb2_error_t ec_sync_update_aux_fw(struct vb2_context *ctx) -{ - vb2_error_t rv = VbExUpdateAuxFw(); - if (rv) { - if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) { - VB2_DEBUG("AUX firmware update requires RO reboot.\n"); - } else { - VB2_DEBUG("AUX firmware update/protect failed.\n"); - request_recovery(ctx, VB2_RECOVERY_AUX_FW_UPDATE); - } - } - return rv; -} - -vb2_error_t ec_sync_phase2(struct vb2_context *ctx) -{ - if (!ec_sync_allowed(ctx)) - return VB2_SUCCESS; - - /* Handle updates and jumps for EC */ - vb2_error_t retval = sync_one_ec(ctx, 0); - if (retval != VB2_SUCCESS) - return retval; - -#ifdef PD_SYNC - /* Handle updates and jumps for PD */ - struct vb2_gbb_header *gbb = vb2_get_gbb(ctx); - if (!(gbb->flags & VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) { - retval = sync_one_ec(ctx, 1); - if (retval != VB2_SUCCESS) - return retval; - } -#endif - - return VB2_SUCCESS; -} - -vb2_error_t ec_sync_phase3(struct vb2_context *ctx) -{ - struct vb2_shared_data *sd = vb2_get_sd(ctx); - - /* EC verification (and possibly updating / jumping) is done */ - vb2_error_t rv = VbExEcVbootDone(!!sd->recovery_reason); - if (rv) - return rv; - - /* Check if we need to cut-off battery. This must be done after EC - * firmware updating and before kernel started. */ - if (vb2_nv_get(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST)) { - VB2_DEBUG("Request to cut-off battery\n"); - vb2_nv_set(ctx, VB2_NV_BATTERY_CUTOFF_REQUEST, 0); - /* May lose power immediately, so commit our update now. */ - vb2_nv_commit(ctx); - VbExEcBatteryCutOff(); - return VBERROR_SHUTDOWN_REQUESTED; - } - - return VB2_SUCCESS; -} - -static int check_reboot_for_display(struct vb2_context *ctx) -{ - if (!(vb2_get_sd(ctx)->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE)) { - VB2_DEBUG("Reboot to initialize display\n"); - vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1); - return 1; - } - return 0; -} - -static void display_wait_screen(struct vb2_context *ctx, const char *fw_name) -{ - VB2_DEBUG("%s update is slow. Show WAIT screen.\n", fw_name); - VbDisplayScreen(ctx, VB_SCREEN_WAIT, 0, NULL); -} - -vb2_error_t ec_sync_all(struct vb2_context *ctx) -{ - VbAuxFwUpdateSeverity_t fw_update = VB_AUX_FW_NO_UPDATE; - vb2_error_t rv; - - /* Phase 1; this determines if we need an update */ - vb2_error_t phase1_rv = ec_sync_phase1(ctx); - int need_wait_screen = ec_will_update_slowly(ctx); - - /* Check if EC SW Sync Phase1 needs reboot */ - if (phase1_rv) { - ec_sync_check_aux_fw(ctx, &fw_update); - /* It does -- speculatively check if we need display as well */ - if (need_wait_screen || fw_update == VB_AUX_FW_SLOW_UPDATE) - check_reboot_for_display(ctx); - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - /* Is EC already in RO and needs slow update? */ - if (need_wait_screen) { - /* Might still need display in that case */ - if (check_reboot_for_display(ctx)) - return VBERROR_REBOOT_REQUIRED; - /* Display is available, so pop up the wait screen */ - display_wait_screen(ctx, "EC FW"); - } - - /* Phase 2; Applies update and/or jumps to the correct EC image */ - rv = ec_sync_phase2(ctx); - if (rv) - return rv; - - /* EC in RW, now we can check the severity of the AUX FW update */ - rv = ec_sync_check_aux_fw(ctx, &fw_update); - if (rv) - return rv; - - /* If AUX FW update is slow display the wait screen */ - if (fw_update == VB_AUX_FW_SLOW_UPDATE) { - /* Display should be available, but better check again */ - if (check_reboot_for_display(ctx)) - return VBERROR_REBOOT_REQUIRED; - display_wait_screen(ctx, "AUX FW"); - } - - if (fw_update > VB_AUX_FW_NO_UPDATE) { - /* Do Aux FW software sync */ - rv = ec_sync_update_aux_fw(ctx); - if (rv) - return rv; - /* - * AUX FW Update is applied successfully. Request EC reboot to - * RO, so that the chips that had FW update gets reset to a - * clean state. - */ - return VBERROR_EC_REBOOT_TO_RO_REQUIRED; - } - - /* Phase 3; Completes sync and handles battery cutoff */ - rv = ec_sync_phase3(ctx); - if (rv) - return rv; - - return VB2_SUCCESS; -} diff --git a/firmware/lib/include/ec_sync.h b/firmware/lib/include/ec_sync.h deleted file mode 100644 index ec1be2b2..00000000 --- a/firmware/lib/include/ec_sync.h +++ /dev/null @@ -1,94 +0,0 @@ -/* Copyright 2016 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 for verified boot - */ - -#ifndef VBOOT_REFERENCE_EC_SYNC_H_ -#define VBOOT_REFERENCE_EC_SYNC_H_ - -#include "vboot_api.h" - -struct vb2_context; - -/** - * EC sync, phase 1 - * - * This checks whether the EC is running the correct image to do EC sync, and - * whether any updates are necessary. - * - * @param ctx Vboot2 context - * @return VB2_SUCCESS, VBERROR_EC_REBOOT_TO_RO_REQUIRED if the EC must - * reboot back to its RO code to continue EC sync, or other non-zero error - * code. - */ -vb2_error_t ec_sync_phase1(struct vb2_context *ctx); - -/** - * Returns non-zero if the EC will perform a slow update during phase 2. - * - * This is only valid after calling ec_sync_phase1(), before calling - * ec_sync_phase2(). - * - * @param ctx Vboot2 context - * @return non-zero if a slow update will be done; zero if no update or a - * fast update. - */ -int ec_will_update_slowly(struct vb2_context *ctx); - -/** - * Check if auxiliary firmware blobs need to be updated. - * - * @param ctx Vboot2 context - * @param severity VB_AUX_FW_{NO,FAST,SLOW}_UPDATE - * @return VB2_SUCCESS or non-zero error code. - */ -vb2_error_t ec_sync_check_aux_fw(struct vb2_context *ctx, - VbAuxFwUpdateSeverity_t *severity); - -/** - * Update and protect auxiliary firmware. - * - * @param ctx Vboot2 context - * @return VB2_SUCCESS or non-zero error code. - */ -vb2_error_t ec_sync_update_aux_fw(struct vb2_context *ctx); - -/** - * EC sync, phase 2 - * - * This updates the EC if necessary, makes sure it has protected its image(s), - * and makes sure it has jumped to the correct image. - * - * If ec_will_update_slowly(), it is suggested that the caller display a - * warning screen before calling phase 2. - * - * @param ctx Vboot2 context - * @return VB2_SUCCESS, VBERROR_EC_REBOOT_TO_RO_REQUIRED if the EC must - * reboot back to its RO code to continue EC sync, or other non-zero error - * code. - */ -vb2_error_t ec_sync_phase2(struct vb2_context *ctx); - -/** - * EC sync, phase 3 - * - * This completes EC sync and handles battery cutoff if needed. - * - * @param ctx Vboot2 context - * @return VB2_SUCCESS or non-zero error code. - */ -vb2_error_t ec_sync_phase3(struct vb2_context *ctx); - -/** - * Sync all EC devices to expected versions. - * - * This is a high-level function which calls the functions above. - * - * @param ctx Vboot context - * @return VB2_SUCCESS, or non-zero if error. - */ -vb2_error_t ec_sync_all(struct vb2_context *ctx); - -#endif /* VBOOT_REFERENCE_EC_SYNC_H_ */ diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 7108e903..fe1e7e3d 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -6,12 +6,12 @@ */ #include "2common.h" +#include "2ec_sync.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "ec_sync.h" #include "load_kernel_fw.h" #include "secdata_tpm.h" #include "utility.h" diff --git a/firmware/lib/vboot_ui.c b/firmware/lib/vboot_ui.c index dee766f8..864ad971 100644 --- a/firmware/lib/vboot_ui.c +++ b/firmware/lib/vboot_ui.c @@ -6,12 +6,12 @@ */ #include "2common.h" +#include "2ec_sync.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "ec_sync.h" #include "load_kernel_fw.h" #include "secdata_tpm.h" #include "tlcl.h" diff --git a/firmware/lib/vboot_ui_menu.c b/firmware/lib/vboot_ui_menu.c index 38dd3053..15859c23 100644 --- a/firmware/lib/vboot_ui_menu.c +++ b/firmware/lib/vboot_ui_menu.c @@ -6,12 +6,12 @@ */ #include "2common.h" +#include "2ec_sync.h" #include "2misc.h" #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" #include "2sysincludes.h" -#include "ec_sync.h" #include "load_kernel_fw.h" #include "secdata_tpm.h" #include "utility.h" diff --git a/tests/ec_sync_tests.c b/tests/ec_sync_tests.c deleted file mode 100644 index ee0434f1..00000000 --- a/tests/ec_sync_tests.c +++ /dev/null @@ -1,508 +0,0 @@ -/* 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. - * - * Tests for vboot_api_kernel, part 3 - software sync - */ - -#include -#include -#include - -#include "2common.h" -#include "2misc.h" -#include "2nvstorage.h" -#include "2sysincludes.h" -#include "ec_sync.h" -#include "host_common.h" -#include "load_kernel_fw.h" -#include "secdata_tpm.h" -#include "test_common.h" -#include "vboot_audio.h" -#include "vboot_common.h" -#include "vboot_display.h" -#include "vboot_kernel.h" -#include "vboot_struct.h" - -/* Mock data */ -static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; -static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; - -static int mock_in_rw; -static vb2_error_t in_rw_retval; -static int protect_retval; -static int ec_ro_protected; -static int ec_rw_protected; -static int run_retval; -static int ec_run_image; -static int update_retval; -static int ec_ro_updated; -static int ec_rw_updated; -static int get_expected_retval; -static int shutdown_request_calls_left; - -static uint8_t mock_ec_ro_hash[32]; -static uint8_t mock_ec_rw_hash[32]; -static int mock_ec_ro_hash_size; -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 struct vb2_context ctx; -static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]; -static struct vb2_shared_data *sd; -static struct vb2_gbb_header gbb; - -static uint32_t screens_displayed[8]; -static uint32_t screens_count = 0; - -static vb2_error_t ec_aux_fw_retval; -static int ec_aux_fw_update_req; -static VbAuxFwUpdateSeverity_t ec_aux_fw_mock_severity; -static VbAuxFwUpdateSeverity_t ec_aux_fw_update_severity; -static int ec_aux_fw_protected; - -/* Reset mock data (for use before each test) */ -static void ResetMocks(void) -{ - memset(&ctx, 0, sizeof(ctx)); - ctx.workbuf = workbuf; - ctx.workbuf_size = sizeof(workbuf); - ctx.flags = VB2_CONTEXT_EC_SYNC_SUPPORTED; - vb2_init_context(&ctx); - vb2_nv_init(&ctx); - - sd = vb2_get_sd(&ctx); - sd->vbsd = shared; - sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; - - memset(&gbb, 0, sizeof(gbb)); - - memset(&shared_data, 0, sizeof(shared_data)); - VbSharedDataInit(shared, sizeof(shared_data)); - - mock_in_rw = 0; - ec_ro_protected = 0; - ec_rw_protected = 0; - ec_run_image = 0; /* 0 = RO, 1 = RW */ - ec_ro_updated = 0; - ec_rw_updated = 0; - in_rw_retval = VB2_SUCCESS; - protect_retval = VB2_SUCCESS; - update_retval = VB2_SUCCESS; - run_retval = VB2_SUCCESS; - get_expected_retval = VB2_SUCCESS; - shutdown_request_calls_left = -1; - - memset(mock_ec_ro_hash, 0, sizeof(mock_ec_ro_hash)); - mock_ec_ro_hash[0] = 42; - mock_ec_ro_hash_size = sizeof(mock_ec_ro_hash); - - memset(mock_ec_rw_hash, 0, sizeof(mock_ec_rw_hash)); - mock_ec_rw_hash[0] = 42; - mock_ec_rw_hash_size = sizeof(mock_ec_rw_hash); - - memset(want_ec_hash, 0, sizeof(want_ec_hash)); - want_ec_hash[0] = 42; - want_ec_hash_size = sizeof(want_ec_hash); - - update_hash = 42; - - // TODO: ensure these are actually needed - - memset(screens_displayed, 0, sizeof(screens_displayed)); - screens_count = 0; - - ec_aux_fw_retval = VB2_SUCCESS; - ec_aux_fw_mock_severity = VB_AUX_FW_NO_UPDATE; - ec_aux_fw_update_severity = VB_AUX_FW_NO_UPDATE; - ec_aux_fw_update_req = 0; - ec_aux_fw_protected = 0; -} - -/* Mock functions */ -struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) -{ - return &gbb; -} - -uint32_t VbExIsShutdownRequested(void) -{ - if (shutdown_request_calls_left == 0) - return 1; - else if (shutdown_request_calls_left > 0) - shutdown_request_calls_left--; - - return 0; -} - -int VbExTrustEC(int devidx) -{ - return !mock_in_rw; -} - -vb2_error_t VbExEcRunningRW(int devidx, int *in_rw) -{ - *in_rw = mock_in_rw; - return in_rw_retval; -} - -vb2_error_t VbExEcProtect(int devidx, enum VbSelectFirmware_t select) -{ - if (select == VB_SELECT_FIRMWARE_READONLY) - ec_ro_protected = 1; - else - ec_rw_protected = 1; - return protect_retval; -} - -vb2_error_t VbExEcDisableJump(int devidx) -{ - return run_retval; -} - -vb2_error_t VbExEcJumpToRW(int devidx) -{ - ec_run_image = 1; - mock_in_rw = 1; - return run_retval; -} - -vb2_error_t VbExEcHashImage(int devidx, enum VbSelectFirmware_t select, - const uint8_t **hash, int *hash_size) -{ - *hash = select == VB_SELECT_FIRMWARE_READONLY ? - mock_ec_ro_hash : mock_ec_rw_hash; - *hash_size = select == VB_SELECT_FIRMWARE_READONLY ? - mock_ec_ro_hash_size : mock_ec_rw_hash_size; - return *hash_size ? VB2_SUCCESS : VB2_ERROR_MOCK; -} - -vb2_error_t VbExEcGetExpectedImage(int devidx, enum VbSelectFirmware_t select, - const uint8_t **image, int *image_size) -{ - static uint8_t fake_image[64] = {5, 6, 7, 8}; - *image = fake_image; - *image_size = sizeof(fake_image); - return get_expected_retval; -} - -vb2_error_t VbExEcGetExpectedImageHash(int devidx, - enum VbSelectFirmware_t select, - const uint8_t **hash, int *hash_size) -{ - *hash = want_ec_hash; - *hash_size = want_ec_hash_size; - - return want_ec_hash_size ? VB2_SUCCESS : VB2_ERROR_MOCK; -} - -vb2_error_t VbExEcUpdateImage(int devidx, enum VbSelectFirmware_t select, - const uint8_t *image, int image_size) -{ - if (select == VB_SELECT_FIRMWARE_READONLY) { - ec_ro_updated = 1; - mock_ec_ro_hash[0] = update_hash; - } else { - ec_rw_updated = 1; - mock_ec_rw_hash[0] = update_hash; - } - return update_retval; -} - -vb2_error_t VbDisplayScreen(struct vb2_context *c, uint32_t screen, int force, - const VbScreenData *data) -{ - if (screens_count < ARRAY_SIZE(screens_displayed)) - screens_displayed[screens_count++] = screen; - - return VB2_SUCCESS; -} - -vb2_error_t VbExCheckAuxFw(VbAuxFwUpdateSeverity_t *severity) -{ - *severity = ec_aux_fw_mock_severity; - ec_aux_fw_update_severity = ec_aux_fw_mock_severity; - return VB2_SUCCESS; -} - -vb2_error_t VbExUpdateAuxFw() -{ - if (ec_aux_fw_update_severity != VB_AUX_FW_NO_DEVICE && - ec_aux_fw_update_severity != VB_AUX_FW_NO_UPDATE) - ec_aux_fw_update_req = 1; - return ec_aux_fw_retval; -} - -vb2_error_t VbExEcVbootDone(int in_recovery) -{ - ec_aux_fw_protected = ec_aux_fw_update_severity != VB_AUX_FW_NO_DEVICE; - return ec_aux_fw_retval; -} - -static void test_ssync(vb2_error_t retval, int recovery_reason, - const char *desc) -{ - TEST_EQ(ec_sync_all(&ctx), retval, desc); - TEST_EQ(vb2_nv_get(&ctx, VB2_NV_RECOVERY_REQUEST), - recovery_reason, " recovery reason"); -} - -/* Tests */ - -static void VbSoftwareSyncTest(void) -{ - /* AP-RO cases */ - ResetMocks(); - in_rw_retval = VB2_ERROR_MOCK; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image"); - - /* Calculate hashes */ - ResetMocks(); - mock_ec_rw_hash_size = 0; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_HASH_FAILED, "Bad EC hash"); - - ResetMocks(); - mock_ec_rw_hash_size = 16; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_HASH_SIZE, "Bad EC hash size"); - - ResetMocks(); - want_ec_hash_size = 0; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash"); - - ResetMocks(); - want_ec_hash_size = 16; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_HASH_SIZE, - "Hash size mismatch"); - - ResetMocks(); - want_ec_hash_size = 4; - mock_ec_rw_hash_size = 4; - test_ssync(0, 0, "Custom hash size"); - - /* Updates required */ - ResetMocks(); - mock_in_rw = 1; - mock_ec_rw_hash[0]++; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - 0, "Pending update needs reboot"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - vb2_nv_set(&ctx, VB2_NV_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"); - TEST_EQ(ec_rw_updated, 1, " ec rw updated"); - TEST_EQ(ec_ro_protected, 1, " ec ro protected"); - TEST_EQ(ec_ro_updated, 0, " ec ro updated"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - mock_ec_ro_hash[0]++; - vb2_nv_set(&ctx, VB2_NV_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"); - TEST_EQ(ec_rw_updated, 1, " ec rw updated"); - TEST_EQ(ec_ro_protected, 1, " ec ro protected"); - TEST_EQ(ec_ro_updated, 1, " ec ro updated"); - - ResetMocks(); - vb2_nv_set(&ctx, VB2_NV_TRY_RO_SYNC, 1); - mock_ec_ro_hash[0]++; - vb2_nv_set(&ctx, VB2_NV_DISPLAY_REQUEST, 1); - test_ssync(0, 0, "rw update not needed"); - TEST_EQ(ec_rw_protected, 1, " ec rw protected"); - TEST_EQ(ec_run_image, 1, " ec run image"); - TEST_EQ(ec_rw_updated, 0, " ec rw not updated"); - TEST_EQ(ec_ro_protected, 1, " ec ro protected"); - TEST_EQ(ec_ro_updated, 1, " ec ro updated"); - TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DISPLAY_REQUEST), 1, - " DISPLAY_REQUEST left untouched"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - mock_ec_ro_hash[0]++; - test_ssync(0, 0, "ro update not requested"); - TEST_EQ(ec_rw_protected, 1, " ec rw protected"); - TEST_EQ(ec_run_image, 1, " ec run image"); - TEST_EQ(ec_rw_updated, 1, " ec rw updated"); - TEST_EQ(ec_ro_protected, 1, " ec ro protected"); - TEST_EQ(ec_ro_updated, 0, " ec ro updated"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - update_hash++; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_UPDATE, "updated hash mismatch"); - TEST_EQ(ec_rw_protected, 0, " ec rw protected"); - TEST_EQ(ec_run_image, 0, " ec run image"); - TEST_EQ(ec_rw_updated, 1, " ec rw updated"); - TEST_EQ(ec_ro_protected, 0, " ec ro protected"); - TEST_EQ(ec_ro_updated, 0, " ec ro updated"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - update_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - 0, "Reboot after rw update"); - TEST_EQ(ec_rw_updated, 1, " ec rw updated"); - TEST_EQ(ec_ro_updated, 0, " ec rw updated"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - update_retval = VB2_ERROR_MOCK; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_UPDATE, "Update failed"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; - test_ssync(0, 0, "Slow update"); - TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; - sd->flags &= ~VB2_SD_FLAG_DISPLAY_AVAILABLE; - test_ssync(VBERROR_REBOOT_REQUIRED, 0, - "Slow update - reboot for display"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; - vb2_nv_set(&ctx, VB2_NV_DISPLAY_REQUEST, 1); - test_ssync(VB2_SUCCESS, 0, - "Slow update with display request"); - TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen"); - TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DISPLAY_REQUEST), 1, - " DISPLAY_REQUEST left untouched"); - - ResetMocks(); - mock_ec_rw_hash[0]++; - ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; - vb2_nv_set(&ctx, VB2_NV_DISPLAY_REQUEST, 0); - test_ssync(VB2_SUCCESS, 0, - "Slow update without display request (no reboot needed)"); - TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen"); - TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DISPLAY_REQUEST), 0, - " DISPLAY_REQUEST left untouched"); - - /* RW cases, no update */ - ResetMocks(); - mock_in_rw = 1; - test_ssync(0, 0, "AP-RW, EC-RW"); - - ResetMocks(); - test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW"); - TEST_EQ(ec_rw_protected, 1, " ec rw protected"); - TEST_EQ(ec_run_image, 1, " ec run image"); - TEST_EQ(ec_rw_updated, 0, " ec rw updated"); - TEST_EQ(ec_ro_protected, 1, " ec ro protected"); - TEST_EQ(ec_ro_updated, 0, " ec ro updated"); - - ResetMocks(); - run_retval = VB2_ERROR_MOCK; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - VB2_RECOVERY_EC_JUMP_RW, "Jump to RW fail"); - - ResetMocks(); - run_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, - 0, "Jump to RW fail because locked"); - - ResetMocks(); - protect_retval = VB2_ERROR_MOCK; - test_ssync(VB2_ERROR_MOCK, - VB2_RECOVERY_EC_PROTECT, "Protect error"); - - /* No longer check for shutdown requested */ - ResetMocks(); - shutdown_request_calls_left = 0; - test_ssync(0, 0, - "AP-RW, EC-RO -> EC-RW shutdown requested"); - - ResetMocks(); - mock_in_rw = 1; - shutdown_request_calls_left = 0; - test_ssync(0, 0, "AP-RW shutdown requested"); - - ResetMocks(); - gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC; - ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; - test_ssync(VB2_SUCCESS, 0, - "VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC" - " disables auxiliary FW update request"); - TEST_EQ(ec_aux_fw_update_req, 0, " aux fw update disabled"); - TEST_EQ(ec_aux_fw_protected, 1, " aux fw protected"); - - ResetMocks(); - gbb.flags |= VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC; - ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; - test_ssync(VB2_SUCCESS, 0, - "VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC" - " disables auxiliary FW update request"); - TEST_EQ(ec_aux_fw_update_req, 0, " aux fw update disabled"); - TEST_EQ(ec_aux_fw_protected, 1, " aux fw protected"); - - ResetMocks(); - ec_aux_fw_mock_severity = VB_AUX_FW_NO_DEVICE; - test_ssync(VB2_SUCCESS, 0, - "No auxiliary FW update needed"); - TEST_EQ(screens_count, 0, - " wait screen skipped"); - TEST_EQ(ec_aux_fw_update_req, 0, " no aux fw update requested"); - TEST_EQ(ec_aux_fw_protected, 0, " no aux fw protected"); - - ResetMocks(); - ec_aux_fw_mock_severity = VB_AUX_FW_NO_UPDATE; - test_ssync(VB2_SUCCESS, 0, - "No auxiliary FW update needed"); - TEST_EQ(screens_count, 0, - " wait screen skipped"); - TEST_EQ(ec_aux_fw_update_req, 0, " no aux fw update requested"); - TEST_EQ(ec_aux_fw_protected, 1, " aux fw protected"); - - ResetMocks(); - ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, 0, - "Fast auxiliary FW update needed"); - TEST_EQ(screens_count, 0, - " wait screen skipped"); - TEST_EQ(ec_aux_fw_update_req, 1, " aux fw update requested"); - TEST_EQ(ec_aux_fw_protected, 0, " aux fw protected"); - - ResetMocks(); - ec_aux_fw_mock_severity = VB_AUX_FW_SLOW_UPDATE; - sd->flags &= ~VB2_SD_FLAG_DISPLAY_AVAILABLE; - test_ssync(VBERROR_REBOOT_REQUIRED, 0, - "Slow auxiliary FW update needed - reboot for display"); - - ResetMocks(); - ec_aux_fw_mock_severity = VB_AUX_FW_SLOW_UPDATE; - test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, 0, - "Slow auxiliary FW update needed"); - TEST_EQ(ec_aux_fw_update_req, 1, " aux fw update requested"); - TEST_EQ(ec_aux_fw_protected, 0, " aux fw protected"); - TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, - " wait screen forced"); - - ResetMocks(); - ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; - ec_aux_fw_retval = VB2_ERROR_UNKNOWN; - test_ssync(VB2_ERROR_UNKNOWN, VB2_RECOVERY_AUX_FW_UPDATE, - "Error updating AUX firmware"); -} - -int main(void) -{ - VbSoftwareSyncTest(); - - return gTestSuccess ? 0 : 255; -} diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c new file mode 100644 index 00000000..d93c9629 --- /dev/null +++ b/tests/vb2_ec_sync_tests.c @@ -0,0 +1,508 @@ +/* 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. + * + * Tests for vboot_api_kernel, part 3 - software sync + */ + +#include +#include +#include + +#include "2common.h" +#include "2ec_sync.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "2sysincludes.h" +#include "host_common.h" +#include "load_kernel_fw.h" +#include "secdata_tpm.h" +#include "test_common.h" +#include "vboot_audio.h" +#include "vboot_common.h" +#include "vboot_display.h" +#include "vboot_kernel.h" +#include "vboot_struct.h" + +/* Mock data */ +static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE]; +static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data; + +static int mock_in_rw; +static vb2_error_t in_rw_retval; +static int protect_retval; +static int ec_ro_protected; +static int ec_rw_protected; +static int run_retval; +static int ec_run_image; +static int update_retval; +static int ec_ro_updated; +static int ec_rw_updated; +static int get_expected_retval; +static int shutdown_request_calls_left; + +static uint8_t mock_ec_ro_hash[32]; +static uint8_t mock_ec_rw_hash[32]; +static int mock_ec_ro_hash_size; +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 struct vb2_context ctx; +static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]; +static struct vb2_shared_data *sd; +static struct vb2_gbb_header gbb; + +static uint32_t screens_displayed[8]; +static uint32_t screens_count = 0; + +static vb2_error_t ec_aux_fw_retval; +static int ec_aux_fw_update_req; +static VbAuxFwUpdateSeverity_t ec_aux_fw_mock_severity; +static VbAuxFwUpdateSeverity_t ec_aux_fw_update_severity; +static int ec_aux_fw_protected; + +/* Reset mock data (for use before each test) */ +static void ResetMocks(void) +{ + memset(&ctx, 0, sizeof(ctx)); + ctx.workbuf = workbuf; + ctx.workbuf_size = sizeof(workbuf); + ctx.flags = VB2_CONTEXT_EC_SYNC_SUPPORTED; + vb2_init_context(&ctx); + vb2_nv_init(&ctx); + + sd = vb2_get_sd(&ctx); + sd->vbsd = shared; + sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE; + + memset(&gbb, 0, sizeof(gbb)); + + memset(&shared_data, 0, sizeof(shared_data)); + VbSharedDataInit(shared, sizeof(shared_data)); + + mock_in_rw = 0; + ec_ro_protected = 0; + ec_rw_protected = 0; + ec_run_image = 0; /* 0 = RO, 1 = RW */ + ec_ro_updated = 0; + ec_rw_updated = 0; + in_rw_retval = VB2_SUCCESS; + protect_retval = VB2_SUCCESS; + update_retval = VB2_SUCCESS; + run_retval = VB2_SUCCESS; + get_expected_retval = VB2_SUCCESS; + shutdown_request_calls_left = -1; + + memset(mock_ec_ro_hash, 0, sizeof(mock_ec_ro_hash)); + mock_ec_ro_hash[0] = 42; + mock_ec_ro_hash_size = sizeof(mock_ec_ro_hash); + + memset(mock_ec_rw_hash, 0, sizeof(mock_ec_rw_hash)); + mock_ec_rw_hash[0] = 42; + mock_ec_rw_hash_size = sizeof(mock_ec_rw_hash); + + memset(want_ec_hash, 0, sizeof(want_ec_hash)); + want_ec_hash[0] = 42; + want_ec_hash_size = sizeof(want_ec_hash); + + update_hash = 42; + + // TODO: ensure these are actually needed + + memset(screens_displayed, 0, sizeof(screens_displayed)); + screens_count = 0; + + ec_aux_fw_retval = VB2_SUCCESS; + ec_aux_fw_mock_severity = VB_AUX_FW_NO_UPDATE; + ec_aux_fw_update_severity = VB_AUX_FW_NO_UPDATE; + ec_aux_fw_update_req = 0; + ec_aux_fw_protected = 0; +} + +/* Mock functions */ +struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) +{ + return &gbb; +} + +uint32_t VbExIsShutdownRequested(void) +{ + if (shutdown_request_calls_left == 0) + return 1; + else if (shutdown_request_calls_left > 0) + shutdown_request_calls_left--; + + return 0; +} + +int VbExTrustEC(int devidx) +{ + return !mock_in_rw; +} + +vb2_error_t VbExEcRunningRW(int devidx, int *in_rw) +{ + *in_rw = mock_in_rw; + return in_rw_retval; +} + +vb2_error_t VbExEcProtect(int devidx, enum VbSelectFirmware_t select) +{ + if (select == VB_SELECT_FIRMWARE_READONLY) + ec_ro_protected = 1; + else + ec_rw_protected = 1; + return protect_retval; +} + +vb2_error_t VbExEcDisableJump(int devidx) +{ + return run_retval; +} + +vb2_error_t VbExEcJumpToRW(int devidx) +{ + ec_run_image = 1; + mock_in_rw = 1; + return run_retval; +} + +vb2_error_t VbExEcHashImage(int devidx, enum VbSelectFirmware_t select, + const uint8_t **hash, int *hash_size) +{ + *hash = select == VB_SELECT_FIRMWARE_READONLY ? + mock_ec_ro_hash : mock_ec_rw_hash; + *hash_size = select == VB_SELECT_FIRMWARE_READONLY ? + mock_ec_ro_hash_size : mock_ec_rw_hash_size; + return *hash_size ? VB2_SUCCESS : VB2_ERROR_MOCK; +} + +vb2_error_t VbExEcGetExpectedImage(int devidx, enum VbSelectFirmware_t select, + const uint8_t **image, int *image_size) +{ + static uint8_t fake_image[64] = {5, 6, 7, 8}; + *image = fake_image; + *image_size = sizeof(fake_image); + return get_expected_retval; +} + +vb2_error_t VbExEcGetExpectedImageHash(int devidx, + enum VbSelectFirmware_t select, + const uint8_t **hash, int *hash_size) +{ + *hash = want_ec_hash; + *hash_size = want_ec_hash_size; + + return want_ec_hash_size ? VB2_SUCCESS : VB2_ERROR_MOCK; +} + +vb2_error_t VbExEcUpdateImage(int devidx, enum VbSelectFirmware_t select, + const uint8_t *image, int image_size) +{ + if (select == VB_SELECT_FIRMWARE_READONLY) { + ec_ro_updated = 1; + mock_ec_ro_hash[0] = update_hash; + } else { + ec_rw_updated = 1; + mock_ec_rw_hash[0] = update_hash; + } + return update_retval; +} + +vb2_error_t VbDisplayScreen(struct vb2_context *c, uint32_t screen, int force, + const VbScreenData *data) +{ + if (screens_count < ARRAY_SIZE(screens_displayed)) + screens_displayed[screens_count++] = screen; + + return VB2_SUCCESS; +} + +vb2_error_t VbExCheckAuxFw(VbAuxFwUpdateSeverity_t *severity) +{ + *severity = ec_aux_fw_mock_severity; + ec_aux_fw_update_severity = ec_aux_fw_mock_severity; + return VB2_SUCCESS; +} + +vb2_error_t VbExUpdateAuxFw() +{ + if (ec_aux_fw_update_severity != VB_AUX_FW_NO_DEVICE && + ec_aux_fw_update_severity != VB_AUX_FW_NO_UPDATE) + ec_aux_fw_update_req = 1; + return ec_aux_fw_retval; +} + +vb2_error_t VbExEcVbootDone(int in_recovery) +{ + ec_aux_fw_protected = ec_aux_fw_update_severity != VB_AUX_FW_NO_DEVICE; + return ec_aux_fw_retval; +} + +static void test_ssync(vb2_error_t retval, int recovery_reason, + const char *desc) +{ + TEST_EQ(ec_sync_all(&ctx), retval, desc); + TEST_EQ(vb2_nv_get(&ctx, VB2_NV_RECOVERY_REQUEST), + recovery_reason, " recovery reason"); +} + +/* Tests */ + +static void VbSoftwareSyncTest(void) +{ + /* AP-RO cases */ + ResetMocks(); + in_rw_retval = VB2_ERROR_MOCK; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image"); + + /* Calculate hashes */ + ResetMocks(); + mock_ec_rw_hash_size = 0; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_HASH_FAILED, "Bad EC hash"); + + ResetMocks(); + mock_ec_rw_hash_size = 16; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_HASH_SIZE, "Bad EC hash size"); + + ResetMocks(); + want_ec_hash_size = 0; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash"); + + ResetMocks(); + want_ec_hash_size = 16; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_HASH_SIZE, + "Hash size mismatch"); + + ResetMocks(); + want_ec_hash_size = 4; + mock_ec_rw_hash_size = 4; + test_ssync(0, 0, "Custom hash size"); + + /* Updates required */ + ResetMocks(); + mock_in_rw = 1; + mock_ec_rw_hash[0]++; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + 0, "Pending update needs reboot"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + vb2_nv_set(&ctx, VB2_NV_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"); + TEST_EQ(ec_rw_updated, 1, " ec rw updated"); + TEST_EQ(ec_ro_protected, 1, " ec ro protected"); + TEST_EQ(ec_ro_updated, 0, " ec ro updated"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + mock_ec_ro_hash[0]++; + vb2_nv_set(&ctx, VB2_NV_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"); + TEST_EQ(ec_rw_updated, 1, " ec rw updated"); + TEST_EQ(ec_ro_protected, 1, " ec ro protected"); + TEST_EQ(ec_ro_updated, 1, " ec ro updated"); + + ResetMocks(); + vb2_nv_set(&ctx, VB2_NV_TRY_RO_SYNC, 1); + mock_ec_ro_hash[0]++; + vb2_nv_set(&ctx, VB2_NV_DISPLAY_REQUEST, 1); + test_ssync(0, 0, "rw update not needed"); + TEST_EQ(ec_rw_protected, 1, " ec rw protected"); + TEST_EQ(ec_run_image, 1, " ec run image"); + TEST_EQ(ec_rw_updated, 0, " ec rw not updated"); + TEST_EQ(ec_ro_protected, 1, " ec ro protected"); + TEST_EQ(ec_ro_updated, 1, " ec ro updated"); + TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DISPLAY_REQUEST), 1, + " DISPLAY_REQUEST left untouched"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + mock_ec_ro_hash[0]++; + test_ssync(0, 0, "ro update not requested"); + TEST_EQ(ec_rw_protected, 1, " ec rw protected"); + TEST_EQ(ec_run_image, 1, " ec run image"); + TEST_EQ(ec_rw_updated, 1, " ec rw updated"); + TEST_EQ(ec_ro_protected, 1, " ec ro protected"); + TEST_EQ(ec_ro_updated, 0, " ec ro updated"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + update_hash++; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_UPDATE, "updated hash mismatch"); + TEST_EQ(ec_rw_protected, 0, " ec rw protected"); + TEST_EQ(ec_run_image, 0, " ec run image"); + TEST_EQ(ec_rw_updated, 1, " ec rw updated"); + TEST_EQ(ec_ro_protected, 0, " ec ro protected"); + TEST_EQ(ec_ro_updated, 0, " ec ro updated"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + update_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + 0, "Reboot after rw update"); + TEST_EQ(ec_rw_updated, 1, " ec rw updated"); + TEST_EQ(ec_ro_updated, 0, " ec rw updated"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + update_retval = VB2_ERROR_MOCK; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_UPDATE, "Update failed"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; + test_ssync(0, 0, "Slow update"); + TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; + sd->flags &= ~VB2_SD_FLAG_DISPLAY_AVAILABLE; + test_ssync(VBERROR_REBOOT_REQUIRED, 0, + "Slow update - reboot for display"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; + vb2_nv_set(&ctx, VB2_NV_DISPLAY_REQUEST, 1); + test_ssync(VB2_SUCCESS, 0, + "Slow update with display request"); + TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen"); + TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DISPLAY_REQUEST), 1, + " DISPLAY_REQUEST left untouched"); + + ResetMocks(); + mock_ec_rw_hash[0]++; + ctx.flags |= VB2_CONTEXT_EC_SYNC_SLOW; + vb2_nv_set(&ctx, VB2_NV_DISPLAY_REQUEST, 0); + test_ssync(VB2_SUCCESS, 0, + "Slow update without display request (no reboot needed)"); + TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen"); + TEST_EQ(vb2_nv_get(&ctx, VB2_NV_DISPLAY_REQUEST), 0, + " DISPLAY_REQUEST left untouched"); + + /* RW cases, no update */ + ResetMocks(); + mock_in_rw = 1; + test_ssync(0, 0, "AP-RW, EC-RW"); + + ResetMocks(); + test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW"); + TEST_EQ(ec_rw_protected, 1, " ec rw protected"); + TEST_EQ(ec_run_image, 1, " ec run image"); + TEST_EQ(ec_rw_updated, 0, " ec rw updated"); + TEST_EQ(ec_ro_protected, 1, " ec ro protected"); + TEST_EQ(ec_ro_updated, 0, " ec ro updated"); + + ResetMocks(); + run_retval = VB2_ERROR_MOCK; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + VB2_RECOVERY_EC_JUMP_RW, "Jump to RW fail"); + + ResetMocks(); + run_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, + 0, "Jump to RW fail because locked"); + + ResetMocks(); + protect_retval = VB2_ERROR_MOCK; + test_ssync(VB2_ERROR_MOCK, + VB2_RECOVERY_EC_PROTECT, "Protect error"); + + /* No longer check for shutdown requested */ + ResetMocks(); + shutdown_request_calls_left = 0; + test_ssync(0, 0, + "AP-RW, EC-RO -> EC-RW shutdown requested"); + + ResetMocks(); + mock_in_rw = 1; + shutdown_request_calls_left = 0; + test_ssync(0, 0, "AP-RW shutdown requested"); + + ResetMocks(); + gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC; + ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; + test_ssync(VB2_SUCCESS, 0, + "VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC" + " disables auxiliary FW update request"); + TEST_EQ(ec_aux_fw_update_req, 0, " aux fw update disabled"); + TEST_EQ(ec_aux_fw_protected, 1, " aux fw protected"); + + ResetMocks(); + gbb.flags |= VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC; + ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; + test_ssync(VB2_SUCCESS, 0, + "VB2_GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC" + " disables auxiliary FW update request"); + TEST_EQ(ec_aux_fw_update_req, 0, " aux fw update disabled"); + TEST_EQ(ec_aux_fw_protected, 1, " aux fw protected"); + + ResetMocks(); + ec_aux_fw_mock_severity = VB_AUX_FW_NO_DEVICE; + test_ssync(VB2_SUCCESS, 0, + "No auxiliary FW update needed"); + TEST_EQ(screens_count, 0, + " wait screen skipped"); + TEST_EQ(ec_aux_fw_update_req, 0, " no aux fw update requested"); + TEST_EQ(ec_aux_fw_protected, 0, " no aux fw protected"); + + ResetMocks(); + ec_aux_fw_mock_severity = VB_AUX_FW_NO_UPDATE; + test_ssync(VB2_SUCCESS, 0, + "No auxiliary FW update needed"); + TEST_EQ(screens_count, 0, + " wait screen skipped"); + TEST_EQ(ec_aux_fw_update_req, 0, " no aux fw update requested"); + TEST_EQ(ec_aux_fw_protected, 1, " aux fw protected"); + + ResetMocks(); + ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, 0, + "Fast auxiliary FW update needed"); + TEST_EQ(screens_count, 0, + " wait screen skipped"); + TEST_EQ(ec_aux_fw_update_req, 1, " aux fw update requested"); + TEST_EQ(ec_aux_fw_protected, 0, " aux fw protected"); + + ResetMocks(); + ec_aux_fw_mock_severity = VB_AUX_FW_SLOW_UPDATE; + sd->flags &= ~VB2_SD_FLAG_DISPLAY_AVAILABLE; + test_ssync(VBERROR_REBOOT_REQUIRED, 0, + "Slow auxiliary FW update needed - reboot for display"); + + ResetMocks(); + ec_aux_fw_mock_severity = VB_AUX_FW_SLOW_UPDATE; + test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED, 0, + "Slow auxiliary FW update needed"); + TEST_EQ(ec_aux_fw_update_req, 1, " aux fw update requested"); + TEST_EQ(ec_aux_fw_protected, 0, " aux fw protected"); + TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, + " wait screen forced"); + + ResetMocks(); + ec_aux_fw_mock_severity = VB_AUX_FW_FAST_UPDATE; + ec_aux_fw_retval = VB2_ERROR_UNKNOWN; + test_ssync(VB2_ERROR_UNKNOWN, VB2_RECOVERY_AUX_FW_UPDATE, + "Error updating AUX firmware"); +} + +int main(void) +{ + VbSoftwareSyncTest(); + + return gTestSuccess ? 0 : 255; +} diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c index a33c5bc2..ee02fe30 100644 --- a/tests/vboot_api_kernel4_tests.c +++ b/tests/vboot_api_kernel4_tests.c @@ -7,11 +7,11 @@ #include "2api.h" #include "2common.h" +#include "2ec_sync.h" #include "2misc.h" #include "2nvstorage.h" #include "2secdata.h" #include "2sysincludes.h" -#include "ec_sync.h" #include "host_common.h" #include "load_kernel_fw.h" #include "secdata_tpm.h" -- cgit v1.2.1