コード例 #1
0
int RestoreNvFromBackup(VbNvContext *vnc)
{
	VbNvContext bvnc;
	uint32_t value;
	int i;

	VBDEBUG(("TPM: %s()\n", __func__));

	if (TPM_SUCCESS != RollbackBackupRead(bvnc.raw))
		return 1;

	VbNvSetup(&bvnc);
	if (bvnc.regenerate_crc) {
		VBDEBUG(("TPM: Oops, backup is no good.\n"));
		return 1;
	}

	for (i = 0; i < ARRAY_SIZE(backup_params); i++) {
		VbNvGet(&bvnc, backup_params[i], &value);
		VbNvSet(vnc, backup_params[i], value);
	}

	/* VbNvTeardown(&bvnc); is not needed. We're done with it. */
	return 0;
}
コード例 #2
0
ファイル: main.c プロジェクト: kleopatra999/depthcharge
static void enable_graphics(void)
{
	if (!CONFIG_OPROM_MATTERS)
		return;

	int oprom_loaded = flag_fetch(FLAG_OPROM);

	// Manipulating vboot's internal data and calling its internal
	// functions is NOT NICE and will give you athlete's foot and make
	// you unpopular at parties. Right now it's the only way to ensure
	// graphics are enabled, though, so it's a necessary evil.
	if (!oprom_loaded) {
		printf("Enabling graphics.\n");

		VbNvContext context;

		VbExNvStorageRead(context.raw);
		VbNvSetup(&context);

		VbNvSet(&context, VBNV_OPROM_NEEDED, 1);

		VbNvTeardown(&context);
		VbExNvStorageWrite(context.raw);

		printf("Rebooting.\n");
		if (cold_reboot())
			halt();
	}
}
コード例 #3
0
ファイル: crossystem.c プロジェクト: latelee/vboot
int VbSetNvStorage(VbNvParam param, int value) {
  VbNvContext vnc;
  int retval = -1;
  int i;

  if (0 != VbReadNvStorage(&vnc))
    return -1;

  if (0 != VbNvSetup(&vnc))
    goto VbSetNvCleanup;
  i = VbNvSet(&vnc, param, (uint32_t)value);
  if (0 != VbNvTeardown(&vnc))
    goto VbSetNvCleanup;
  if (0 != i)
    goto VbSetNvCleanup;

  if (vnc.raw_changed) {
    vnc_read = 0;
    if (0 != VbWriteNvStorage(&vnc))
      goto VbSetNvCleanup;
  }

  /* Success */
  retval = 0;

VbSetNvCleanup:
  /* TODO: release lock */
  return retval;
}
コード例 #4
0
ファイル: vboot_display_tests.c プロジェクト: latelee/vboot
/* Test display key checking */
static void DisplayKeyTest(void)
{
	uint32_t u;

	ResetMocks();
	VbCheckDisplayKey(&cparams, 'q', &vnc);
	TEST_EQ(*debug_info, '\0', "DisplayKey q = does nothing");
	VbApiKernelFree(&cparams);

	ResetMocks();
	VbCheckDisplayKey(&cparams, '\t', &vnc);
	TEST_NEQ(*debug_info, '\0', "DisplayKey tab = display");
	VbApiKernelFree(&cparams);

	/* Toggle localization */
	ResetMocks();
	VbNvSet(&vnc, VBNV_LOCALIZATION_INDEX, 0);
	VbNvTeardown(&vnc);
	VbCheckDisplayKey(&cparams, VB_KEY_DOWN, &vnc);
	VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
	TEST_EQ(u, 2, "DisplayKey up");
	VbCheckDisplayKey(&cparams, VB_KEY_LEFT, &vnc);
	VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
	TEST_EQ(u, 1, "DisplayKey left");
	VbCheckDisplayKey(&cparams, VB_KEY_RIGHT, &vnc);
	VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
	TEST_EQ(u, 2, "DisplayKey right");
	VbCheckDisplayKey(&cparams, VB_KEY_UP, &vnc);
	VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
	TEST_EQ(u, 0, "DisplayKey up");
	VbApiKernelFree(&cparams);

	/* Reset localization if localization count is invalid */
	ResetMocks();
	VbNvSet(&vnc, VBNV_LOCALIZATION_INDEX, 1);
	VbNvTeardown(&vnc);
	bhdr->signature[0] ^= 0x5a;
	VbCheckDisplayKey(&cparams, VB_KEY_UP, &vnc);
	VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
	TEST_EQ(u, 0, "DisplayKey invalid");
	VbApiKernelFree(&cparams);
}
コード例 #5
0
int SaveNvToBackup(VbNvContext *vnc)
{
	VbNvContext bvnc;
	uint32_t value;
	int i;

	VBDEBUG(("TPM: %s()\n", __func__));

	/* Read it first. No point in writing the same data. */
	if (TPM_SUCCESS != RollbackBackupRead(bvnc.raw))
		return 1;

	VbNvSetup(&bvnc);
	VBDEBUG(("TPM: existing backup is %s\n",
		 bvnc.regenerate_crc ? "bad" : "good"));

	for (i = 0; i < ARRAY_SIZE(backup_params); i++) {
		VbNvGet(vnc, backup_params[i], &value);
		VbNvSet(&bvnc, backup_params[i], value);
	}

	VbNvTeardown(&bvnc);

	if (!bvnc.raw_changed) {
		VBDEBUG(("TPM: Nothing's changed, not writing backup\n"));
		/* Clear the request flag, since we're happy. */
		VbNvSet(vnc, VBNV_BACKUP_NVRAM_REQUEST, 0);
		return 0;
	}

	if (TPM_SUCCESS == RollbackBackupWrite(bvnc.raw)) {
		/* Clear the request flag if we wrote successfully too */
		VbNvSet(vnc, VBNV_BACKUP_NVRAM_REQUEST, 0);
		return 0;
	}

	VBDEBUG(("TPM: Sorry, couldn't write backup.\n"));
	return 1;
}
コード例 #6
0
VbError_t VbCheckDisplayKey(VbCommonParams *cparams, uint32_t key,
                            VbNvContext *vncptr)
{
	int i;

	/* Update key buffer */
	for(i = 1; i < MAGIC_WORD_LEN; i++)
		MagicBuffer[i - 1] = MagicBuffer[i];
	/* Save as lower-case ASCII */
	MagicBuffer[MAGIC_WORD_LEN - 1] = (key | 0x20) & 0xFF;

	if ('\t' == key) {
		/* Tab = display debug info */
		return VbDisplayDebugInfo(cparams, vncptr);
	} else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key ||
		   VB_KEY_DOWN == key || VB_KEY_UP == key) {
		/* Arrow keys = change localization */
		uint32_t loc = 0;
		uint32_t count = 0;

		VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &loc);
		if (VBERROR_SUCCESS != VbGetLocalizationCount(cparams, &count))
			loc = 0;  /* No localization count (bad GBB?) */
		else if (VB_KEY_RIGHT == key || VB_KEY_UP == key)
			loc = (loc < count - 1 ? loc + 1 : 0);
		else
			loc = (loc > 0 ? loc - 1 : count - 1);
		VBDEBUG(("VbCheckDisplayKey() - change localization to %d\n",
			 (int)loc));
		VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, loc);

