mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-23 17:55:01 +00:00
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:
@@ -97,6 +97,10 @@ typedef enum VbNvParam {
|
||||
/* Recovery mode TPM initialization requires a system reboot. The system was
|
||||
* already in recovery mode for some other reason when this happened. */
|
||||
#define VBNV_RECOVERY_RO_TPM_REBOOT 0x21
|
||||
/* Other EC software sync error */
|
||||
#define VBNV_RECOVERY_EC_SOFTWARE_SYNC 0x22
|
||||
/* Unable to determine active EC image */
|
||||
#define VBNV_RECOVERY_EC_UNKNOWN_IMAGE 0x23
|
||||
/* Unspecified/unknown error in read-only firmware */
|
||||
#define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F
|
||||
/* User manually requested recovery by pressing a key at developer
|
||||
|
||||
@@ -231,8 +231,10 @@ typedef struct VbKernelPreambleHeader {
|
||||
#define VBSD_BOOT_S3_RESUME 0x00000100
|
||||
/* Read-only firmware supports the normal/developer code path */
|
||||
#define VBSD_BOOT_RO_NORMAL_SUPPORT 0x00000200
|
||||
/* VbInit was told that the system has a virtual dev-switch */
|
||||
/* VbInit() was told that the system has a virtual dev-switch */
|
||||
#define VBSD_HONOR_VIRT_DEV_SWITCH 0x00000400
|
||||
/* VbInit() was told the system supports EC software sync */
|
||||
#define VBSD_EC_SOFTWARE_SYNC 0x00000800
|
||||
|
||||
/* Result codes for VbSharedDataHeader.check_fw_a_result (and b_result) */
|
||||
#define VBSD_LF_CHECK_NOT_DONE 0
|
||||
|
||||
@@ -49,6 +49,7 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
|
||||
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;
|
||||
@@ -58,6 +59,8 @@ VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
|
||||
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;
|
||||
|
||||
is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -443,6 +443,10 @@ static const char *RecoveryReasonString(uint8_t code) {
|
||||
return "Firmware problem outside of verified boot";
|
||||
case VBNV_RECOVERY_RO_TPM_REBOOT:
|
||||
return "TPM requires a system reboot (should be transient)";
|
||||
case VBNV_RECOVERY_EC_SOFTWARE_SYNC:
|
||||
return "EC software sync error";
|
||||
case VBNV_RECOVERY_EC_UNKNOWN_IMAGE:
|
||||
return "Unable to determine active EC image";
|
||||
case VBNV_RECOVERY_RO_UNSPECIFIED:
|
||||
return "Unspecified/unknown error in RO firmware";
|
||||
case VBNV_RECOVERY_RW_DEV_SCREEN:
|
||||
|
||||
Reference in New Issue
Block a user