summaryrefslogtreecommitdiff
path: root/firmware/lib/vboot_api_kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/lib/vboot_api_kernel.c')
-rw-r--r--firmware/lib/vboot_api_kernel.c29
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);