#ifdef SAVE_LOCALE_IMMEDIATELY
		VbNvTeardown(vncptr);  /* really only computes checksum */
		if (vncptr->raw_changed)
			VbExNvStorageWrite(vncptr->raw);
#endif

		/* Force redraw of current screen */
		return VbDisplayScreen(cparams, disp_current_screen, 1, vncptr);
	}

	if (0 == Memcmp(MagicBuffer, MAGIC_WORD, MAGIC_WORD_LEN)) {
		if (VBEASTEREGG)
			(void)VbDisplayScreen(cparams, disp_current_screen,
					      1, vncptr);
	}

  return VBERROR_SUCCESS;
}
コード例 #7
0
VbError_t VbLockDevice(void)
{
    VbExNvStorageRead(vnc.raw);
    VbNvSetup(&vnc);

    VBDEBUG(("%s() - Storing request to leave dev-mode.\n",
             __func__));
    VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST,
            1);

    VbNvTeardown(&vnc);
    if (vnc.raw_changed)
        VbExNvStorageWrite(vnc.raw);

    VBDEBUG(("%s() Mode change will take effect on next reboot.\n",
             __func__));

    return VBERROR_SUCCESS;
}
コード例 #8
0
VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams)
{
	VbSharedDataHeader *shared =
		(VbSharedDataHeader *)cparams->shared_data_blob;
	GoogleBinaryBlockHeader gbb;
	VbNvContext vnc;
	VbError_t retval = VBERROR_SUCCESS;
	uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
	int is_s3_resume = 0;
	uint32_t s3_debug_boot = 0;
	uint32_t require_official_os = 0;
	uint32_t tpm_version = 0;
	uint32_t tpm_status = 0;
	int has_virt_dev_switch = 0;
	int is_hw_dev = 0;
	int is_virt_dev = 0;
	uint32_t disable_dev_request = 0;
	uint32_t clear_tpm_owner_request = 0;
	int is_dev = 0;
	uint32_t backup_requested = 0;
	uint32_t backup_for_safety = 0;
	int lost_nvram;

	/* Initialize output flags */
	iparams->out_flags = 0;

	retval = VbGbbReadHeader_static(cparams, &gbb);
	if (retval)
		return retval;

	VBDEBUG(("VbInit() input flags 0x%x gbb flags 0x%x\n", iparams->flags,
		 gbb.flags));

	/* Set up NV storage */
	VbExNvStorageRead(vnc.raw);
	VbNvSetup(&vnc);
	lost_nvram = vnc.regenerate_crc;

	/* Initialize shared data structure */
	if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) {
		VBDEBUG(("Shared data init error\n"));
		return VBERROR_INIT_SHARED_DATA;
	}

	shared->timer_vb_init_enter = VbExGetTimer();

	/* Copy some boot switch flags */
	/* TODO: in next refactor, just save in/out flags in VbSharedData */
	shared->flags = 0;
	if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
		shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
	if (iparams->flags & VB_INIT_FLAG_WP_ENABLED)
		shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
	if (iparams->flags & VB_INIT_FLAG_SW_WP_ENABLED)
		shared->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED;
	if (iparams->flags & VB_INIT_FLAG_S3_RESUME)
		shared->flags |= VBSD_BOOT_S3_RESUME;
	if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT)
		shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT;
	if (iparams->flags & VB_INIT_FLAG_EC_SOFTWARE_SYNC)
		shared->flags |= VBSD_EC_SOFTWARE_SYNC;
	if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE)
		shared->flags |= VBSD_EC_SLOW_UPDATE;
	if (iparams->flags & VB_INIT_FLAG_VIRTUAL_REC_SWITCH)
		shared->flags |= VBSD_BOOT_REC_SWITCH_VIRTUAL;
	if (iparams->flags & VB_INIT_FLAG_OPROM_MATTERS)
		shared->flags |= VBSD_OPROM_MATTERS;
	if (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)
		shared->flags |= VBSD_OPROM_LOADED;

	is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);

	/* Check if the OS is requesting a debug S3 reset */
	VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot);
	if (s3_debug_boot) {
		if (is_s3_resume) {
			VBDEBUG(("VbInit() requesting S3 debug boot\n"));
			iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT;
			is_s3_resume = 0;  /* Proceed as if normal boot */
		}

		/*
		 * Clear the request even if this is a normal boot, since we
		 * don't want the NEXT S3 resume to be a debug reset unless the
		 * OS asserts the request again.
		 */
		VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0);
	}

	/*
	 * If this isn't a S3 resume, read the current recovery request, then
	 * clear it so we don't get stuck in recovery mode.
	 */
	if (!is_s3_resume) {
		VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery);
		VBDEBUG(("VbInit sees recovery request = %d\n", recovery));
		if (VBNV_RECOVERY_NOT_REQUESTED != recovery)
			VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
				VBNV_RECOVERY_NOT_REQUESTED);
	}

	/*
	 * If the previous boot failed in the firmware somewhere outside of
	 * verified boot, and recovery is not requested for our own reasons,
	 * request recovery mode.  This gives the calling firmware a way to
	 * request recovery if it finds something terribly wrong.
	 */
	if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
	    iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
		recovery = VBNV_RECOVERY_RO_FIRMWARE;
	}

	/*
	 * If recovery button is pressed, override recovery reason.  Note that
	 * we do this in the S3 resume path also.
	 */
	if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
		recovery = VBNV_RECOVERY_RO_MANUAL;

	/*
	 * Copy current recovery reason to shared data. If we fail later on, it
	 * won't matter, since we'll just reboot.
	 */
	shared->recovery_reason = (uint8_t)recovery;
	VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));

	/*
	 * If this is a S3 resume, resume the TPM.
	 *
	 * FIXME: I think U-Boot won't ever ask us to do this. Can we remove
	 * it?
	 */
	if (is_s3_resume) {
		if (TPM_SUCCESS != RollbackS3Resume()) {
			/*
			 * If we can't resume, just do a full reboot.  No need
			 * to go to recovery mode here, since if the TPM is
			 * really broken we'll catch it on the next boot.
			 */
			retval = VBERROR_TPM_S3_RESUME;
		}
	} else {
		/* Should we pay attention to the TPM's virtual dev-switch? */
		if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) {
			shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
			has_virt_dev_switch = 1;
		}

		/*
		 * We always believe the HW dev-switch, since there's one
		 * attached to servo which may be active even on systems
		 * without a physical switch. The EC may also implement a fake
		 * dev-switch for testing.
		 */
		if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
			is_hw_dev = 1;

		/* We may be asked to clear the virtual dev-switch at boot. */
		VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);

		/* Allow GBB flag to override dev switch */
		if (gbb.flags & GBB_FLAG_FORCE_DEV_SWITCH_ON)
			is_hw_dev = 1;

		/* Have we been explicitly asked to clear the TPM owner? */
		VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST,
			&clear_tpm_owner_request);

		/*
		 * Initialize the TPM. If the developer mode state has changed
		 * since the last boot, we need to clear TPM ownership. If the
		 * TPM space is initialized by this call, the virtual
		 * dev-switch will be disabled by default)
		 */
		VBDEBUG(("TPM: Call RollbackFirmwareSetup(r%d, d%d)\n",
			 recovery, is_hw_dev));
		tpm_status = RollbackFirmwareSetup(is_hw_dev,
						   disable_dev_request,
						   clear_tpm_owner_request,
						   /* two outputs on success */
						   &is_virt_dev, &tpm_version);

		if (0 != tpm_status) {
			VBDEBUG(("Unable to setup TPM and read "
				 "firmware version (0x%x)\n", tpm_status));

			if (TPM_E_MUST_REBOOT == tpm_status) {
				/*
				 * TPM wants to reboot into the same mode we're
				 * in now
				 */
				VBDEBUG(("TPM requires a reboot.\n"));
				if (!recovery) {
					/*
					 * Not recovery mode.  Just reboot (not
					 * into recovery).
					 */
					retval = VBERROR_TPM_REBOOT_REQUIRED;
					goto VbInit_exit;
				} else if (VBNV_RECOVERY_RO_TPM_REBOOT !=
					   shared->recovery_reason) {
					/*
					 * In recovery mode now, and we haven't
					 * requested a TPM reboot yet, so
					 * request one.
					 */
					VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
						VBNV_RECOVERY_RO_TPM_REBOOT);
					retval = VBERROR_TPM_REBOOT_REQUIRED;
					goto VbInit_exit;
				}
			}

			if (!recovery) {
				VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
					VBNV_RECOVERY_RO_TPM_S_ERROR);
				VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE,
					tpm_status);
				retval = VBERROR_TPM_FIRMWARE_SETUP;
				goto VbInit_exit;
			}
		}

		/* TPM setup succeeded, or we're in recovery mode and ignoring
		 * errors. What did we learn? */
		shared->fw_version_tpm_start = tpm_version;
		shared->fw_version_tpm = tpm_version;
		if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) {
			is_dev = 1;
			shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
		}
		if (disable_dev_request && !is_virt_dev)
			VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0);
		if (clear_tpm_owner_request) {
			VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0);
			VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1);
		}
	}

	/*
	 * If the nvram state was lost, try to restore the bits we care about
	 * from the backup in the TPM. It's okay if we can't, though.
	 * Note: None of the bits that we back up should have been referenced
	 * before this point. Otherwise, they'll just be overwritten here.
	 * All the other bits will be unchanged from whatever has happened to
	 * them since VbNvSetup() reinitialized the VbNvContext.
	 */
	if (lost_nvram)
		RestoreNvFromBackup(&vnc);

	/* Allow BIOS to load arbitrary option ROMs? */
	if (gbb.flags & GBB_FLAG_LOAD_OPTION_ROMS)
		iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM;

	/* Factory may need to boot custom OSes when the dev-switch is on */
	if (is_dev && (gbb.flags & GBB_FLAG_ENABLE_ALTERNATE_OS))
		iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;

	/* Set output flags */
	if (VBNV_RECOVERY_NOT_REQUESTED != recovery) {
		/* Requesting recovery mode */
		iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY |
				       VB_INIT_OUT_CLEAR_RAM |
				       VB_INIT_OUT_ENABLE_DISPLAY |
				       VB_INIT_OUT_ENABLE_USB_STORAGE);
	} else if (is_dev) {
		/* Developer switch is on, so need to support dev mode */
		iparams->out_flags |= (VB_INIT_OUT_ENABLE_DEVELOPER |
				       VB_INIT_OUT_CLEAR_RAM |
				       VB_INIT_OUT_ENABLE_DISPLAY |
				       VB_INIT_OUT_ENABLE_USB_STORAGE);
		/* ... which may or may not include custom OSes */
		VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
		if (!require_official_os)
			iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;

		/*
		 * Dev-mode needs the VGA option ROM to be loaded so it can
		 * display the scary boot screen. If we don't have it, we need
		 * to request it and reboot so it can be loaded.
		 */
		if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
		    !(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
			VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
			/*
			 * If VbInit() is run before Option ROMs are run it
			 * can still respond to the VbNv flag and does not
			 * need to reboot here.
			 */
			if (!(iparams->flags & VB_INIT_FLAG_BEFORE_OPROM_LOAD))
				retval = VBERROR_VGA_OPROM_MISMATCH;
			VBDEBUG(("VbInit() needs oprom, doesn't have it\n"));
		}

	} else {
		/*
		 * Normal mode, so disable dev_boot_* flags.  This ensures they
		 * will be initially disabled if the user later transitions
		 * back into developer mode.
		 */
		VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
		VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0);
		VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0);
		/*
		 * Back up any changes now, so these values can't be forgotten
		 * by draining the battery. We really only care about these
		 * three fields, but it's uncommon for any others to change so
		 * this is an easier test than checking each one.
		 */
		if (vnc.regenerate_crc)
			backup_for_safety = 1;

		/*
		 * If we don't need the VGA option ROM but got it anyway, stop
		 * asking for it and reboot in case there's some vulnerability
		 * in using it.
		 */
		if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
		    (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
			VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
			/*
			 * If VbInit() is run before Option ROMs are run it
			 * can still respond to the VbNv flag and does not
			 * need to reboot here.
			 */
			if (!(iparams->flags & VB_INIT_FLAG_BEFORE_OPROM_LOAD))
				retval = VBERROR_VGA_OPROM_MISMATCH;
			VBDEBUG(("VbInit() has oprom, doesn't need it\n"));
		}
	}

