mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 18:25:10 +00:00
vboot: Split ec software sync to its own file
This was previously done inside vboot_api_kernel. But it has nothing to do with kernel verification; that's just the only place where we could easily put it given that vboot (currently) owns the firmware UI. No outwardly-visible functionality changes. BUG=chromium:611535 BRANCH=none TEST=make runtests; emerge-kevin coreboot depthcharge Change-Id: I8a434eb4449a5a86b129ecac61ad81d0ad55549c Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/404920
This commit is contained in:
committed by
chrome-bot
parent
e5500a319b
commit
2603675460
@@ -57,6 +57,12 @@ static void VbSetRecoverySubcode(uint32_t recovery_request)
|
||||
VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE, recovery_request);
|
||||
}
|
||||
|
||||
static void VbNvLoad(void)
|
||||
{
|
||||
VbExNvStorageRead(vnc.raw);
|
||||
VbNvSetup(&vnc);
|
||||
}
|
||||
|
||||
static void VbNvCommit(void)
|
||||
{
|
||||
VbNvTeardown(&vnc);
|
||||
@@ -694,367 +700,6 @@ VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p)
|
||||
return VBERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around VbExEcProtect() which sets recovery reason on error.
|
||||
*/
|
||||
static VbError_t EcProtect(int devidx, enum VbSelectFirmware_t select)
|
||||
{
|
||||
int rv = VbExEcProtect(devidx, select);
|
||||
|
||||
if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
|
||||
VBDEBUG(("VbExEcProtect() needs reboot\n"));
|
||||
} else if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("VbExEcProtect() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_PROTECT);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static VbError_t EcUpdateImage(int devidx, VbCommonParams *cparams,
|
||||
enum VbSelectFirmware_t select,
|
||||
int *need_update, int in_rw)
|
||||
{
|
||||
VbSharedDataHeader *shared =
|
||||
(VbSharedDataHeader *)cparams->shared_data_blob;
|
||||
int rv;
|
||||
int hash_size;
|
||||
int ec_hash_size;
|
||||
const uint8_t *hash = NULL;
|
||||
const uint8_t *expected = NULL;
|
||||
const uint8_t *ec_hash = NULL;
|
||||
int expected_size;
|
||||
int i;
|
||||
int rw_request = select != VB_SELECT_FIRMWARE_READONLY;
|
||||
|
||||
*need_update = 0;
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"Check for %s update\n", rw_request ? "RW" : "RO"));
|
||||
|
||||
/* Get current EC hash. */
|
||||
rv = VbExEcHashImage(devidx, select, &ec_hash, &ec_hash_size);
|
||||
if (rv) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"VbExEcHashImage() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
VBDEBUG(("EC-%s hash: ", rw_request ? "RW" : "RO"));
|
||||
for (i = 0; i < ec_hash_size; i++)
|
||||
VBDEBUG(("%02x",ec_hash[i]));
|
||||
VBDEBUG(("\n"));
|
||||
|
||||
/* Get expected EC hash. */
|
||||
rv = VbExEcGetExpectedImageHash(devidx, select, &hash, &hash_size);
|
||||
if (rv) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"VbExEcGetExpectedImageHash() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
if (ec_hash_size != hash_size) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"EC uses %d-byte hash, but AP-RW contains %d bytes\n",
|
||||
ec_hash_size, hash_size));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
VBDEBUG(("Expected hash: "));
|
||||
for (i = 0; i < hash_size; i++)
|
||||
VBDEBUG(("%02x", hash[i]));
|
||||
VBDEBUG(("\n"));
|
||||
*need_update = vb2_safe_memcmp(ec_hash, hash, hash_size);
|
||||
|
||||
if (!*need_update)
|
||||
return VBERROR_SUCCESS;
|
||||
|
||||
/* Get expected EC image */
|
||||
rv = VbExEcGetExpectedImage(devidx, select, &expected, &expected_size);
|
||||
if (rv) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"VbExEcGetExpectedImage() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
VBDEBUG(("EcUpdateImage() - image len = %d\n", expected_size));
|
||||
|
||||
if (in_rw && rw_request) {
|
||||
/*
|
||||
* Check if BIOS should also load VGA Option ROM when
|
||||
* rebooting to save another reboot if possible.
|
||||
*/
|
||||
if ((shared->flags & VBSD_EC_SLOW_UPDATE) &&
|
||||
(shared->flags & VBSD_OPROM_MATTERS) &&
|
||||
!(shared->flags & VBSD_OPROM_LOADED)) {
|
||||
VBDEBUG(("EcUpdateImage() - Reboot to "
|
||||
"load VGA Option ROM\n"));
|
||||
VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* EC is running the wrong RW image. Reboot the EC to
|
||||
* RO so we can update it on the next boot.
|
||||
*/
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"in RW, need to update RW, so reboot\n"));
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
VBDEBUG(("EcUpdateImage() updating EC-%s...\n",
|
||||
rw_request ? "RW" : "RO"));
|
||||
|
||||
if (shared->flags & VBSD_EC_SLOW_UPDATE) {
|
||||
VBDEBUG(("EcUpdateImage() - EC is slow. Show WAIT screen.\n"));
|
||||
|
||||
/* Ensure the VGA Option ROM is loaded */
|
||||
if ((shared->flags & VBSD_OPROM_MATTERS) &&
|
||||
!(shared->flags & VBSD_OPROM_LOADED)) {
|
||||
VBDEBUG(("EcUpdateImage() - Reboot to "
|
||||
"load VGA Option ROM\n"));
|
||||
VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
|
||||
return VBERROR_VGA_OPROM_MISMATCH;
|
||||
}
|
||||
|
||||
VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
|
||||
}
|
||||
|
||||
rv = VbExEcUpdateImage(devidx, select, expected, expected_size);
|
||||
if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"VbExEcUpdateImage() returned %d\n", rv));
|
||||
|
||||
/*
|
||||
* The EC may know it needs a reboot. It may need to
|
||||
* unprotect the region before updating, or may need to
|
||||
* reboot after updating. Either way, it's not an error
|
||||
* requiring recovery mode.
|
||||
*
|
||||
* If we fail for any other reason, trigger recovery
|
||||
* mode.
|
||||
*/
|
||||
if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
|
||||
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
/* Verify the EC was updated properly */
|
||||
rv = VbExEcHashImage(devidx, select, &ec_hash, &ec_hash_size);
|
||||
if (rv) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"VbExEcHashImage() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
if (hash_size != ec_hash_size) {
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"VbExEcHashImage() says size %d, not %d\n",
|
||||
ec_hash_size, hash_size));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
VBDEBUG(("Updated EC-%s hash: ", rw_request ? "RW" : "RO"));
|
||||
for (i = 0; i < ec_hash_size; i++)
|
||||
VBDEBUG(("%02x",ec_hash[i]));
|
||||
VBDEBUG(("\n"));
|
||||
|
||||
if (vb2_safe_memcmp(ec_hash, hash, hash_size)){
|
||||
VBDEBUG(("EcUpdateImage() - "
|
||||
"Failed to update EC-%s\n", rw_request ?
|
||||
"RW" : "RO"));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
return VBERROR_SUCCESS;
|
||||
}
|
||||
|
||||
VbError_t VbEcSoftwareSync(int devidx, VbCommonParams *cparams)
|
||||
{
|
||||
VbSharedDataHeader *shared =
|
||||
(VbSharedDataHeader *)cparams->shared_data_blob;
|
||||
enum VbSelectFirmware_t select_rw =
|
||||
shared->firmware_index ? VB_SELECT_FIRMWARE_B :
|
||||
VB_SELECT_FIRMWARE_A;
|
||||
enum VbSelectFirmware_t select_ro = VB_SELECT_FIRMWARE_READONLY;
|
||||
int in_rw = 0;
|
||||
int ro_try_count = 2;
|
||||
int num_tries = 0;
|
||||
uint32_t try_ro_sync, recovery_request;
|
||||
int rv, updated_rw, updated_ro;
|
||||
|
||||
VBDEBUG(("VbEcSoftwareSync(devidx=%d)\n", devidx));
|
||||
|
||||
/* Determine whether the EC is in RO or RW */
|
||||
rv = VbExEcRunningRW(devidx, &in_rw);
|
||||
|
||||
if (shared->recovery_reason) {
|
||||
/* Recovery mode; just verify the EC is in RO code */
|
||||
if (rv == VBERROR_SUCCESS && in_rw == 1) {
|
||||
/*
|
||||
* EC is definitely in RW firmware. We want it in
|
||||
* read-only code, so preserve the current recovery
|
||||
* reason and reboot.
|
||||
*
|
||||
* We don't reboot on error or unknown EC code, because
|
||||
* we could end up in an endless reboot loop. If we
|
||||
* had some way to track that we'd already rebooted for
|
||||
* this reason, we could retry only once.
|
||||
*/
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"want recovery but got EC-RW\n"));
|
||||
VbSetRecoveryRequest(shared->recovery_reason);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
|
||||
return VBERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Not in recovery. If we couldn't determine where the EC was,
|
||||
* reboot to recovery.
|
||||
*/
|
||||
if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"VbExEcRunningRW() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
/* If AP is read-only normal, EC should be in its RO code also. */
|
||||
if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
|
||||
/* If EC is in RW code, request reboot back to RO */
|
||||
if (in_rw == 1) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"want RO-normal but got EC-RW\n"));
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
/* Protect the RW flash and stay in EC-RO */
|
||||
rv = EcProtect(devidx, select_rw);
|
||||
if (rv != VBERROR_SUCCESS)
|
||||
return rv;
|
||||
|
||||
rv = VbExEcDisableJump(devidx);
|
||||
if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"VbExEcDisableJump() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
|
||||
return VBERROR_SUCCESS;
|
||||
}
|
||||
|
||||
VBDEBUG(("VbEcSoftwareSync() check for RW update.\n"));
|
||||
|
||||
/* Update the RW Image. */
|
||||
rv = EcUpdateImage(devidx, cparams, select_rw, &updated_rw, in_rw);
|
||||
|
||||
if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"EcUpdateImage() returned %d\n", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Tell EC to jump to its RW image */
|
||||
if (!in_rw) {
|
||||
VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
|
||||
rv = VbExEcJumpToRW(devidx);
|
||||
if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"VbExEcJumpToRW() returned %x\n", rv));
|
||||
|
||||
/*
|
||||
* If the EC booted RO-normal and a previous AP boot
|
||||
* has called VbExEcStayInRO(), we need to reboot the EC
|
||||
* to unlock the ability to jump to the RW firmware.
|
||||
*
|
||||
* All other errors trigger recovery mode.
|
||||
*/
|
||||
if (rv != VBERROR_EC_REBOOT_TO_RO_REQUIRED)
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
|
||||
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
}
|
||||
|
||||
VbNvGet(&vnc, VBNV_TRY_RO_SYNC, &try_ro_sync);
|
||||
|
||||
if (!devidx && try_ro_sync &&
|
||||
!(shared->flags & VBSD_BOOT_FIRMWARE_WP_ENABLED)) {
|
||||
/* Reset RO Software Sync NV flag */
|
||||
VbNvSet(&vnc, VBNV_TRY_RO_SYNC, 0);
|
||||
|
||||
VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery_request);
|
||||
|
||||
/* Update the RO Image. */
|
||||
while (num_tries < ro_try_count) {
|
||||
VBDEBUG(("VbEcSoftwareSync() RO Software Sync\n"));
|
||||
|
||||
/* Get expected EC-RO Image. */
|
||||
rv = EcUpdateImage(devidx, cparams, select_ro,
|
||||
&updated_ro, in_rw);
|
||||
if (rv == VBERROR_SUCCESS) {
|
||||
/*
|
||||
* If the RO update had failed, reset the
|
||||
* recovery request.
|
||||
*/
|
||||
if (num_tries)
|
||||
VbSetRecoveryRequest(recovery_request);
|
||||
break;
|
||||
} else
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"EcUpdateImage() returned %d\n", rv));
|
||||
|
||||
num_tries++;
|
||||
}
|
||||
}
|
||||
if (rv != VBERROR_SUCCESS)
|
||||
return rv;
|
||||
|
||||
/* Protect RO flash */
|
||||
rv = EcProtect(devidx, select_ro);
|
||||
if (rv != VBERROR_SUCCESS)
|
||||
return rv;
|
||||
|
||||
/* Protect RW flash */
|
||||
rv = EcProtect(devidx, select_rw);
|
||||
if (rv != VBERROR_SUCCESS)
|
||||
return rv;
|
||||
|
||||
rv = VbExEcDisableJump(devidx);
|
||||
if (rv != VBERROR_SUCCESS) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - "
|
||||
"VbExEcDisableJump() returned %d\n", rv));
|
||||
VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
|
||||
return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reboot to unload VGA Option ROM if:
|
||||
* - RW update was done
|
||||
* - the system is NOT in developer mode
|
||||
* - the system has slow EC update flag set
|
||||
* - the VGA Option ROM was needed and loaded
|
||||
*/
|
||||
if (updated_rw &&
|
||||
!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
|
||||
(shared->flags & VBSD_EC_SLOW_UPDATE) &&
|
||||
(shared->flags & VBSD_OPROM_MATTERS) &&
|
||||
(shared->flags & VBSD_OPROM_LOADED)) {
|
||||
VBDEBUG(("VbEcSoftwareSync() - Reboot to "
|
||||
"unload VGA Option ROM\n"));
|
||||
VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
|
||||
return VBERROR_VGA_OPROM_MISMATCH;
|
||||
}
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* This function is also used by tests */
|
||||
void VbApiKernelFree(VbCommonParams *cparams)
|
||||
{
|
||||
@@ -1082,8 +727,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
|
||||
/* Start timer */
|
||||
shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
|
||||
|
||||
VbExNvStorageRead(vnc.raw);
|
||||
VbNvSetup(&vnc);
|
||||
VbNvLoad();
|
||||
|
||||
/* Fill in params for calls to LoadKernel() */
|
||||
memset(&p, 0, sizeof(p));
|
||||
@@ -1118,7 +762,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
|
||||
!(cparams->gbb->flags & GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)) {
|
||||
int oprom_mismatch = 0;
|
||||
|
||||
retval = VbEcSoftwareSync(0, cparams);
|
||||
retval = VbEcSoftwareSync(0, cparams, &vnc);
|
||||
/* Save reboot requested until after possible PD sync */
|
||||
if (retval == VBERROR_VGA_OPROM_MISMATCH)
|
||||
oprom_mismatch = 1;
|
||||
@@ -1128,7 +772,7 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
|
||||
#ifdef PD_SYNC
|
||||
if (!(cparams->gbb->flags &
|
||||
GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC)) {
|
||||
retval = VbEcSoftwareSync(1, cparams);
|
||||
retval = VbEcSoftwareSync(1, cparams, &vnc);
|
||||
if (retval == VBERROR_VGA_OPROM_MISMATCH)
|
||||
oprom_mismatch = 1;
|
||||
else if (retval != VBERROR_SUCCESS)
|
||||
@@ -1380,8 +1024,7 @@ VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams,
|
||||
*/
|
||||
dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON;
|
||||
|
||||
VbExNvStorageRead(vnc.raw);
|
||||
VbNvSetup(&vnc);
|
||||
VbNvLoad();
|
||||
VbNvGet(&vnc, VBNV_DEV_BOOT_FASTBOOT_FULL_CAP,
|
||||
&allow_fastboot_full_cap);
|
||||
|
||||
@@ -1519,8 +1162,7 @@ VbError_t VbUnlockDevice(void)
|
||||
|
||||
VbError_t VbLockDevice(void)
|
||||
{
|
||||
VbExNvStorageRead(vnc.raw);
|
||||
VbNvSetup(&vnc);
|
||||
VbNvLoad();
|
||||
|
||||
VBDEBUG(("%s() - Storing request to leave dev-mode.\n",
|
||||
__func__));
|
||||
|
||||
Reference in New Issue
Block a user