Partial EC software sync implementation

Doesn't check the EC hash, but does jump to the correct image, for now
assuming the hash is good.

BUG=chrome-os-partner:11087
TEST=manual

- Power+refresh.  System boots.  EC is in RO (verify via 'ectool version')
- Create a BIOS signed *without* RO-normal.
- Power+refresh.  System boots.  EC ends up in A.
- ectool eventgetb.  Event 0x2000 IS present, indicating EC has rebooted
- ectool eventclearb -1
- Power button to shut down, then power button to power back on.
- ectool eventgetb.  Event 0x2000 is NOT present.
- crossystem recovery_request=123 && reboot.  System reboots to recovery mode
  and EC is in read-only (verify via EC console 'sysinfo')
- Power off and on.  System boots.  EC ends up in A again.

Change-Id: I39682d1bf7215c62a4b20613d029e78194b98826
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/27574
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
Randall Spangler
2012-07-16 16:42:40 -07:00
committed by Gerrit
parent cc36ff4073
commit d4faa060cc
5 changed files with 118 additions and 1 deletions

View File

@@ -348,6 +348,103 @@ VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
}
VbError_t VbEcSoftwareSync(VbSharedDataHeader *shared) {
int in_rw = 0;
int rv = VbExEcRunningRW(&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
* preseve 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() - VbEcSoftwareSync() 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 = VbExEcProtectRW();
if (rv != VBERROR_SUCCESS) {
VBDEBUG(("VbEcSoftwareSync() - VbExEcProtectRW() returned %d\n", rv));
VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
}
rv = VbExEcStayInRO();
if (rv != VBERROR_SUCCESS) {
VBDEBUG(("VbEcSoftwareSync() - VbExEcStayInRO() 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"));
/* TODO: If EC-RW wasn't protected when we started, then this boot was
* simply to verify the EC. Shut down instead of continuing. */
return VBERROR_SUCCESS;
}
/* TODO: verify EC-RW hash vs. expected code */
if (in_rw) {
/* TODO: if hash doesn't verify, reboot EC so we can reflash it
* with the expected code. */
VBDEBUG(("VbEcSoftwareSync() in RW; EC-RW\n"));
return VBERROR_SUCCESS;
} else {
/* TODO: if hash doesn't verify, reflash it with expected code. */
/* Protect EC-RW flash */
rv = VbExEcProtectRW();
if (rv != VBERROR_SUCCESS) {
VBDEBUG(("VbEcSoftwareSync() - VbExEcProtectRW() returned %d\n", rv));
VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
}
/* Tell EC to jump to its RW code */
VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
rv = VbExEcJumpToRW();
if (rv != VBERROR_SUCCESS) {
VBDEBUG(("VbEcSoftwareSync() - VbExEcJumpToRW() returned %d\n", rv));
VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
}
/* TODO: If there was no wake event from the EC (such as power button or
* lid-open), shut down. The AP was powered on simply to verify the EC. */
VBDEBUG(("VbEcSoftwareSync() in RW; done jumping to EC-RW\n"));
return VBERROR_SUCCESS;
}
}
VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
VbSelectAndLoadKernelParams* kparams) {
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
@@ -368,6 +465,13 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
kparams->bootloader_size = 0;
Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
/* Do EC software sync if necessary */
if (shared->flags & VBSD_EC_SOFTWARE_SYNC) {
retval = VbEcSoftwareSync(shared);
if (retval != VBERROR_SUCCESS)
goto VbSelectAndLoadKernel_exit;
}
/* Read the kernel version from the TPM. Ignore errors in recovery mode. */
tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
if (0 != tpm_status) {