VbInit_exit:
	/*
	 * If we successfully backup the NV storage, it will clear the
	 * VBNV_BACKUP_NVRAM_REQUEST field, so we want to do it before
	 * calling VbNvTeardown(). It's okay if we can't backup, though.
	 */
	VbNvGet(&vnc, VBNV_BACKUP_NVRAM_REQUEST, &backup_requested);
	if (backup_requested || backup_for_safety)
		SaveNvToBackup(&vnc);

	/* Tear down NV storage */
	VbNvTeardown(&vnc);
	if (vnc.raw_changed)
		VbExNvStorageWrite(vnc.raw);

	VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));

	shared->timer_vb_init_exit = VbExGetTimer();

	VBDEBUG(("VbInit() returning 0x%x\n", retval));

	return retval;
}
コード例 #9
0
int do_cros_bootstub(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int status = LOAD_FIRMWARE_RECOVERY;
	firmware_storage_t file;
	VbNvContext nvcxt;
	uint64_t boot_flags = 0;
	uint32_t recovery_request = 0;
	uint32_t reason = VBNV_RECOVERY_NOT_REQUESTED;
	uint8_t *firmware_data;

	if (firmware_storage_init(&file)) {
		/* FIXME(clchiou) Bring up a sad face as boot has failed */
		VBDEBUG(PREFIX "init_firmware_storage fail\n");
		while (1);
	}

	if (is_firmware_write_protect_gpio_asserted())
		WARN_ON_FAILURE(file.lock_device(file.context));

	clear_kernel_shared_data();

	/* Fill in the RO firmware ID */
	KernelSharedDataType *sd = get_kernel_shared_data();
	if (firmware_storage_read(&file,
			(off_t)CONFIG_OFFSET_RO_FRID,
			(size_t)CONFIG_LENGTH_RO_FRID,
			sd->frid)) {
		VBDEBUG(PREFIX "fail to read fwid\n");
		reason = VBNV_RECOVERY_US_UNSPECIFIED;
		goto RECOVERY;
	}

	if (read_nvcontext(&nvcxt) || VbNvGet(&nvcxt, VBNV_RECOVERY_REQUEST,
				&recovery_request)) {
		VBDEBUG(PREFIX "fail to read nvcontext\n");
		reason = VBNV_RECOVERY_US_UNSPECIFIED;
		goto RECOVERY;
	}

	/* clear VBNV_DEBUG_RESET_MODE after read */
	if (VbNvSet(&nvcxt, VBNV_DEBUG_RESET_MODE, 0)) {
		VBDEBUG(PREFIX "fail to write nvcontext\n");
		reason = VBNV_RECOVERY_US_UNSPECIFIED;
		goto RECOVERY;
	}

	if (recovery_request != VBNV_RECOVERY_NOT_REQUESTED) {
		VBDEBUG(PREFIX "boot recovery cookie set\n");
		reason = recovery_request;
		goto RECOVERY;
	}

	if (is_recovery_mode_gpio_asserted()) {
		VBDEBUG(PREFIX "recovery button pressed\n");
		reason = VBNV_RECOVERY_RO_MANUAL;
		goto RECOVERY;
	}

	if (is_developer_mode_gpio_asserted())
		boot_flags |= BOOT_FLAG_DEVELOPER;

	status = load_firmware_wrapper(&file,
			boot_flags, &nvcxt, NULL, &firmware_data);

	if (nvcxt.raw_changed && write_nvcontext(&nvcxt)) {
		VBDEBUG(PREFIX "fail to write nvcontext\n");
		reason = VBNV_RECOVERY_US_UNSPECIFIED;
		goto RECOVERY;
	}

	if (status == LOAD_FIRMWARE_SUCCESS) {
		jump_to_firmware((void (*)(void)) firmware_data);
	} else if (status == LOAD_FIRMWARE_REBOOT) {
		cold_reboot();
	}

	/* assert(status == LOAD_FIRMWARE_RECOVERY) */

RECOVERY:
	VBDEBUG(PREFIX "write to recovery cookie\n");

	/*
	 * Although writing back VbNvContext cookies may fail, we boot
	 * recovery firmware anyway. In this way, the recovery reason
	 * would be incorrect, but this is much better than not booting
	 * anything.
	 */

	if (reason != VBNV_RECOVERY_NOT_REQUESTED &&
			VbNvSet(&nvcxt, VBNV_RECOVERY_REQUEST, reason)) {
		/* FIXME: bring up a sad face? */
		VBDEBUG(PREFIX "error: cannot write recovery reason\n");
	}

	if (VbNvTeardown(&nvcxt)) {
		/* FIXME: bring up a sad face? */
		VBDEBUG(PREFIX "error: cannot tear down cookie\n");
	}

	if (nvcxt.raw_changed && write_nvcontext(&nvcxt)) {
		/* FIXME: bring up a sad face? */
		VBDEBUG(PREFIX "error: cannot write recovery cookie\n");
	}

	VBDEBUG(PREFIX "jump to recovery firmware and never return\n");

	firmware_data = malloc(CONFIG_LENGTH_RECOVERY);
	WARN_ON_FAILURE(load_recovery_firmware(&file, firmware_data));
	jump_to_firmware((void (*)(void)) firmware_data);

	/* never reach here */
	return 1;
}
コード例 #10
0
static void VbSoftwareSyncTest(void)
{
	/* Recovery cases */
	ResetMocks();
	shared->recovery_reason = 123;
	test_ssync(0, 0, "In recovery, EC-RO");
	TEST_EQ(ec_rw_protected, 0, "  ec rw protected");

	ResetMocks();
	shared->recovery_reason = 123;
	mock_in_rw = 1;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   123, "Recovery needs EC-RO");

	/* AP-RO cases */
	ResetMocks();
	in_rw_retval = VBERROR_SIMULATED;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");

	ResetMocks();
	shared->flags |= VBSD_LF_USE_RO_NORMAL;
	mock_in_rw = 1;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   0, "AP-RO needs EC-RO");

	ResetMocks();
	shared->flags |= VBSD_LF_USE_RO_NORMAL;
	test_ssync(0, 0, "AP-RO, EC-RO");
	TEST_EQ(ec_rw_protected, 1, "  ec rw protected");
	TEST_EQ(ec_run_image, 0, "  ec run image");

	ResetMocks();
	shared->flags |= VBSD_LF_USE_RO_NORMAL;
	run_retval = VBERROR_SIMULATED;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_SOFTWARE_SYNC, "Stay in RO fail");

	ResetMocks();
	shared->flags |= VBSD_LF_USE_RO_NORMAL;
	protect_retval = VBERROR_SIMULATED;
	test_ssync(VBERROR_SIMULATED,
		   VBNV_RECOVERY_EC_PROTECT, "Protect error");

	/* No longer check for shutdown requested */
	ResetMocks();
	shared->flags |= VBSD_LF_USE_RO_NORMAL;
	shutdown_request_calls_left = 0;
	test_ssync(0, 0, "AP-RO shutdown requested");

	/* Calculate hashes */
	ResetMocks();
	mock_ec_rw_hash_size = 0;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_HASH_FAILED, "Bad EC hash");

	ResetMocks();
	mock_ec_rw_hash_size = 16;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_HASH_SIZE, "Bad EC hash size");

	ResetMocks();
	want_ec_hash_size = 0;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash");

	ResetMocks();
	want_ec_hash_size = 16;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_EXPECTED_HASH,
		   "Bad precalculated hash size");

	ResetMocks();
	mock_in_rw = 1;
	want_ec_hash_size = -1;
	test_ssync(0, 0, "No precomputed hash");

	ResetMocks();
	want_ec_hash_size = -1;
	get_expected_retval = VBERROR_SIMULATED;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_EXPECTED_IMAGE, "Can't fetch image");

	/* Updates required */
	ResetMocks();
	mock_in_rw = 1;
	want_ec_hash[0]++;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_HASH_MISMATCH,
		   "Precalculated hash mismatch");

	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]++;
	VbNvSet(VbApiKernelGetVnc(), 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");
	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]++;
	VbNvSet(VbApiKernelGetVnc(), 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");
	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();
	shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
	VbNvSet(VbApiKernelGetVnc(), VBNV_TRY_RO_SYNC, 1);
	mock_ec_rw_hash[0]++;
	mock_ec_ro_hash[0]++;
	test_ssync(0, 0, "WP enabled");
	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();
	VbNvSet(VbApiKernelGetVnc(), 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");
	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");

	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,
		   VBNV_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 = VBERROR_SIMULATED;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_RECOVERY_EC_UPDATE, "Update failed");

	ResetMocks();
	mock_ec_rw_hash[0]++;
	shared->flags |= VBSD_EC_SLOW_UPDATE;
	test_ssync(0, 0, "Slow update");
	TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, "  wait screen");

	/* 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 = VBERROR_SIMULATED;
	test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
		   VBNV_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 = VBERROR_SIMULATED;
	test_ssync(VBERROR_SIMULATED,
		   VBNV_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");
}
コード例 #11
0
VbError_t VbDisplayScreenFromGBB(VbCommonParams *cparams, uint32_t screen,
                                 VbNvContext *vncptr)
{
	char *fullimage = NULL;
	BmpBlockHeader hdr;
	uint32_t screen_index;
	uint32_t localization = 0;
	VbError_t retval = VBERROR_UNKNOWN;   /* Assume error until proven ok */
	uint32_t inoutsize;
	uint32_t i;
	VbFont_t *font;
	const char *text_to_show;
	int rtol = 0;
	VbError_t ret;

	ret = VbGbbReadBmpHeader(cparams, &hdr);
	if (ret)
		return ret;

	/*
	 * Translate screen ID into index.  Note that not all screens are in
	 * the GBB.
	 *
	 * TODO: ensure screen IDs match indices?  Having this translation here
	 * is awful.
	 */
	switch (screen) {
	case VB_SCREEN_DEVELOPER_WARNING:
		screen_index = SCREEN_DEVELOPER_WARNING;
		break;
	case VB_SCREEN_RECOVERY_REMOVE:
		screen_index = SCREEN_RECOVERY_REMOVE;
		break;
	case VB_SCREEN_RECOVERY_NO_GOOD:
		screen_index = SCREEN_RECOVERY_NO_GOOD;
		break;
	case VB_SCREEN_RECOVERY_INSERT:
		screen_index = SCREEN_RECOVERY_INSERT;
		break;
	case VB_SCREEN_RECOVERY_TO_DEV:
		screen_index = SCREEN_RECOVERY_TO_DEV;
		break;
	case VB_SCREEN_DEVELOPER_TO_NORM:
		screen_index = SCREEN_DEVELOPER_TO_NORM;
		break;
	case VB_SCREEN_WAIT:
		screen_index = SCREEN_WAIT;
		break;
	case VB_SCREEN_TO_NORM_CONFIRMED:
		screen_index = SCREEN_TO_NORM_CONFIRMED;
		break;
	case VB_SCREEN_BLANK:
	case VB_SCREEN_DEVELOPER_EGG:
	default:
		/* Screens which aren't in the GBB */
		VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n",
			 (int)screen));
		retval = VBERROR_INVALID_SCREEN_INDEX;
		goto VbDisplayScreenFromGBB_exit;
	}

	if (screen_index >= hdr.number_of_screenlayouts) {
		VBDEBUG(("VbDisplayScreenFromGBB(): "
			 "screen %d index %d not in the GBB\n",
			 (int)screen, (int)screen_index));
		retval = VBERROR_INVALID_SCREEN_INDEX;
		goto VbDisplayScreenFromGBB_exit;
	}

	/* Clip localization to number of localizations present in the GBB */
	VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &localization);
	if (localization >= hdr.number_of_localizations) {
		localization = 0;
		VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, localization);
	}

	/* Display all bitmaps for the image */
	for (i = 0; i < MAX_IMAGE_IN_LAYOUT; i++) {
		ScreenLayout layout;
		ImageInfo image_info;
		char hwid[256];

		ret = VbGbbReadImage(cparams, localization, screen_index,
				    i, &layout, &image_info,
				    &fullimage, &inoutsize);
		if (ret == VBERROR_NO_IMAGE_PRESENT) {
			continue;
		} else if (ret) {
			retval = ret;
			goto VbDisplayScreenFromGBB_exit;
		}

		switch(image_info.format) {
		case FORMAT_BMP:
			if (i == 0) {
				/**
				 * In current version GBB bitmaps, first image
				 * is always the background.
				 */
				ret = VbExDisplaySetDimension(
						image_info.width,
						image_info.height);
				if (ret) {
					VBDEBUG(("VbExDisplaySetDimension"
						 "(%d,%d): failed (%#x).\n",
						 image_info.width,
						 image_info.height, ret));
				}
			}

			retval = VbExDisplayImage(layout.images[i].x,
						  layout.images[i].y,
						  fullimage, inoutsize);
			break;

		case FORMAT_FONT:
			/*
			 * The uncompressed blob is our font structure. Cache
			 * it as needed.
			 */
			font = VbInternalizeFontData(
					(FontArrayHeader *)fullimage);

			/* TODO: handle text in general here */
			if (TAG_HWID == image_info.tag ||
			    TAG_HWID_RTOL == image_info.tag) {
				VbRegionReadHWID(cparams, hwid, sizeof(hwid));
				text_to_show = hwid;
				rtol = (TAG_HWID_RTOL == image_info.tag);
			} else {
				text_to_show = "";
				rtol = 0;
			}

			VbRenderTextAtPos(text_to_show, rtol,
					  layout.images[i].x,
					  layout.images[i].y, font);

			VbDoneWithFontForNow(font);
			break;

		default:
			VBDEBUG(("VbDisplayScreenFromGBB(): "
				 "unsupported ImageFormat %d\n",
				 image_info.format));
			retval = VBERROR_INVALID_GBB;
		}

		VbExFree(fullimage);

		if (VBERROR_SUCCESS != retval)
			goto VbDisplayScreenFromGBB_exit;
	}

	/* Successful if all bitmaps displayed */
	retval = VBERROR_SUCCESS;

	VbRegionCheckVersion(cparams);

 VbDisplayScreenFromGBB_exit:
	VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval));
	return retval;
}
コード例 #12
0
static void VbNvStorageTest(void) {

  VbNvField* vnf;
  VbNvContext c;
  uint8_t goodcrc;
  uint32_t data;

  memset(&c, 0xA6, sizeof(c));

  /* Open with invalid data should set defaults */
  TEST_EQ(VbNvSetup(&c), 0, "VbNvSetup()");
  TEST_EQ(c.raw[0], 0x70, "VbNvSetup() reset header byte");
  /* Close then regenerates the CRC */
  TEST_EQ(VbNvTeardown(&c), 0, "VbNvTeardown()");
  TEST_NEQ(c.raw[15], 0, "VbNvTeardown() CRC");
  TEST_EQ(c.raw_changed, 1, "VbNvTeardown() changed");
  goodcrc = c.raw[15];
  /* Another open-close pair should not cause further changes */
  VbNvSetup(&c);
  VbNvTeardown(&c);
  TEST_EQ(c.raw_changed, 0, "VbNvTeardown() didn't change");
  TEST_EQ(c.raw[15], goodcrc, "VbNvTeardown() CRC same");

  /* Perturbing the header should force defaults */
  c.raw[0] ^= 0x40;
  VbNvSetup(&c);
  TEST_EQ(c.raw[0], 0x70, "VbNvSetup() reset header byte again");
  /* Close then regenerates the CRC */
  VbNvTeardown(&c);
  TEST_EQ(c.raw_changed, 1, "VbNvTeardown() changed again");
  TEST_EQ(c.raw[15], goodcrc, "VbNvTeardown() CRC same again");

  /* So should perturbing some other byte */
  TEST_EQ(c.raw[11], 0, "Kernel byte starts at 0");
  c.raw[11] = 12;
  VbNvSetup(&c);
  TEST_EQ(c.raw[11], 0, "VbNvSetup() reset kernel byte");
  /* Close then regenerates the CRC */
  VbNvTeardown(&c);
  TEST_EQ(c.raw_changed, 1, "VbNvTeardown() changed again");
  TEST_EQ(c.raw[15], goodcrc, "VbNvTeardown() CRC same again");

  /* Clear the kernel and firmware flags */
  VbNvSetup(&c);
  TEST_EQ(VbNvGet(&c, VBNV_FIRMWARE_SETTINGS_RESET, &data), 0,
          "Get firmware settings reset");
  TEST_EQ(data, 1, "Firmware settings are reset");
  TEST_EQ(VbNvSet(&c, VBNV_FIRMWARE_SETTINGS_RESET, 0), 0,
          "Clear firmware settings reset");
  VbNvGet(&c, VBNV_FIRMWARE_SETTINGS_RESET, &data);
  TEST_EQ(data, 0, "Firmware settings are clear");

  TEST_EQ(VbNvGet(&c, VBNV_KERNEL_SETTINGS_RESET, &data), 0,
          "Get kernel settings reset");
  TEST_EQ(data, 1, "Kernel settings are reset");
  TEST_EQ(VbNvSet(&c, VBNV_KERNEL_SETTINGS_RESET, 0), 0,
          "Clear kernel settings reset");
  VbNvGet(&c, VBNV_KERNEL_SETTINGS_RESET, &data);
  TEST_EQ(data, 0, "Kernel settings are clear");
  TEST_EQ(c.raw[0], 0x40, "Header byte now just has the header bit");
  VbNvTeardown(&c);
  /* That should have changed the CRC */
  TEST_NEQ(c.raw[15], goodcrc, "VbNvTeardown() CRC changed due to flags clear");

  /* Test explicitly setting the reset flags again */
  VbNvSetup(&c);
  VbNvSet(&c, VBNV_FIRMWARE_SETTINGS_RESET, 1);
  VbNvGet(&c, VBNV_FIRMWARE_SETTINGS_RESET, &data);
  TEST_EQ(data, 1, "Firmware settings forced reset");
  VbNvSet(&c, VBNV_FIRMWARE_SETTINGS_RESET, 0);

  VbNvSet(&c, VBNV_KERNEL_SETTINGS_RESET, 1);
  VbNvGet(&c, VBNV_KERNEL_SETTINGS_RESET, &data);
  TEST_EQ(data, 1, "Kernel settings forced reset");
  VbNvSet(&c, VBNV_KERNEL_SETTINGS_RESET, 0);
  VbNvTeardown(&c);

  /* Get/set an invalid field */
  VbNvSetup(&c);
  TEST_EQ(VbNvGet(&c, -1, &data), 1, "Get invalid setting");
  TEST_EQ(VbNvSet(&c, -1, 0), 1, "Set invalid setting");
  VbNvTeardown(&c);

  /* Test other fields */
  VbNvSetup(&c);
  for (vnf = nvfields; vnf->desc; vnf++) {
    TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, vnf->desc);
    TEST_EQ(data, vnf->default_value, vnf->desc);

    TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value), 0, vnf->desc);
    TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, vnf->desc);
    TEST_EQ(data, vnf->test_value, vnf->desc);

    TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value2), 0, vnf->desc);
    TEST_EQ(VbNvGet(&c, vnf->param, &data), 0, vnf->desc);
    TEST_EQ(data, vnf->test_value2, vnf->desc);
  }
  VbNvTeardown(&c);

  /* None of those changes should have caused a reset to defaults */
  VbNvSetup(&c);
  VbNvGet(&c, VBNV_FIRMWARE_SETTINGS_RESET, &data);
  TEST_EQ(data, 0, "Firmware settings are still clear");
  VbNvGet(&c, VBNV_KERNEL_SETTINGS_RESET, &data);
  TEST_EQ(data, 0, "Kernel settings are still clear");
  VbNvTeardown(&c);

  /* Verify writing identical settings doesn't cause the CRC to regenerate */
  VbNvSetup(&c);
  TEST_EQ(c.regenerate_crc, 0, "No regen CRC on open");
  for (vnf = nvfields; vnf->desc; vnf++)
    TEST_EQ(VbNvSet(&c, vnf->param, vnf->test_value2), 0, vnf->desc);
  TEST_EQ(c.regenerate_crc, 0, "No regen CRC if data not changed");
  VbNvTeardown(&c);
  TEST_EQ(c.raw_changed, 0, "No raw change if data not changed");

  /* Test out-of-range fields mapping to defaults */
  VbNvSetup(&c);
  VbNvSet(&c, VBNV_TRY_B_COUNT, 16);
  VbNvGet(&c, VBNV_TRY_B_COUNT, &data);
  TEST_EQ(data, 15, "Try b count out of range");
  VbNvSet(&c, VBNV_RECOVERY_REQUEST, 0x101);
  VbNvGet(&c, VBNV_RECOVERY_REQUEST, &data);
  TEST_EQ(data, VBNV_RECOVERY_LEGACY, "Recovery request out of range");
  VbNvSet(&c, VBNV_LOCALIZATION_INDEX, 0x102);
  VbNvGet(&c, VBNV_LOCALIZATION_INDEX, &data);
  TEST_EQ(data, 0, "Localization index out of range");
  VbNvTeardown(&c);
}
コード例 #13
0
VbError_t VbSelectFirmware(VbCommonParams *cparams,
                           VbSelectFirmwareParams *fparams)
{
	VbSharedDataHeader *shared =
		(VbSharedDataHeader *)cparams->shared_data_blob;
	VbNvContext vnc;
	VbError_t retval = VBERROR_UNKNOWN; /* Default to error */
	int is_rec = (shared->recovery_reason ? 1 : 0);
	int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
	uint32_t tpm_status = 0;

	/* Start timer */
	shared->timer_vb_select_firmware_enter = VbExGetTimer();

	/* Load NV storage */
	VbExNvStorageRead(vnc.raw);
	VbNvSetup(&vnc);

	if (is_rec) {
		/*
		 * Recovery is requested; go straight to recovery without
		 * checking the RW firmware.
		 */
		VBDEBUG(("VbSelectFirmware() detected recovery request\n"));

		/* Go directly to recovery mode */
		fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
	} else {
		/* Chain to LoadFirmware() */
		retval = LoadFirmware(cparams, fparams, &vnc);

		/* Exit if we failed to find an acceptable firmware */
		if (VBERROR_SUCCESS != retval)
			goto VbSelectFirmware_exit;

		/* Translate the selected firmware path */
		if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
			/* Request the read-only normal/dev code path */
			fparams->selected_firmware =
				VB_SELECT_FIRMWARE_READONLY;
		} else if (0 == shared->firmware_index)
			fparams->selected_firmware = VB_SELECT_FIRMWARE_A;
		else {
			fparams->selected_firmware = VB_SELECT_FIRMWARE_B;
		}

		/* Update TPM if necessary */
		if (shared->fw_version_tpm_start < shared->fw_version_tpm) {
			tpm_status =
				RollbackFirmwareWrite(shared->fw_version_tpm);
			if (0 != tpm_status) {
				VBDEBUG(("Can't write FW version to TPM.\n"));
				VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
					VBNV_RECOVERY_RO_TPM_W_ERROR);
				retval = VBERROR_TPM_WRITE_FIRMWARE;
				goto VbSelectFirmware_exit;
			}
		}

		/* Lock firmware versions in TPM */
		tpm_status = RollbackFirmwareLock();
		if (0 != tpm_status) {
			VBDEBUG(("Unable to lock firmware version in TPM.\n"));
			VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
				VBNV_RECOVERY_RO_TPM_L_ERROR);
			retval = VBERROR_TPM_LOCK_FIRMWARE;
			goto VbSelectFirmware_exit;
		}
	}

	/*
	 * At this point, we have a good idea of how we are going to
	 * boot. Update the TPM with this state information.
	 */
	tpm_status = SetTPMBootModeState(is_dev, is_rec,
					 shared->fw_keyblock_flags);
	if (0 != tpm_status) {
		VBDEBUG(("Can't update the TPM with boot mode information.\n"));
		if (!is_rec) {
			VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
				VBNV_RECOVERY_RO_TPM_U_ERROR);
			retval = VBERROR_TPM_SET_BOOT_MODE_STATE;
			goto VbSelectFirmware_exit;
		}
	}

	/* Success! */
	retval = VBERROR_SUCCESS;

 VbSelectFirmware_exit:

	/* Save NV storage */
	VbNvTeardown(&vnc);
	if (vnc.raw_changed)
		VbExNvStorageWrite(vnc.raw);

	/* Stop timer */
	shared->timer_vb_select_firmware_exit = VbExGetTimer();

	/* Should always have a known error code */
	VbAssert(VBERROR_UNKNOWN != retval);

	return retval;
}
コード例 #14
0
VbError_t VbBootDeveloper(VbCommonParams *cparams, LoadKernelParams *p)
{
    GoogleBinaryBlockHeader *gbb = cparams->gbb;
    VbSharedDataHeader *shared =
        (VbSharedDataHeader *)cparams->shared_data_blob;
    uint32_t allow_usb = 0, allow_legacy = 0, ctrl_d_pressed = 0;
    VbAudioContext *audio = 0;

    VBDEBUG(("Entering %s()\n", __func__));

    /* Check if USB booting is allowed */
    VbNvGet(&vnc, VBNV_DEV_BOOT_USB, &allow_usb);
    VbNvGet(&vnc, VBNV_DEV_BOOT_LEGACY, &allow_legacy);

    /* Handle GBB flag override */
    if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
        allow_usb = 1;
    if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
        allow_legacy = 1;

    /* Show the dev mode warning screen */
    VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);

    /* Get audio/delay context */
    audio = VbAudioOpen(cparams);

    /* We'll loop until we finish the delay or are interrupted */
    do {
        uint32_t key;

        if (VbWantShutdown(gbb->flags)) {
            VBDEBUG(("VbBootDeveloper() - shutdown requested!\n"));
            VbAudioClose(audio);
            return VBERROR_SHUTDOWN_REQUESTED;
        }

        key = VbExKeyboardRead();
        switch (key) {
        case 0:
            /* nothing pressed */
            break;
        case '\r':
            /* Only disable virtual dev switch if allowed by GBB */
            if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
                break;
        case ' ':
            /* See if we should disable virtual dev-mode switch. */
            VBDEBUG(("%s shared->flags=0x%x\n",
                     __func__, shared->flags));
            if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
                    shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
                /* Stop the countdown while we go ask... */
                VbAudioClose(audio);
                if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
                    /*
                     * TONORM won't work (only for
                     * non-shipping devices).
                     */
                    VBDEBUG(("%s() - TONORM rejected by "
                             "FORCE_DEV_SWITCH_ON\n",
                             __func__));
                    VbExDisplayDebugInfo(
                        "WARNING: TONORM prohibited by "
                        "GBB FORCE_DEV_SWITCH_ON.\n\n");
                    VbExBeep(120, 400);
                    break;
                }
                VbDisplayScreen(cparams,
                                VB_SCREEN_DEVELOPER_TO_NORM,
                                0, &vnc);
                /* Ignore space in VbUserConfirms()... */
                switch (VbUserConfirms(cparams, 0)) {
                case 1:
                    VBDEBUG(("%s() - leaving dev-mode.\n",
                             __func__));
                    VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST,
                            1);
                    VbDisplayScreen(
                        cparams,
                        VB_SCREEN_TO_NORM_CONFIRMED,
                        0, &vnc);
                    VbExSleepMs(5000);
                    return VBERROR_TPM_REBOOT_REQUIRED;
                case -1:
                    VBDEBUG(("%s() - shutdown requested\n",
                             __func__));
                    return VBERROR_SHUTDOWN_REQUESTED;
                default:
                    /* Stay in dev-mode */
                    VBDEBUG(("%s() - stay in dev-mode\n",
                             __func__));
                    VbDisplayScreen(
                        cparams,
                        VB_SCREEN_DEVELOPER_WARNING,
                        0, &vnc);
                    /* Start new countdown */
                    audio = VbAudioOpen(cparams);
                }
            } else {
                /*
                 * No virtual dev-mode switch, so go directly
                 * to recovery mode.
                 */
                VBDEBUG(("%s() - going to recovery\n",
                         __func__));
                VbSetRecoveryRequest(
                    VBNV_RECOVERY_RW_DEV_SCREEN);
                VbAudioClose(audio);
                return VBERROR_LOAD_KERNEL_RECOVERY;
            }
            break;
        case 0x04:
            /* Ctrl+D = dismiss warning; advance to timeout */
            VBDEBUG(("VbBootDeveloper() - "
                     "user pressed Ctrl+D; skip delay\n"));
            ctrl_d_pressed = 1;
            goto fallout;
            break;
        case 0x0c:
            VBDEBUG(("VbBootDeveloper() - "
                     "user pressed Ctrl+L; Try legacy boot\n"));
            VbTryLegacy(allow_legacy);
            break;

        case VB_KEY_CTRL_ENTER:
        /*
         * The Ctrl-Enter is special for Lumpy test purpose;
         * fall through to Ctrl+U handler.
         */
        case 0x15:
            /* Ctrl+U = try USB boot, or beep if failure */
            VBDEBUG(("VbBootDeveloper() - "
                     "user pressed Ctrl+U; try USB\n"));
            if (!allow_usb) {
                VBDEBUG(("VbBootDeveloper() - "
                         "USB booting is disabled\n"));
                VbExDisplayDebugInfo(
                    "WARNING: Booting from external media "
                    "(USB/SD) has not been enabled. Refer "
                    "to the developer-mode documentation "
                    "for details.\n");
                VbExBeep(120, 400);
                VbExSleepMs(120);
                VbExBeep(120, 400);
            } else {
                /*
                 * Clear the screen to show we get the Ctrl+U
                 * key press.
                 */
                VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0,
                                &vnc);
                if (VBERROR_SUCCESS ==
                        VbTryLoadKernel(cparams, p,
                                        VB_DISK_FLAG_REMOVABLE)) {
                    VBDEBUG(("VbBootDeveloper() - "
                             "booting USB\n"));
                    VbAudioClose(audio);
                    return VBERROR_SUCCESS;
                } else {
                    VBDEBUG(("VbBootDeveloper() - "
                             "no kernel found on USB\n"));
                    VbExBeep(250, 200);
                    VbExSleepMs(120);
                    /*
                     * Clear recovery requests from failed
                     * kernel loading, so that powering off
                     * at this point doesn't put us into
                     * recovery mode.
                     */
                    VbSetRecoveryRequest(
                        VBNV_RECOVERY_NOT_REQUESTED);
                    /* Show dev mode warning screen again */
                    VbDisplayScreen(
                        cparams,
                        VB_SCREEN_DEVELOPER_WARNING,
                        0, &vnc);
                }
            }
            break;
        default:
            VBDEBUG(("VbBootDeveloper() - pressed key %d\n", key));
            VbCheckDisplayKey(cparams, key, &vnc);
            break;
        }
    } while(VbAudioLooping(audio));

