diff options
Diffstat (limited to 'firmware/lib/vboot_api_kernel.c')
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c index 692e3b08..5331526c 100644 --- a/firmware/lib/vboot_api_kernel.c +++ b/firmware/lib/vboot_api_kernel.c @@ -625,11 +625,30 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, /* Normal boot */ retval = VbBootNormal(cparams, &p); - /* See if we need to update the TPM. */ - if (!((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED))) { - /* We don't advance the TPM if we're trying a new firmware B, because - * that firmware may have a key change and roll forward the TPM too - * soon. */ + if ((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED)) { + /* Special cases for when we're trying a new firmware B. These are + * needed because firmware updates also usually change the kernel key, + * which means that the B firmware can only boot a new kernel, and the + * old firmware in A can only boot the previous kernel. */ + + /* Don't advance the TPM if we're trying a new firmware B, because we + * don't yet know if the new kernel will successfully boot. We still + * want to be able to fall back to the previous firmware+kernel if the + * new firmware+kernel fails. */ + + /* If we found only invalid kernels, reboot and try again. This allows + * us to fall back to the previous firmware+kernel instead of giving up + * and going to recovery mode right away. We'll still go to recovery + * mode if we run out of tries and the old firmware can't find a kernel + * it likes. */ + if (VBERROR_INVALID_KERNEL_FOUND == retval) { + VBDEBUG(("Trying firmware B, and only found invalid kernels.\n")); + VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED); + goto VbSelectAndLoadKernel_exit; + } + } else { + /* Not trying a new firmware B. */ + /* See if we need to update the TPM. */ VBDEBUG(("Checking if TPM kernel version needs advancing\n")); if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) { tpm_status = RollbackKernelWrite(shared->kernel_version_tpm); |