fallout:

    /* If defaulting to legacy boot, try that unless Ctrl+D was pressed */
    if ((gbb->flags & GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY) &&
            !ctrl_d_pressed) {
        VBDEBUG(("VbBootDeveloper() - defaulting to legacy\n"));
        VbTryLegacy(allow_legacy);
    }

    /* Timeout or Ctrl+D; attempt loading from fixed disk */
    VBDEBUG(("VbBootDeveloper() - trying fixed disk\n"));
    VbAudioClose(audio);
    return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
}
コード例 #15
0
/**
 * Set recovery request (called from vboot_api_kernel.c functions only)
 */
static void VbSetRecoveryRequest(uint32_t recovery_request)
{
    VBDEBUG(("VbSetRecoveryRequest(%d)\n", (int)recovery_request));
    VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request);
}
コード例 #16
0
static void VbAllowUsbBoot(void)
{
    VBDEBUG(("%s\n", __func__));
    VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 1);
}
コード例 #17
0
VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams)
{
    VbSharedDataHeader *shared =
        (VbSharedDataHeader *)cparams->shared_data_blob;
    int in_rw = 0;
    int rv;
    const uint8_t *ec_hash = NULL;
    int ec_hash_size;
    const uint8_t *rw_hash = NULL;
    int rw_hash_size;
    const uint8_t *expected = NULL;
    int expected_size;
    uint8_t expected_hash[SHA256_DIGEST_SIZE];
    int need_update = 0;
    int i;

    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 = EcProtectRW(devidx);
        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;
    }

    /* Get hash of EC-RW */
    rv = VbExEcHashRW(devidx, &ec_hash, &ec_hash_size);
    if (rv) {
        VBDEBUG(("VbEcSoftwareSync() - "
                 "VbExEcHashRW() returned %d\n", rv));
        VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
        return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
    }
    if (ec_hash_size != SHA256_DIGEST_SIZE) {
        VBDEBUG(("VbEcSoftwareSync() - "
                 "VbExEcHashRW() says size %d, not %d\n",
                 ec_hash_size, SHA256_DIGEST_SIZE));
        VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
        return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
    }

    VBDEBUG(("EC hash:"));
    for (i = 0; i < SHA256_DIGEST_SIZE; i++)
        VBDEBUG(("%02x", ec_hash[i]));
    VBDEBUG(("\n"));

    /*
     * Get expected EC-RW hash. Note that we've already checked for
     * RO_NORMAL, so we know that the BIOS must be RW-A or RW-B, and
     * therefore the EC must match.
     */
    rv = VbExEcGetExpectedRWHash(devidx, shared->firmware_index ?
                                 VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
                                 &rw_hash, &rw_hash_size);

    if (rv == VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE) {
        /*
         * BIOS has verified EC image but doesn't have a precomputed
         * hash for it, so we must compute the hash ourselves.
         */
        rw_hash = NULL;
    } else if (rv) {
        VBDEBUG(("VbEcSoftwareSync() - "
                 "VbExEcGetExpectedRWHash() returned %d\n", rv));
        VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
        return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
    } else if (rw_hash_size != SHA256_DIGEST_SIZE) {
        VBDEBUG(("VbEcSoftwareSync() - "
                 "VbExEcGetExpectedRWHash() says size %d, not %d\n",
                 rw_hash_size, SHA256_DIGEST_SIZE));
        VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
        return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
    } else {
        VBDEBUG(("Expected hash:"));
        for (i = 0; i < SHA256_DIGEST_SIZE; i++)
            VBDEBUG(("%02x", rw_hash[i]));
        VBDEBUG(("\n"));

        need_update = SafeMemcmp(ec_hash, rw_hash, SHA256_DIGEST_SIZE);
    }

    /*
     * Get expected EC-RW image if we're sure we need to update (because the
     * expected hash didn't match the EC) or we still don't know (because
     * there was no expected hash and we need the image to compute one
     * ourselves).
     */
    if (need_update || !rw_hash) {
        /* Get expected EC-RW image */
        rv = VbExEcGetExpectedRW(devidx, shared->firmware_index ?
                                 VB_SELECT_FIRMWARE_B :
                                 VB_SELECT_FIRMWARE_A,
                                 &expected, &expected_size);
        if (rv) {
            VBDEBUG(("VbEcSoftwareSync() - "
                     "VbExEcGetExpectedRW() returned %d\n", rv));
            VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
            return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
        }
        VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n",
                 expected_size));

        /* Hash expected image */
        internal_SHA256(expected, expected_size, expected_hash);
        VBDEBUG(("Computed hash of expected image:"));
        for (i = 0; i < SHA256_DIGEST_SIZE; i++)
            VBDEBUG(("%02x", expected_hash[i]));
        VBDEBUG(("\n"));
    }

    if (!rw_hash) {
        /*
         * BIOS didn't have expected EC hash, so check if we need
         * update by comparing EC hash to the one we just computed.
         */
        need_update = SafeMemcmp(ec_hash, expected_hash,
                                 SHA256_DIGEST_SIZE);
    } else if (need_update &&
               SafeMemcmp(rw_hash, expected_hash, SHA256_DIGEST_SIZE)) {
        /*
         * We need to update, but the expected EC image doesn't match
         * the expected EC hash we were given.
         */
        VBDEBUG(("VbEcSoftwareSync() - "
                 "VbExEcGetExpectedRW() returned %d\n", rv));
        VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_MISMATCH);
        return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
    }

    /*
     * TODO: GBB flag to override whether we need update; needed for EC
     * development.
     */

    if (in_rw) {
        if (need_update) {
            /*
             * 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(("VbEcSoftwareSync() - 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(("VbEcSoftwareSync() - "
                     "in RW, need to update RW, so reboot\n"));
            return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
        }

        VBDEBUG(("VbEcSoftwareSync() in EC-RW and it matches\n"));
        return VBERROR_SUCCESS;
    }

    /* Update EC if necessary */
    if (need_update) {
        VBDEBUG(("VbEcSoftwareSync() updating EC-RW...\n"));

        if (shared->flags & VBSD_EC_SLOW_UPDATE) {
            VBDEBUG(("VbEcSoftwareSync() - "
                     "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(("VbEcSoftwareSync() - 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 = VbExEcUpdateRW(devidx, expected, expected_size);

        if (rv != VBERROR_SUCCESS) {
            VBDEBUG(("VbEcSoftwareSync() - "
                     "VbExEcUpdateRW() returned %d\n", rv));

            /*
             * The EC may know it needs a reboot.  It may need to
             * unprotect RW before updating, or may need to reboot
             * after RW updated.  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;
        }

        /*
         * TODO: should ask EC to recompute its hash to verify it's
         * correct before continuing?
         */
    }

    /* Protect EC-RW flash */
    rv = EcProtectRW(devidx);
    if (rv != VBERROR_SUCCESS)
        return rv;

    /* Tell EC to jump to its RW image */
    VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
    rv = VbExEcJumpToRW(devidx);
    if (rv != VBERROR_SUCCESS) {
        VBDEBUG(("VbEcSoftwareSync() - "
                 "VbExEcJumpToRW() returned %d\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;
    }

    VBDEBUG(("VbEcSoftwareSync() jumped to EC-RW\n"));

    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 (need_update &&
            !(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"));
        return VBERROR_VGA_OPROM_MISMATCH;
    }

    VBDEBUG(("VbEcSoftwareSync() in RW; done\n"));
    return VBERROR_SUCCESS;
}