Merge commit '5c0fcf0f8725b98043a4b18f36e21489375d133a' into cros_sdk

Updated vboot_reference to CrOS version 14056.0.0

BUG=b/192265868
TEST=local BE run
RELEASE_NOTE=Updated ChromeOS base to ChromeOS version 14056.0.0.

Signed-off-by: Robert Kolchmeyer <rkolchmeyer@google.com>
Change-Id: I60a04a25a1dad1b0a9508acdc912a2344deabf2b
diff --git a/Android.mk b/Android.mk
index 64d89e1..c54a3b7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -54,7 +54,6 @@
 	firmware/lib/gpt_misc.c \
 	firmware/lib/utility_string.c \
 	firmware/lib/vboot_api_kernel.c \
-	firmware/lib/vboot_audio.c \
 	firmware/lib/vboot_display.c \
 	firmware/lib/vboot_kernel.c \
 	firmware/lib/region-kernel.c \
@@ -62,7 +61,6 @@
 VBINIT_SRCS += \
 	firmware/stub/tpm_lite_stub.c \
 	firmware/stub/utility_stub.c \
-	firmware/stub/vboot_api_stub_init.c \
 	firmware/stub/vboot_api_stub_region.c
 
 VBSF_SRCS += \
diff --git a/Makefile b/Makefile
index 3a72d3d..327b753 100644
--- a/Makefile
+++ b/Makefile
@@ -187,6 +187,12 @@
 CFLAGS += -DTPM2_MODE
 endif
 
+# Support devices with GPT in SPI-NOR (for nand device)
+# TODO(b:184812319): Consider removing this code if nobody uses it.
+ifneq (${GPT_SPI_NOR},)
+CFLAGS += -DGPT_SPI_NOR
+endif
+
 # Enable boot from external disk when switching to dev mode
 ifneq ($(filter-out 0,${BOOT_EXTERNAL_ON_DEV}),)
 CFLAGS += -DBOOT_EXTERNAL_ON_DEV=1
@@ -213,6 +219,15 @@
 CFLAGS += -DTPM2_SIMULATOR=0
 endif
 
+# VTPM_PROXY indicates whether the TPM driver simulator feature
+# is enable or not.
+# This flag only takes effect when TPM2_SIMULATOR is enabled.
+ifneq ($(filter-out 0,${VTPM_PROXY}),)
+CFLAGS += -DVTPM_PROXY=1
+else
+CFLAGS += -DVTPM_PROXY=0
+endif
+
 # DETACHABLE indicates whether the device is a detachable or not.
 ifneq ($(filter-out 0,${DETACHABLE}),)
 CFLAGS += -DDETACHABLE=1
@@ -358,6 +373,9 @@
 ifeq (${FIRMWARE_ARCH},)
 INCLUDES += -Ihost/include -Ihost/lib/include
 INCLUDES += -Ihost/lib21/include
+ifeq ($(shell uname -s), OpenBSD)
+INCLUDES += -I/usr/local/include
+endif
 endif
 
 # Firmware library, used by the other firmware components (depthcharge,
@@ -376,11 +394,13 @@
 	firmware/2lib/2crc8.c \
 	firmware/2lib/2crypto.c \
 	firmware/2lib/2ec_sync.c \
+	firmware/2lib/2firmware.c \
 	firmware/2lib/2gbb.c \
 	firmware/2lib/2hmac.c \
 	firmware/2lib/2kernel.c \
 	firmware/2lib/2misc.c \
 	firmware/2lib/2nvstorage.c \
+	firmware/2lib/2packed_key.c \
 	firmware/2lib/2recovery_reasons.c \
 	firmware/2lib/2rsa.c \
 	firmware/2lib/2secdata_firmware.c \
@@ -390,6 +410,7 @@
 	firmware/2lib/2sha256.c \
 	firmware/2lib/2sha512.c \
 	firmware/2lib/2sha_utility.c \
+	firmware/2lib/2struct.c \
 	firmware/2lib/2stub_hwcrypto.c \
 	firmware/2lib/2tpm_bootmode.c \
 	firmware/lib/cgptlib/cgptlib.c \
@@ -399,16 +420,13 @@
 	firmware/lib/vboot_api_kernel.c \
 	firmware/lib/vboot_kernel.c \
 	firmware/lib20/api_kernel.c \
-	firmware/lib20/kernel.c \
-	firmware/lib20/misc.c \
-	firmware/lib20/packed_key.c
+	firmware/lib20/kernel.c
 
 # Only add these to firmware and test builds,
 # as regular host builds don't need them
 $(if ${FIRMWARE_ARCH},FWLIB_SRCS,TESTLIB_SRCS) += \
 	firmware/2lib/2ui.c \
 	firmware/2lib/2ui_screens.c \
-	firmware/lib/vboot_audio.c
 
 # TPM lightweight command library
 ifeq (${TPM2_MODE},)
@@ -434,7 +452,6 @@
 	firmware/stub/tpm_lite_stub.c \
 	firmware/stub/vboot_api_stub.c \
 	firmware/stub/vboot_api_stub_disk.c \
-	firmware/stub/vboot_api_stub_init.c \
 	firmware/stub/vboot_api_stub_stream.c \
 	firmware/2lib/2stub.c
 endif
@@ -491,7 +508,6 @@
 	cgpt/cgpt_create.c \
 	cgpt/cgpt_edit.c \
 	cgpt/cgpt_find.c \
-	cgpt/cgpt_nor.c \
 	cgpt/cgpt_prioritize.c \
 	cgpt/cgpt_show.c \
 	firmware/2lib/2common.c \
@@ -507,6 +523,7 @@
 	firmware/2lib/2sha256.c \
 	firmware/2lib/2sha512.c \
 	firmware/2lib/2sha_utility.c \
+	firmware/2lib/2struct.c \
 	firmware/2lib/2stub.c \
 	firmware/2lib/2stub_hwcrypto.c \
 	firmware/lib/cgptlib/cgptlib_internal.c \
@@ -515,7 +532,6 @@
 	firmware/stub/tpm_lite_stub.c \
 	firmware/stub/vboot_api_stub.c \
 	firmware/stub/vboot_api_stub_disk.c \
-	firmware/stub/vboot_api_stub_init.c \
 	futility/dump_kernel_config_lib.c \
 	$(CROSSYSTEM_ARCH_C) \
 	host/lib/chromeos_config.c \
@@ -529,6 +545,10 @@
 	host/lib21/host_misc.c \
 	${TLCL_SRCS}
 
+ifneq (${GPT_SPI_NOR},)
+HOSTLIB_SRCS += cgpt/cgpt_nor.c
+endif
+
 HOSTLIB_OBJS = ${HOSTLIB_SRCS:%.c=${BUILD}/%.o}
 ALL_OBJS += ${HOSTLIB_OBJS}
 
@@ -546,7 +566,6 @@
 	cgpt/cgpt_edit.c \
 	cgpt/cgpt_find.c \
 	cgpt/cgpt_legacy.c \
-	cgpt/cgpt_nor.c \
 	cgpt/cgpt_prioritize.c \
 	cgpt/cgpt_repair.c \
 	cgpt/cgpt_show.c \
@@ -560,6 +579,10 @@
 	cgpt/cmd_repair.c \
 	cgpt/cmd_show.c
 
+ifneq (${GPT_SPI_NOR},)
+CGPT_SRCS += cgpt/cgpt_nor.c
+endif
+
 CGPT_OBJS = ${CGPT_SRCS:%.c=${BUILD}/%.o}
 
 ALL_OBJS += ${CGPT_OBJS}
@@ -653,7 +676,6 @@
 	futility/file_type_rwsig.c \
 	futility/file_type_usbpd1.c \
 	futility/misc.c \
-	futility/ryu_root_header.c \
 	futility/updater.c \
 	futility/updater_archive.c \
 	futility/updater_quirks.c \
@@ -716,6 +738,7 @@
 	tests/vb2_common3_tests \
 	tests/vb2_crypto_tests \
 	tests/vb2_ec_sync_tests \
+	tests/vb2_firmware_tests \
 	tests/vb2_gbb_tests \
 	tests/vb2_host_flashrom_tests \
 	tests/vb2_host_key_tests \
@@ -739,7 +762,6 @@
 	tests/vb20_api_kernel_tests \
 	tests/vb20_verify_fw.c \
 	tests/vb20_kernel_tests \
-	tests/vb20_misc_tests \
 	tests/vb20_rsa_padding_tests \
 	tests/vb20_verify_fw
 
@@ -942,10 +964,12 @@
 	${Q}${LD} -o ${CGPT_WRAPPER} ${LDFLAGS} $^ ${LDLIBS}
 
 .PHONY: cgpt
-cgpt: ${CGPT} ${CGPT_WRAPPER}
+cgpt: ${CGPT} $(if ${GPT_SPI_NOR},cgpt_wrapper)
 
 # on FreeBSD: install misc/e2fsprogs-libuuid from ports,
 # or e2fsprogs-libuuid from its binary package system.
+# on OpenBSD: install sysutils/e2fsprogs from ports,
+# or e2fsprogs from its binary package system, to install uuid/uid.h
 ${CGPT}: LDLIBS += -luuid
 
 ${CGPT}: ${CGPT_OBJS} ${UTILLIB}
@@ -1121,6 +1145,9 @@
 ifeq ($(shell uname -s), FreeBSD)
 CRYPTO_LIBS += -lcrypto
 endif
+ifeq ($(shell uname -s), OpenBSD)
+LDFLAGS += -Wl,-z,notext
+endif
 
 ${BUILD}/utility/dumpRSAPublicKey: LDLIBS += ${CRYPTO_LIBS}
 ${BUILD}/utility/pad_digest_utility: LDLIBS += ${CRYPTO_LIBS}
@@ -1246,6 +1273,7 @@
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_common3_tests ${TEST_KEYS}
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_crypto_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_ec_sync_tests
+	${RUNTEST} ${BUILD_RUN}/tests/vb2_firmware_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_gbb_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_host_key_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_kernel_tests
@@ -1262,7 +1290,6 @@
 	${RUNTEST} ${BUILD_RUN}/tests/vb2_ui_utility_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb20_api_kernel_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb20_kernel_tests
-	${RUNTEST} ${BUILD_RUN}/tests/vb20_misc_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb21_host_common_tests
 	${RUNTEST} ${BUILD_RUN}/tests/vb21_host_common2_tests ${TEST_KEYS}
 	${RUNTEST} ${BUILD_RUN}/tests/vb21_host_key_tests ${TEST_KEYS} ${BUILD}
diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h
index 0747b5c..89c357e 100644
--- a/cgpt/cgpt.h
+++ b/cgpt/cgpt.h
@@ -7,7 +7,7 @@
 #define VBOOT_REFERENCE_CGPT_H_
 
 #include <fcntl.h>
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <features.h>
 #endif
 #include <stdint.h>
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index 426be3b..c3edd0f 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -9,7 +9,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <linux/major.h>
 #include <mtd/mtd-user.h>
 #endif
@@ -295,7 +295,7 @@
   if (fstat(fd, &stat) == -1) {
     return -1;
   }
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
   if ((stat.st_mode & S_IFMT) != S_IFREG) {
     if (ioctl(fd, BLKGETSIZE64, size) < 0) {
       return -1;
@@ -325,7 +325,7 @@
   memset(drive, 0, sizeof(struct drive));
 
   drive->fd = open(drive_path, mode |
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 		               O_LARGEFILE |
 #endif
 			       O_NOFOLLOW);
diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c
index 6f4bbae..8046aad 100644
--- a/cgpt/cgpt_find.c
+++ b/cgpt/cgpt_find.c
@@ -96,19 +96,6 @@
     EntryDetails(entry, partnum - 1, params->numeric);
 }
 
-// This handles the MTD devices. ChromeOS uses /dev/mtdX for kernel partitions,
-// /dev/ubiblockX_0 for root partitions, and /dev/ubiX for stateful partition.
-static void chromeos_mtd_show(CgptFindParams *params, const char *filename,
-                              int partnum, GptEntry *entry) {
-  if (GuidEqual(&guid_chromeos_kernel, &entry->type)) {
-    printf("/dev/mtd%d\n", partnum);
-  } else if (GuidEqual(&guid_chromeos_rootfs, &entry->type)) {
-    printf("/dev/ubiblock%d_0\n", partnum);
-  } else {
-    printf("/dev/ubi%d_0\n", partnum);
-  }
-}
-
 // This returns true if a GPT partition matches the search criteria. If a match
 // isn't found (or if the file doesn't contain a GPT), it returns false. The
 // filename and partition number that matched is left in a global, since we
@@ -214,6 +201,76 @@
   return 0;
 }
 
+#ifdef GPT_SPI_NOR
+// This handles the MTD devices. ChromeOS uses /dev/mtdX for kernel partitions,
+// /dev/ubiblockX_0 for root partitions, and /dev/ubiX for stateful partition.
+static void chromeos_mtd_show(CgptFindParams *params, const char *filename,
+                              int partnum, GptEntry *entry) {
+  if (GuidEqual(&guid_chromeos_kernel, &entry->type)) {
+    printf("/dev/mtd%d\n", partnum);
+  } else if (GuidEqual(&guid_chromeos_rootfs, &entry->type)) {
+    printf("/dev/ubiblock%d_0\n", partnum);
+  } else {
+    printf("/dev/ubi%d_0\n", partnum);
+  }
+}
+
+static int scan_spi_gpt(CgptFindParams *params) {
+  int found = 0;
+  char partname[MAX_PARTITION_NAME_LEN];
+  FILE *fp;
+  size_t line_length = 0;
+  char *line = NULL;
+
+  fp = fopen(PROC_MTD, "re");
+  if (!fp) {
+    return found;
+  }
+
+  while (getline(&line, &line_length, fp) != -1) {
+    uint64_t sz;
+    uint32_t erasesz;
+    char name[128];
+    // dev:  size  erasesize  name
+    if (sscanf(line, "%64[^:]: %" PRIx64 " %x \"%127[^\"]\"",
+               partname, &sz, &erasesz, name) != 4)
+      continue;
+    if (strcmp(partname, "mtd0") == 0) {
+      char temp_dir[] = "/tmp/cgpt_find.XXXXXX";
+      if (params->drive_size == 0) {
+        if (GetMtdSize("/dev/mtd0", &params->drive_size) != 0) {
+          perror("GetMtdSize");
+          goto cleanup;
+        }
+      }
+      if (ReadNorFlash(temp_dir) != 0) {
+        perror("ReadNorFlash");
+        goto cleanup;
+      }
+      char nor_file[64];
+      if (snprintf(nor_file, sizeof(nor_file), "%s/rw_gpt", temp_dir) > 0) {
+        params->show_fn = chromeos_mtd_show;
+        if (do_search(params, nor_file)) {
+          found++;
+        }
+        params->show_fn = NULL;
+      }
+      RemoveDir(temp_dir);
+      break;
+    }
+  }
+cleanup:
+  fclose(fp);
+  free(line);
+  return found;
+}
+#else
+// Stub
+static int scan_spi_gpt(CgptFindParams *params) {
+  return 0;
+}
+#endif
+
 // This scans all the physical devices it can find, looking for a match. It
 // returns true if any matches were found, false otherwise.
 static int scan_real_devs(CgptFindParams *params) {
@@ -255,48 +312,10 @@
   }
 
   fclose(fp);
-
-  fp = fopen(PROC_MTD, "re");
-  if (!fp) {
-    free(line);
-    return found;
-  }
-
-  while (getline(&line, &line_length, fp) != -1) {
-    uint64_t sz;
-    uint32_t erasesz;
-    char name[128];
-    // dev:  size  erasesize  name
-    if (sscanf(line, "%64[^:]: %" PRIx64 " %x \"%127[^\"]\"",
-               partname, &sz, &erasesz, name) != 4)
-      continue;
-    if (strcmp(partname, "mtd0") == 0) {
-      char temp_dir[] = "/tmp/cgpt_find.XXXXXX";
-      if (params->drive_size == 0) {
-        if (GetMtdSize("/dev/mtd0", &params->drive_size) != 0) {
-          perror("GetMtdSize");
-          goto cleanup;
-        }
-      }
-      if (ReadNorFlash(temp_dir) != 0) {
-        perror("ReadNorFlash");
-        goto cleanup;
-      }
-      char nor_file[64];
-      if (snprintf(nor_file, sizeof(nor_file), "%s/rw_gpt", temp_dir) > 0) {
-        params->show_fn = chromeos_mtd_show;
-        if (do_search(params, nor_file)) {
-          found++;
-        }
-        params->show_fn = NULL;
-      }
-      RemoveDir(temp_dir);
-      break;
-    }
-  }
-cleanup:
-  fclose(fp);
   free(line);
+
+  found += scan_spi_gpt(params);
+
   return found;
 }
 
diff --git a/cgpt/cgpt_nor.c b/cgpt/cgpt_nor.c
index fd18446..2e43918 100644
--- a/cgpt/cgpt_nor.c
+++ b/cgpt/cgpt_nor.c
@@ -24,6 +24,7 @@
 
 #include "cgpt.h"
 #include "cgpt_nor.h"
+#include "subprocess.h"
 
 static const char FLASHROM_PATH[] = "/usr/sbin/flashrom";
 
@@ -48,6 +49,7 @@
   return ret;
 }
 
+// TODO(b:184812319): Remove these functions and use subprocess_run everywhere.
 int ForkExecV(const char *cwd, const char *const argv[]) {
   pid_t pid = fork();
   if (pid == -1) {
@@ -200,6 +202,7 @@
 // Read RW_GPT from NOR flash to "rw_gpt" in a temp dir |temp_dir_template|.
 // |temp_dir_template| is passed to mkdtemp() so it must satisfy all
 // requirements by mkdtemp.
+// TODO(b:184812319): Replace this function with flashrom_read.
 int ReadNorFlash(char *temp_dir_template) {
   int ret = 0;
 
@@ -212,27 +215,40 @@
 
   // Read RW_GPT section from NOR flash to "rw_gpt".
   ret++;
-  int fd_flags = fcntl(1, F_GETFD);
-  // Close stdout on exec so that flashrom does not muck up cgpt's output.
-  if (0 != fcntl(1, F_SETFD, FD_CLOEXEC))
-    Warning("Can't stop flashrom from mucking up our output\n");
-  if (ForkExecL(temp_dir_template, FLASHROM_PATH, "-i", "RW_GPT:rw_gpt", "-r",
-                NULL) != 0) {
+
+  char *cwd = getcwd(NULL, 0);
+  if (!cwd) {
+    Error("Cannot get current directory.\n");
+    return ret;
+  }
+  if (chdir(temp_dir_template) < 0) {
+    Error("Cannot change directory.\n");
+    goto out_free;
+  }
+  const char *const argv[] = {FLASHROM_PATH, "-i", "RW_GPT:rw_gpt", "-r"};
+  // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
+  // output.
+  if (subprocess_run(argv, &subprocess_null, &subprocess_null, NULL) != 0) {
     Error("Cannot exec flashrom to read from RW_GPT section.\n");
     RemoveDir(temp_dir_template);
   } else {
     ret = 0;
   }
+  if (chdir(cwd) < 0) {
+    Error("Cannot change directory back to original.\n");
+    goto out_free;
+  }
 
-  // Restore stdout flags
-  if (0 != fcntl(1, F_SETFD, fd_flags))
-    Warning("Can't restore stdout flags\n");
+out_free:
+  free(cwd);
   return ret;
 }
 
 // Write "rw_gpt" back to NOR flash. We write the file in two parts for safety.
+// TODO(b:184812319): Replace this function with flashrom_write.
 int WriteNorFlash(const char *dir) {
   int ret = 0;
+
   ret++;
   if (split_gpt(dir, "rw_gpt") != 0) {
     Error("Cannot split rw_gpt in two.\n");
@@ -240,26 +256,43 @@
   }
   ret++;
   int nr_fails = 0;
-  int fd_flags = fcntl(1, F_GETFD);
-  // Close stdout on exec so that flashrom does not muck up cgpt's output.
-  if (0 != fcntl(1, F_SETFD, FD_CLOEXEC))
-    Warning("Can't stop flashrom from mucking up our output\n");
-  if (ForkExecL(dir, FLASHROM_PATH, "-i", "RW_GPT_PRIMARY:rw_gpt_1",
-                "-w", "--fast-verify", NULL) != 0) {
+
+  char *cwd = getcwd(NULL, 0);
+  if (!cwd) {
+    Error("Cannot get current directory.\n");
+    return ret;
+  }
+  if (chdir(dir) < 0) {
+    Error("Cannot change directory.\n");
+    goto out_free;
+  }
+  const char *const argv1[] = {FLASHROM_PATH, "-i", "RW_GPT_PRIMARY:rw_gpt_1",
+                "-w", "--noverify-all"};
+  // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
+  // output.
+  if (subprocess_run(argv1, &subprocess_null, &subprocess_null, NULL) != 0) {
     Warning("Cannot write the 1st half of rw_gpt back with flashrom.\n");
     nr_fails++;
   }
-  if (ForkExecL(dir, FLASHROM_PATH, "-i", "RW_GPT_SECONDARY:rw_gpt_2",
-                "-w", "--fast-verify", NULL) != 0) {
+  const char *const argv2[] = {FLASHROM_PATH, "-i", "RW_GPT_SECONDARY:rw_gpt_2",
+                "-w", "--noverify-all"};
+  // Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
+  // output.
+  if (subprocess_run(argv2, &subprocess_null, &subprocess_null, NULL) != 0) {
     Warning("Cannot write the 2nd half of rw_gpt back with flashrom.\n");
     nr_fails++;
   }
-  if (0 != fcntl(1, F_SETFD, fd_flags))
-    Warning("Can't restore stdout flags\n");
+  if (chdir(cwd) < 0) {
+    Error("Cannot change directory back to original.\n");
+    goto out_free;
+  }
   switch (nr_fails) {
     case 0: ret = 0; break;
     case 1: Warning("It might still be okay.\n"); break;
     case 2: Error("Cannot write both parts back with flashrom.\n"); break;
   }
+
+out_free:
+  free(cwd);
   return ret;
 }
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c
index 2beb9ed..aa1d25d 100644
--- a/firmware/2lib/2api.c
+++ b/firmware/2lib/2api.c
@@ -15,7 +15,6 @@
 #include "2sha.h"
 #include "2sysincludes.h"
 #include "2tpm_bootmode.h"
-#include "vb2_common.h"
 
 vb2_error_t vb2api_fw_phase1(struct vb2_context *ctx)
 {
diff --git a/firmware/2lib/2common.c b/firmware/2lib/2common.c
index a88bc2e..fa0585e 100644
--- a/firmware/2lib/2common.c
+++ b/firmware/2lib/2common.c
@@ -8,8 +8,6 @@
 
 #include "2common.h"
 #include "2rsa.h"
-#include "2sha.h"
-#include "2sysincludes.h"
 
 vb2_error_t vb2_safe_memcmp(const void *s1, const void *s2, size_t size)
 {
@@ -190,9 +188,9 @@
 			    const struct vb2_workbuf *wb)
 {
 	struct vb2_workbuf wblocal = *wb;
-	struct vb2_digest_context *dc;
 	uint8_t *digest;
 	uint32_t digest_size;
+	vb2_error_t rv;
 
 	if (sig->data_size > size) {
 		VB2_DEBUG("Data buffer smaller than length of signed data.\n");
@@ -208,164 +206,26 @@
 	if (!digest)
 		return VB2_ERROR_VDATA_WORKBUF_DIGEST;
 
-	/* Hashing requires temp space for the context */
-	dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
-	if (!dc)
-		return VB2_ERROR_VDATA_WORKBUF_HASHING;
-
-	VB2_TRY(vb2_digest_init(dc, key->hash_alg));
-	VB2_TRY(vb2_digest_extend(dc, data, sig->data_size));
-	VB2_TRY(vb2_digest_finalize(dc, digest, digest_size));
-
-	vb2_workbuf_free(&wblocal, sizeof(*dc));
+	if (key->allow_hwcrypto) {
+		rv = vb2ex_hwcrypto_digest_init(key->hash_alg, sig->data_size);
+		if (rv == VB2_SUCCESS) {
+			VB2_DEBUG("Using HW crypto engine for hash_alg %d\n", key->hash_alg);
+			VB2_TRY(vb2ex_hwcrypto_digest_extend(data, sig->data_size));
+			VB2_TRY(vb2ex_hwcrypto_digest_finalize(digest, digest_size));
+		} else if (rv == VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED) {
+			VB2_DEBUG("HW crypto for hash_alg %d not supported, using SW\n",
+				  key->hash_alg);
+			VB2_TRY(vb2_digest_buffer(data, sig->data_size, key->hash_alg,
+						  digest, digest_size));
+		} else {
+			VB2_DEBUG("HW crypto init error : %d\n", rv);
+			return rv;
+		}
+	} else {
+		VB2_DEBUG("HW crypto forbidden by TPM flag, using SW\n");
+		VB2_TRY(vb2_digest_buffer(data, sig->data_size, key->hash_alg,
+					  digest, digest_size));
+	}
 
 	return vb2_verify_digest(key, sig, digest, &wblocal);
 }
-
-vb2_error_t vb2_check_keyblock(const struct vb2_keyblock *block, uint32_t size,
-			       const struct vb2_signature *sig)
-{
-	if(size < sizeof(*block)) {
-		VB2_DEBUG("Not enough space for keyblock header.\n");
-		return VB2_ERROR_KEYBLOCK_TOO_SMALL_FOR_HEADER;
-	}
-
-	if (memcmp(block->magic, VB2_KEYBLOCK_MAGIC, VB2_KEYBLOCK_MAGIC_SIZE)) {
-		VB2_DEBUG("Not a valid verified boot keyblock.\n");
-		return VB2_ERROR_KEYBLOCK_MAGIC;
-	}
-
-	if (block->header_version_major != VB2_KEYBLOCK_VERSION_MAJOR) {
-		VB2_DEBUG("Incompatible keyblock header version.\n");
-		return VB2_ERROR_KEYBLOCK_HEADER_VERSION;
-	}
-
-	if (size < block->keyblock_size) {
-		VB2_DEBUG("Not enough data for keyblock.\n");
-		return VB2_ERROR_KEYBLOCK_SIZE;
-	}
-
-	if (vb2_verify_signature_inside(block, block->keyblock_size, sig)) {
-		VB2_DEBUG("Keyblock signature off end of block\n");
-		return VB2_ERROR_KEYBLOCK_SIG_OUTSIDE;
-	}
-
-	/* Make sure advertised signature data sizes are valid. */
-	if (block->keyblock_size < sig->data_size) {
-		VB2_DEBUG("Signature calculated past end of block\n");
-		return VB2_ERROR_KEYBLOCK_SIGNED_TOO_MUCH;
-	}
-
-	/* Verify we signed enough data */
-	if (sig->data_size < sizeof(struct vb2_keyblock)) {
-		VB2_DEBUG("Didn't sign enough data\n");
-		return VB2_ERROR_KEYBLOCK_SIGNED_TOO_LITTLE;
-	}
-
-	/* Verify data key is inside the block and inside signed data */
-	if (vb2_verify_packed_key_inside(block, block->keyblock_size,
-					 &block->data_key)) {
-		VB2_DEBUG("Data key off end of keyblock\n");
-		return VB2_ERROR_KEYBLOCK_DATA_KEY_OUTSIDE;
-	}
-	if (vb2_verify_packed_key_inside(block, sig->data_size,
-					 &block->data_key)) {
-		VB2_DEBUG("Data key off end of signed data\n");
-		return VB2_ERROR_KEYBLOCK_DATA_KEY_UNSIGNED;
-	}
-
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_verify_keyblock(struct vb2_keyblock *block, uint32_t size,
-				const struct vb2_public_key *key,
-				const struct vb2_workbuf *wb)
-{
-	struct vb2_signature *sig = &block->keyblock_signature;
-	vb2_error_t rv;
-
-	/* Validity check keyblock before attempting signature check of data */
-	VB2_TRY(vb2_check_keyblock(block, size, sig));
-
-	VB2_DEBUG("Checking keyblock signature...\n");
-	rv = vb2_verify_data((const uint8_t *)block, size, sig, key, wb);
-	if (rv) {
-		VB2_DEBUG("Invalid keyblock signature.\n");
-		return VB2_ERROR_KEYBLOCK_SIG_INVALID;
-	}
-
-	/* Success */
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
-				   uint32_t size,
-				   const struct vb2_public_key *key,
-				   const struct vb2_workbuf *wb)
-{
-	struct vb2_signature *sig = &preamble->preamble_signature;
-
-	VB2_DEBUG("Verifying preamble.\n");
-
-	/* Validity checks before attempting signature of data */
-	if(size < sizeof(*preamble)) {
-		VB2_DEBUG("Not enough data for preamble header\n");
-		return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
-	}
-	if (preamble->header_version_major !=
-	    VB2_FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) {
-		VB2_DEBUG("Incompatible firmware preamble header version.\n");
-		return VB2_ERROR_PREAMBLE_HEADER_VERSION;
-	}
-
-	if (preamble->header_version_minor < 1) {
-		VB2_DEBUG("Only preamble header 2.1+ supported\n");
-		return VB2_ERROR_PREAMBLE_HEADER_OLD;
-	}
-
-	if (size < preamble->preamble_size) {
-		VB2_DEBUG("Not enough data for preamble.\n");
-		return VB2_ERROR_PREAMBLE_SIZE;
-	}
-
-	/* Check signature */
-	if (vb2_verify_signature_inside(preamble, preamble->preamble_size,
-					sig)) {
-		VB2_DEBUG("Preamble signature off end of preamble\n");
-		return VB2_ERROR_PREAMBLE_SIG_OUTSIDE;
-	}
-
-	/* Make sure advertised signature data sizes are valid. */
-	if (preamble->preamble_size < sig->data_size) {
-		VB2_DEBUG("Signature calculated past end of the block\n");
-		return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH;
-	}
-
-	if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) {
-		VB2_DEBUG("Preamble signature validation failed\n");
-		return VB2_ERROR_PREAMBLE_SIG_INVALID;
-	}
-
-	/* Verify we signed enough data */
-	if (sig->data_size < sizeof(struct vb2_fw_preamble)) {
-		VB2_DEBUG("Didn't sign enough data\n");
-		return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE;
-	}
-
-	/* Verify body signature is inside the signed data */
-	if (vb2_verify_signature_inside(preamble, sig->data_size,
-					&preamble->body_signature)) {
-		VB2_DEBUG("Firmware body signature off end of preamble\n");
-		return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE;
-	}
-
-	/* Verify kernel subkey is inside the signed data */
-	if (vb2_verify_packed_key_inside(preamble, sig->data_size,
-					 &preamble->kernel_subkey)) {
-		VB2_DEBUG("Kernel subkey off end of preamble\n");
-		return VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE;
-	}
-
-	/* Success */
-	return VB2_SUCCESS;
-}
diff --git a/firmware/lib20/misc.c b/firmware/2lib/2firmware.c
similarity index 98%
rename from firmware/lib20/misc.c
rename to firmware/2lib/2firmware.c
index bc8e995..bc708dc 100644
--- a/firmware/lib20/misc.c
+++ b/firmware/2lib/2firmware.c
@@ -6,13 +6,13 @@
  */
 
 #include "2api.h"
+#include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
 #include "2rsa.h"
 #include "2secdata.h"
 #include "2sha.h"
 #include "2sysincludes.h"
-#include "vb2_common.h"
 
 vb2_error_t vb2_load_fw_keyblock(struct vb2_context *ctx)
 {
diff --git a/firmware/2lib/2kernel.c b/firmware/2lib/2kernel.c
index 8c6d191..763214d 100644
--- a/firmware/2lib/2kernel.c
+++ b/firmware/2lib/2kernel.c
@@ -11,7 +11,6 @@
 #include "2nvstorage.h"
 #include "2rsa.h"
 #include "2secdata.h"
-#include "vb2_common.h"
 #include "vboot_kernel.h"
 
 /**
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index 7c4ca26..75a9f36 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -15,7 +15,6 @@
 #include "2sha.h"
 #include "2struct.h"
 #include "2sysincludes.h"
-#include "vb2_common.h"
 #include "vboot_api.h"
 #include "vboot_struct.h"
 
@@ -251,7 +250,7 @@
 		 * developer mode.
 		 */
 		vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 0);
-		vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 0);
+		vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 0);
 		vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 0);
 		vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, 0);
 	}
@@ -409,7 +408,7 @@
 	 * return false (=RW). That's ok because if recovery is manual, we will
 	 * get the right signal and that's the case we care about.
 	 */
-	if (!vb2ex_ec_trusted())
+	if (!(ctx->flags & VB2_CONTEXT_EC_TRUSTED) && !vb2ex_ec_trusted())
 		return 0;
 
 	/* Now we confidently check the recovery switch state at boot */
@@ -528,8 +527,8 @@
 {
 	struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
 
-	if (gbb->flags & VB2_GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY)
-		return VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY;
+	if (gbb->flags & VB2_GBB_FLAG_DEFAULT_DEV_BOOT_ALTFW)
+		return VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW;
 
 	switch (vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT)) {
 		case VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL:
@@ -537,9 +536,9 @@
 				return VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
 			break;
 
-		case VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY:
-			if (vb2_dev_boot_legacy_allowed(ctx))
-				return VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY;
+		case VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW:
+			if (vb2_dev_boot_altfw_allowed(ctx))
+				return VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW;
 			break;
 	}
 
@@ -556,14 +555,14 @@
 	return 1;
 }
 
-int vb2_dev_boot_legacy_allowed(struct vb2_context *ctx)
+int vb2_dev_boot_altfw_allowed(struct vb2_context *ctx)
 {
 	struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
 
-	return vb2_nv_get(ctx, VB2_NV_DEV_BOOT_LEGACY) ||
-	       (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY) ||
+	return vb2_nv_get(ctx, VB2_NV_DEV_BOOT_ALTFW) ||
+	       (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW) ||
 	       vb2_secdata_fwmp_get_flag(ctx,
-					 VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY);
+					 VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW);
 }
 
 int vb2_dev_boot_external_allowed(struct vb2_context *ctx)
@@ -661,9 +660,9 @@
 	i = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL);
 	DEBUG_INFO_APPEND("\ndev_boot_usb: %d", i);
 
-	/* Add dev_boot_legacy flag */
-	i = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_LEGACY);
-	DEBUG_INFO_APPEND("\ndev_boot_legacy: %d", i);
+	/* Add dev_boot_altfw flag */
+	i = vb2_nv_get(ctx, VB2_NV_DEV_BOOT_ALTFW);
+	DEBUG_INFO_APPEND("\ndev_boot_altfw: %d", i);
 
 	/* Add dev_default_boot flag */
 	i = vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT);
diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c
index c3cdca5..1cd5ba2 100644
--- a/firmware/2lib/2nvstorage.c
+++ b/firmware/2lib/2nvstorage.c
@@ -145,7 +145,7 @@
 	case VB2_NV_DEV_BOOT_EXTERNAL:
 		return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_EXTERNAL);
 
-	case VB2_NV_DEV_BOOT_LEGACY:
+	case VB2_NV_DEV_BOOT_ALTFW:
 		return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
 
 	case VB2_NV_DEV_BOOT_SIGNED_ONLY:
@@ -331,7 +331,7 @@
 		SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_EXTERNAL);
 		break;
 
-	case VB2_NV_DEV_BOOT_LEGACY:
+	case VB2_NV_DEV_BOOT_ALTFW:
 		SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
 		break;
 
diff --git a/firmware/lib20/packed_key.c b/firmware/2lib/2packed_key.c
similarity index 98%
rename from firmware/lib20/packed_key.c
rename to firmware/2lib/2packed_key.c
index 3870288..4e2c654 100644
--- a/firmware/lib20/packed_key.c
+++ b/firmware/2lib/2packed_key.c
@@ -6,9 +6,9 @@
  */
 
 #include "2common.h"
+#include "2packed_key.h"
 #include "2rsa.h"
 #include "2sysincludes.h"
-#include "vb2_common.h"
 
 test_mockable
 vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key,
diff --git a/firmware/2lib/2recovery_reasons.c b/firmware/2lib/2recovery_reasons.c
index 093ef86..8c43dce 100644
--- a/firmware/2lib/2recovery_reasons.c
+++ b/firmware/2lib/2recovery_reasons.c
@@ -152,8 +152,8 @@
 		return "Recovery hash space lock error in RO firmware";
 	/* 0x60 */ case VB2_RECOVERY_TPM_DISABLE_FAILED:
 		return "Failed to disable TPM before running untrusted code";
-	/* 0x61 */ case VB2_RECOVERY_ALTFW_HASH_FAILED:
-		return "Verification of alternative firmware payload failed";
+	/* 0x61 */ case VB2_RECOVERY_ALTFW_HASH_MISMATCH:
+		return "Verification of alternate bootloader payload failed";
 	/* 0x62 */ case VB2_RECOVERY_SECDATA_FWMP_INIT:
 		return "FWMP secure NVRAM (TPM) initialization error";
 	/* 0x63 */ case VB2_RECOVERY_CR50_BOOT_MODE:
diff --git a/firmware/2lib/2rsa.c b/firmware/2lib/2rsa.c
index 962558d..dcd8bad 100644
--- a/firmware/2lib/2rsa.c
+++ b/firmware/2lib/2rsa.c
@@ -11,6 +11,7 @@
 
 #include "2common.h"
 #include "2rsa.h"
+#include "2rsa_private.h"
 #include "2sha.h"
 #include "2sysincludes.h"
 #include "vboot_test.h"
diff --git a/firmware/2lib/2secdata_fwmp.c b/firmware/2lib/2secdata_fwmp.c
index a28b5bb..cec2481 100644
--- a/firmware/2lib/2secdata_fwmp.c
+++ b/firmware/2lib/2secdata_fwmp.c
@@ -60,6 +60,25 @@
 	return VB2_SUCCESS;
 }
 
+uint32_t vb2api_secdata_fwmp_create(struct vb2_context *ctx)
+{
+	struct vb2_secdata_fwmp *sec = (void *)&ctx->secdata_fwmp;
+
+	/* Clear the entire struct */
+	memset(sec, 0, sizeof(*sec));
+
+	/* Set to current version */
+	sec->struct_version = VB2_SECDATA_FWMP_VERSION;
+
+	/* Set the structure size */
+	sec->struct_size = sizeof(*sec);
+
+	/* Calculate initial CRC */
+	sec->crc8 = vb2_secdata_fwmp_crc(sec);
+
+	return sizeof(*sec);
+}
+
 vb2_error_t vb2_secdata_fwmp_init(struct vb2_context *ctx)
 {
 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
diff --git a/firmware/2lib/2secdata_kernel.c b/firmware/2lib/2secdata_kernel.c
index de12ca0..0d4208f 100644
--- a/firmware/2lib/2secdata_kernel.c
+++ b/firmware/2lib/2secdata_kernel.c
@@ -22,7 +22,13 @@
 	return MAJOR_VER(sec->struct_version) == 0;
 }
 
-uint8_t vb2_secdata_kernel_crc(struct vb2_context *ctx)
+/**
+ * Calculate crc8 of kernel secure storage.
+ *
+ * @param ctx		Context pointer
+ * @return Calculated crc8 value.
+ */
+static uint8_t secdata_kernel_crc(struct vb2_context *ctx)
 {
 	size_t offset, size;
 
@@ -54,7 +60,7 @@
 	*size = VB2_SECDATA_KERNEL_SIZE_V02;
 
 	/* Verify CRC */
-	if (sec->crc8 != vb2_secdata_kernel_crc(ctx)) {
+	if (sec->crc8 != secdata_kernel_crc(ctx)) {
 		VB2_DEBUG("secdata_kernel: bad CRC\n");
 		return VB2_ERROR_SECDATA_KERNEL_CRC;
 	}
@@ -101,7 +107,7 @@
 	*size = sec->struct_size;
 
 	/* Verify CRC */
-	if (sec->crc8 != vb2_secdata_kernel_crc(ctx)) {
+	if (sec->crc8 != secdata_kernel_crc(ctx)) {
 		VB2_DEBUG("secdata_kernel: bad CRC\n");
 		return VB2_ERROR_SECDATA_KERNEL_CRC;
 	}
@@ -131,7 +137,7 @@
 	memset(sec, 0, sizeof(*sec));
 	sec->struct_version = VB2_SECDATA_KERNEL_VERSION_LATEST;
 	sec->struct_size = sizeof(*sec);
-	sec->crc8 = vb2_secdata_kernel_crc(ctx);
+	sec->crc8 = secdata_kernel_crc(ctx);
 
 	/* Mark as changed */
 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
@@ -256,9 +262,9 @@
 	}
 
 	if (is_v0(ctx))
-		v0->crc8 = vb2_secdata_kernel_crc(ctx);
+		v0->crc8 = secdata_kernel_crc(ctx);
 	else
-		v1->crc8 = vb2_secdata_kernel_crc(ctx);
+		v1->crc8 = secdata_kernel_crc(ctx);
 
 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
 	return;
@@ -300,7 +306,7 @@
 	}
 
 	memcpy(sec->ec_hash, sha256, sizeof(sec->ec_hash));
-	sec->crc8 = vb2_secdata_kernel_crc(ctx);
+	sec->crc8 = secdata_kernel_crc(ctx);
 
 	ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
 
diff --git a/firmware/2lib/2struct.c b/firmware/2lib/2struct.c
new file mode 100644
index 0000000..a16f869
--- /dev/null
+++ b/firmware/2lib/2struct.c
@@ -0,0 +1,317 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Functions for reading, checking and verifying firmware and
+ * kernel data structures.
+ */
+
+#include "2common.h"
+
+vb2_error_t vb2_check_keyblock(const struct vb2_keyblock *block, uint32_t size,
+			       const struct vb2_signature *sig)
+{
+	if(size < sizeof(*block)) {
+		VB2_DEBUG("Not enough space for keyblock header.\n");
+		return VB2_ERROR_KEYBLOCK_TOO_SMALL_FOR_HEADER;
+	}
+
+	if (memcmp(block->magic, VB2_KEYBLOCK_MAGIC, VB2_KEYBLOCK_MAGIC_SIZE)) {
+		VB2_DEBUG("Not a valid verified boot keyblock.\n");
+		return VB2_ERROR_KEYBLOCK_MAGIC;
+	}
+
+	if (block->header_version_major != VB2_KEYBLOCK_VERSION_MAJOR) {
+		VB2_DEBUG("Incompatible keyblock header version.\n");
+		return VB2_ERROR_KEYBLOCK_HEADER_VERSION;
+	}
+
+	if (size < block->keyblock_size) {
+		VB2_DEBUG("Not enough data for keyblock.\n");
+		return VB2_ERROR_KEYBLOCK_SIZE;
+	}
+
+	if (vb2_verify_signature_inside(block, block->keyblock_size, sig)) {
+		VB2_DEBUG("Keyblock signature off end of block\n");
+		return VB2_ERROR_KEYBLOCK_SIG_OUTSIDE;
+	}
+
+	/* Make sure advertised signature data sizes are valid. */
+	if (block->keyblock_size < sig->data_size) {
+		VB2_DEBUG("Signature calculated past end of block\n");
+		return VB2_ERROR_KEYBLOCK_SIGNED_TOO_MUCH;
+	}
+
+	/* Verify we signed enough data */
+	if (sig->data_size < sizeof(struct vb2_keyblock)) {
+		VB2_DEBUG("Didn't sign enough data\n");
+		return VB2_ERROR_KEYBLOCK_SIGNED_TOO_LITTLE;
+	}
+
+	/* Verify data key is inside the block and inside signed data */
+	if (vb2_verify_packed_key_inside(block, block->keyblock_size,
+					 &block->data_key)) {
+		VB2_DEBUG("Data key off end of keyblock\n");
+		return VB2_ERROR_KEYBLOCK_DATA_KEY_OUTSIDE;
+	}
+	if (vb2_verify_packed_key_inside(block, sig->data_size,
+					 &block->data_key)) {
+		VB2_DEBUG("Data key off end of signed data\n");
+		return VB2_ERROR_KEYBLOCK_DATA_KEY_UNSIGNED;
+	}
+
+	return VB2_SUCCESS;
+}
+
+vb2_error_t vb2_verify_keyblock(struct vb2_keyblock *block, uint32_t size,
+				const struct vb2_public_key *key,
+				const struct vb2_workbuf *wb)
+{
+	struct vb2_signature *sig = &block->keyblock_signature;
+	vb2_error_t rv;
+
+	/* Validity check keyblock before attempting signature check of data */
+	VB2_TRY(vb2_check_keyblock(block, size, sig));
+
+	VB2_DEBUG("Checking keyblock signature...\n");
+	rv = vb2_verify_data((const uint8_t *)block, size, sig, key, wb);
+	if (rv) {
+		VB2_DEBUG("Invalid keyblock signature.\n");
+		return VB2_ERROR_KEYBLOCK_SIG_INVALID;
+	}
+
+	/* Success */
+	return VB2_SUCCESS;
+}
+
+vb2_error_t vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
+				   uint32_t size,
+				   const struct vb2_public_key *key,
+				   const struct vb2_workbuf *wb)
+{
+	struct vb2_signature *sig = &preamble->preamble_signature;
+
+	VB2_DEBUG("Verifying preamble.\n");
+
+	/* Validity checks before attempting signature of data */
+	if(size < sizeof(*preamble)) {
+		VB2_DEBUG("Not enough data for preamble header\n");
+		return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
+	}
+	if (preamble->header_version_major !=
+	    VB2_FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) {
+		VB2_DEBUG("Incompatible firmware preamble header version.\n");
+		return VB2_ERROR_PREAMBLE_HEADER_VERSION;
+	}
+
+	if (preamble->header_version_minor < 1) {
+		VB2_DEBUG("Only preamble header 2.1+ supported\n");
+		return VB2_ERROR_PREAMBLE_HEADER_OLD;
+	}
+
+	if (size < preamble->preamble_size) {
+		VB2_DEBUG("Not enough data for preamble.\n");
+		return VB2_ERROR_PREAMBLE_SIZE;
+	}
+
+	/* Check signature */
+	if (vb2_verify_signature_inside(preamble, preamble->preamble_size,
+					sig)) {
+		VB2_DEBUG("Preamble signature off end of preamble\n");
+		return VB2_ERROR_PREAMBLE_SIG_OUTSIDE;
+	}
+
+	/* Make sure advertised signature data sizes are valid. */
+	if (preamble->preamble_size < sig->data_size) {
+		VB2_DEBUG("Signature calculated past end of the block\n");
+		return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH;
+	}
+
+	if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) {
+		VB2_DEBUG("Preamble signature validation failed\n");
+		return VB2_ERROR_PREAMBLE_SIG_INVALID;
+	}
+
+	/* Verify we signed enough data */
+	if (sig->data_size < sizeof(struct vb2_fw_preamble)) {
+		VB2_DEBUG("Didn't sign enough data\n");
+		return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE;
+	}
+
+	/* Verify body signature is inside the signed data */
+	if (vb2_verify_signature_inside(preamble, sig->data_size,
+					&preamble->body_signature)) {
+		VB2_DEBUG("Firmware body signature off end of preamble\n");
+		return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE;
+	}
+
+	/* Verify kernel subkey is inside the signed data */
+	if (vb2_verify_packed_key_inside(preamble, sig->data_size,
+					 &preamble->kernel_subkey)) {
+		VB2_DEBUG("Kernel subkey off end of preamble\n");
+		return VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE;
+	}
+
+	/* Success */
+	return VB2_SUCCESS;
+}
+
+uint32_t vb2_kernel_get_flags(const struct vb2_kernel_preamble *preamble)
+{
+	if (preamble->header_version_minor < 2)
+		return 0;
+
+	return preamble->flags;
+}
+
+test_mockable
+vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
+				     uint32_t size,
+				     const struct vb2_workbuf *wb)
+{
+	const struct vb2_signature *sig = &block->keyblock_hash;
+	struct vb2_workbuf wblocal = *wb;
+	struct vb2_digest_context *dc;
+	uint8_t *digest;
+	uint32_t digest_size;
+
+	/* Validity check keyblock before attempting hash check of data */
+	VB2_TRY(vb2_check_keyblock(block, size, sig));
+
+	VB2_DEBUG("Checking keyblock hash...\n");
+
+	/* Digest goes at start of work buffer */
+	digest_size = vb2_digest_size(VB2_HASH_SHA512);
+	digest = vb2_workbuf_alloc(&wblocal, digest_size);
+	if (!digest)
+		return VB2_ERROR_VDATA_WORKBUF_DIGEST;
+
+	/* Hashing requires temp space for the context */
+	dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
+	if (!dc)
+		return VB2_ERROR_VDATA_WORKBUF_HASHING;
+
+	VB2_TRY(vb2_digest_init(dc, VB2_HASH_SHA512));
+
+	VB2_TRY(vb2_digest_extend(dc, (const uint8_t *)block, sig->data_size));
+
+	VB2_TRY(vb2_digest_finalize(dc, digest, digest_size));
+
+	if (vb2_safe_memcmp(vb2_signature_data(sig), digest,
+			    digest_size) != 0) {
+		VB2_DEBUG("Invalid keyblock hash.\n");
+		return VB2_ERROR_KEYBLOCK_HASH_INVALID_IN_DEV_MODE;
+	}
+
+	/* Success */
+	return VB2_SUCCESS;
+}
+
+test_mockable
+vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
+				       uint32_t size,
+				       const struct vb2_public_key *key,
+				       const struct vb2_workbuf *wb)
+{
+	struct vb2_signature *sig = &preamble->preamble_signature;
+	uint32_t min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_0_SIZE;
+
+	VB2_DEBUG("Verifying kernel preamble.\n");
+
+	/* Make sure it's even safe to look at the struct */
+	if(size < min_size) {
+		VB2_DEBUG("Not enough data for preamble header.\n");
+		return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
+	}
+	if (preamble->header_version_major !=
+	    VB2_KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) {
+		VB2_DEBUG("Incompatible kernel preamble header version.\n");
+		return VB2_ERROR_PREAMBLE_HEADER_VERSION;
+	}
+
+	if (preamble->header_version_minor >= 2)
+		min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_2_SIZE;
+	else if (preamble->header_version_minor == 1)
+		min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_1_SIZE;
+	if(preamble->preamble_size < min_size) {
+		VB2_DEBUG("Preamble size too small for header.\n");
+		return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
+	}
+	if (size < preamble->preamble_size) {
+		VB2_DEBUG("Not enough data for preamble.\n");
+		return VB2_ERROR_PREAMBLE_SIZE;
+	}
+
+	/* Check signature */
+	if (vb2_verify_signature_inside(preamble, preamble->preamble_size,
+					sig)) {
+		VB2_DEBUG("Preamble signature off end of preamble\n");
+		return VB2_ERROR_PREAMBLE_SIG_OUTSIDE;
+	}
+
+	/* Make sure advertised signature data sizes are valid. */
+	if (preamble->preamble_size < sig->data_size) {
+		VB2_DEBUG("Signature calculated past end of the block\n");
+		return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH;
+	}
+
+	if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) {
+		VB2_DEBUG("Preamble signature validation failed\n");
+		return VB2_ERROR_PREAMBLE_SIG_INVALID;
+	}
+
+	/* Verify we signed enough data */
+	if (sig->data_size < sizeof(struct vb2_fw_preamble)) {
+		VB2_DEBUG("Didn't sign enough data\n");
+		return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE;
+	}
+
+	/* Verify body signature is inside the signed data */
+	if (vb2_verify_signature_inside(preamble, sig->data_size,
+					&preamble->body_signature)) {
+		VB2_DEBUG("Body signature off end of preamble\n");
+		return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE;
+	}
+
+	/*
+	 * If bootloader is present, verify it's covered by the body
+	 * signature.
+	 */
+	if (preamble->bootloader_size) {
+		const void *body_ptr =
+			(const void *)(uintptr_t)preamble->body_load_address;
+		const void *bootloader_ptr =
+			(const void *)(uintptr_t)preamble->bootloader_address;
+		if (vb2_verify_member_inside(body_ptr,
+					     preamble->body_signature.data_size,
+					     bootloader_ptr,
+					     preamble->bootloader_size,
+					     0, 0)) {
+			VB2_DEBUG("Bootloader off end of signed data\n");
+			return VB2_ERROR_PREAMBLE_BOOTLOADER_OUTSIDE;
+		}
+	}
+
+	/*
+	 * If vmlinuz header is present, verify it's covered by the body
+	 * signature.
+	 */
+	if (preamble->header_version_minor >= 1 &&
+	    preamble->vmlinuz_header_size) {
+		const void *body_ptr =
+			(const void *)(uintptr_t)preamble->body_load_address;
+		const void *vmlinuz_header_ptr = (const void *)
+			(uintptr_t)preamble->vmlinuz_header_address;
+		if (vb2_verify_member_inside(body_ptr,
+					     preamble->body_signature.data_size,
+					     vmlinuz_header_ptr,
+					     preamble->vmlinuz_header_size,
+					     0, 0)) {
+			VB2_DEBUG("Vmlinuz header off end of signed data\n");
+			return VB2_ERROR_PREAMBLE_VMLINUZ_HEADER_OUTSIDE;
+		}
+	}
+
+	/* Success */
+	return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/2stub.c b/firmware/2lib/2stub.c
index 782ad42..7cec2e5 100644
--- a/firmware/2lib/2stub.c
+++ b/firmware/2lib/2stub.c
@@ -8,10 +8,15 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <sys/time.h>
 
 #include "2api.h"
+#include "2common.h"
 #include "2sysincludes.h"
 
+/*****************************************************************************/
+/* General utility stubs */
+
 __attribute__((weak))
 void vb2ex_printf(const char *func, const char *fmt, ...)
 {
@@ -26,10 +31,18 @@
 }
 
 __attribute__((weak))
-vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *ctx)
+void vb2ex_abort(void)
 {
-	fprintf(stderr, "%s: function not implemented\n", __func__);
-	return VB2_ERROR_EX_UNIMPLEMENTED;
+	/* Stub simply exits. */
+	abort();
+}
+
+__attribute__((weak))
+uint32_t vb2ex_mtime(void)
+{
+	struct timeval tv;
+	gettimeofday(&tv, NULL);
+	return tv.tv_sec * VB2_MSEC_PER_SEC + tv.tv_usec / VB2_USEC_PER_MSEC;
 }
 
 __attribute__((weak))
@@ -41,6 +54,16 @@
 	return VB2_ERROR_EX_UNIMPLEMENTED;
 }
 
+/*****************************************************************************/
+/* TPM-related stubs */
+
+__attribute__((weak))
+vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *ctx)
+{
+	fprintf(stderr, "%s: function not implemented\n", __func__);
+	return VB2_ERROR_EX_UNIMPLEMENTED;
+}
+
 __attribute__((weak))
 vb2_error_t vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val)
 {
@@ -48,6 +71,80 @@
 	return VB2_ERROR_EX_UNIMPLEMENTED;
 }
 
+/*****************************************************************************/
+/* auxfw and EC-related stubs */
+
+__attribute__((weak))
+int vb2ex_ec_trusted(void)
+{
+	return 1;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_running_rw(int *in_rw)
+{
+	*in_rw = 0;
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_jump_to_rw(void)
+{
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_disable_jump(void)
+{
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_hash_image(enum vb2_firmware_selection select,
+				const uint8_t **hash, int *hash_size)
+{
+	static const uint8_t fake_hash[32] = {1, 2, 3, 4};
+
+	*hash = fake_hash;
+	*hash_size = sizeof(fake_hash);
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select,
+					     const uint8_t **hash, int *hash_size)
+{
+	static const uint8_t fake_hash[32] = {1, 2, 3, 4};
+
+	*hash = fake_hash;
+	*hash_size = sizeof(fake_hash);
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select)
+{
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_protect(enum vb2_firmware_selection select)
+{
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *ctx)
+{
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_ec_battery_cutoff(void)
+{
+	return VB2_SUCCESS;
+}
+
 __attribute__((weak))
 vb2_error_t vb2ex_auxfw_check(enum vb2_auxfw_update_severity *severity)
 {
@@ -67,12 +164,8 @@
 	return VB2_SUCCESS;
 }
 
-__attribute__((weak))
-void vb2ex_abort(void)
-{
-	/* Stub simply exits. */
-	abort();
-}
+/*****************************************************************************/
+/* UI-related stubs */
 
 __attribute__((weak))
 const char *vb2ex_get_debug_info(struct vb2_context *ctx)
@@ -94,9 +187,23 @@
 }
 
 __attribute__((weak))
-const char *vb2ex_get_diagnostic_storage(void)
+vb2_error_t vb2ex_diag_get_storage_health(const char **out)
 {
-	return "mock";
+	*out = "mock";
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_diag_get_storage_test_log(const char **out)
+{
+	*out = "mock";
+	return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_diag_storage_test_control(enum vb2_diag_storage_test ops)
+{
+	return VB2_SUCCESS;
 }
 
 __attribute__((weak))
@@ -112,3 +219,40 @@
 	*out = "mock";
 	return VB2_SUCCESS;
 }
+
+__attribute__((weak))
+void vb2ex_msleep(uint32_t msec)
+{
+}
+
+__attribute__((weak))
+void vb2ex_beep(uint32_t msec, uint32_t frequency)
+{
+}
+
+__attribute__((weak))
+uint32_t vb2ex_get_locale_count(void)
+{
+	return 0;
+}
+
+__attribute__((weak))
+uint32_t vb2ex_get_altfw_count(void)
+{
+	return 0;
+}
+
+__attribute__((weak))
+int vb2ex_physical_presence_pressed(void)
+{
+	return 0;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_commit_data(struct vb2_context *ctx)
+{
+	ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
+	ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
+	ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
+	return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/2ui.c b/firmware/2lib/2ui.c
index 10de176..7173450 100644
--- a/firmware/2lib/2ui.c
+++ b/firmware/2lib/2ui.c
@@ -24,7 +24,7 @@
  * shutdown is required.
  *
  * @param ui		UI context pointer
- * @return VB2_REQUEST_SHUTDOWN if shutdown needed, or VB2_REQUEST_UI_CONTINUE
+ * @return VB2_REQUEST_SHUTDOWN if shutdown needed, or VB2_SUCCESS
  */
 vb2_error_t check_shutdown_request(struct vb2_ui_context *ui)
 {
@@ -64,7 +64,7 @@
 	if (shutdown_request)
 		return VB2_REQUEST_SHUTDOWN;
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /*****************************************************************************/
@@ -81,7 +81,7 @@
 		ui->error_code = VB2_UI_ERROR_NONE;
 		ui->key = 0;
 	}
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /*****************************************************************************/
@@ -131,7 +131,7 @@
 				  ui->key, ui->key_trusted);
 	}
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2_ui_menu_prev(struct vb2_ui_context *ui)
@@ -139,7 +139,7 @@
 	int item;
 
 	if (!DETACHABLE && ui->key == VB_BUTTON_VOL_UP_SHORT_PRESS)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	item = ui->state->selected_item - 1;
 	while (item >= 0 && VB2_GET_BIT(ui->state->hidden_item_mask, item))
@@ -148,7 +148,7 @@
 	if (item >= 0)
 		ui->state->selected_item = item;
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2_ui_menu_next(struct vb2_ui_context *ui)
@@ -157,7 +157,7 @@
 	const struct vb2_menu *menu;
 
 	if (!DETACHABLE && ui->key == VB_BUTTON_VOL_DOWN_SHORT_PRESS)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	menu = get_menu(ui);
 	item = ui->state->selected_item + 1;
@@ -168,7 +168,7 @@
 	if (item < menu->num_items)
 		ui->state->selected_item = item;
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui)
@@ -177,11 +177,11 @@
 	const struct vb2_menu_item *menu_item;
 
 	if (!DETACHABLE && ui->key == VB_BUTTON_POWER_SHORT_PRESS)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	menu = get_menu(ui);
 	if (menu->num_items == 0)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	menu_item = &menu->items[ui->state->selected_item];
 
@@ -190,7 +190,7 @@
 			ui->state->selected_item)) {
 		VB2_DEBUG("Menu item <%s> disabled; ignoring\n",
 			  menu_item->text);
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 	}
 
 	if (menu_item->action) {
@@ -204,7 +204,7 @@
 
 	VB2_DEBUG("Menu item <%s> no action or target screen\n",
 		  menu_item->text);
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /*****************************************************************************/
@@ -219,7 +219,7 @@
 		free(ui->state);
 		ui->state = tmp;
 		if (ui->state->screen->reinit)
-			return ui->state->screen->reinit(ui);
+			VB2_TRY(ui->state->screen->reinit(ui));
 	} else {
 		VB2_DEBUG("ERROR: No previous screen; ignoring\n");
 	}
@@ -233,7 +233,7 @@
 	ui->state->selected_item = 0;
 	if (menu->num_items > 1 && menu->items[0].is_language_select)
 		ui->state->selected_item = 1;
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2_ui_screen_change(struct vb2_ui_context *ui, enum vb2_screen id)
@@ -266,7 +266,7 @@
 			free(cur_state);
 		}
 		if (ui->state->screen->reinit)
-			return ui->state->screen->reinit(ui);
+			VB2_TRY(ui->state->screen->reinit(ui));
 	} else {
 		/* Allocate the requested screen on top of the stack. */
 		cur_state = malloc(sizeof(*ui->state));
@@ -279,9 +279,9 @@
 		cur_state->screen = new_screen_info;
 		ui->state = cur_state;
 		if (ui->state->screen->init)
-			return ui->state->screen->init(ui);
+			VB2_TRY(ui->state->screen->init(ui));
 		else
-			return default_screen_init(ui);
+			VB2_TRY(default_screen_init(ui));
 	}
 
 	return VB2_REQUEST_UI_CONTINUE;
@@ -290,8 +290,9 @@
 /*****************************************************************************/
 /* Core UI loop */
 
-vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id,
-		    vb2_error_t (*global_action)(struct vb2_ui_context *ui))
+static vb2_error_t ui_loop_impl(
+	struct vb2_context *ctx, enum vb2_screen root_screen_id,
+	vb2_error_t (*global_action)(struct vb2_ui_context *ui))
 {
 	struct vb2_ui_context ui;
 	struct vb2_screen_state prev_state;
@@ -309,9 +310,11 @@
 	if (root_info == NULL)
 		VB2_DIE("Root screen not found.\n");
 	ui.locale_id = vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX);
+
 	rv = vb2_ui_screen_change(&ui, root_screen_id);
-	if (rv != VB2_REQUEST_UI_CONTINUE)
+	if (rv && rv != VB2_REQUEST_UI_CONTINUE)
 		return rv;
+
 	memset(&prev_state, 0, sizeof(prev_state));
 	prev_disable_timer = 0;
 	prev_error_code = VB2_UI_ERROR_NONE;
@@ -365,32 +368,32 @@
 
 		/* Check for shutdown request. */
 		rv = check_shutdown_request(&ui);
-		if (rv != VB2_REQUEST_UI_CONTINUE) {
+		if (rv && rv != VB2_REQUEST_UI_CONTINUE) {
 			VB2_DEBUG("Shutdown requested!\n");
 			return rv;
 		}
 
 		/* Check if we need to exit an error box. */
 		rv = error_exit_action(&ui);
-		if (rv != VB2_REQUEST_UI_CONTINUE)
+		if (rv && rv != VB2_REQUEST_UI_CONTINUE)
 			return rv;
 
 		/* Run screen action. */
 		if (ui.state->screen->action) {
 			rv = ui.state->screen->action(&ui);
-			if (rv != VB2_REQUEST_UI_CONTINUE)
+			if (rv && rv != VB2_REQUEST_UI_CONTINUE)
 				return rv;
 		}
 
 		/* Run menu navigation action. */
 		rv = menu_navigation_action(&ui);
-		if (rv != VB2_REQUEST_UI_CONTINUE)
+		if (rv && rv != VB2_REQUEST_UI_CONTINUE)
 			return rv;
 
 		/* Run global action function if available. */
 		if (global_action) {
 			rv = global_action(&ui);
-			if (rv != VB2_REQUEST_UI_CONTINUE)
+			if (rv && rv != VB2_REQUEST_UI_CONTINUE)
 				return rv;
 		}
 
@@ -403,17 +406,38 @@
 	return VB2_SUCCESS;
 }
 
+vb2_error_t ui_loop(struct vb2_context *ctx, enum vb2_screen root_screen_id,
+		    vb2_error_t (*global_action)(struct vb2_ui_context *ui))
+{
+	vb2_error_t rv = ui_loop_impl(ctx, root_screen_id, global_action);
+	if (rv == VB2_REQUEST_UI_EXIT)
+		return VB2_SUCCESS;
+	return rv;
+}
+
 /*****************************************************************************/
 /* Developer mode */
 
 vb2_error_t vb2_developer_menu(struct vb2_context *ctx)
 {
-	return ui_loop(ctx, VB2_SCREEN_DEVELOPER_MODE, developer_action);
+	enum vb2_screen root_screen_id = VB2_SCREEN_DEVELOPER_MODE;
+	if (!vb2_dev_boot_allowed(ctx)) {
+		VB2_DEBUG("WARNING: Dev boot not allowed; forcing to-norm\n");
+		root_screen_id = VB2_SCREEN_DEVELOPER_TO_NORM;
+	}
+	return ui_loop(ctx, root_screen_id, developer_action);
 }
 
 vb2_error_t developer_action(struct vb2_ui_context *ui)
 {
 	/* Developer mode keyboard shortcuts */
+	if (ui->key == '\t')
+		return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO);
+
+	/* Ignore other shortcuts */
+	if (!vb2_dev_boot_allowed(ui->ctx))
+		return VB2_REQUEST_UI_CONTINUE;
+
 	if (ui->key == VB_KEY_CTRL('S'))
 		return vb2_ui_screen_change(ui, VB2_SCREEN_DEVELOPER_TO_NORM);
 	if (ui->key == VB_KEY_CTRL('U') ||
@@ -422,12 +446,10 @@
 	if (ui->key == VB_KEY_CTRL('D') ||
 	    (DETACHABLE && ui->key == VB_BUTTON_VOL_DOWN_LONG_PRESS))
 		return vb2_ui_developer_mode_boot_internal_action(ui);
-	if (ui->key == VB_KEY_CTRL('L'))
-		return vb2_ui_developer_mode_boot_alternate_action(ui);
-	if (ui->key == '\t')
-		return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO);
+	if (ui->key == VB_KEY_CTRL('L'))  /* L for aLtfw (formerly Legacy) */
+		return vb2_ui_developer_mode_boot_altfw_action(ui);
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /*****************************************************************************/
@@ -444,7 +466,7 @@
 	if (ui->key == '\t')
 		return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO);
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /*****************************************************************************/
@@ -460,7 +482,7 @@
 	/* See if we have a recovery kernel available yet. */
 	vb2_error_t rv = VbTryLoadKernel(ui->ctx, VB_DISK_FLAG_REMOVABLE);
 	if (rv == VB2_SUCCESS)
-		return rv;
+		return VB2_REQUEST_UI_EXIT;
 
 	/* If disk validity state changed, switch to appropriate screen. */
 	if (ui->recovery_rv != rv) {
@@ -481,7 +503,7 @@
 	if (ui->key == '\t')
 		return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO);
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /*****************************************************************************/
diff --git a/firmware/2lib/2ui_screens.c b/firmware/2lib/2ui_screens.c
index 4aeeda1..a9359b5 100644
--- a/firmware/2lib/2ui_screens.c
+++ b/firmware/2lib/2ui_screens.c
@@ -53,6 +53,32 @@
 
 /******************************************************************************/
 /*
+ * Functions for ui error handling
+ */
+
+static vb2_error_t set_ui_error(struct vb2_ui_context *ui,
+				enum vb2_ui_error error_code)
+{
+	/* Keep the first occurring error. */
+	if (ui->error_code)
+		VB2_DEBUG("When handling ui error %#x, another ui error "
+			  "occurred: %#x",
+			  ui->error_code, error_code);
+	else
+		ui->error_code = error_code;
+	/* Return to the ui loop to show the error code. */
+	return VB2_REQUEST_UI_CONTINUE;
+}
+
+static vb2_error_t set_ui_error_and_go_back(struct vb2_ui_context *ui,
+					    enum vb2_ui_error error_code)
+{
+	set_ui_error(ui, error_code);
+	return vb2_ui_screen_back(ui);
+}
+
+/******************************************************************************/
+/*
  * Functions used for log screens
  *
  * Expects that the page_count is valid and page_up_item and page_down_item are
@@ -60,73 +86,83 @@
  * current_page is valid in prev and next actions, and the back_item is assigned
  * to a correct menu item index.
  */
-/* TODO(b/174127808): Split out enabling/disabling buttons. */
 
-static vb2_error_t log_page_init(struct vb2_ui_context *ui)
+static vb2_error_t log_page_update(struct vb2_ui_context *ui,
+				   const char *new_log_string)
+{
+	const struct vb2_screen_info *screen = ui->state->screen;
+
+	if (new_log_string) {
+		ui->state->page_count = vb2ex_prepare_log_screen(
+			screen->id, ui->locale_id, new_log_string);
+		if (ui->state->page_count == 0) {
+			VB2_DEBUG("vb2ex_prepare_log_screen failed");
+			return VB2_ERROR_UI_LOG_INIT;
+		}
+		if (ui->state->current_page >= ui->state->page_count)
+			ui->state->current_page = ui->state->page_count - 1;
+		ui->force_display = 1;
+	}
+	VB2_CLR_BIT(ui->state->disabled_item_mask, screen->page_up_item);
+	VB2_CLR_BIT(ui->state->disabled_item_mask, screen->page_down_item);
+	if (ui->state->current_page == 0)
+		VB2_SET_BIT(ui->state->disabled_item_mask,
+			    screen->page_up_item);
+	if (ui->state->current_page == ui->state->page_count - 1)
+		VB2_SET_BIT(ui->state->disabled_item_mask,
+			    screen->page_down_item);
+
+	return VB2_SUCCESS;
+}
+
+static vb2_error_t log_page_reset_to_top(struct vb2_ui_context *ui)
 {
 	const struct vb2_screen_info *screen = ui->state->screen;
 
 	ui->state->current_page = 0;
+	ui->state->selected_item = ui->state->page_count > 1
+					   ? screen->page_down_item
+					   : screen->back_item;
+	return log_page_update(ui, NULL);
+}
 
-	if (ui->state->page_count == 1) {
-		VB2_SET_BIT(ui->state->disabled_item_mask,
-			    screen->page_up_item);
-		VB2_SET_BIT(ui->state->disabled_item_mask,
-			    screen->page_down_item);
-		ui->state->selected_item = screen->back_item;
+static vb2_error_t log_page_show_back_or_cancel(struct vb2_ui_context *ui,
+						int is_show_cancel)
+{
+	int back_item = ui->state->screen->back_item;
+	int cancel_item = ui->state->screen->cancel_item;
+	VB2_CLR_BIT(ui->state->hidden_item_mask, back_item);
+	VB2_CLR_BIT(ui->state->hidden_item_mask, cancel_item);
+	if (is_show_cancel) {
+		VB2_SET_BIT(ui->state->hidden_item_mask, back_item);
+		if (ui->state->selected_item == back_item)
+			ui->state->selected_item = cancel_item;
 	} else {
-		VB2_SET_BIT(ui->state->disabled_item_mask,
-			    screen->page_up_item);
-		ui->state->selected_item = screen->page_down_item;
+		VB2_SET_BIT(ui->state->hidden_item_mask, cancel_item);
+		if (ui->state->selected_item == cancel_item)
+			ui->state->selected_item = back_item;
 	}
-
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t log_page_prev_action(struct vb2_ui_context *ui)
 {
-	const struct vb2_screen_info *screen = ui->state->screen;
-
 	/* Validity check. */
 	if (ui->state->current_page == 0)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	ui->state->current_page--;
-
-	/* Clear bits of page down. */
-	if (ui->state->current_page != ui->state->page_count - 1)
-		VB2_CLR_BIT(ui->state->disabled_item_mask,
-			    screen->page_down_item);
-
-	/* Disable page up at the first page. */
-	if (ui->state->current_page == 0)
-		VB2_SET_BIT(ui->state->disabled_item_mask,
-			    screen->page_up_item);
-
-	return VB2_REQUEST_UI_CONTINUE;
+	return log_page_update(ui, NULL);
 }
 
 static vb2_error_t log_page_next_action(struct vb2_ui_context *ui)
 {
-	const struct vb2_screen_info *screen = ui->state->screen;
-
 	/* Validity check. */
 	if (ui->state->current_page == ui->state->page_count - 1)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	ui->state->current_page++;
-
-	/* Clear bits of page up. */
-	if (ui->state->current_page != 0)
-		VB2_CLR_BIT(ui->state->disabled_item_mask,
-			    screen->page_up_item);
-
-	/* Disable page down at the last page. */
-	if (ui->state->current_page == ui->state->page_count - 1)
-		VB2_SET_BIT(ui->state->disabled_item_mask,
-			    screen->page_down_item);
-
-	return VB2_REQUEST_UI_CONTINUE;
+	return log_page_update(ui, NULL);
 }
 
 #define PAGE_UP_ITEM ((struct vb2_menu_item){ \
@@ -140,14 +176,6 @@
 })
 
 /******************************************************************************/
-/* VB2_SCREEN_BLANK */
-
-static const struct vb2_screen_info blank_screen = {
-	.id = VB2_SCREEN_BLANK,
-	.name = "Blank",
-};
-
-/******************************************************************************/
 /* VB2_SCREEN_LANGUAGE_SELECT */
 
 static vb2_error_t language_select_action(struct vb2_ui_context *ui)
@@ -214,7 +242,7 @@
 			  "initializing selected_item to 0\n");
 		ui->state->selected_item = 0;
 	}
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 static const struct vb2_screen_info language_select_screen = {
@@ -255,7 +283,7 @@
 		ui->state->selected_item = ADVANCED_OPTIONS_ITEM_DEBUG_INFO;
 	}
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 static const struct vb2_menu_item advanced_options_items[] = {
@@ -290,42 +318,27 @@
 #define DEBUG_INFO_ITEM_PAGE_DOWN 2
 #define DEBUG_INFO_ITEM_BACK 3
 
-static vb2_error_t debug_info_init(struct vb2_ui_context *ui)
+static vb2_error_t debug_info_set_content(struct vb2_ui_context *ui)
 {
 	const char *log_string = vb2ex_get_debug_info(ui->ctx);
-	if (!log_string) {
-		VB2_DEBUG("ERROR: Failed to retrieve debug info\n");
-		ui->error_code = VB2_UI_ERROR_DEBUG_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-	ui->state->page_count = vb2ex_prepare_log_screen(
-		ui->state->screen->id, ui->locale_id, log_string);
-	if (ui->state->page_count == 0) {
-		VB2_DEBUG("ERROR: Failed to prepare debug info screen\n");
-		ui->error_code = VB2_UI_ERROR_DEBUG_LOG;
-		return vb2_ui_screen_back(ui);
-	}
+	if (!log_string)
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DEBUG_LOG);
+	if (vb2_is_error(log_page_update(ui, log_string)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DEBUG_LOG);
+	return VB2_SUCCESS;
+}
 
-	return log_page_init(ui);
+static vb2_error_t debug_info_init(struct vb2_ui_context *ui)
+{
+	VB2_TRY(debug_info_set_content(ui));
+	if (vb2_is_error(log_page_reset_to_top(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DEBUG_LOG);
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t debug_info_reinit(struct vb2_ui_context *ui)
 {
-	const char *log_string = vb2ex_get_debug_info(ui->ctx);
-	if (!log_string) {
-		VB2_DEBUG("ERROR: Failed to retrieve debug info\n");
-		ui->error_code = VB2_UI_ERROR_DEBUG_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-	ui->state->page_count = vb2ex_prepare_log_screen(
-		ui->state->screen->id, ui->locale_id, log_string);
-	if (ui->state->page_count == 0) {
-		VB2_DEBUG("ERROR: Failed to prepare debug info screen\n");
-		ui->error_code = VB2_UI_ERROR_DEBUG_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-
-	return VB2_REQUEST_UI_CONTINUE;
+	return debug_info_set_content(ui);
 }
 
 static const struct vb2_menu_item debug_info_items[] = {
@@ -354,42 +367,28 @@
 #define FIRMWARE_LOG_ITEM_PAGE_DOWN 2
 #define FIRMWARE_LOG_ITEM_BACK 3
 
+static vb2_error_t firmware_log_set_content(struct vb2_ui_context *ui,
+					    int reset)
+{
+	const char *log_string = vb2ex_get_firmware_log(reset);
+	if (!log_string)
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_FIRMWARE_LOG);
+	if (vb2_is_error(log_page_update(ui, log_string)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_FIRMWARE_LOG);
+	return VB2_SUCCESS;
+}
+
 static vb2_error_t firmware_log_init(struct vb2_ui_context *ui)
 {
-	const char *log_string = vb2ex_get_firmware_log(1);
-	if (!log_string) {
-		VB2_DEBUG("ERROR: Failed to retrieve firmware log\n");
-		ui->error_code = VB2_UI_ERROR_FIRMWARE_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-	ui->state->page_count = vb2ex_prepare_log_screen(
-		ui->state->screen->id, ui->locale_id, log_string);
-	if (ui->state->page_count == 0) {
-		VB2_DEBUG("ERROR: Failed to prepare firmware log screen\n");
-		ui->error_code = VB2_UI_ERROR_FIRMWARE_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-
-	return log_page_init(ui);
+	VB2_TRY(firmware_log_set_content(ui, 1));
+	if (vb2_is_error(log_page_reset_to_top(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_FIRMWARE_LOG);
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t firmware_log_reinit(struct vb2_ui_context *ui)
 {
-	const char *log_string = vb2ex_get_firmware_log(0);
-	if (!log_string) {
-		VB2_DEBUG("ERROR: Failed to retrieve firmware log\n");
-		ui->error_code = VB2_UI_ERROR_FIRMWARE_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-	ui->state->page_count = vb2ex_prepare_log_screen(
-		ui->state->screen->id, ui->locale_id, log_string);
-	if (ui->state->page_count == 0) {
-		VB2_DEBUG("ERROR: Failed to prepare firmware log screen\n");
-		ui->error_code = VB2_UI_ERROR_FIRMWARE_LOG;
-		return vb2_ui_screen_back(ui);
-	}
-
-	return VB2_REQUEST_UI_CONTINUE;
+	return firmware_log_set_content(ui, 0);
 }
 
 static const struct vb2_menu_item firmware_log_items[] = {
@@ -440,7 +439,7 @@
 		VB2_SET_BIT(ui->state->hidden_item_mask,
 			    RECOVERY_SELECT_ITEM_DIAGNOSTICS);
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 static const struct vb2_menu_item recovery_select_items[] = {
@@ -490,11 +489,10 @@
 
 vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui)
 {
-	if (vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED) {
+	if (vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED)
 		/* We're in dev mode, so let user know they can't transition */
-		ui->error_code = VB2_UI_ERROR_DEV_MODE_ALREADY_ENABLED;
-		return vb2_ui_screen_back(ui);
-	}
+		return set_ui_error_and_go_back(
+			ui, VB2_UI_ERROR_DEV_MODE_ALREADY_ENABLED);
 
 	if (!PHYSICAL_PRESENCE_KEYBOARD && vb2ex_physical_presence_pressed()) {
 		VB2_DEBUG("Presence button stuck?\n");
@@ -512,7 +510,7 @@
 
 	ui->physical_presence_button_pressed = 0;
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t recovery_to_dev_finalize(struct vb2_ui_context *ui)
@@ -524,7 +522,7 @@
 	    (vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED) ||
 	    !vb2_allow_recovery(ui->ctx)) {
 		VB2_DEBUG("ERROR: Dev transition validity check failed\n");
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 	}
 
 	VB2_DEBUG("Enabling dev mode and rebooting...\n");
@@ -543,8 +541,9 @@
 		 * from an untrusted keyboard.
 		 */
 		if (PHYSICAL_PRESENCE_KEYBOARD && ui->key == VB_KEY_ENTER)
-			ui->error_code = VB2_UI_ERROR_UNTRUSTED_CONFIRMATION;
-		return VB2_REQUEST_UI_CONTINUE;
+			return set_ui_error(
+				ui, VB2_UI_ERROR_UNTRUSTED_CONFIRMATION);
+		return VB2_SUCCESS;
 	}
 	return recovery_to_dev_finalize(ui);
 }
@@ -560,17 +559,17 @@
 
 	/* Keyboard physical presence case covered by "Confirm" action. */
 	if (PHYSICAL_PRESENCE_KEYBOARD)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	pressed = vb2ex_physical_presence_pressed();
 	if (pressed) {
 		VB2_DEBUG("Physical presence button pressed, "
 			  "awaiting release\n");
 		ui->physical_presence_button_pressed = 1;
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 	}
 	if (!ui->physical_presence_button_pressed)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 	VB2_DEBUG("Physical presence button released\n");
 
 	return recovery_to_dev_finalize(ui);
@@ -681,17 +680,13 @@
 #define DEVELOPER_MODE_ITEM_RETURN_TO_SECURE 1
 #define DEVELOPER_MODE_ITEM_BOOT_INTERNAL 2
 #define DEVELOPER_MODE_ITEM_BOOT_EXTERNAL 3
-#define DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER 4
+#define DEVELOPER_MODE_ITEM_SELECT_ALTFW 4
 
 vb2_error_t developer_mode_init(struct vb2_ui_context *ui)
 {
 	enum vb2_dev_default_boot_target default_boot =
 		vb2api_get_dev_default_boot_target(ui->ctx);
 
-	/* TODO(b/159579189): Split this case into a separate root screen */
-	if (!vb2_dev_boot_allowed(ui->ctx))
-		vb2_ui_screen_change(ui, VB2_SCREEN_DEVELOPER_TO_NORM);
-
 	/* Don't show "Return to secure mode" button if GBB forces dev mode. */
 	if (vb2_get_gbb(ui->ctx)->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON)
 		VB2_SET_BIT(ui->state->hidden_item_mask,
@@ -703,18 +698,18 @@
 			    DEVELOPER_MODE_ITEM_BOOT_EXTERNAL);
 
 	/* Don't show "Select alternate bootloader" button if not allowed. */
-	if (!vb2_dev_boot_legacy_allowed(ui->ctx))
+	if (!vb2_dev_boot_altfw_allowed(ui->ctx))
 		VB2_SET_BIT(ui->state->hidden_item_mask,
-			    DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER);
+			    DEVELOPER_MODE_ITEM_SELECT_ALTFW);
 
 	/* Choose the default selection. */
 	switch (default_boot) {
 	case VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL:
 		ui->state->selected_item = DEVELOPER_MODE_ITEM_BOOT_EXTERNAL;
 		break;
-	case VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY:
+	case VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW:
 		ui->state->selected_item =
-			DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER;
+			DEVELOPER_MODE_ITEM_SELECT_ALTFW;
 		break;
 	default:
 		ui->state->selected_item = DEVELOPER_MODE_ITEM_BOOT_INTERNAL;
@@ -723,7 +718,7 @@
 
 	ui->start_time_ms = vb2ex_mtime();
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 vb2_error_t vb2_ui_developer_mode_boot_internal_action(
@@ -732,11 +727,11 @@
 	if (!(ui->ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ||
 	    !vb2_dev_boot_allowed(ui->ctx)) {
 		VB2_DEBUG("ERROR: Dev mode internal boot not allowed\n");
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 	}
 
 	VB2_TRY(VbTryLoadKernel(ui->ctx, VB_DISK_FLAG_FIXED));
-	return VB2_SUCCESS;
+	return VB2_REQUEST_UI_EXIT;
 }
 
 vb2_error_t vb2_ui_developer_mode_boot_external_action(
@@ -750,13 +745,12 @@
 	    !vb2_dev_boot_external_allowed(ui->ctx)) {
 		VB2_DEBUG("ERROR: Dev mode external boot not allowed\n");
 		ui->error_beep = 1;
-		ui->error_code = VB2_UI_ERROR_EXTERNAL_BOOT_NOT_ENABLED;
-		return VB2_REQUEST_UI_CONTINUE;
+		return set_ui_error(ui, VB2_UI_ERROR_EXTERNAL_BOOT_DISABLED);
 	}
 
 	rv = VbTryLoadKernel(ui->ctx, VB_DISK_FLAG_REMOVABLE);
 	if (rv == VB2_SUCCESS) {
-		return VB2_SUCCESS;
+		return VB2_REQUEST_UI_EXIT;
 	} else if (rv == VB2_ERROR_LK_NO_DISK_FOUND) {
 		if (ui->state->screen->id !=
 		    VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL) {
@@ -781,15 +775,11 @@
 	const int use_short = vb2api_use_short_dev_screen_delay(ui->ctx);
 	uint64_t elapsed_ms;
 
-	/* TODO(b/159579189): Split this case into a separate root screen */
-	if (!vb2_dev_boot_allowed(ui->ctx))
-		vb2_ui_screen_change(ui, VB2_SCREEN_DEVELOPER_TO_NORM);
-
 	/* Once any user interaction occurs, stop the timer. */
 	if (ui->key)
 		ui->disable_timer = 1;
 	if (ui->disable_timer)
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 
 	elapsed_ms = vb2ex_mtime() - ui->start_time_ms;
 
@@ -814,7 +804,7 @@
 		return vb2_ui_menu_select(ui);
 	}
 
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 static const struct vb2_menu_item developer_mode_items[] = {
@@ -831,9 +821,9 @@
 		.text = "Boot from external disk",
 		.action = vb2_ui_developer_mode_boot_external_action,
 	},
-	[DEVELOPER_MODE_ITEM_SELECT_BOOTLOADER] = {
+	[DEVELOPER_MODE_ITEM_SELECT_ALTFW] = {
 		.text = "Select alternate bootloader",
-		.target = VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER,
+		.target = VB2_SCREEN_DEVELOPER_SELECT_ALTFW,
 	},
 	ADVANCED_OPTIONS_ITEM,
 	POWER_OFF_ITEM,
@@ -851,24 +841,29 @@
 /* VB2_SCREEN_DEVELOPER_TO_NORM */
 
 #define DEVELOPER_TO_NORM_ITEM_CONFIRM 1
+#define DEVELOPER_TO_NORM_ITEM_CANCEL 2
 
 static vb2_error_t developer_to_norm_init(struct vb2_ui_context *ui)
 {
 	/* Don't allow to-norm if GBB forces dev mode */
 	if (vb2_get_gbb(ui->ctx)->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) {
 		VB2_DEBUG("ERROR: to-norm not allowed\n");
-		ui->error_code = VB2_UI_ERROR_TO_NORM_NOT_ALLOWED;
-		return vb2_ui_screen_back(ui);
+		return set_ui_error_and_go_back(
+			ui, VB2_UI_ERROR_TO_NORM_NOT_ALLOWED);
 	}
 	ui->state->selected_item = DEVELOPER_TO_NORM_ITEM_CONFIRM;
-	return VB2_REQUEST_UI_CONTINUE;
+	/* Hide "Cancel" button if dev boot is not allowed */
+	if (!vb2_dev_boot_allowed(ui->ctx))
+		VB2_SET_BIT(ui->state->hidden_item_mask,
+			    DEVELOPER_TO_NORM_ITEM_CANCEL);
+	return VB2_SUCCESS;
 }
 
 vb2_error_t developer_to_norm_action(struct vb2_ui_context *ui)
 {
 	if (vb2_get_gbb(ui->ctx)->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) {
 		VB2_DEBUG("ERROR: dev mode forced by GBB flag\n");
-		return VB2_REQUEST_UI_CONTINUE;
+		return VB2_SUCCESS;
 	}
 
 	VB2_DEBUG("Leaving dev mode\n");
@@ -878,11 +873,11 @@
 
 static const struct vb2_menu_item developer_to_norm_items[] = {
 	LANGUAGE_SELECT_ITEM,
-	{
+	[DEVELOPER_TO_NORM_ITEM_CONFIRM] = {
 		.text = "Confirm",
 		.action = developer_to_norm_action,
 	},
-	{
+	[DEVELOPER_TO_NORM_ITEM_CANCEL] = {
 		.text = "Cancel",
 		.action = vb2_ui_screen_back,
 	},
@@ -929,7 +924,7 @@
 };
 
 /******************************************************************************/
-/* VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER */
+/* VB2_SCREEN_DEVELOPER_SELECT_ALTFW */
 
 static const struct vb2_menu_item developer_select_bootloader_items_before[] = {
 	LANGUAGE_SELECT_ITEM,
@@ -942,51 +937,46 @@
 
 static vb2_error_t developer_select_bootloader_init(struct vb2_ui_context *ui)
 {
-	if (get_menu(ui)->num_items == 0) {
-		ui->error_code = VB2_UI_ERROR_NO_BOOTLOADER;
-		return vb2_ui_screen_back(ui);
-	}
+	if (get_menu(ui)->num_items == 0)
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_ALTFW_EMPTY);
 	/* Select the first bootloader. */
 	ui->state->selected_item =
 		ARRAY_SIZE(developer_select_bootloader_items_before);
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
-vb2_error_t vb2_ui_developer_mode_boot_alternate_action(
+vb2_error_t vb2_ui_developer_mode_boot_altfw_action(
 	struct vb2_ui_context *ui)
 {
-	uint32_t altfw_num;
+	uint32_t altfw_id;
 	const size_t menu_before_len =
 		ARRAY_SIZE(developer_select_bootloader_items_before);
 
 	if (!(ui->ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ||
 	    !vb2_dev_boot_allowed(ui->ctx) ||
-	    !vb2_dev_boot_legacy_allowed(ui->ctx)) {
+	    !vb2_dev_boot_altfw_allowed(ui->ctx)) {
 		VB2_DEBUG("ERROR: Dev mode alternate bootloader not allowed\n");
-		ui->error_code = VB2_UI_ERROR_ALTERNATE_BOOT_DISABLED;
-		return VB2_REQUEST_UI_CONTINUE;
+		return set_ui_error(ui, VB2_UI_ERROR_ALTFW_DISABLED);
 	}
 
-	if (vb2ex_get_bootloader_count() == 0) {
+	if (vb2ex_get_altfw_count() == 0) {
 		VB2_DEBUG("ERROR: No alternate bootloader was found\n");
-		ui->error_code = VB2_UI_ERROR_NO_BOOTLOADER;
-		return VB2_REQUEST_UI_CONTINUE;
+		return set_ui_error(ui, VB2_UI_ERROR_ALTFW_EMPTY);
 	}
 
 	if (ui->key == VB_KEY_CTRL('L')) {
-		altfw_num = 0;
+		altfw_id = 0;
 		VB2_DEBUG("Try booting from default bootloader\n");
 	} else {
-		altfw_num = ui->state->selected_item - menu_before_len + 1;
-		VB2_DEBUG("Try booting from bootloader #%u\n", altfw_num);
+		altfw_id = ui->state->selected_item - menu_before_len + 1;
+		VB2_DEBUG("Try booting from bootloader #%u\n", altfw_id);
 	}
 
-	/* VbExLegacy will not return if successful */
-	VbExLegacy(altfw_num);
+	/* vb2ex_run_altfw will not return if successful */
+	vb2ex_run_altfw(altfw_id);
 
 	VB2_DEBUG("ERROR: Alternate bootloader failed\n");
-	ui->error_code = VB2_UI_ERROR_ALTERNATE_BOOT_FAILED;
-	return VB2_REQUEST_UI_CONTINUE;
+	return set_ui_error(ui, VB2_UI_ERROR_ALTFW_FAILED);
 }
 
 static const struct vb2_menu *get_bootloader_menu(struct vb2_ui_context *ui)
@@ -1002,7 +992,7 @@
 	if (ui->bootloader_menu.num_items > 0)
 		return &ui->bootloader_menu;
 
-	num_bootloaders = vb2ex_get_bootloader_count();
+	num_bootloaders = vb2ex_get_altfw_count();
 	if (num_bootloaders == 0) {
 		VB2_DEBUG("ERROR: No bootloader was found\n");
 		return NULL;
@@ -1024,7 +1014,7 @@
 	for (i = 0; i < num_bootloaders; i++) {
 		items[i + menu_before_len].text = "Some bootloader";
 		items[i + menu_before_len].action =
-			vb2_ui_developer_mode_boot_alternate_action;
+			vb2_ui_developer_mode_boot_altfw_action;
 	}
 
 	/* Copy postfix items to the end. */
@@ -1039,7 +1029,7 @@
 }
 
 static const struct vb2_screen_info developer_select_bootloader_screen = {
-	.id = VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER,
+	.id = VB2_SCREEN_DEVELOPER_SELECT_ALTFW,
 	.name = "Select alternate bootloader",
 	.init = developer_select_bootloader_init,
 	.get_menu = get_bootloader_menu,
@@ -1048,18 +1038,44 @@
 /******************************************************************************/
 /* VB2_SCREEN_DIAGNOSTICS */
 
+#define DIAGNOSTICS_ITEM_STORAGE_HEALTH 1
+#define DIAGNOSTICS_ITEM_STORAGE_TEST_SHORT 2
+#define DIAGNOSTICS_ITEM_STORAGE_TEST_EXTENDED 3
+
+static vb2_error_t diagnostics_init(struct vb2_ui_context *ui)
+{
+	const char *unused_log_string;
+	vb2_error_t rv = vb2ex_diag_get_storage_test_log(&unused_log_string);
+	if (rv == VB2_ERROR_EX_UNIMPLEMENTED) {
+		VB2_SET_BIT(ui->state->disabled_item_mask,
+			    DIAGNOSTICS_ITEM_STORAGE_TEST_SHORT);
+		VB2_SET_BIT(ui->state->disabled_item_mask,
+			    DIAGNOSTICS_ITEM_STORAGE_TEST_EXTENDED);
+	}
+	ui->state->selected_item = DIAGNOSTICS_ITEM_STORAGE_HEALTH;
+	return VB2_SUCCESS;
+}
+
 static const struct vb2_menu_item diagnostics_items[] = {
 	LANGUAGE_SELECT_ITEM,
-	{
-		.text = "Storage",
-		.target = VB2_SCREEN_DIAGNOSTICS_STORAGE,
+	[DIAGNOSTICS_ITEM_STORAGE_HEALTH] = {
+		.text = "Storage health info",
+		.target = VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH,
+	},
+	[DIAGNOSTICS_ITEM_STORAGE_TEST_SHORT] = {
+		.text = "Storage self-test (short)",
+		.target = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT,
+	},
+	[DIAGNOSTICS_ITEM_STORAGE_TEST_EXTENDED] = {
+		.text = "Storage self-test (Extended)",
+		.target = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED,
 	},
 	{
-		.text = "Quick memory check",
+		.text = "Memory check (quick)",
 		.target = VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK,
 	},
 	{
-		.text = "Full memory check",
+		.text = "Memory check (full)",
 		.target = VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL,
 	},
 	POWER_OFF_ITEM,
@@ -1068,50 +1084,167 @@
 static const struct vb2_screen_info diagnostics_screen = {
 	.id = VB2_SCREEN_DIAGNOSTICS,
 	.name = "Diagnostic tools",
+	.init = diagnostics_init,
 	.menu = MENU_ITEMS(diagnostics_items),
 };
 
 /******************************************************************************/
-/* VB2_SCREEN_DIAGNOSTICS_STORAGE */
+/* VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH */
 
-#define DIAGNOSTICS_STORAGE_ITEM_PAGE_UP 0
-#define DIAGNOSTICS_STORAGE_ITEM_PAGE_DOWN 1
-#define DIAGNOSTICS_STORAGE_ITEM_BACK 2
+#define DIAGNOSTICS_STORAGE_HEALTH_ITEM_PAGE_UP 0
+#define DIAGNOSTICS_STORAGE_HEALTH_ITEM_PAGE_DOWN 1
+#define DIAGNOSTICS_STORAGE_HEALTH_ITEM_BACK 2
 
-static vb2_error_t diagnostics_storage_init(struct vb2_ui_context *ui)
+static vb2_error_t diagnostics_storage_health_init_impl(
+	struct vb2_ui_context *ui)
 {
-	const char *log_string = vb2ex_get_diagnostic_storage();
-	if (!log_string) {
-		VB2_DEBUG("ERROR: Failed to retrieve storage log message\n");
-		ui->error_code = VB2_UI_ERROR_DIAGNOSTICS;
-		return vb2_ui_screen_back(ui);
-	}
-
-	ui->state->page_count = vb2ex_prepare_log_screen(
-		ui->state->screen->id, ui->locale_id, log_string);
-	if (ui->state->page_count == 0) {
-		VB2_DEBUG("ERROR: Failed to prepare storage log screen\n");
-		ui->error_code = VB2_UI_ERROR_DIAGNOSTICS;
-		return vb2_ui_screen_back(ui);
-	}
-	return log_page_init(ui);
+	const char *log_string;
+	VB2_TRY(vb2ex_diag_get_storage_health(&log_string));
+	VB2_TRY(log_page_update(ui, log_string));
+	return log_page_reset_to_top(ui);
 }
 
-static const struct vb2_menu_item diagnostics_storage_items[] = {
-	[DIAGNOSTICS_STORAGE_ITEM_PAGE_UP] = PAGE_UP_ITEM,
-	[DIAGNOSTICS_STORAGE_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM,
-	[DIAGNOSTICS_STORAGE_ITEM_BACK] = BACK_ITEM,
+static vb2_error_t diagnostics_storage_health_init(struct vb2_ui_context *ui)
+{
+	if (vb2_is_error(diagnostics_storage_health_init_impl(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
+}
+
+static const struct vb2_menu_item diagnostics_storage_health_items[] = {
+	[DIAGNOSTICS_STORAGE_HEALTH_ITEM_PAGE_UP] = PAGE_UP_ITEM,
+	[DIAGNOSTICS_STORAGE_HEALTH_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM,
+	[DIAGNOSTICS_STORAGE_HEALTH_ITEM_BACK] = BACK_ITEM,
 	POWER_OFF_ITEM,
 };
 
-static const struct vb2_screen_info diagnostics_storage_screen = {
-	.id = VB2_SCREEN_DIAGNOSTICS_STORAGE,
-	.name = "Storage",
-	.init = diagnostics_storage_init,
-	.menu = MENU_ITEMS(diagnostics_storage_items),
-	.page_up_item = DIAGNOSTICS_STORAGE_ITEM_PAGE_UP,
-	.page_down_item = DIAGNOSTICS_STORAGE_ITEM_PAGE_DOWN,
-	.back_item = DIAGNOSTICS_STORAGE_ITEM_BACK,
+static const struct vb2_screen_info diagnostics_storage_health_screen = {
+	.id = VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH,
+	.name = "Storage health info",
+	.init = diagnostics_storage_health_init,
+	.menu = MENU_ITEMS(diagnostics_storage_health_items),
+	.page_up_item = DIAGNOSTICS_STORAGE_HEALTH_ITEM_PAGE_UP,
+	.page_down_item = DIAGNOSTICS_STORAGE_HEALTH_ITEM_PAGE_DOWN,
+	.back_item = DIAGNOSTICS_STORAGE_HEALTH_ITEM_BACK,
+};
+
+/******************************************************************************/
+/* VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST */
+
+#define DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP 0
+#define DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN 1
+#define DIAGNOSTICS_STORAGE_TEST_ITEM_BACK 2
+#define DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL 3
+
+static vb2_error_t diagnostics_storage_test_update_impl(
+	struct vb2_ui_context *ui)
+{
+	const char *log_string;
+	int is_test_running = 0;
+
+	/* Early return if the test is done. */
+	if (ui->state->test_finished)
+		return VB2_SUCCESS;
+
+	vb2_error_t rv = vb2ex_diag_get_storage_test_log(&log_string);
+	switch (rv) {
+	case VB2_ERROR_EX_DIAG_TEST_RUNNING:
+		is_test_running = 1;
+		break;
+	case VB2_SUCCESS:
+		ui->state->test_finished = 1;
+		break;
+	default:
+		VB2_DEBUG("vb2ex_diag_get_storage_test_log returned %#x\n", rv);
+		return rv;
+	}
+	VB2_TRY(log_page_show_back_or_cancel(ui, is_test_running));
+	return log_page_update(ui, log_string);
+}
+
+static vb2_error_t diagnostics_storage_test_update(struct vb2_ui_context *ui)
+{
+	if (vb2_is_error(diagnostics_storage_test_update_impl(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
+}
+
+static vb2_error_t diagnostics_storage_test_control(
+	struct vb2_ui_context *ui, enum vb2_diag_storage_test op)
+{
+	if (vb2_is_error(vb2ex_diag_storage_test_control(op)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
+}
+
+static vb2_error_t diagnostics_storage_test_init(struct vb2_ui_context *ui)
+{
+	VB2_TRY(diagnostics_storage_test_update(ui));
+	if (vb2_is_error(log_page_reset_to_top(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
+}
+
+static vb2_error_t diagnostics_storage_test_short_init(
+	struct vb2_ui_context *ui)
+{
+	VB2_TRY(diagnostics_storage_test_control(ui,
+						 VB2_DIAG_STORAGE_TEST_STOP));
+	VB2_TRY(diagnostics_storage_test_control(ui,
+						 VB2_DIAG_STORAGE_TEST_SHORT));
+	return diagnostics_storage_test_init(ui);
+}
+
+static vb2_error_t diagnostics_storage_test_extended_init(
+	struct vb2_ui_context *ui)
+{
+	VB2_TRY(diagnostics_storage_test_control(ui,
+						 VB2_DIAG_STORAGE_TEST_STOP));
+	VB2_TRY(diagnostics_storage_test_control(
+		ui, VB2_DIAG_STORAGE_TEST_EXTENDED));
+	return diagnostics_storage_test_init(ui);
+}
+
+static vb2_error_t diagnostics_storage_test_cancel(struct vb2_ui_context *ui)
+{
+	VB2_TRY(diagnostics_storage_test_control(ui,
+						 VB2_DIAG_STORAGE_TEST_STOP));
+	return vb2_ui_screen_back(ui);
+}
+
+static const struct vb2_menu_item diagnostics_storage_test_items[] = {
+	[DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP] = PAGE_UP_ITEM,
+	[DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM,
+	[DIAGNOSTICS_STORAGE_TEST_ITEM_BACK] = BACK_ITEM,
+	[DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL] = {
+		.text = "Cancel",
+		.action = diagnostics_storage_test_cancel,
+	},
+	POWER_OFF_ITEM,
+};
+
+static const struct vb2_screen_info diagnostics_storage_test_short_screen = {
+	.id = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT,
+	.name = "Storage self-test (short)",
+	.init = diagnostics_storage_test_short_init,
+	.action = diagnostics_storage_test_update,
+	.menu = MENU_ITEMS(diagnostics_storage_test_items),
+	.page_up_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP,
+	.page_down_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN,
+	.back_item = DIAGNOSTICS_STORAGE_TEST_ITEM_BACK,
+	.cancel_item = DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL,
+};
+
+static const struct vb2_screen_info diagnostics_storage_test_extended_screen = {
+	.id = VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED,
+	.name = "Storage self-test (extended)",
+	.init = diagnostics_storage_test_extended_init,
+	.action = diagnostics_storage_test_update,
+	.menu = MENU_ITEMS(diagnostics_storage_test_items),
+	.page_up_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_UP,
+	.page_down_item = DIAGNOSTICS_STORAGE_TEST_ITEM_PAGE_DOWN,
+	.back_item = DIAGNOSTICS_STORAGE_TEST_ITEM_BACK,
+	.cancel_item = DIAGNOSTICS_STORAGE_TEST_ITEM_CANCEL,
 };
 
 /******************************************************************************/
@@ -1120,88 +1253,65 @@
 
 #define DIAGNOSTICS_MEMORY_ITEM_PAGE_UP 0
 #define DIAGNOSTICS_MEMORY_ITEM_PAGE_DOWN 1
-#define DIAGNOSTICS_MEMORY_ITEM_CANCEL 2
-#define DIAGNOSTICS_MEMORY_ITEM_BACK 3
+#define DIAGNOSTICS_MEMORY_ITEM_BACK 2
+#define DIAGNOSTICS_MEMORY_ITEM_CANCEL 3
 
 typedef vb2_error_t (*memory_test_op_t)(int reset, const char **out);
+static vb2_error_t diagnostics_memory_update_screen_impl(
+	struct vb2_ui_context *ui, memory_test_op_t op, int reset)
+{
+	const char *log_string = NULL;
+	vb2_error_t rv;
+	int is_test_running = 0;
+
+	/* Early return if the memory test is done. */
+	if (ui->state->test_finished)
+		return VB2_SUCCESS;
+
+	rv = op(reset, &log_string);
+	switch (rv) {
+	/* The test is still running but the output buffer was unchanged. */
+	case VB2_ERROR_EX_DIAG_TEST_RUNNING:
+		return VB2_SUCCESS;
+	case VB2_ERROR_EX_DIAG_TEST_UPDATED:
+		is_test_running = 1;
+		break;
+	case VB2_SUCCESS:
+		ui->state->test_finished = 1;
+		break;
+	default:
+		VB2_DEBUG("memory_test_op returned %#x\n", rv);
+		return rv;
+	}
+	VB2_TRY(log_page_show_back_or_cancel(ui, is_test_running));
+	return log_page_update(ui, log_string);
+}
+
 static vb2_error_t diagnostics_memory_update_screen(struct vb2_ui_context *ui,
 						    memory_test_op_t op,
 						    int reset)
 {
-	const char *log_string = NULL;
-
-	/* Early return if the memory test is done. */
-	if (ui->state->test_finished)
-		return VB2_REQUEST_UI_CONTINUE;
-
-	vb2_error_t rv = op(reset, &log_string);
-
-	/* The test is still running but the output buffer was unchanged. */
-	if (rv == VB2_ERROR_EX_DIAG_TEST_RUNNING)
-		return VB2_REQUEST_UI_CONTINUE;
-
-	if ((rv && rv != VB2_ERROR_EX_DIAG_TEST_UPDATED) || !log_string) {
-		VB2_DEBUG("ERROR: Failed to retrieve memory test status\n");
-		ui->error_code = VB2_UI_ERROR_DIAGNOSTICS;
-		return vb2_ui_screen_back(ui);
-	}
-
-	ui->state->page_count = vb2ex_prepare_log_screen(
-		ui->state->screen->id, ui->locale_id, log_string);
-	if (ui->state->page_count == 0) {
-		VB2_DEBUG("ERROR: Failed to prepare memory log screen, error: "
-			  "%#x\n", rv);
-		ui->error_code = VB2_UI_ERROR_DIAGNOSTICS;
-		return vb2_ui_screen_back(ui);
-	}
-	/* TODO(b/174127808): Integrate this into a new log_page_* function. */
-	if (ui->state->current_page >= ui->state->page_count)
-		ui->state->current_page = ui->state->page_count - 1;
-
-	ui->force_display = 1;
-
-	/* Show cancel button when the test is running, otherwise show the back
-	 * button. VB2_SUCCESS indicates the test is finished. */
-	VB2_CLR_BIT(ui->state->hidden_item_mask,
-		    DIAGNOSTICS_MEMORY_ITEM_CANCEL);
-	VB2_CLR_BIT(ui->state->hidden_item_mask, DIAGNOSTICS_MEMORY_ITEM_BACK);
-	if (rv == VB2_ERROR_EX_DIAG_TEST_UPDATED) {
-		VB2_SET_BIT(ui->state->hidden_item_mask,
-			    DIAGNOSTICS_MEMORY_ITEM_BACK);
-		if (ui->state->selected_item == DIAGNOSTICS_MEMORY_ITEM_BACK)
-			ui->state->selected_item =
-				DIAGNOSTICS_MEMORY_ITEM_CANCEL;
-	} else {
-		VB2_SET_BIT(ui->state->hidden_item_mask,
-			    DIAGNOSTICS_MEMORY_ITEM_CANCEL);
-		if (ui->state->selected_item == DIAGNOSTICS_MEMORY_ITEM_CANCEL)
-			ui->state->selected_item = DIAGNOSTICS_MEMORY_ITEM_BACK;
-		ui->state->test_finished = 1;
-	}
-
-	return VB2_REQUEST_UI_CONTINUE;
+	if (vb2_is_error(diagnostics_memory_update_screen_impl(ui, op, reset)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t diagnostics_memory_init_quick(struct vb2_ui_context *ui)
 {
-	vb2_error_t rv;
-	rv = diagnostics_memory_update_screen(
-		ui, &vb2ex_diag_memory_quick_test, 1);
-
-	if (rv != VB2_REQUEST_UI_CONTINUE)
-		return rv;
-	return log_page_init(ui);
+	VB2_TRY(diagnostics_memory_update_screen(
+		ui, &vb2ex_diag_memory_quick_test, 1));
+	if (vb2_is_error(log_page_reset_to_top(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t diagnostics_memory_init_full(struct vb2_ui_context *ui)
 {
-	vb2_error_t rv;
-	rv = diagnostics_memory_update_screen(
-		ui, &vb2ex_diag_memory_full_test, 1);
-
-	if (rv != VB2_REQUEST_UI_CONTINUE)
-		return rv;
-	return log_page_init(ui);
+	VB2_TRY(diagnostics_memory_update_screen(
+		ui, &vb2ex_diag_memory_full_test, 1));
+	if (vb2_is_error(log_page_reset_to_top(ui)))
+		return set_ui_error_and_go_back(ui, VB2_UI_ERROR_DIAGNOSTICS);
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t diagnostics_memory_update_quick(struct vb2_ui_context *ui)
@@ -1219,34 +1329,36 @@
 static const struct vb2_menu_item diagnostics_memory_items[] = {
 	[DIAGNOSTICS_MEMORY_ITEM_PAGE_UP] = PAGE_UP_ITEM,
 	[DIAGNOSTICS_MEMORY_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM,
+	[DIAGNOSTICS_MEMORY_ITEM_BACK] = BACK_ITEM,
 	[DIAGNOSTICS_MEMORY_ITEM_CANCEL] = {
-		.text = "Cancel and go back",
+		.text = "Cancel",
 		.action = vb2_ui_screen_back,
 	},
-	[DIAGNOSTICS_MEMORY_ITEM_BACK] = BACK_ITEM,
 	POWER_OFF_ITEM,
 };
 
 static const struct vb2_screen_info diagnostics_memory_quick_screen = {
 	.id = VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK,
-	.name = "Quick memory check",
+	.name = "Memory check (quick)",
 	.init = diagnostics_memory_init_quick,
 	.action = diagnostics_memory_update_quick,
 	.menu = MENU_ITEMS(diagnostics_memory_items),
 	.page_up_item = DIAGNOSTICS_MEMORY_ITEM_PAGE_UP,
 	.page_down_item = DIAGNOSTICS_MEMORY_ITEM_PAGE_DOWN,
-	.back_item = DIAGNOSTICS_MEMORY_ITEM_CANCEL,
+	.back_item = DIAGNOSTICS_MEMORY_ITEM_BACK,
+	.cancel_item = DIAGNOSTICS_MEMORY_ITEM_CANCEL,
 };
 
 static const struct vb2_screen_info diagnostics_memory_full_screen = {
 	.id = VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL,
-	.name = "Full memory check",
+	.name = "Memory check (full)",
 	.init = diagnostics_memory_init_full,
 	.action = diagnostics_memory_update_full,
 	.menu = MENU_ITEMS(diagnostics_memory_items),
 	.page_up_item = DIAGNOSTICS_MEMORY_ITEM_PAGE_UP,
 	.page_down_item = DIAGNOSTICS_MEMORY_ITEM_PAGE_DOWN,
-	.back_item = DIAGNOSTICS_MEMORY_ITEM_CANCEL,
+	.back_item = DIAGNOSTICS_MEMORY_ITEM_BACK,
+	.cancel_item = DIAGNOSTICS_MEMORY_ITEM_CANCEL,
 };
 
 /******************************************************************************/
@@ -1258,7 +1370,6 @@
  * screen, based on the menu information passed from vboot.
  */
 static const struct vb2_screen_info *screens[] = {
-	&blank_screen,
 	&language_select_screen,
 	&recovery_broken_screen,
 	&advanced_options_screen,
@@ -1278,7 +1389,9 @@
 	&developer_invalid_disk_screen,
 	&developer_select_bootloader_screen,
 	&diagnostics_screen,
-	&diagnostics_storage_screen,
+	&diagnostics_storage_health_screen,
+	&diagnostics_storage_test_short_screen,
+	&diagnostics_storage_test_extended_screen,
 	&diagnostics_memory_quick_screen,
 	&diagnostics_memory_full_screen,
 };
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 94f0df5..fb656da 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -64,6 +64,17 @@
  */
 #define VB2_TRY(expr, ...) _VB2_TRY_IMPL(expr, ##__VA_ARGS__, NULL, 0)
 
+/**
+ * Check if the return value is an error.
+ *
+ * @param rv	The return value.
+ * @return True if the value is an error.
+ */
+static inline int vb2_is_error(vb2_error_t rv)
+{
+	return rv >= VB2_ERROR_BASE && rv <= VB2_ERROR_MAX;
+}
+
 /* Flags for vb2_context.
  *
  * Unless otherwise noted, flags are set by verified boot and may be read (but
@@ -222,6 +233,13 @@
 	 * NO_BOOT means the OS is not allowed to boot. Only relevant for EFS2.
 	 */
 	VB2_CONTEXT_NO_BOOT = (1 << 23),
+
+	/*
+	 * TRUSTED means EC is running an RO copy and PD isn't enabled. At
+	 * least that was last known to the GSC. If EC RO is correctly behaving,
+	 * it doesn't jump to RW when this flag is set.
+	 */
+	VB2_CONTEXT_EC_TRUSTED = (1 << 24),
 };
 
 /* Helper for aligning fields in vb2_context. */
@@ -567,6 +585,15 @@
 uint32_t vb2api_secdata_kernel_create_v0(struct vb2_context *ctx);
 
 /**
+ * Create an empty Firmware Management Parameters (FWMP) in secure storage
+ * context.
+ *
+ * @param ctx		Context pointer
+ * @return size of created FWMP secure storage data in bytes
+ */
+uint32_t vb2api_secdata_fwmp_create(struct vb2_context *ctx);
+
+/**
  * Check the validity of firmware management parameters (FWMP) space.
  *
  * Checks size, version, and CRC.  If the struct size is larger than the size
@@ -875,8 +902,8 @@
 	/* Default to boot from external disk. */
 	VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL = 1,
 
-	/* Default to boot legacy OS. */
-	VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY = 2,
+	/* Default to boot altfw. */
+	VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW = 2,
 };
 
 /**
@@ -1005,7 +1032,7 @@
  * caller may not get a chance to commit this data.
  *
  * @param ctx		Vboot context
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2ex_commit_data(struct vb2_context *ctx);
 
@@ -1015,7 +1042,7 @@
 /**
  * Initialize the TPM.
  *
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2ex_tpm_init(void);
 
@@ -1026,7 +1053,7 @@
  * TPM_TakeOwnership, since the TPM device can be opened only by one process at
  * a time.
  *
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2ex_tpm_close(void);
 vb2_error_t vb2ex_tpm_open(void);
@@ -1061,7 +1088,7 @@
  * the TPM RNG directly. Otherwise, an attacker with communication interception
  * abilities could launch replay attacks by reusing previous nonces.
  *
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2ex_tpm_get_random(uint8_t *buf, uint32_t length);
 
@@ -1093,7 +1120,7 @@
  *
  * @param mode_val       Desired TPM mode to set.  May be one of ENABLED
  *                       or DISABLED from vb2_tpm_mode enum.
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val);
 
@@ -1304,8 +1331,6 @@
 
 /* Screens. */
 enum vb2_screen {
-	/* Blank screen */
-	VB2_SCREEN_BLANK			= 0x0,
 	/* Wait screen for EC sync and AUXFW sync */
 	VB2_SCREEN_FIRMWARE_SYNC		= 0x100,
 	/* Broken screen */
@@ -1339,12 +1364,14 @@
 	VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL	= 0x320,
 	/* Invalid external disk inserted */
 	VB2_SCREEN_DEVELOPER_INVALID_DISK	= 0x330,
-	/* Select alternate bootloader ("legacy boot") */
-	VB2_SCREEN_DEVELOPER_SELECT_BOOTLOADER	= 0x340,
+	/* Select alternate bootloader ("altfw") */
+	VB2_SCREEN_DEVELOPER_SELECT_ALTFW	= 0x340,
 	/* Diagnostic tools */
 	VB2_SCREEN_DIAGNOSTICS			= 0x400,
 	/* Storage diagnostic screen */
-	VB2_SCREEN_DIAGNOSTICS_STORAGE	      	= 0x410,
+	VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH	= 0x410,
+	VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT	= 0x411,
+	VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED	= 0x412,
 	/* Memory diagnostic screens */
 	VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK    	= 0x420,
 	VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL     	= 0x421,
@@ -1355,22 +1382,22 @@
 	VB2_UI_ERROR_NONE = 0,
 	/* Dev mode already enabled */
 	VB2_UI_ERROR_DEV_MODE_ALREADY_ENABLED,
-	/* To-norm not allowed */
-	VB2_UI_ERROR_TO_NORM_NOT_ALLOWED,
-	/* Debug info screen initialization failed */
-	VB2_UI_ERROR_DEBUG_LOG,
-	/* External boot not enabled */
-	VB2_UI_ERROR_EXTERNAL_BOOT_NOT_ENABLED,
-	/* Firmware log screen initialization failed */
-	VB2_UI_ERROR_FIRMWARE_LOG,
 	/* Untrusted confirmation */
 	VB2_UI_ERROR_UNTRUSTED_CONFIRMATION,
+	/* To-norm not allowed */
+	VB2_UI_ERROR_TO_NORM_NOT_ALLOWED,
+	/* External boot is disabled */
+	VB2_UI_ERROR_EXTERNAL_BOOT_DISABLED,
 	/* Alternate bootloader is disabled */
-	VB2_UI_ERROR_ALTERNATE_BOOT_DISABLED,
-	/* No bootloader was found */
-	VB2_UI_ERROR_NO_BOOTLOADER,
+	VB2_UI_ERROR_ALTFW_DISABLED,
+	/* No alternate bootloader was found */
+	VB2_UI_ERROR_ALTFW_EMPTY,
 	/* Alternate bootloader failed */
-	VB2_UI_ERROR_ALTERNATE_BOOT_FAILED,
+	VB2_UI_ERROR_ALTFW_FAILED,
+	/* Debug info screen initialization failed */
+	VB2_UI_ERROR_DEBUG_LOG,
+	/* Firmware log screen initialization failed */
+	VB2_UI_ERROR_FIRMWARE_LOG,
 	/* Diagnostics internal failure */
 	VB2_UI_ERROR_DIAGNOSTICS,
 };
@@ -1410,23 +1437,34 @@
 /**
  * Check that physical presence button is currently pressed by the user.
  *
- * @returns 1 for pressed, 0 for not.
+ * @return 1 for pressed, 0 for not.
  */
 int vb2ex_physical_presence_pressed(void);
 
 /**
  * Get the number of supported locales.
  *
- * @returns Number of locales.  0 if none or on error.
+ * @return Number of locales.  0 if none or on error.
  */
 uint32_t vb2ex_get_locale_count(void);
 
 /**
  * Return the number of available alternate bootloaders.
  *
- * @returns Number of alternate bootloaders.  0 if none or on error.
+ * @return Number of alternate bootloaders.  0 if none or on error.
  */
-uint32_t vb2ex_get_bootloader_count(void);
+uint32_t vb2ex_get_altfw_count(void);
+
+/**
+ * Run alternate bootloader.
+ *
+ * @param altfw_id	ID of alternate bootloader to run, where
+ *                      altfw_id <= vb2ex_get_altfw_count().  0 for default,
+ *                      which corresponds to an alternate bootloader in
+ *                      the range 1 <= altfw_id <= vb2ex_getfw_count().
+ * @return VB2_SUCCESS, or error code on error.
+ */
+vb2_error_t vb2ex_run_altfw(uint32_t altfw_id);
 
 /**
  * Delay for at least the specified number of milliseconds.
@@ -1504,16 +1542,30 @@
 				  const char *str);
 
 /**
- * Get the full storage diagnostic log.
+ * Get the health info of the storage.
  *
- * Return a pointer of full log string which is guaranteed to be
- * null-terminated.  The function implementation should manage string memory
- * internally.  Subsequent calls may update the string and/or may return a new
- * pointer.
- *
- * @return The pointer to the full debug info string.  NULL on error.
+ * @param out	For returning a read-only pointer of full log string which is
+ *		guaranteed to be null-terminated. The function will manage
+ *		memory internally, so the returned pointer will only be valid
+ *		until next call.
+ * @return VB2_SUCCESS, or error code on error.
  */
-const char *vb2ex_get_diagnostic_storage(void);
+vb2_error_t vb2ex_diag_get_storage_health(const char **out);
+
+/**
+ * Get the storage self-test log.
+ *
+ * @param out	For returning a read-only pointer of full log string which is
+ *		guaranteed to be null-terminated. The function will manage
+ *		memory internally, so the returned pointer will only be valid
+ *		until next call.
+ * @return The status of storage test. VB2_SUCCESS means the test is finished,
+ * regardless of passing or failing. VB2_ERROR_EX_DIAG_TEST_RUNNING means
+ * the test is still running. VB2_ERROR_EX_UNIMPLEMENTED means the storage
+ * self-test is not supported on this device. Other non-zero codes for internal
+ * errors.
+ */
+vb2_error_t vb2ex_diag_get_storage_test_log(const char **out);
 
 /**
  * Get the memory diagnostic status. When it is called, it will take over the
@@ -1537,6 +1589,17 @@
 vb2_error_t vb2ex_diag_memory_full_test(int reset, const char **out);
 
 /*****************************************************************************/
+/* Functions for diagnostics control. */
+
+enum vb2_diag_storage_test {
+	VB2_DIAG_STORAGE_TEST_STOP = 0,
+	VB2_DIAG_STORAGE_TEST_SHORT,
+	VB2_DIAG_STORAGE_TEST_EXTENDED,
+};
+
+vb2_error_t vb2ex_diag_storage_test_control(enum vb2_diag_storage_test ops);
+
+/*****************************************************************************/
 /* Timer. */
 
 /**
diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h
index e610093..918c50d 100644
--- a/firmware/2lib/include/2common.h
+++ b/firmware/2lib/include/2common.h
@@ -10,6 +10,7 @@
 
 #include "2api.h"
 #include "2gbb.h"
+#include "2packed_key.h"
 #include "2return_codes.h"
 #include "2sha.h"
 #include "2struct.h"
@@ -427,4 +428,44 @@
 				   const struct vb2_public_key *key,
 				   const struct vb2_workbuf *wb);
 
+/**
+ * Get the flags for the kernel preamble.
+ *
+ * @param preamble	Preamble to check
+ * @return Flags for the preamble.  Old preamble versions (<2.2) return 0.
+ */
+uint32_t vb2_kernel_get_flags(const struct vb2_kernel_preamble *preamble);
+
+/**
+ * Verify a keyblock using its hash.
+ *
+ * Header fields are also checked for validity. Does not verify key index or key
+ * block flags.  Use this for self-signed keyblocks in developer mode.
+ *
+ * @param block		Keyblock to verify
+ * @param size		Size of keyblock buffer
+ * @param key		Key to use to verify block
+ * @param wb		Work buffer
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
+				     uint32_t size,
+				     const struct vb2_workbuf *wb);
+
+/**
+ * Check the validity of a kernel preamble using a public key.
+ *
+ * The signature in the preamble is destroyed during the check.
+ *
+ * @param preamble     	Preamble to verify
+ * @param size		Size of preamble buffer
+ * @param key		Key to use to verify preamble
+ * @param wb		Work buffer
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
+				       uint32_t size,
+				       const struct vb2_public_key *key,
+				       const struct vb2_workbuf *wb);
+
 #endif  /* VBOOT_REFERENCE_2COMMON_H_ */
diff --git a/firmware/2lib/include/2gbb_flags.h b/firmware/2lib/include/2gbb_flags.h
index c1c937c..0eff7f7 100644
--- a/firmware/2lib/include/2gbb_flags.h
+++ b/firmware/2lib/include/2gbb_flags.h
@@ -53,8 +53,8 @@
 	/* Allow Enter key to trigger dev->tonorm screen transition */
 	VB2_GBB_FLAG_ENTER_TRIGGERS_TONORM = 1 << 6,
 
-	/* Allow booting Legacy OSes in dev mode even if dev_boot_legacy=0. */
-	VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY = 1 << 7,
+	/* Allow booting Legacy OSes in dev mode even if dev_boot_altfw=0. */
+	VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW = 1 << 7,
 
 	/*
 	 * Currently running FAFT tests.  May be used as a hint to disable
@@ -69,7 +69,7 @@
 	VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC = 1 << 9,
 
 	/* Default to booting legacy OS when dev screen times out */
-	VB2_GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY = 1 << 10,
+	VB2_GBB_FLAG_DEFAULT_DEV_BOOT_ALTFW = 1 << 10,
 
 	/* Disable auxiliary firmware (auxfw) software sync */
 	VB2_GBB_FLAG_DISABLE_AUXFW_SOFTWARE_SYNC = 1 << 11,
diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h
index 334b148..3d96293 100644
--- a/firmware/2lib/include/2misc.h
+++ b/firmware/2lib/include/2misc.h
@@ -224,13 +224,13 @@
  * Determine if booting from legacy BIOS is allowed.
  *
  * Legacy BIOS is allowed if any of these flags are set:
- * VB2_NV_DEV_BOOT_LEGACY, VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY, and
- * VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY.
+ * VB2_NV_DEV_BOOT_ALTFW, VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW, and
+ * VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW.
  *
  * @param ctx		Vboot context
  * @return 1 if allowed, or 0 otherwise.
  */
-int vb2_dev_boot_legacy_allowed(struct vb2_context *ctx);
+int vb2_dev_boot_altfw_allowed(struct vb2_context *ctx);
 
 /**
  * Determine if booting from external disk is allowed.
diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h
index 9de8056..2f40b23 100644
--- a/firmware/2lib/include/2nvstorage.h
+++ b/firmware/2lib/include/2nvstorage.h
@@ -49,7 +49,7 @@
 	/* Allow booting from external disk in developer mode.  0=no, 1=yes. */
 	VB2_NV_DEV_BOOT_EXTERNAL,
 	/* Allow booting of legacy OSes in developer mode.  0=no, 1=yes. */
-	VB2_NV_DEV_BOOT_LEGACY,
+	VB2_NV_DEV_BOOT_ALTFW,
 	/* Only boot Google-signed images in developer mode.  0=no, 1=yes. */
 	VB2_NV_DEV_BOOT_SIGNED_ONLY,
 	/*
diff --git a/firmware/2lib/include/2packed_key.h b/firmware/2lib/include/2packed_key.h
new file mode 100644
index 0000000..09c7355
--- /dev/null
+++ b/firmware/2lib/include/2packed_key.h
@@ -0,0 +1,39 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Functions related to unpacking keys and key buffers.
+ */
+
+#ifndef VBOOT_REFERENCE_2PACKED_KEY_H_
+#define VBOOT_REFERENCE_2PACKED_KEY_H_
+
+/**
+ * Unpack a vboot1-format key buffer for use in verification
+ *
+ * The elements of the unpacked key will point into the source buffer, so don't
+ * free the source buffer until you're done with the key.
+ *
+ * @param key		Destintion for unpacked key
+ * @param buf		Source buffer containing packed key
+ * @param size		Size of buffer in bytes
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key,
+				  const uint8_t *buf, uint32_t size);
+
+/**
+ * Unpack a vboot1-format key for use in verification
+ *
+ * The elements of the unpacked key will point into the source packed key, so
+ * don't free the source until you're done with the public key.
+ *
+ * @param key		Destintion for unpacked key
+ * @param packed_key	Source packed key
+ * @param size		Size of buffer in bytes
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+vb2_error_t vb2_unpack_key(struct vb2_public_key *key,
+			   const struct vb2_packed_key *packed_key);
+
+#endif  /* VBOOT_REFERENCE_2PACKED_KEY_H_ */
diff --git a/firmware/2lib/include/2recovery_reasons.h b/firmware/2lib/include/2recovery_reasons.h
index 514ee4f..30dbd2e 100644
--- a/firmware/2lib/include/2recovery_reasons.h
+++ b/firmware/2lib/include/2recovery_reasons.h
@@ -14,7 +14,7 @@
  * Return a description of the recovery reason code.
  *
  * @param		recovery reason code
- * @returns A string literal with English description of the recovery reason
+ * @return A string literal with English description of the recovery reason
  */
 const char *vb2_get_recovery_reason_string(uint8_t code);
 
@@ -265,8 +265,8 @@
 	/* Failed to disable the TPM [prior to running untrusted code] */
 	VB2_RECOVERY_TPM_DISABLE_FAILED = 0x60,
 
-	/* Alt FW Failed hash verification */
-	VB2_RECOVERY_ALTFW_HASH_FAILED = 0x61,
+	/* Verification of altfw payload failed (deprecated) */
+	VB2_RECOVERY_ALTFW_HASH_MISMATCH = 0x61,
 
 	/* FWMP secure data initialization error */
 	VB2_RECOVERY_SECDATA_FWMP_INIT = 0x62,
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 49f9935..4512ff8 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -44,6 +44,9 @@
 	/* Continue in the UI loop.  This is used in UI internal functions. */
 	VB2_REQUEST_UI_CONTINUE = 0x1005,
 
+	/* Break from the UI loop.  This is used in UI internal functions. */
+	VB2_REQUEST_UI_EXIT = 0x1006,
+
 	/* End of VB2_REQUEST_* */
 	VB2_REQUEST_END = 0x5000,
 
@@ -395,6 +398,9 @@
 	/* No signature matching key ID */
 	VB2_ERROR_KEYBLOCK_SIG_ID,
 
+	/* Invalid keyblock hash in dev mode (self-signed kernel) */
+	VB2_ERROR_KEYBLOCK_HASH_INVALID_IN_DEV_MODE,
+
 	/**********************************************************************
 	 * Preamble verification errors (all in vb2_verify_preamble())
 	 */
@@ -538,23 +544,27 @@
 	/* Kernel preamble not loaded before calling vb2api_get_kernel_size() */
 	VB2_ERROR_API_GET_KERNEL_SIZE_PREAMBLE,
 
-	/* Unable to unpack kernel subkey in vb2_verify_vblock() */
-	VB2_ERROR_VBLOCK_KERNEL_SUBKEY,
+	/* Unable to unpack kernel subkey in vb2_verify_vblock();
+	 * deprecated and replaced with VB2_ERROR_UNPACK_KEY_* */
+	VB2_ERROR_DEPRECATED_VBLOCK_KERNEL_SUBKEY,
 
 	/*
 	 * Got a self-signed kernel in vb2_verify_vblock(), but need an
-	 * officially signed one.
+	 * officially signed one; deprecated and replaced with
+	 * VB2_ERROR_KERNEL_KEYBLOCK_*.
 	 */
-	VB2_ERROR_VBLOCK_SELF_SIGNED,
+	VB2_ERROR_DEPRECATED_VBLOCK_SELF_SIGNED,
 
-	/* Invalid keyblock hash in vb2_verify_vblock() */
-	VB2_ERROR_VBLOCK_KEYBLOCK_HASH,
+	/* Invalid keyblock hash in vb2_verify_vblock();
+	 * deprecated and replaced with VB2_ERROR_KERNEL_KEYBLOCK_* */
+	VB2_ERROR_DEPRECATED_VBLOCK_KEYBLOCK_HASH,
 
-	/* Invalid keyblock in vb2_verify_vblock() */
-	VB2_ERROR_VBLOCK_KEYBLOCK,
+	/* Invalid keyblock in vb2_verify_vblock();
+	 * deprecated and replaced with VB2_ERROR_KERNEL_KEYBLOCK_* */
+	VB2_ERROR_DEPRECATED_VBLOCK_KEYBLOCK,
 
-	/* Wrong developer key hash in vb2_verify_vblock() */
-	VB2_ERROR_VBLOCK_DEV_KEY_HASH,
+	/* Wrong dev key hash in vb2_verify_kernel_vblock_dev_key_hash() */
+	VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH,
 
 	/* Work buffer too small in vb2_load_partition() */
 	VB2_ERROR_LOAD_PARTITION_WORKBUF,
diff --git a/firmware/2lib/include/2rsa_private.h b/firmware/2lib/include/2rsa_private.h
new file mode 100644
index 0000000..23a2aac
--- /dev/null
+++ b/firmware/2lib/include/2rsa_private.h
@@ -0,0 +1,21 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Internal functions from 2rsa.c that have error conditions we can't trigger
+ * from the public APIs.  These include checks for bad algorithms where the
+ * next call level up already checks for bad algorithms, etc.
+ *
+ * These functions aren't in 2rsa.h because they're not part of the public
+ * APIs.
+ */
+
+#ifndef VBOOT_REFERENCE_2RSA_PRIVATE_H_
+#define VBOOT_REFERENCE_2RSA_PRIVATE_H_
+
+struct vb2_public_key;
+int vb2_mont_ge(const struct vb2_public_key *key, uint32_t *a);
+vb2_error_t vb2_check_padding(const uint8_t *sig,
+			      const struct vb2_public_key *key);
+
+#endif  /* VBOOT_REFERENCE_2RSA_PRIVATE_H_ */
diff --git a/firmware/2lib/include/2secdata.h b/firmware/2lib/include/2secdata.h
index 5e41934..f9a0e30 100644
--- a/firmware/2lib/include/2secdata.h
+++ b/firmware/2lib/include/2secdata.h
@@ -181,7 +181,7 @@
 	VB2_SECDATA_FWMP_DEV_DISABLE_BOOT = (1 << 0),
 	VB2_SECDATA_FWMP_DEV_DISABLE_RECOVERY = (1 << 1),
 	VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL = (1 << 2),
-	VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY = (1 << 3),
+	VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW = (1 << 3),
 	VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY = (1 << 4),
 	VB2_SECDATA_FWMP_DEV_USE_KEY_HASH = (1 << 5),
 	/* CCD = case-closed debugging on cr50; flag implemented on cr50 */
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index e0ef606..b79bbd0 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -304,43 +304,6 @@
 
 /****************************************************************************/
 
-/*
- * Root key hash for Ryu devices only.  Contains the hash of the root key.
- * This will be embedded somewhere inside the RO part of the firmware, so that
- * it can verify the GBB contains only the official root key.
- */
-#define RYU_ROOT_KEY_HASH_MAGIC "RtKyHash"
-#define RYU_ROOT_KEY_HASH_MAGIC_INVCASE "rTkYhASH"
-#define RYU_ROOT_KEY_HASH_MAGIC_SIZE 8
-
-#define RYU_ROOT_KEY_HASH_VERSION_MAJOR 1
-#define RYU_ROOT_KEY_HASH_VERSION_MINOR 0
-
-struct vb2_ryu_root_key_hash {
-	/* Magic number (RYU_ROOT_KEY_HASH_MAGIC) */
-	uint8_t magic[RYU_ROOT_KEY_HASH_MAGIC_SIZE];
-
-	/* Version of this struct */
-	uint16_t header_version_major;
-	uint16_t header_version_minor;
-
-	/*
-	 * Length of this struct, in bytes, including any variable length data
-	 * which follows (there is none, yet).
-	 */
-	uint32_t struct_size;
-
-	/*
-	 * SHA-256 hash digest of the entire root key section from the GBB.  If
-	 * all 0 bytes, all root keys will be treated as if matching.
-	 */
-	uint8_t root_key_hash_digest[32];
-};
-
-#define EXPECTED_VB2_RYU_ROOT_KEY_HASH_SIZE 48
-
-/****************************************************************************/
-
 /* Packed public key data */
 struct vb2_packed_key {
 	/* Offset of key data from start of this struct */
diff --git a/firmware/2lib/include/2ui.h b/firmware/2lib/include/2ui.h
index 77c5acf..bfb2b8b 100644
--- a/firmware/2lib/include/2ui.h
+++ b/firmware/2lib/include/2ui.h
@@ -66,6 +66,7 @@
 	uint32_t page_up_item;
 	uint32_t page_down_item;
 	uint32_t back_item;
+	uint32_t cancel_item;
 };
 
 struct vb2_screen_state {
@@ -78,7 +79,7 @@
 	uint32_t page_count;
 	uint32_t current_page;
 
-	/* For memory check screen. */
+	/* For minidiag test screens. */
 	int test_finished;  /* Do not update screen if the content is done */
 
 	struct vb2_screen_state *prev;
@@ -132,13 +133,13 @@
 	struct vb2_ui_context *ui);
 vb2_error_t vb2_ui_developer_mode_boot_external_action(
 	struct vb2_ui_context *ui);
-vb2_error_t vb2_ui_developer_mode_boot_alternate_action(
+vb2_error_t vb2_ui_developer_mode_boot_altfw_action(
 	struct vb2_ui_context *ui);
 
 /**
  * Get info struct of a screen.
  *
- * @param screen	Screen from enum vb2_screen
+ * @param id		Screen from enum vb2_screen
  *
  * @return screen info struct on success, NULL on error.
  */
@@ -155,7 +156,7 @@
  * on 0 when we hit the start of the menu.
  *
  * @param ui		UI context pointer
- * @return VB2_REQUEST_UI_CONTINUE, or error code on error.
+ * @return VB2_SUCCESS, or error code on error.
  */
 vb2_error_t vb2_ui_menu_prev(struct vb2_ui_context *ui);
 
@@ -167,29 +168,43 @@
  * on the max index when we hit the end of the menu.
  *
  * @param ui		UI context pointer
- * @return VB2_REQUEST_UI_CONTINUE, or error code on error.
+ * @return VB2_SUCCESS, or error code on error.
  */
 vb2_error_t vb2_ui_menu_next(struct vb2_ui_context *ui);
 
 /**
  * Select the current menu item.
  *
+ * The caller should take care of returning after this function, and should not
+ * continue executing under the assumption that the screen has *not* changed.
+ *
  * If the current menu item has an action associated with it, run the action.
  * Otherwise, navigate to the target screen.  If neither of these are set, then
  * selecting the menu item is a no-op.
  *
  * @param ui		UI context pointer
- * @return VB2_REQUEST_UI_CONTINUE, or error code on error.
+ * @return VB2_SUCCESS, or error code on error.
  */
 vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui);
 
 /*****************************************************************************/
 /* Screen navigation functions */
-
+/**
+ * After these functions are called, no assumptions may be made about which
+ * screen is currently displayed, and thus execution should return to ui_loop.
+ * VB2_REQUEST_UI_CONTINUE is returned rather than VB2_SUCCESS, so VB2_TRY can
+ * be used to wrapped to these functions and the callers of these functions.
+ */
 /**
  * Return back to the previous screen.
  *
- * If the current screen is already the root scren, the request is ignored.
+ * The caller should take care of returning after this function, and should not
+ * continue executing under the assumption that the screen has *not* changed.
+ *
+ * If the current screen is already the root screen, the request is ignored.
+ *
+ * TODO(b/157625765): Consider falling into recovery mode (BROKEN screen) when
+ * the current screen is already the root screen.
  *
  * @param ui		UI context pointer
  * @return VB2_REQUEST_UI_CONTINUE, or error code on error.
@@ -199,9 +214,16 @@
 /**
  * Change to the given screen.
  *
+ * The caller should take care of returning after this function, and should not
+ * continue executing under the assumption that the screen has *not* changed.
+ *
  * If the screen is not found, the request is ignored.
  *
+ * TODO(b/157625765): Consider falling into recovery mode (BROKEN screen) when
+ * the target screen is not found.
+ *
  * @param ui		UI context pointer
+ * @param id		Screen from enum vb2_screen
  * @return VB2_REQUEST_UI_CONTINUE, or error code on error.
  */
 vb2_error_t vb2_ui_screen_change(struct vb2_ui_context *ui, enum vb2_screen id);
@@ -219,7 +241,7 @@
  * If a timeout occurs, take the default boot action.
  *
  * @param ctx		Vboot context
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2_developer_menu(struct vb2_context *ctx);
 
@@ -230,7 +252,7 @@
  * encountered last boot. Wait for the user to physically reset or shut down.
  *
  * @param ctx		Vboot context
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2_broken_recovery_menu(struct vb2_context *ctx);
 
@@ -241,7 +263,7 @@
  * navigate the step-by-step recovery, or enter developer mode if allowed.
  *
  * @param ctx		Vboot context
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2_manual_recovery_menu(struct vb2_context *ctx);
 
@@ -252,7 +274,7 @@
  * diagnostic tests of various hardware components.
  *
  * @param ctx		Vboot context
- * @returns VB2_SUCCESS, or non-zero error code.
+ * @return VB2_SUCCESS, or non-zero error code.
  */
 vb2_error_t vb2_diagnostic_menu(struct vb2_context *ctx);
 
diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h
index 7374735..becd710 100644
--- a/firmware/include/tpm2_tss_constants.h
+++ b/firmware/include/tpm2_tss_constants.h
@@ -34,9 +34,13 @@
 #define TPM2_NV_ReadPublic     ((TPM_CC)0x00000169)
 #define TPM2_GetCapability     ((TPM_CC)0x0000017A)
 #define TPM2_GetRandom         ((TPM_CC)0x0000017B)
+#define TPM2_PCR_Extend        ((TPM_CC)0x00000182)
+
+#define TPM_HT_PCR             0x00
+#define TPM_HT_NV_INDEX        0x01
 
 #define HR_SHIFT               24
-#define TPM_HT_NV_INDEX        0x01
+#define HR_PCR                (TPM_HT_PCR <<  HR_SHIFT)
 #define HR_NV_INDEX           (TPM_HT_NV_INDEX <<  HR_SHIFT)
 #define TPM_RH_OWNER        0x40000001
 #define TPM_RH_PLATFORM     0x4000000C
@@ -110,9 +114,15 @@
 #define TPMI_RH_NV_INDEX_TCG_WG_START	((TPMI_RH_NV_INDEX)0x01C40000)
 #define TPMI_RH_NV_INDEX_RESERVED_START	((TPMI_RH_NV_INDEX)0x01C90000)
 
+#define HASH_COUNT 1 /* Only SHA-256 is supported */
+
+/* Table 206 - Defines for SHA256 Hash Values */
+#define SHA256_DIGEST_SIZE  32
+
 typedef uint8_t TPMI_YES_NO;
 typedef uint32_t TPM_CC;
 typedef uint32_t TPM_HANDLE;
+typedef TPM_HANDLE TPMI_DH_PCR;
 typedef TPM_HANDLE TPMI_RH_NV_INDEX;
 typedef TPM_HANDLE TPMI_RH_ENABLES;
 typedef uint32_t TPM_CAP;
@@ -146,6 +156,20 @@
 } TPML_TAGGED_TPM_PROPERTY;
 
 typedef union {
+	uint8_t sha256[SHA256_DIGEST_SIZE];
+} TPMU_HA;
+
+typedef struct {
+	TPMI_ALG_HASH  hashAlg;
+	TPMU_HA        digest;
+} TPMT_HA;
+
+typedef struct {
+	uint32_t   count;
+	TPMT_HA digests[HASH_COUNT];
+} TPML_DIGEST_VALUES;
+
+typedef union {
 	TPML_TAGGED_TPM_PROPERTY tpm_properties;
 } TPMU_CAPABILITIES;
 
@@ -223,6 +247,11 @@
 	TPM_SU shutdown_type;
 };
 
+struct tpm2_pcr_extend_cmd {
+	TPMI_DH_PCR pcrHandle;
+	TPML_DIGEST_VALUES digests;
+};
+
 /* Common command/response header. */
 struct tpm_header {
 	uint16_t tpm_tag;
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 739019a..2b1d838 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -44,7 +44,6 @@
  */
 typedef void *VbExDiskHandle_t;
 
-/* Data used only by VbSelectAndLoadKernel() */
 typedef struct VbSelectAndLoadKernelParams {
 	/* Inputs to VbSelectAndLoadKernel() */
 	/* Destination buffer for kernel (normally at 0x100000 on x86) */
@@ -68,12 +67,6 @@
 	uint8_t partition_guid[16];
 	/* Flags set by signer */
 	uint32_t flags;
-	/*
-	 * TODO: in H2C, all that pretty much just gets passed to the
-	 * bootloader as KernelBootloaderOptions, though the disk handle is
-	 * passed as an index instead of a handle.  Is that used anymore now
-	 * that we're passing partition_guid?
-	 */
 } VbSelectAndLoadKernelParams;
 
 /**
@@ -88,13 +81,22 @@
 /* Disk access (previously in boot_device.h) */
 
 /* Flags for VbDisk APIs */
+
+/*
+ * Disk selection in the lower 16 bits (where the disk lives), and disk
+ * attributes in the higher 16 bits (extra information about the disk
+ * needed to access it correctly).
+ */
+#define VB_DISK_FLAG_SELECT_MASK 0xffff
+#define VB_DISK_FLAG_ATTRIBUTE_MASK (0xffff << 16)
+
 /* Disk is removable.  Example removable disks: SD cards, USB keys.  */
-#define VB_DISK_FLAG_REMOVABLE 0x00000001
+#define VB_DISK_FLAG_REMOVABLE (1 << 0)
 /*
  * Disk is fixed.  If this flag is present, disk is internal to the system and
  * not removable.  Example fixed disks: internal SATA SSD, eMMC.
  */
-#define VB_DISK_FLAG_FIXED     0x00000002
+#define VB_DISK_FLAG_FIXED (1 << 1)
 /*
  * Note that VB_DISK_FLAG_REMOVABLE and VB_DISK_FLAG_FIXED are
  * mutually-exclusive for a single disk.  VbExDiskGetInfo() may specify both
@@ -130,7 +132,7 @@
  * streaming aspects of the disk. If a disk is random-access (i.e.
  * not raw NAND) then these fields are equal.
  */
-#define VB_DISK_FLAG_EXTERNAL_GPT	0x00000004
+#define VB_DISK_FLAG_EXTERNAL_GPT (1 << 16)
 
 /* Information on a single disk */
 typedef struct VbDiskInfo {
@@ -355,33 +357,6 @@
 /* Shutdown requested due to a power button being pressed. */
 #define VB_SHUTDOWN_REQUEST_POWER_BUTTON	0x00000004
 
-enum VbAltFwIndex_t {
-	VB_ALTFW_DIAGNOSTIC = -1,
-	VB_ALTFW_DEFAULT = 0,
-	VB_ALTFW_FIRST = 1,
-	VB_ALTFW_SECOND,
-	VB_ALTFW_THIRD,
-	VB_ALTFW_FOURTH,
-	VB_ALTFW_FIFTH,
-	VB_ALTFW_SIXTH,
-	VB_ALTFW_SEVENTH,
-	VB_ALTFW_EIGHTH,
-	VB_ALTFW_NINTH,
-};
-
-/**
- * Execute legacy boot option.
- *
- * @param altfw_num	Bootloader sequence number to execute. Use
- *	0 to boot the default payload, if any
- *     >0 (i.e., positive #) run a payload by # based in altfw/list file
- *     <0 (i.e., negative #) run a specific payload by name without using
- *        the altfw/list file.  Typically payloads in this category will be
- *        verified before they are run. Currently these #s are defined:
- *          -1 diagnostic payload
- */
-vb2_error_t VbExLegacy(enum VbAltFwIndex_t altfw_num);
-
 #ifdef __cplusplus
 }
 #endif  /* __cplusplus */
diff --git a/firmware/lib/include/load_kernel_fw.h b/firmware/lib/include/load_kernel_fw.h
index 9e4db8e..96c8f86 100644
--- a/firmware/lib/include/load_kernel_fw.h
+++ b/firmware/lib/include/load_kernel_fw.h
@@ -11,47 +11,6 @@
 
 #include "vboot_api.h"
 
-struct vb2_context;
-
-/* Interface provided by verified boot library to BDS */
-
-/* Boot flags for LoadKernel().boot_flags */
-/* GPT is external */
-#define BOOT_FLAG_EXTERNAL_GPT (0x04ULL)
-
-typedef struct LoadKernelParams {
-	/* Inputs to LoadKernel() */
-	/* Disk handle for current device */
-	VbExDiskHandle_t disk_handle;
-	/* Bytes per lba sector on current device */
-	uint64_t bytes_per_lba;
-	/* Number of LBA-addressable sectors on the main device */
-	uint64_t streaming_lba_count;
-	/* Random-access GPT size */
-	uint64_t gpt_lba_count;
-	/* Destination buffer for kernel (normally at 0x100000) */
-	void *kernel_buffer;
-	/* Size of kernel buffer in bytes */
-	uint64_t kernel_buffer_size;
-	/* Boot flags */
-	uint64_t boot_flags;
-
-	/*
-	 * Outputs from LoadKernel(); valid only if LoadKernel() returns
-	 * LOAD_KERNEL_SUCCESS
-	 */
-	/* Partition number to boot on current device (1...M) */
-	uint32_t partition_number;
-	/* Address of bootloader image in RAM */
-	uint64_t bootloader_address;
-	/* Size of bootloader image in bytes */
-	uint32_t bootloader_size;
-	/* UniquePartitionGuid for boot partition */
-	uint8_t  partition_guid[16];
-	/* Flags passed in by signer */
-	uint32_t flags;
-} LoadKernelParams;
-
 /**
  * Attempt to load the kernel from the current device.
  *
@@ -60,6 +19,8 @@
  *
  * Returns VB2_SUCCESS if successful.  If unsuccessful, returns an error code.
  */
-vb2_error_t LoadKernel(struct vb2_context *ctx, LoadKernelParams *params);
+vb2_error_t LoadKernel(struct vb2_context *ctx,
+		       VbSelectAndLoadKernelParams *params,
+		       VbDiskInfo *disk_info);
 
 #endif  /* VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ */
diff --git a/firmware/lib/include/vboot_audio.h b/firmware/lib/include/vboot_audio.h
deleted file mode 100644
index 64cf0a7..0000000
--- a/firmware/lib/include/vboot_audio.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Delay/beep functions used in dev-mode kernel selection.
- */
-
-#ifndef VBOOT_REFERENCE_VBOOT_AUDIO_H_
-#define VBOOT_REFERENCE_VBOOT_AUDIO_H_
-
-#include "vboot_api.h"
-
-/**
- * Initialization function.
- */
-void vb2_audio_start(struct vb2_context *ctx);
-
-/**
- * Caller should loop without extra delay until this returns false.
- */
-int vb2_audio_looping(void);
-
-#endif  /* VBOOT_REFERENCE_VBOOT_AUDIO_H_ */
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h
index 661f0c4..a9dc824 100644
--- a/firmware/lib/include/vboot_kernel.h
+++ b/firmware/lib/include/vboot_kernel.h
@@ -16,84 +16,6 @@
 
 struct vb2_context;
 
-/* Flags for VbSharedDataKernelPart.flags */
-#define VBSD_LKP_FLAG_KEYBLOCK_VALID   0x01
-
-/* Result codes for VbSharedDataKernelPart.check_result */
-#define VBSD_LKP_CHECK_NOT_DONE           0
-#define VBSD_LKP_CHECK_TOO_SMALL          1
-#define VBSD_LKP_CHECK_READ_START         2
-#define VBSD_LKP_CHECK_KEYBLOCK_SIG      3
-#define VBSD_LKP_CHECK_KEYBLOCK_HASH     4
-#define VBSD_LKP_CHECK_DEV_MISMATCH       5
-#define VBSD_LKP_CHECK_REC_MISMATCH       6
-#define VBSD_LKP_CHECK_KEY_ROLLBACK       7
-#define VBSD_LKP_CHECK_DATA_KEY_PARSE     8
-#define VBSD_LKP_CHECK_VERIFY_PREAMBLE    9
-#define VBSD_LKP_CHECK_KERNEL_ROLLBACK    10
-#define VBSD_LKP_CHECK_PREAMBLE_VALID     11
-/*
- * Body load address check is omitted; this result code is deprecated and not
- * used anywhere in the codebase.
- */
-#define VBSD_LKP_CHECK_BODY_ADDRESS       12
-#define VBSD_LKP_CHECK_BODY_OFFSET        13
-#define VBSD_LKP_CHECK_SELF_SIGNED        14
-#define VBSD_LKP_CHECK_BODY_EXCEEDS_MEM   15
-#define VBSD_LKP_CHECK_BODY_EXCEEDS_PART  16
-#define VBSD_LKP_CHECK_READ_DATA          17
-#define VBSD_LKP_CHECK_VERIFY_DATA        18
-#define VBSD_LKP_CHECK_KERNEL_GOOD        19
-
-/* Information about a single kernel partition check in LoadKernel() */
-typedef struct VbSharedDataKernelPart {
-	uint64_t sector_start;     /* Start sector of partition */
-	uint64_t sector_count;     /* Sector count of partition */
-	uint32_t combined_version; /* Combined key+kernel version */
-	uint8_t gpt_index;         /* Index of partition in GPT */
-	uint8_t check_result;      /* Check result; see VBSD_LKP_CHECK_* */
-	uint8_t flags;             /* Flags (see VBSD_LKP_FLAG_* */
-	uint8_t reserved0;         /* Reserved for padding */
-} VbSharedDataKernelPart;
-
-/* Number of kernel partitions to track per call.  Must be power of 2. */
-#define VBSD_MAX_KERNEL_PARTS 8
-
-/* Result codes for VbSharedDataKernelCall.check_result */
-#define VBSD_LKC_CHECK_NOT_DONE            0
-#define VBSD_LKC_CHECK_DEV_SWITCH_MISMATCH 1
-#define VBSD_LKC_CHECK_GPT_READ_ERROR      2
-#define VBSD_LKC_CHECK_GPT_PARSE_ERROR     3
-#define VBSD_LKC_CHECK_GOOD_PARTITION      4
-#define VBSD_LKC_CHECK_INVALID_PARTITIONS  5
-#define VBSD_LKC_CHECK_NO_PARTITIONS       6
-
-/* Information about a single call to LoadKernel() */
-typedef struct VbSharedDataKernelCall {
-	/* Bottom 32 bits of flags passed in LoadKernelParams.boot_flags */
-	uint32_t boot_flags;
-	/* Debug flags; see VBSD_LK_FLAG_* */
-	uint32_t flags;
-	/* Number of sectors on drive */
-	uint64_t sector_count;
-	/* Sector size in bytes */
-	uint32_t sector_size;
-	/* Check result; see VBSD_LKC_CHECK_* */
-	uint8_t check_result;
-	/* Boot mode for LoadKernel(); see VBSD_LK_BOOT_MODE_* constants */
-	uint8_t boot_mode;
-	/* Test error number, if non-zero */
-	uint8_t test_error_num;
-	/* Return code from LoadKernel() */
-	uint8_t return_code;
-	/* Number of kernel partitions found */
-	uint8_t kernel_parts_found;
-	/* Reserved for padding */
-	uint8_t reserved0[7];
-	/* Data on kernels */
-	VbSharedDataKernelPart parts[VBSD_MAX_KERNEL_PARTS];
-} VbSharedDataKernelCall;
-
 /**
  * Attempt loading a kernel from the specified type(s) of disks.
  *
@@ -101,9 +23,9 @@
  * VB2_SUCCESS.
  *
  * @param ctx			Vboot context
- * @param get_info_flags	Flags to pass to VbExDiskGetInfo()
+ * @param disk_flags		Flags to pass to VbExDiskGetInfo()
  * @return VB2_SUCCESS or the most specific VB2_ERROR_LK error.
  */
-vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags);
+vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags);
 
 #endif  /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */
diff --git a/firmware/lib/include/vboot_struct.h b/firmware/lib/include/vboot_struct.h
index caca1f2..8a06892 100644
--- a/firmware/lib/include/vboot_struct.h
+++ b/firmware/lib/include/vboot_struct.h
@@ -53,9 +53,6 @@
 /* NvStorage uses 64-byte record, not 16-byte */
 #define VBSD_NVDATA_V2                   0x00100000
 
-/* Number of kernel calls to track.  Must be power of 2. */
-#define VBSD_MAX_KERNEL_CALLS 4
-
 /* Data shared to OS. */
 typedef struct VbSharedDataHeader {
 	/* Fields present in version 1 */
@@ -117,8 +114,8 @@
 	/* Debugging information from LoadKernel() */
 	/* Number of times LoadKernel() called */
 	uint32_t lk_call_count;
-	/* Info on calls */
-	VbSharedDataKernelCall lk_calls[VBSD_MAX_KERNEL_CALLS];
+	/* Reserved for padding */
+	uint8_t reserved3[896];
 
 	/*
 	 * Offset and size of supplemental kernel data.  Reserve space for
@@ -137,7 +134,7 @@
 	/* Recovery reason for current boot */
 	uint8_t recovery_reason;
 	/* Reserved for padding */
-	uint8_t reserved3[7];
+	uint8_t reserved4[7];
 	/* Flags from firmware keyblock */
 	uint64_t fw_keyblock_flags;
 	/* Kernel TPM version at start of VbSelectAndLoadKernel() */
diff --git a/firmware/lib/include/vboot_test.h b/firmware/lib/include/vboot_test.h
index 9c84909..41e8e5d 100644
--- a/firmware/lib/include/vboot_test.h
+++ b/firmware/lib/include/vboot_test.h
@@ -9,35 +9,9 @@
 #define VBOOT_REFERENCE_TEST_API_H_
 
 /****************************************************************************
- * 2rsa.c
- *
- * Internal functions from 2rsa.c that have error conditions we can't trigger
- * from the public APIs.  These include checks for bad algorithms where the
- * next call level up already checks for bad algorithms, etc.
- *
- * These functions aren't in 2rsa.h because they're not part of the public
- * APIs.
- */
-struct vb2_public_key;
-int vb2_mont_ge(const struct vb2_public_key *key, uint32_t *a);
-vb2_error_t vb2_check_padding(const uint8_t *sig,
-			      const struct vb2_public_key *key);
-
-/****************************************************************************
  * vboot_api_kernel.c */
 
-struct LoadKernelParams;
-struct LoadKernelParams *VbApiKernelGetParams(void);
-
-/****************************************************************************
- * 2secdata_kernel.c */
-
-/**
- * Calculate crc8 of kernel secure storage.
- *
- * @param ctx		Context pointer
- * @return Calculated crc8 value.
- */
-uint8_t vb2_secdata_kernel_crc(struct vb2_context *ctx);
+struct VbSelectAndLoadKernelParams;
+struct VbSelectAndLoadKernelParams *VbApiKernelGetParams(void);
 
 #endif  /* VBOOT_REFERENCE_TEST_API_H_ */
diff --git a/firmware/lib/tpm2_lite/marshaling.c b/firmware/lib/tpm2_lite/marshaling.c
index ef3606b..b9857d4 100644
--- a/firmware/lib/tpm2_lite/marshaling.c
+++ b/firmware/lib/tpm2_lite/marshaling.c
@@ -283,7 +283,7 @@
 	}
 
 	memcpy(*buffer, blob, blob_size);
-	buffer_space -= blob_size;
+	*buffer_space -= blob_size;
 	*buffer = (void *)((uintptr_t)(*buffer) + blob_size);
 }
 
@@ -327,6 +327,7 @@
 #define marshal_TPM_HANDLE(a, b, c) marshal_u32(a, b, c)
 #define marshal_TPM_SU(a, b, c) marshal_u16(a, b, c)
 #define marshal_ALG_ID(a, b, c) marshal_u16(a, b, c)
+#define marshal_TPMI_ALG_HASH(a, b, c) marshal_u16(a, b, c)
 
 /*
  * For TPM2B* structures the size field (16 or 32 bits) goes before the data.
@@ -671,6 +672,48 @@
 	marshal_TPM_SU(buffer, command_body->shutdown_type, buffer_space);
 }
 
+static void marshal_TPMT_HA(void **buffer,
+			    TPMT_HA *data,
+			    int *buffer_space)
+{
+	if (data->hashAlg != TPM_ALG_SHA256)
+	{
+		VB2_DEBUG("Unsupported TPMT_HA hash algorithm: %#x\n",
+			  data->hashAlg);
+		*buffer_space = -1;
+		return;
+	}
+	marshal_TPMI_ALG_HASH(buffer, data->hashAlg, buffer_space);
+	/* We only support SHA256 now. */
+	marshal_blob(buffer, data->digest.sha256,
+		     SHA256_DIGEST_SIZE, buffer_space);
+}
+
+static void marshal_TPML_DIGEST_VALUES(void **buffer,
+				       TPML_DIGEST_VALUES *data,
+				       int *buffer_space)
+{
+	int i;
+
+	marshal_u32(buffer, data->count, buffer_space);
+	for (i = 0; i < data->count; i++)
+		marshal_TPMT_HA(buffer, &data->digests[i], buffer_space);
+}
+
+static void marshal_pcr_extend(void **buffer,
+			       struct tpm2_pcr_extend_cmd *command_body,
+			       int *buffer_space)
+{
+	struct tpm2_session_header session_header;
+
+	tpm_tag = TPM_ST_SESSIONS;
+	marshal_TPM_HANDLE(buffer, command_body->pcrHandle, buffer_space);
+	memset(&session_header, 0, sizeof(session_header));
+	session_header.session_handle = TPM_RS_PW;
+	marshal_session_header(buffer, &session_header, buffer_space);
+	marshal_TPML_DIGEST_VALUES(buffer, &command_body->digests, buffer_space);
+}
+
 int tpm_marshal_command(TPM_CC command, void *tpm_command_body,
 			void *buffer, int buffer_size)
 {
@@ -740,6 +783,10 @@
 		marshal_shutdown(&cmd_body, tpm_command_body, &body_size);
 		break;
 
+	case TPM2_PCR_Extend:
+		marshal_pcr_extend(&cmd_body, tpm_command_body, &body_size);
+		break;
+
 	default:
 		body_size = -1;
 		VB2_DEBUG("Request to marshal unsupported command %#x\n",
@@ -811,6 +858,7 @@
 	case TPM2_Shutdown:
 	case TPM2_NV_DefineSpace:
 	case TPM2_NV_UndefineSpace:
+	case TPM2_PCR_Extend:
 		/* Session data included in response can be safely ignored. */
 		cr_size = 0;
 		break;
diff --git a/firmware/lib/tpm2_lite/tlcl.c b/firmware/lib/tpm2_lite/tlcl.c
index e4695d1..b91119b 100644
--- a/firmware/lib/tpm2_lite/tlcl.c
+++ b/firmware/lib/tpm2_lite/tlcl.c
@@ -314,8 +314,15 @@
 
 uint32_t TlclExtend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
 {
-	VB2_DEBUG("NOT YET IMPLEMENTED\n");
-	return TPM_SUCCESS;
+	struct tpm2_pcr_extend_cmd pcr_ext_cmd;
+
+	pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
+	pcr_ext_cmd.digests.count = 1;
+	pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
+	memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
+	       sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
+
+	return tpm_get_response_code(TPM2_PCR_Extend, &pcr_ext_cmd);
 }
 
 
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index e2d1431..93de040 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -15,18 +15,17 @@
 #include "2sysincludes.h"
 #include "2ui.h"
 #include "load_kernel_fw.h"
-#include "vb2_common.h"
 #include "vboot_api.h"
 #include "vboot_kernel.h"
 #include "vboot_struct.h"
 #include "vboot_test.h"
 
 /* Global variables */
-static LoadKernelParams lkp;
+static VbSelectAndLoadKernelParams lkp;
 
 #ifdef CHROMEOS_ENVIRONMENT
 /* Global variable accessor for unit tests */
-struct LoadKernelParams *VbApiKernelGetParams(void)
+struct VbSelectAndLoadKernelParams *VbApiKernelGetParams(void)
 {
 	return &lkp;
 }
@@ -54,8 +53,18 @@
 	return VB2_SUCCESS;
 }
 
+static int is_valid_disk(VbDiskInfo *info, uint32_t disk_flags)
+{
+	return info->bytes_per_lba >= 512 &&
+		(info->bytes_per_lba & (info->bytes_per_lba - 1)) == 0 &&
+		info->lba_count >= 16 &&
+		(info->flags & disk_flags & VB_DISK_FLAG_SELECT_MASK) &&
+		((info->flags & VB_DISK_FLAG_SELECT_MASK) &
+		 ((info->flags & VB_DISK_FLAG_SELECT_MASK) - 1)) == 0;
+}
+
 test_mockable
-vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t get_info_flags)
+vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags)
 {
 	vb2_error_t rv = VB2_ERROR_LK_NO_DISK_FOUND;
 	VbDiskInfo* disk_info = NULL;
@@ -65,26 +74,14 @@
 	lkp.disk_handle = NULL;
 
 	/* Find disks */
-	if (VB2_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
-					   get_info_flags))
+	if (VB2_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count, disk_flags))
 		disk_count = 0;
 
 	/* Loop over disks */
 	for (i = 0; i < disk_count; i++) {
 		VB2_DEBUG("trying disk %d\n", (int)i);
-		/*
-		 * Validity-check what we can. FWIW, VbTryLoadKernel() is always
-		 * called with only a single bit set in get_info_flags.
-		 *
-		 * Ensure that we got a partition with only the flags we asked
-		 * for.
-		 */
-		if (disk_info[i].bytes_per_lba < 512 ||
-			(disk_info[i].bytes_per_lba &
-				(disk_info[i].bytes_per_lba  - 1)) != 0 ||
-					16 > disk_info[i].lba_count ||
-					get_info_flags != (disk_info[i].flags &
-					~VB_DISK_FLAG_EXTERNAL_GPT)) {
+
+		if (!is_valid_disk(&disk_info[i], disk_flags)) {
 			VB2_DEBUG("  skipping: bytes_per_lba=%" PRIu64
 				  " lba_count=%" PRIu64 " flags=%#x\n",
 				  disk_info[i].bytes_per_lba,
@@ -92,20 +89,14 @@
 				  disk_info[i].flags);
 			continue;
 		}
-		lkp.disk_handle = disk_info[i].handle;
-		lkp.bytes_per_lba = disk_info[i].bytes_per_lba;
-		lkp.gpt_lba_count = disk_info[i].lba_count;
-		lkp.streaming_lba_count = disk_info[i].streaming_lba_count
-						?: lkp.gpt_lba_count;
-		lkp.boot_flags |= disk_info[i].flags & VB_DISK_FLAG_EXTERNAL_GPT
-				? BOOT_FLAG_EXTERNAL_GPT : 0;
 
-		vb2_error_t new_rv = LoadKernel(ctx, &lkp);
+		lkp.disk_handle = disk_info[i].handle;
+		vb2_error_t new_rv = LoadKernel(ctx, &lkp, &disk_info[i]);
 		VB2_DEBUG("LoadKernel() = %#x\n", new_rv);
 
 		/* Stop now if we found a kernel. */
 		if (VB2_SUCCESS == new_rv) {
-			VbExDiskFreeInfo(disk_info, lkp.disk_handle);
+			VbExDiskFreeInfo(disk_info, disk_info[i].handle);
 			return VB2_SUCCESS;
 		}
 
@@ -115,7 +106,8 @@
 	}
 
 	/* If we drop out of the loop, we didn't find any usable kernel. */
-	if (get_info_flags & VB_DISK_FLAG_FIXED) {
+	if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE) &&
+	    !(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE)) {
 		switch (rv) {
 		case VB2_ERROR_LK_INVALID_KERNEL_FOUND:
 			vb2api_fail(ctx, VB2_RECOVERY_RW_INVALID_OS, rv);
@@ -236,7 +228,13 @@
 			VB2_TRY(vb2_broken_recovery_menu(ctx));
 	} else if (DIAGNOSTIC_UI && vb2api_diagnostic_ui_enabled(ctx) &&
 		   vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) {
+		/*
+		 * Need to clear the request flag and commit nvdata changes
+		 * immediately to avoid booting back into diagnostic tool when a
+		 * forced system reset occurs.
+		 */
 		vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 0);
+		vb2ex_commit_data(ctx);
 
 		/* Diagnostic boot.  This has UI. */
 		VB2_TRY(vb2_diagnostic_menu(ctx));
diff --git a/firmware/lib/vboot_audio.c b/firmware/lib/vboot_audio.c
deleted file mode 100644
index c2c599b..0000000
--- a/firmware/lib/vboot_audio.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Delay/beep functions used in dev-mode kernel selection.
- */
-
-#include "2api.h"
-#include "2common.h"
-#include "2misc.h"
-#include "2sysincludes.h"
-#include "vboot_api.h"
-#include "vboot_audio.h"
-
-int audio_open_count = 0;	/* Times audio has been opened */
-static int audio_use_short;	/* Use short delay? */
-static uint32_t open_time;	/* Time of last open */
-static int beep_count;		/* Number of beeps so far */
-
-/**
- * Initialization function.
- */
-void vb2_audio_start(struct vb2_context *ctx)
-{
-	open_time = vb2ex_mtime(); /* "zero" starts now */
-	beep_count = 0;
-
-	if (vb2api_use_short_dev_screen_delay(ctx) &&
-	    (audio_open_count++ == 0)) {
-		VB2_DEBUG("vb2_audio_start() - using short dev screen delay\n");
-		audio_use_short = 1;
-	} else {
-		audio_use_short = 0;
-	}
-}
-
-/**
- * Caller should loop without extra delay until this returns false.
- */
-int vb2_audio_looping(void)
-{
-	uint32_t now = vb2ex_mtime() - open_time;
-
-	/* If we're using short delay, wait 2 seconds and don't beep */
-	if (audio_use_short)
-		return now < 2 * VB2_MSEC_PER_SEC;
-
-	/* Otherwise, beep at 20 and 20.5 seconds */
-	if ((beep_count == 0 && now > 20 * VB2_MSEC_PER_SEC) ||
-	    (beep_count == 1 && now > 20 * VB2_MSEC_PER_SEC + 500)) {
-		vb2ex_beep(250, 400);
-		beep_count++;
-	}
-
-	/* Stop after 30 seconds */
-	return (now < 30 * VB2_MSEC_PER_SEC);
-}
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 6a0b0f3..05458b0 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -9,64 +9,68 @@
 #include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
-#include "2rsa.h"
-#include "2sha.h"
+#include "2packed_key.h"
 #include "2secdata.h"
 #include "2sysincludes.h"
 #include "cgptlib.h"
 #include "cgptlib_internal.h"
 #include "gpt_misc.h"
 #include "load_kernel_fw.h"
-#include "vb2_common.h"
 #include "vboot_api.h"
-#include "vboot_kernel.h"
-#include "vboot_struct.h"
 
 #define LOWEST_TPM_VERSION 0xffffffff
 
-enum vboot_mode {
-	kBootRecovery = 0,  /* Recovery firmware, any dev switch position */
-	kBootNormal = 1,    /* Normal boot - kernel must be verified */
-	kBootDev = 2        /* Developer boot - self-signed kernel ok */
+enum vb2_boot_mode {
+	/* Normal boot: kernel must be verified. */
+	VB2_BOOT_MODE_NORMAL = 0,
+
+	/* Recovery boot, regardless of dev mode state. */
+	VB2_BOOT_MODE_RECOVERY = 1,
+
+	/* Developer boot: self-signed kernel okay. */
+	VB2_BOOT_MODE_DEVELOPER = 2,
 };
 
 /**
- * Return the boot mode based on the parameters.
+ * Return the current boot mode (normal, recovery, or dev).
  *
- * @param params	Load kernel parameters
- * @return The current boot mode.
+ * @param ctx          Vboot context
+ * @return Current boot mode (see vb2_boot_mode enum).
  */
-static enum vboot_mode get_kernel_boot_mode(struct vb2_context *ctx)
+static enum vb2_boot_mode get_boot_mode(struct vb2_context *ctx)
 {
 	if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
-		return kBootRecovery;
+		return VB2_BOOT_MODE_RECOVERY;
 
 	if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE)
-		return kBootDev;
+		return VB2_BOOT_MODE_DEVELOPER;
 
-	return kBootNormal;
-};
+	return VB2_BOOT_MODE_NORMAL;
+}
 
 /**
- * Check if the parameters require an officially signed OS.
+ * Check if a valid keyblock is required.
  *
- * @param params	Load kernel parameters
- * @return 1 if official OS required; 0 if self-signed kernels are ok
+ * @param ctx		Vboot context
+ * @return 1 if valid keyblock required (officially signed kernel);
+ *         0 if valid hash is enough (self-signed kernel).
  */
-static int require_official_os(struct vb2_context *ctx,
-			       const LoadKernelParams *params)
+static int need_valid_keyblock(struct vb2_context *ctx)
 {
 	/* Normal and recovery modes always require official OS */
-	if (get_kernel_boot_mode(ctx) != kBootDev)
+	if (get_boot_mode(ctx) != VB2_BOOT_MODE_DEVELOPER)
 		return 1;
 
-	/* FWMP can require developer mode to use official OS */
+	/* FWMP can require developer mode to use signed kernels */
 	if (vb2_secdata_fwmp_get_flag(
 		ctx, VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY))
 		return 1;
 
-	/* Developer can request official OS via nvstorage */
-	return vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY);
+	/* Developers may require signed kernels */
+	if (vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY))
+		return 1;
+
+	return 0;
 }
 
 /**
@@ -111,53 +115,109 @@
 }
 
 /**
+ * Verify developer mode key hash.
+ *
+ * @param ctx		Vboot context
+ * @param keyblock	Keyblock to verify
+ * @return VB2_SUCCESS, or non-zero error code.
+ */
+static vb2_error_t vb2_verify_kernel_dev_key_hash(
+	struct vb2_context *ctx, struct vb2_keyblock *keyblock)
+{
+	struct vb2_packed_key *key = &keyblock->data_key;
+	uint8_t *buf = ((uint8_t *)key) + key->key_offset;
+	uint32_t buflen = key->key_size;
+	uint8_t digest[VB2_SHA256_DIGEST_SIZE];
+
+	VB2_DEBUG("Checking developer key hash.\n");
+	VB2_TRY(vb2_digest_buffer(buf, buflen, VB2_HASH_SHA256, digest,
+				  sizeof(digest)));
+
+	uint8_t *fwmp_dev_key_hash =
+		vb2_secdata_fwmp_get_dev_key_hash(ctx);
+	if (fwmp_dev_key_hash == NULL) {
+		VB2_DEBUG("Couldn't retrieve developer key hash.\n");
+		return VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH;
+	}
+
+	if (vb2_safe_memcmp(digest, fwmp_dev_key_hash,
+			    VB2_SHA256_DIGEST_SIZE)) {
+		int i;
+
+		VB2_DEBUG("Wrong developer key hash.\n");
+		VB2_DEBUG("Want: ");
+		for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++)
+			VB2_DEBUG_RAW("%02x ", fwmp_dev_key_hash[i]);
+		VB2_DEBUG_RAW("\n");
+		VB2_DEBUG("Got:  ");
+		for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++)
+			VB2_DEBUG_RAW("%02x ", digest[i]);
+		VB2_DEBUG_RAW("\n");
+
+		return VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH;
+	}
+
+	return VB2_SUCCESS;
+}
+
+/**
  * Verify a kernel vblock.
  *
  * @param kbuf		Buffer containing the vblock
  * @param kbuf_size	Size of the buffer in bytes
- * @param kernel_subkey	Packed kernel subkey to use in validating keyblock
- * @param params	Load kernel parameters
- * @param min_version	Minimum kernel version
- * @param shpart	Destination for verification results
  * @param wb		Work buffer.  Must be at least
  *			VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES bytes.
  * @return VB2_SUCCESS, or non-zero error code.
  */
 static vb2_error_t vb2_verify_kernel_vblock(
 	struct vb2_context *ctx, uint8_t *kbuf, uint32_t kbuf_size,
-	const struct vb2_packed_key *kernel_subkey,
-	const LoadKernelParams *params, uint32_t min_version,
-	VbSharedDataKernelPart *shpart, struct vb2_workbuf *wb)
+	struct vb2_workbuf *wb)
 {
-	/* Unpack kernel subkey */
-	struct vb2_public_key kernel_subkey2;
-	if (VB2_SUCCESS != vb2_unpack_key(&kernel_subkey2, kernel_subkey)) {
-		VB2_DEBUG("Unable to unpack kernel subkey\n");
-		return VB2_ERROR_VBLOCK_KERNEL_SUBKEY;
-	}
+	struct vb2_shared_data *sd = vb2_get_sd(ctx);
+
+	uint8_t *key_data;
+	uint32_t key_size;
+	struct vb2_public_key kernel_key;
+
+	int need_keyblock_valid = need_valid_keyblock(ctx);
+	int keyblock_valid = 1;  /* Assume valid */
+
+	vb2_error_t rv;
+
+	/* Locate key to verify kernel.  This will either be a recovery key, or
+	   a kernel subkey passed from firmware verification. */
+	key_data = vb2_member_of(sd, sd->kernel_key_offset);
+	key_size = sd->kernel_key_size;
+	VB2_TRY(vb2_unpack_key_buffer(&kernel_key, key_data, key_size));
+
+	if (vb2_hwcrypto_allowed(ctx))
+		kernel_key.allow_hwcrypto = 1;
+
+	/*
+	 * Clear any previous keyblock-valid flag (for example, from a previous
+	 * kernel where the keyblock was signed but the preamble failed
+	 * verification).
+	 */
+	sd->flags &= ~VB2_SD_FLAG_KERNEL_SIGNED;
 
 	/* Verify the keyblock. */
-	int keyblock_valid = 1;  /* Assume valid */
 	struct vb2_keyblock *keyblock = get_keyblock(kbuf);
-	if (VB2_SUCCESS != vb2_verify_keyblock(keyblock, kbuf_size,
-					       &kernel_subkey2, wb)) {
+	rv = vb2_verify_keyblock(keyblock, kbuf_size, &kernel_key, wb);
+	if (rv) {
 		VB2_DEBUG("Verifying keyblock signature failed.\n");
-		shpart->check_result = VBSD_LKP_CHECK_KEYBLOCK_SIG;
 		keyblock_valid = 0;
 
 		/* Check if we must have an officially signed kernel */
-		if (require_official_os(ctx, params)) {
+		if (need_keyblock_valid) {
 			VB2_DEBUG("Self-signed kernels not enabled.\n");
-			shpart->check_result = VBSD_LKP_CHECK_SELF_SIGNED;
-			return VB2_ERROR_VBLOCK_SELF_SIGNED;
+			return rv;
 		}
 
 		/* Otherwise, allow the kernel if the keyblock hash is valid */
-		if (VB2_SUCCESS !=
-		    vb2_verify_keyblock_hash(keyblock, kbuf_size, wb)) {
+		rv = vb2_verify_keyblock_hash(keyblock, kbuf_size, wb);
+		if (rv) {
 			VB2_DEBUG("Verifying keyblock hash failed.\n");
-			shpart->check_result = VBSD_LKP_CHECK_KEYBLOCK_HASH;
-			return VB2_ERROR_VBLOCK_KEYBLOCK_HASH;
+			return rv;
 		}
 	}
 
@@ -167,126 +227,97 @@
 	       VB2_KEYBLOCK_FLAG_DEVELOPER_1 :
 	       VB2_KEYBLOCK_FLAG_DEVELOPER_0))) {
 		VB2_DEBUG("Keyblock developer flag mismatch.\n");
-		shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
 		keyblock_valid = 0;
+		if (need_keyblock_valid)
+			return VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG;
 	}
 	if (!(keyblock->keyblock_flags &
 	      ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE) ?
 	       VB2_KEYBLOCK_FLAG_RECOVERY_1 :
 	       VB2_KEYBLOCK_FLAG_RECOVERY_0))) {
 		VB2_DEBUG("Keyblock recovery flag mismatch.\n");
-		shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
 		keyblock_valid = 0;
+		if (need_keyblock_valid)
+			return VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG;
 	}
 
 	/* Check for rollback of key version except in recovery mode. */
-	enum vboot_mode boot_mode = get_kernel_boot_mode(ctx);
+	enum vb2_boot_mode boot_mode = get_boot_mode(ctx);
 	uint32_t key_version = keyblock->data_key.key_version;
-	if (kBootRecovery != boot_mode) {
-		if (key_version < (min_version >> 16)) {
-			VB2_DEBUG("Key version too old.\n");
-			shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
+	if (boot_mode != VB2_BOOT_MODE_RECOVERY) {
+		if (key_version < (sd->kernel_version_secdata >> 16)) {
 			keyblock_valid = 0;
+			if (need_keyblock_valid) {
+				VB2_DEBUG("Key version too old.\n");
+				return VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK;
+			}
 		}
-		if (key_version > 0xFFFF) {
+		if (key_version > VB2_MAX_KEY_VERSION) {
 			/*
 			 * Key version is stored in 16 bits in the TPM, so key
 			 * versions greater than 0xFFFF can't be stored
 			 * properly.
 			 */
 			VB2_DEBUG("Key version > 0xFFFF.\n");
-			shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
 			keyblock_valid = 0;
+			if (need_keyblock_valid)
+				return VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE;
 		}
 	}
 
-	/* If not in developer mode, keyblock required to be valid. */
-	if (kBootDev != boot_mode && !keyblock_valid) {
-		VB2_DEBUG("Keyblock is invalid.\n");
-		return VB2_ERROR_VBLOCK_KEYBLOCK;
-	}
-
-	/* If in developer mode and using key hash, check it */
-	if ((kBootDev == boot_mode) &&
+	/* If in developer mode and using key hash, check it. */
+	if (boot_mode == VB2_BOOT_MODE_DEVELOPER &&
 	    vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_USE_KEY_HASH)) {
-		struct vb2_packed_key *key = &keyblock->data_key;
-		uint8_t *buf = ((uint8_t *)key) + key->key_offset;
-		uint32_t buflen = key->key_size;
-		uint8_t digest[VB2_SHA256_DIGEST_SIZE];
-
-		VB2_DEBUG("Checking developer key hash.\n");
-		vb2_digest_buffer(buf, buflen, VB2_HASH_SHA256,
-				  digest, sizeof(digest));
-
-		uint8_t *fwmp_dev_key_hash =
-			vb2_secdata_fwmp_get_dev_key_hash(ctx);
-		if (fwmp_dev_key_hash == NULL) {
-			VB2_DEBUG("Couldn't retrieve developer key hash.\n");
-			return VB2_ERROR_VBLOCK_DEV_KEY_HASH;
-		}
-
-		if (0 != vb2_safe_memcmp(digest, fwmp_dev_key_hash,
-					 VB2_SHA256_DIGEST_SIZE)) {
-			int i;
-
-			VB2_DEBUG("Wrong developer key hash.\n");
-			VB2_DEBUG("Want: ");
-			for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++)
-				VB2_DEBUG("%02x", fwmp_dev_key_hash[i]);
-			VB2_DEBUG("\nGot:  ");
-			for (i = 0; i < VB2_SHA256_DIGEST_SIZE; i++)
-				VB2_DEBUG("%02x", digest[i]);
-			VB2_DEBUG("\n");
-
-			return VB2_ERROR_VBLOCK_DEV_KEY_HASH;
-		}
+		VB2_TRY(vb2_verify_kernel_dev_key_hash(ctx, keyblock));
 	}
 
+	/*
+	 * At this point, we've checked everything.  The kernel keyblock is at
+	 * least self-consistent, and has either a valid signature or a valid
+	 * hash.  Track if it had a valid signature (that is, would we have
+	 * been willing to boot it even if developer mode was off).
+	 */
+	if (keyblock_valid)
+		sd->flags |= VB2_SD_FLAG_KERNEL_SIGNED;
+
 	/* Get key for preamble verification from the keyblock. */
 	struct vb2_public_key data_key;
-	if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
+	rv = vb2_unpack_key(&data_key, &keyblock->data_key);
+	if (rv) {
 		VB2_DEBUG("Unable to unpack kernel data key\n");
-		shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
-		return VB2_ERROR_UNKNOWN;
+		return rv;
 	}
 
 	/* Verify the preamble, which follows the keyblock */
 	struct vb2_kernel_preamble *preamble = get_preamble(kbuf);
-	if (VB2_SUCCESS !=
-	    vb2_verify_kernel_preamble(preamble,
-				       kbuf_size - keyblock->keyblock_size,
-				       &data_key,
-				       wb)) {
+	rv = vb2_verify_kernel_preamble(preamble,
+					kbuf_size - keyblock->keyblock_size,
+					&data_key,
+					wb);
+	if (rv) {
 		VB2_DEBUG("Preamble verification failed.\n");
-		shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
-		return VB2_ERROR_UNKNOWN;
+		return rv;
 	}
 
 	/*
-	 * If the keyblock is valid and we're not in recovery mode, check for
-	 * rollback of the kernel version.
+	 * Kernel preamble version is the lower 16 bits of the composite
+	 * kernel version.
 	 */
-	uint32_t combined_version = (key_version << 16) |
-			(preamble->kernel_version & 0xFFFF);
-	shpart->combined_version = combined_version;
-	if (keyblock_valid && kBootRecovery != boot_mode) {
-		if (combined_version < min_version) {
-			VB2_DEBUG("Kernel version too low.\n");
-			shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK;
-			/*
-			 * If not in developer mode, kernel version
-			 * must be valid.
-			 */
-			if (kBootDev != boot_mode)
-				return VB2_ERROR_UNKNOWN;
-		}
+	if (preamble->kernel_version > VB2_MAX_PREAMBLE_VERSION)
+		return VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE;
+
+	/* Combine with the key version. */
+	sd->kernel_version = key_version << 16 | preamble->kernel_version;
+
+	/* If not in recovery mode, check for rollback of the kernel version. */
+	if (need_keyblock_valid &&
+	    boot_mode != VB2_BOOT_MODE_RECOVERY &&
+	    sd->kernel_version < sd->kernel_version_secdata) {
+		VB2_DEBUG("Kernel version too low.\n");
+		return VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK;
 	}
 
 	VB2_DEBUG("Kernel preamble is good.\n");
-	shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
-	if (keyblock_valid)
-		shpart->flags |= VBSD_LKP_FLAG_KEYBLOCK_VALID;
-
 	return VB2_SUCCESS;
 }
 
@@ -306,39 +337,32 @@
  *
  * @param ctx		Vboot context
  * @param stream	Stream to load kernel from
- * @param kernel_subkey	Key to use to verify vblock
  * @param flags		Flags (one or more of vb2_load_partition_flags)
  * @param params	Load-kernel parameters
- * @param min_version	Minimum kernel version from TPM
- * @param shpart	Destination for verification results
- * @param wb            Workbuf for data storage
  * @return VB2_SUCCESS, or non-zero error code.
  */
 static vb2_error_t vb2_load_partition(
-	struct vb2_context *ctx, VbExStream_t stream,
-	const struct vb2_packed_key *kernel_subkey, uint32_t flags,
-	LoadKernelParams *params, uint32_t min_version,
-	VbSharedDataKernelPart *shpart, struct vb2_workbuf *wb)
+	struct vb2_context *ctx, VbExStream_t stream, uint32_t flags,
+	VbSelectAndLoadKernelParams *params)
 {
 	uint32_t read_ms = 0, start_ts;
-	struct vb2_workbuf wblocal = *wb;
+	struct vb2_workbuf wb;
+
+	vb2_workbuf_from_ctx(ctx, &wb);
 
 	/* Allocate kernel header buffer in workbuf */
-	uint8_t *kbuf = vb2_workbuf_alloc(&wblocal, KBUF_SIZE);
+	uint8_t *kbuf = vb2_workbuf_alloc(&wb, KBUF_SIZE);
 	if (!kbuf)
 		return VB2_ERROR_LOAD_PARTITION_WORKBUF;
 
 	start_ts = vb2ex_mtime();
 	if (VbExStreamRead(stream, KBUF_SIZE, kbuf)) {
 		VB2_DEBUG("Unable to read start of partition.\n");
-		shpart->check_result = VBSD_LKP_CHECK_READ_START;
 		return VB2_ERROR_LOAD_PARTITION_READ_VBLOCK;
 	}
 	read_ms += vb2ex_mtime() - start_ts;
 
-	if (VB2_SUCCESS !=
-	    vb2_verify_kernel_vblock(ctx, kbuf, KBUF_SIZE, kernel_subkey,
-				     params, min_version, shpart, &wblocal)) {
+	if (vb2_verify_kernel_vblock(ctx, kbuf, KBUF_SIZE, &wb)) {
 		return VB2_ERROR_LOAD_PARTITION_VERIFY_VBLOCK;
 	}
 
@@ -357,7 +381,6 @@
 	 */
 	uint32_t body_offset = get_body_offset(kbuf);
 	if (body_offset > KBUF_SIZE) {
-		shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
 		VB2_DEBUG("Kernel body offset is %u > 64KB.\n", body_offset);
 		return VB2_ERROR_LOAD_PARTITION_BODY_OFFSET;
 	}
@@ -370,7 +393,6 @@
 		kernbuf_size = preamble->body_signature.data_size;
 	} else if (preamble->body_signature.data_size > kernbuf_size) {
 		VB2_DEBUG("Kernel body doesn't fit in memory.\n");
-		shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
 		return 	VB2_ERROR_LOAD_PARTITION_BODY_SIZE;
 	}
 
@@ -392,7 +414,6 @@
 	start_ts = vb2ex_mtime();
 	if (body_toread && VbExStreamRead(stream, body_toread, body_readptr)) {
 		VB2_DEBUG("Unable to read kernel data.\n");
-		shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
 		return VB2_ERROR_LOAD_PARTITION_READ_BODY;
 	}
 	read_ms += vb2ex_mtime() - start_ts;
@@ -405,24 +426,23 @@
 
 	/* Get key for preamble/data verification from the keyblock. */
 	struct vb2_public_key data_key;
-	if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
+	if (vb2_unpack_key(&data_key, &keyblock->data_key)) {
 		VB2_DEBUG("Unable to unpack kernel data key\n");
-		shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
 		return VB2_ERROR_LOAD_PARTITION_DATA_KEY;
 	}
 
+	if (vb2_hwcrypto_allowed(ctx))
+		data_key.allow_hwcrypto = 1;
+
 	/* Verify kernel data */
-	if (VB2_SUCCESS != vb2_verify_data(kernbuf, kernbuf_size,
-					   &preamble->body_signature,
-					   &data_key, &wblocal)) {
+	if (vb2_verify_data(kernbuf, kernbuf_size, &preamble->body_signature,
+			    &data_key, &wb)) {
 		VB2_DEBUG("Kernel data verification failed.\n");
-		shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
 		return VB2_ERROR_LOAD_PARTITION_VERIFY_BODY;
 	}
 
 	/* If we're still here, the kernel is valid */
 	VB2_DEBUG("Partition is good.\n");
-	shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
 
 	/* Save kernel data back to parameters */
 	params->bootloader_address = preamble->bootloader_address;
@@ -436,94 +456,57 @@
 	return VB2_SUCCESS;
 }
 
-vb2_error_t LoadKernel(struct vb2_context *ctx, LoadKernelParams *params)
+vb2_error_t LoadKernel(struct vb2_context *ctx,
+		       VbSelectAndLoadKernelParams *params,
+		       VbDiskInfo *disk_info)
 {
 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
-	struct vb2_workbuf wb;
-	VbSharedDataKernelCall shcall;
 	int found_partitions = 0;
 	uint32_t lowest_version = LOWEST_TPM_VERSION;
 	vb2_error_t rv;
 
-	vb2_workbuf_from_ctx(ctx, &wb);
-
 	/* Clear output params in case we fail */
 	params->partition_number = 0;
 	params->bootloader_address = 0;
 	params->bootloader_size = 0;
 	params->flags = 0;
 
-	/*
-	 * Set up tracking for this call.  This wraps around if called many
-	 * times, so we need to initialize the call entry each time.
-	 */
-	memset(&shcall, 0, sizeof(shcall));
-	shcall.boot_flags = (uint32_t)params->boot_flags;
-	shcall.boot_mode = get_kernel_boot_mode(ctx);
-	shcall.sector_size = (uint32_t)params->bytes_per_lba;
-	shcall.sector_count = params->streaming_lba_count;
-
-	/* Locate key to verify kernel.  This will either be a recovery key, or
-	   a kernel subkey passed from firmware verification. */
-	struct vb2_packed_key *kernel_subkey =
-		vb2_member_of(sd, sd->kernel_key_offset);
-
 	/* Read GPT data */
 	GptData gpt;
-	gpt.sector_bytes = (uint32_t)params->bytes_per_lba;
-	gpt.streaming_drive_sectors = params->streaming_lba_count;
-	gpt.gpt_drive_sectors = params->gpt_lba_count;
-	gpt.flags = params->boot_flags & BOOT_FLAG_EXTERNAL_GPT
+	gpt.sector_bytes = (uint32_t)disk_info->bytes_per_lba;
+	gpt.streaming_drive_sectors = disk_info->streaming_lba_count
+		?: disk_info->lba_count;
+	gpt.gpt_drive_sectors = disk_info->lba_count;
+	gpt.flags = disk_info->flags & VB_DISK_FLAG_EXTERNAL_GPT
 			? GPT_FLAG_EXTERNAL : 0;
-	if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
+	if (AllocAndReadGptData(disk_info->handle, &gpt)) {
 		VB2_DEBUG("Unable to read GPT data\n");
-		shcall.check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
 		goto gpt_done;
 	}
 
 	/* Initialize GPT library */
-	if (GPT_SUCCESS != GptInit(&gpt)) {
+	if (GptInit(&gpt)) {
 		VB2_DEBUG("Error parsing GPT\n");
-		shcall.check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
 		goto gpt_done;
 	}
 
 	/* Loop over candidate kernel partitions */
 	uint64_t part_start, part_size;
-	while (GPT_SUCCESS ==
-	       GptNextKernelEntry(&gpt, &part_start, &part_size)) {
+	while (GptNextKernelEntry(&gpt, &part_start, &part_size) ==
+	       GPT_SUCCESS) {
 
 		VB2_DEBUG("Found kernel entry at %"
 			  PRIu64 " size %" PRIu64 "\n",
 			  part_start, part_size);
 
-		/*
-		 * Set up tracking for this partition.  This wraps around if
-		 * called many times, so initialize the partition entry each
-		 * time.
-		 */
-		VbSharedDataKernelPart *shpart =
-				shcall.parts + (shcall.kernel_parts_found
-				& (VBSD_MAX_KERNEL_PARTS - 1));
-		memset(shpart, 0, sizeof(VbSharedDataKernelPart));
-		shpart->sector_start = part_start;
-		shpart->sector_count = part_size;
-		/*
-		 * TODO: GPT partitions start at 1, but cgptlib starts them at
-		 * 0.  Adjust here, until cgptlib is fixed.
-		 */
-		shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
-		shcall.kernel_parts_found++;
-
 		/* Found at least one kernel partition. */
 		found_partitions++;
 
 		/* Set up the stream */
 		VbExStream_t stream = NULL;
-		if (VbExStreamOpen(params->disk_handle,
+		if (VbExStreamOpen(disk_info->handle,
 				   part_start, part_size, &stream)) {
 			VB2_DEBUG("Partition error getting stream.\n");
-			shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
 			VB2_DEBUG("Marking kernel as invalid.\n");
 			GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
 			continue;
@@ -538,32 +521,22 @@
 			lpflags |= VB2_LOAD_PARTITION_VBLOCK_ONLY;
 		}
 
-		rv = vb2_load_partition(ctx,
-					stream,
-					kernel_subkey,
-					lpflags,
-					params,
-					sd->kernel_version,
-					shpart,
-					&wb);
+		rv = vb2_load_partition(ctx, stream, lpflags, params);
 		VbExStreamClose(stream);
 
-		if (rv != VB2_SUCCESS) {
+		if (rv) {
 			VB2_DEBUG("Marking kernel as invalid.\n");
 			GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
 			continue;
 		}
 
-		int keyblock_valid = (shpart->flags &
-				      VBSD_LKP_FLAG_KEYBLOCK_VALID);
-		if (keyblock_valid) {
-			sd->flags |= VB2_SD_FLAG_KERNEL_SIGNED;
-			/* Track lowest version from a valid header. */
-			if (lowest_version > shpart->combined_version)
-				lowest_version = shpart->combined_version;
+		int keyblock_valid = sd->flags & VB2_SD_FLAG_KERNEL_SIGNED;
+		/* Track lowest version from a valid header. */
+		if (keyblock_valid && lowest_version > sd->kernel_version) {
+			lowest_version = sd->kernel_version;
 		}
 		VB2_DEBUG("Keyblock valid: %d\n", keyblock_valid);
-		VB2_DEBUG("Combined version: %u\n", shpart->combined_version);
+		VB2_DEBUG("Combined version: %u\n", sd->kernel_version);
 
 		/*
 		 * If we're only looking at headers, we're done with this
@@ -599,7 +572,8 @@
 		 * non-officially-signed kernel, there's no rollback
 		 * protection, so we can stop at the first valid kernel.
 		 */
-		if (kBootRecovery == shcall.boot_mode || !keyblock_valid) {
+		if (get_boot_mode(ctx) == VB2_BOOT_MODE_RECOVERY ||
+		    !keyblock_valid) {
 			VB2_DEBUG("In recovery mode or dev-signed kernel\n");
 			break;
 		}
@@ -611,7 +585,7 @@
 		 * Otherwise, we'll check all the other headers to see if they
 		 * contain a newer key.
 		 */
-		if (shpart->combined_version == sd->kernel_version) {
+		if (sd->kernel_version == sd->kernel_version_secdata) {
 			VB2_DEBUG("Same kernel version\n");
 			break;
 		}
@@ -619,12 +593,11 @@
 
  gpt_done:
 	/* Write and free GPT data */
-	WriteAndFreeGptData(params->disk_handle, &gpt);
+	WriteAndFreeGptData(disk_info->handle, &gpt);
 
 	/* Handle finding a good partition */
 	if (params->partition_number > 0) {
 		VB2_DEBUG("Good partition %d\n", params->partition_number);
-		shcall.check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
 		/*
 		 * Validity check - only store a new TPM version if we found
 		 * one. If lowest_version is still at its initial value, we
@@ -632,19 +605,16 @@
 		 * just didn't look.
 		 */
 		if (lowest_version != LOWEST_TPM_VERSION &&
-		    lowest_version > sd->kernel_version)
+		    lowest_version > sd->kernel_version_secdata)
 			sd->kernel_version = lowest_version;
 
 		/* Success! */
 		rv = VB2_SUCCESS;
 	} else if (found_partitions > 0) {
-		shcall.check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS;
 		rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND;
 	} else {
-		shcall.check_result = VBSD_LKC_CHECK_NO_PARTITIONS;
 		rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
 	}
 
-	shcall.return_code = (uint8_t)rv;
 	return rv;
 }
diff --git a/firmware/lib20/api_kernel.c b/firmware/lib20/api_kernel.c
index 9ab8522..403e932 100644
--- a/firmware/lib20/api_kernel.c
+++ b/firmware/lib20/api_kernel.c
@@ -7,14 +7,13 @@
  */
 
 #include "2api.h"
+#include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
 #include "2rsa.h"
 #include "2secdata.h"
 #include "2sha.h"
 #include "2sysincludes.h"
-#include "vb2_common.h"
-#include "vboot_struct.h"
 
 vb2_error_t vb2api_load_kernel_vblock(struct vb2_context *ctx)
 {
diff --git a/firmware/lib20/include/vb2_common.h b/firmware/lib20/include/vb2_common.h
deleted file mode 100644
index 53a077f..0000000
--- a/firmware/lib20/include/vb2_common.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Common functions between firmware and kernel verified boot.
- */
-
-#ifndef VBOOT_REFERENCE_VB2_COMMON_H_
-#define VBOOT_REFERENCE_VB2_COMMON_H_
-
-#include "2api.h"
-#include "2common.h"
-#include "2return_codes.h"
-#include "2sha.h"
-#include "2struct.h"
-#include "2sysincludes.h"
-
-struct vb2_public_key;
-
-/**
- * Unpack a vboot1-format key buffer for use in verification
- *
- * The elements of the unpacked key will point into the source buffer, so don't
- * free the source buffer until you're done with the key.
- *
- * @param key		Destintion for unpacked key
- * @param buf		Source buffer containing packed key
- * @param size		Size of buffer in bytes
- * @return VB2_SUCCESS, or non-zero error code if error.
- */
-vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key,
-				  const uint8_t *buf, uint32_t size);
-
-/**
- * Unpack a vboot1-format key for use in verification
- *
- * The elements of the unpacked key will point into the source packed key, so
- * don't free the source until you're done with the public key.
- *
- * @param key		Destintion for unpacked key
- * @param packed_key	Source packed key
- * @param size		Size of buffer in bytes
- * @return VB2_SUCCESS, or non-zero error code if error.
- */
-vb2_error_t vb2_unpack_key(struct vb2_public_key *key,
-			   const struct vb2_packed_key *packed_key);
-
-/**
- * Verify a keyblock using its hash.
- *
- * Header fields are also checked for validity. Does not verify key index or key
- * block flags.  Use this for self-signed keyblocks in developer mode.
- *
- * @param block		Keyblock to verify
- * @param size		Size of keyblock buffer
- * @param key		Key to use to verify block
- * @param wb		Work buffer
- * @return VB2_SUCCESS, or non-zero error code if error.
- */
-vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
-				     uint32_t size,
-				     const struct vb2_workbuf *wb);
-
-/**
- * Check the validity of a kernel preamble using a public key.
- *
- * The signature in the preamble is destroyed during the check.
- *
- * @param preamble     	Preamble to verify
- * @param size		Size of preamble buffer
- * @param key		Key to use to verify preamble
- * @param wb		Work buffer
- * @return VB2_SUCCESS, or non-zero error code if error.
- */
-vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
-				       uint32_t size,
-				       const struct vb2_public_key *key,
-				       const struct vb2_workbuf *wb);
-
-/**
- * Retrieve the 16-bit vmlinuz header address and size from the preamble.
- *
- * Size 0 means there is no 16-bit vmlinuz header present.  Old preamble
- * versions (<2.1) return 0 for both fields.
- *
- * @param preamble	Preamble to check
- * @param vmlinuz_header_address	Destination for header address
- * @param vmlinuz_header_size		Destination for header size
- */
-void vb2_kernel_get_vmlinuz_header(const struct vb2_kernel_preamble *preamble,
-				   uint64_t *vmlinuz_header_address,
-				   uint32_t *vmlinuz_header_size);
-
-/**
- * Get the flags for the kernel preamble.
- *
- * @param preamble	Preamble to check
- * @return Flags for the preamble.  Old preamble versions (<2.2) return 0.
- */
-uint32_t vb2_kernel_get_flags(const struct vb2_kernel_preamble *preamble);
-
-#endif  /* VBOOT_REFERENCE_VB2_COMMON_H_ */
diff --git a/firmware/lib20/kernel.c b/firmware/lib20/kernel.c
index 298b14f..81ded65 100644
--- a/firmware/lib20/kernel.c
+++ b/firmware/lib20/kernel.c
@@ -12,7 +12,6 @@
 #include "2secdata.h"
 #include "2sha.h"
 #include "2sysincludes.h"
-#include "vb2_common.h"
 
 /**
  * Returns non-zero if the kernel needs to have a valid signature, instead of
@@ -35,49 +34,6 @@
 	return 0;
 }
 
-test_mockable
-vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
-				     uint32_t size,
-				     const struct vb2_workbuf *wb)
-{
-	const struct vb2_signature *sig = &block->keyblock_hash;
-	struct vb2_workbuf wblocal = *wb;
-	struct vb2_digest_context *dc;
-	uint8_t *digest;
-	uint32_t digest_size;
-
-	/* Validity check keyblock before attempting hash check of data */
-	VB2_TRY(vb2_check_keyblock(block, size, sig));
-
-	VB2_DEBUG("Checking keyblock hash...\n");
-
-	/* Digest goes at start of work buffer */
-	digest_size = vb2_digest_size(VB2_HASH_SHA512);
-	digest = vb2_workbuf_alloc(&wblocal, digest_size);
-	if (!digest)
-		return VB2_ERROR_VDATA_WORKBUF_DIGEST;
-
-	/* Hashing requires temp space for the context */
-	dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
-	if (!dc)
-		return VB2_ERROR_VDATA_WORKBUF_HASHING;
-
-	VB2_TRY(vb2_digest_init(dc, VB2_HASH_SHA512));
-
-	VB2_TRY(vb2_digest_extend(dc, (const uint8_t *)block, sig->data_size));
-
-	VB2_TRY(vb2_digest_finalize(dc, digest, digest_size));
-
-	if (vb2_safe_memcmp(vb2_signature_data(sig), digest,
-			    digest_size) != 0) {
-		VB2_DEBUG("Invalid keyblock hash.\n");
-		return VB2_ERROR_KEYBLOCK_SIG_INVALID;
-	}
-
-	/* Success */
-	return VB2_SUCCESS;
-}
-
 vb2_error_t vb2_load_kernel_keyblock(struct vb2_context *ctx)
 {
 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
@@ -223,115 +179,6 @@
 	return VB2_SUCCESS;
 }
 
-test_mockable
-vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
-				       uint32_t size,
-				       const struct vb2_public_key *key,
-				       const struct vb2_workbuf *wb)
-{
-	struct vb2_signature *sig = &preamble->preamble_signature;
-	uint32_t min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_0_SIZE;
-
-	VB2_DEBUG("Verifying kernel preamble.\n");
-
-	/* Make sure it's even safe to look at the struct */
-	if(size < min_size) {
-		VB2_DEBUG("Not enough data for preamble header.\n");
-		return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
-	}
-	if (preamble->header_version_major !=
-	    VB2_KERNEL_PREAMBLE_HEADER_VERSION_MAJOR) {
-		VB2_DEBUG("Incompatible kernel preamble header version.\n");
-		return VB2_ERROR_PREAMBLE_HEADER_VERSION;
-	}
-
-	if (preamble->header_version_minor >= 2)
-		min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_2_SIZE;
-	else if (preamble->header_version_minor == 1)
-		min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_1_SIZE;
-	if(preamble->preamble_size < min_size) {
-		VB2_DEBUG("Preamble size too small for header.\n");
-		return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
-	}
-	if (size < preamble->preamble_size) {
-		VB2_DEBUG("Not enough data for preamble.\n");
-		return VB2_ERROR_PREAMBLE_SIZE;
-	}
-
-	/* Check signature */
-	if (vb2_verify_signature_inside(preamble, preamble->preamble_size,
-					sig)) {
-		VB2_DEBUG("Preamble signature off end of preamble\n");
-		return VB2_ERROR_PREAMBLE_SIG_OUTSIDE;
-	}
-
-	/* Make sure advertised signature data sizes are valid. */
-	if (preamble->preamble_size < sig->data_size) {
-		VB2_DEBUG("Signature calculated past end of the block\n");
-		return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH;
-	}
-
-	if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) {
-		VB2_DEBUG("Preamble signature validation failed\n");
-		return VB2_ERROR_PREAMBLE_SIG_INVALID;
-	}
-
-	/* Verify we signed enough data */
-	if (sig->data_size < sizeof(struct vb2_fw_preamble)) {
-		VB2_DEBUG("Didn't sign enough data\n");
-		return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE;
-	}
-
-	/* Verify body signature is inside the signed data */
-	if (vb2_verify_signature_inside(preamble, sig->data_size,
-					&preamble->body_signature)) {
-		VB2_DEBUG("Body signature off end of preamble\n");
-		return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE;
-	}
-
-	/*
-	 * If bootloader is present, verify it's covered by the body
-	 * signature.
-	 */
-	if (preamble->bootloader_size) {
-		const void *body_ptr =
-			(const void *)(uintptr_t)preamble->body_load_address;
-		const void *bootloader_ptr =
-			(const void *)(uintptr_t)preamble->bootloader_address;
-		if (vb2_verify_member_inside(body_ptr,
-					     preamble->body_signature.data_size,
-					     bootloader_ptr,
-					     preamble->bootloader_size,
-					     0, 0)) {
-			VB2_DEBUG("Bootloader off end of signed data\n");
-			return VB2_ERROR_PREAMBLE_BOOTLOADER_OUTSIDE;
-		}
-	}
-
-	/*
-	 * If vmlinuz header is present, verify it's covered by the body
-	 * signature.
-	 */
-	if (preamble->header_version_minor >= 1 &&
-	    preamble->vmlinuz_header_size) {
-		const void *body_ptr =
-			(const void *)(uintptr_t)preamble->body_load_address;
-		const void *vmlinuz_header_ptr = (const void *)
-			(uintptr_t)preamble->vmlinuz_header_address;
-		if (vb2_verify_member_inside(body_ptr,
-					     preamble->body_signature.data_size,
-					     vmlinuz_header_ptr,
-					     preamble->vmlinuz_header_size,
-					     0, 0)) {
-			VB2_DEBUG("Vmlinuz header off end of signed data\n");
-			return VB2_ERROR_PREAMBLE_VMLINUZ_HEADER_OUTSIDE;
-		}
-	}
-
-	/* Success */
-	return VB2_SUCCESS;
-}
-
 vb2_error_t vb2_load_kernel_preamble(struct vb2_context *ctx)
 {
 	struct vb2_shared_data *sd = vb2_get_sd(ctx);
@@ -421,30 +268,3 @@
 
 	return VB2_SUCCESS;
 }
-
-void vb2_kernel_get_vmlinuz_header(const struct vb2_kernel_preamble *preamble,
-				   uint64_t *vmlinuz_header_address,
-				   uint32_t *vmlinuz_header_size)
-{
-	if (preamble->header_version_minor < 1) {
-		*vmlinuz_header_address = 0;
-		*vmlinuz_header_size = 0;
-	} else {
-		/*
-		 * Set header and size only if the preamble header version is >
-		 * 2.1 as they don't exist in version 2.0 (Note that we don't
-		 * need to check header_version_major; if that's not 2 then
-		 * vb2_verify_kernel_preamble() would have already failed.
-		 */
-		*vmlinuz_header_address = preamble->vmlinuz_header_address;
-		*vmlinuz_header_size = preamble->vmlinuz_header_size;
-	}
-}
-
-uint32_t vb2_kernel_get_flags(const struct vb2_kernel_preamble *preamble)
-{
-	if (preamble->header_version_minor < 2)
-		return 0;
-
-	return preamble->flags;
-}
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c
index fe1c13d..bc5f2fe 100644
--- a/firmware/stub/vboot_api_stub.c
+++ b/firmware/stub/vboot_api_stub.c
@@ -18,117 +18,26 @@
 #include "vboot_api.h"
 #include "vboot_test.h"
 
-void vb2ex_msleep(uint32_t msec)
-{
-}
-
-void vb2ex_beep(uint32_t msec, uint32_t frequency)
-{
-}
-
-uint32_t vb2ex_get_locale_count(void)
-{
-	return 0;
-}
-
-uint32_t vb2ex_get_bootloader_count(void)
-{
-	return 0;
-}
-
+__attribute__((weak))
 uint32_t VbExKeyboardRead(void)
 {
 	return 0;
 }
 
+__attribute__((weak))
 uint32_t VbExKeyboardReadWithFlags(uint32_t *flags_ptr)
 {
 	return 0;
 }
 
-int vb2ex_physical_presence_pressed(void)
-{
-	return 0;
-}
-
+__attribute__((weak))
 uint32_t VbExIsShutdownRequested(void)
 {
 	return 0;
 }
 
-int vb2ex_ec_trusted(void)
-{
-	return 1;
-}
-
-vb2_error_t vb2ex_ec_running_rw(int *in_rw)
-{
-	*in_rw = 0;
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_jump_to_rw(void)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_disable_jump(void)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_hash_image(enum vb2_firmware_selection select,
-				const uint8_t **hash, int *hash_size)
-{
-	static const uint8_t fake_hash[32] = {1, 2, 3, 4};
-
-	*hash = fake_hash;
-	*hash_size = sizeof(fake_hash);
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_get_expected_image_hash(enum vb2_firmware_selection select,
-					     const uint8_t **hash, int *hash_size)
-{
-	static const uint8_t fake_hash[32] = {1, 2, 3, 4};
-
-	*hash = fake_hash;
-	*hash_size = sizeof(fake_hash);
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_protect(enum vb2_firmware_selection select)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_vboot_done(struct vb2_context *ctx)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_ec_battery_cutoff(void)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_auxfw_check(enum vb2_auxfw_update_severity *severity)
-{
-	*severity = VB2_AUXFW_NO_UPDATE;
-	return VB2_SUCCESS;
-}
-
-vb2_error_t vb2ex_auxfw_update(void)
-{
-	return VB2_SUCCESS;
-}
-
-vb2_error_t VbExLegacy(enum VbAltFwIndex_t altfw_num)
+__attribute__((weak))
+vb2_error_t vb2ex_run_altfw(uint32_t altfw_id)
 {
 	return VB2_SUCCESS;
 }
diff --git a/firmware/stub/vboot_api_stub_disk.c b/firmware/stub/vboot_api_stub_disk.c
index 7dc413f..3244dc6 100644
--- a/firmware/stub/vboot_api_stub_disk.c
+++ b/firmware/stub/vboot_api_stub_disk.c
@@ -16,6 +16,7 @@
 #include "vboot_api.h"
 
 
+__attribute__((weak))
 vb2_error_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count,
 			    uint32_t disk_flags)
 {
@@ -25,6 +26,7 @@
 }
 
 
+__attribute__((weak))
 vb2_error_t VbExDiskFreeInfo(VbDiskInfo* infos_ptr,
 			     VbExDiskHandle_t preserve_handle)
 {
@@ -32,6 +34,7 @@
 }
 
 
+__attribute__((weak))
 vb2_error_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
 			 uint64_t lba_count, void* buffer)
 {
@@ -39,6 +42,7 @@
 }
 
 
+__attribute__((weak))
 vb2_error_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
 			  uint64_t lba_count, const void* buffer)
 {
diff --git a/firmware/stub/vboot_api_stub_init.c b/firmware/stub/vboot_api_stub_init.c
deleted file mode 100644
index bd5c0c2..0000000
--- a/firmware/stub/vboot_api_stub_init.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Stub implementations of firmware-provided API functions.
- */
-
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/time.h>
-
-#include "2common.h"
-#include "vboot_api.h"
-
-uint32_t vb2ex_mtime(void)
-{
-	struct timeval tv;
-	gettimeofday(&tv, NULL);
-	return tv.tv_sec * VB2_MSEC_PER_SEC + tv.tv_usec / VB2_USEC_PER_MSEC;
-}
-
-vb2_error_t vb2ex_commit_data(struct vb2_context *ctx)
-{
-	ctx->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
-	ctx->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
-	ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
-	return VB2_SUCCESS;
-}
diff --git a/firmware/stub/vboot_api_stub_stream.c b/firmware/stub/vboot_api_stub_stream.c
index ae0a674..68e7ec7 100644
--- a/firmware/stub/vboot_api_stub_stream.c
+++ b/firmware/stub/vboot_api_stub_stream.c
@@ -25,6 +25,7 @@
 	uint64_t sectors_left;
 };
 
+__attribute__((weak))
 vb2_error_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start,
 			   uint64_t lba_count, VbExStream_t *stream)
 {
@@ -45,6 +46,7 @@
 	return VB2_SUCCESS;
 }
 
+__attribute__((weak))
 vb2_error_t VbExStreamRead(VbExStream_t stream, uint32_t bytes, void *buffer)
 {
 	struct disk_stream *s = (struct disk_stream *)stream;
@@ -73,6 +75,7 @@
 	return VB2_SUCCESS;
 }
 
+__attribute__((weak))
 void VbExStreamClose(VbExStream_t stream)
 {
 	struct disk_stream *s = (struct disk_stream *)stream;
diff --git a/futility/cmd_create.c b/futility/cmd_create.c
index aca1d4c..16a3733 100644
--- a/futility/cmd_create.c
+++ b/futility/cmd_create.c
@@ -22,7 +22,6 @@
 #include "host_misc21.h"
 #include "openssl_compat.h"
 #include "util_misc.h"
-#include "vb2_common.h"
 #include "vboot_host.h"
 
 /* Command line options */
diff --git a/futility/cmd_gbb_utility.c b/futility/cmd_gbb_utility.c
index 2a76ecb..8f21eee 100644
--- a/futility/cmd_gbb_utility.c
+++ b/futility/cmd_gbb_utility.c
@@ -29,7 +29,6 @@
 		"     --hwid          \tReport hardware id (default).\n"
 		"     --flags         \tReport header flags.\n"
 		"     --digest        \tReport digest of hwid (>= v1.2)\n"
-	        "     --roothash      \tCheck ryu root key hash\n"
 		" -k, --rootkey=FILE  \tFile name to export Root Key.\n"
 		" -b, --bmpfv=FILE    \tFile name to export Bitmap FV.\n"
 		" -r  --recoverykey=FILE\tFile name to export Recovery Key.\n"
@@ -61,7 +60,6 @@
 	OPT_FLAGS,
 	OPT_DIGEST,
 	OPT_HELP,
-	OPT_ROOTHASH,
 };
 
 /* Command line options */
@@ -78,7 +76,6 @@
 	{"flags", 0, NULL, OPT_FLAGS},
 	{"digest", 0, NULL, OPT_DIGEST},
 	{"help", 0, NULL, OPT_HELP},
-	{"roothash", 0, NULL, OPT_ROOTHASH},
 	{NULL, 0, NULL, 0},
 };
 
@@ -367,7 +364,6 @@
 	int sel_hwid = 0;
 	int sel_digest = 0;
 	int sel_flags = 0;
-	int sel_roothash = 0;
 	uint8_t *inbuf = NULL;
 	off_t filesize;
 	uint8_t *outbuf = NULL;
@@ -417,9 +413,6 @@
 		case OPT_DIGEST:
 			sel_digest = 1;
 			break;
-		case OPT_ROOTHASH:
-			sel_roothash = 1;
-			break;
 		case OPT_HELP:
 			print_help(argc, argv);
 			return !!errorcnt;
@@ -498,9 +491,6 @@
 		if (sel_digest)
 			print_hwid_digest(gbb, "digest: ", "\n");
 
-		if (sel_roothash)
-			verify_ryu_root_header(inbuf, filesize, gbb);
-
 		if (sel_flags)
 			printf("flags: 0x%08x\n", gbb->flags);
 		if (opt_rootkey)
@@ -606,9 +596,6 @@
 			read_from_file("root_key", opt_rootkey,
 				       gbb_base + gbb->rootkey_offset,
 				       gbb->rootkey_size);
-
-			if (fill_ryu_root_header(outbuf, filesize, gbb))
-				errorcnt++;
 		}
 		if (opt_bmpfv)
 			read_from_file("bmp_fv", opt_bmpfv,
diff --git a/futility/cmd_show.c b/futility/cmd_show.c
index f3b9163..716b2b2 100644
--- a/futility/cmd_show.c
+++ b/futility/cmd_show.c
@@ -31,7 +31,6 @@
 #include "host_key21.h"
 #include "util_misc.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /* Options */
 struct show_option_s show_option = {
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index 6243e3a..9bfa7fd 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -29,7 +29,6 @@
 #include "kernel_blob.h"
 #include "util_misc.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /* Options */
 struct sign_option_s sign_option = {
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index 3d99664..57fa083 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -31,6 +31,7 @@
 	OPT_QUIRKS_LIST,
 	OPT_REPACK,
 	OPT_SERVO,
+	OPT_SERVO_NORESET,
 	OPT_SERVO_PORT,
 	OPT_SIGNATURE,
 	OPT_SYS_PROPS,
@@ -54,6 +55,7 @@
 
 	{"ccd", 0, NULL, OPT_CCD},
 	{"servo", 0, NULL, OPT_SERVO},
+	{"servo_noreset", 0, NULL, OPT_SERVO_NORESET},
 	{"servo_port", 1, NULL, OPT_SERVO_PORT},
 	{"emulate", 1, NULL, OPT_EMULATE},
 	{"factory", 0, NULL, OPT_FACTORY},
@@ -130,6 +132,7 @@
 		"    --gbb_flags=FLAG\tOverride new GBB flags\n"
 		"    --ccd           \tDo fast,force,wp=0,p=raiden_debug_spi\n"
 		"    --servo         \tFlash using Servo (v2, v4, micro, ...)\n"
+		"    --servo_noreset \tLike servo but with 'custom_rst=true'\n"
 		"    --servo_port=PRT\tOverride servod port, implies --servo\n"
 		"    --signature_id=S\tOverride signature ID for key files\n"
 		"    --sys_props=LIST\tList of system properties to override\n"
@@ -139,12 +142,29 @@
 		argv[0]);
 }
 
+static char *add_servo_noreset(char *programmer)
+{
+	char *ret;
+
+	if (strstr(programmer, "raiden_debug_spi:target=AP") == NULL) {
+		ERROR("servo_noreset only works for AP flashing over CCD.\n");
+		free(programmer);
+
+		return NULL;
+	}
+
+	ASPRINTF(&ret, "%s,custom_rst=true", programmer);
+	free(programmer);
+
+	return ret;
+}
+
 static int do_update(int argc, char *argv[])
 {
 	struct updater_config *cfg;
 	struct updater_config_arguments args = {0};
 	int i, errorcnt = 0, do_update = 1;
-	int detect_servo = 0, do_servo_cpu_fw_spi = 0;
+	int detect_servo = 0, do_servo_cpu_fw_spi = 0, servo_noreset = 0;
 	char *servo_programmer = NULL;
 	char *endptr;
 
@@ -255,6 +275,14 @@
 			args.host_only = 1;
 			detect_servo = 1;
 			break;
+		case OPT_SERVO_NORESET:
+			args.fast_update = 1;
+			args.force_update = 1;
+			args.write_protection = "0";
+			args.host_only = 1;
+			detect_servo = 1;
+			servo_noreset = 1;
+			break;
 		case OPT_SERVO_PORT:
 			setenv(ENV_SERVOD_PORT, optarg, 1);
 			args.fast_update = 1;
@@ -289,6 +317,10 @@
 
 	if (!errorcnt && detect_servo) {
 		servo_programmer = host_detect_servo(&do_servo_cpu_fw_spi);
+
+		if (servo_programmer && servo_noreset)
+			servo_programmer = add_servo_noreset(servo_programmer);
+
 		if (!servo_programmer)
 			errorcnt++;
 		else if (!args.programmer)
diff --git a/futility/cmd_vbutil_firmware.c b/futility/cmd_vbutil_firmware.c
index 7659ed2..b7155f7 100644
--- a/futility/cmd_vbutil_firmware.c
+++ b/futility/cmd_vbutil_firmware.c
@@ -22,7 +22,6 @@
 #include "kernel_blob.h"
 #include "util_misc.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /* Command line options */
 enum {
diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c
index 83a76f8..7268bee 100644
--- a/futility/cmd_vbutil_kernel.c
+++ b/futility/cmd_vbutil_kernel.c
@@ -9,7 +9,7 @@
 #include <fcntl.h>
 #include <getopt.h>
 #include <inttypes.h>		/* For PRIu64 */
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <linux/fs.h>		/* For BLKGETSIZE64 */
 #endif
 #include <stdarg.h>
@@ -26,7 +26,6 @@
 #include "host_common.h"
 #include "kernel_blob.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /* Global opts */
 static int opt_verbose;
@@ -173,7 +172,7 @@
 		FATAL("Unable to stat %s: %s\n", filename, strerror(errno));
 
 	if (S_ISBLK(statbuf.st_mode)) {
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 		int fd = open(filename, O_RDONLY);
 		if (fd >= 0) {
 			ioctl(fd, BLKGETSIZE64, &file_size);
diff --git a/futility/cmd_vbutil_key.c b/futility/cmd_vbutil_key.c
index 0d81254..d26df3f 100644
--- a/futility/cmd_vbutil_key.c
+++ b/futility/cmd_vbutil_key.c
@@ -17,7 +17,6 @@
 #include "host_key21.h"
 #include "util_misc.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /* Command line options */
 enum {
diff --git a/futility/cmd_vbutil_keyblock.c b/futility/cmd_vbutil_keyblock.c
index 977b4aa..bec23c3 100644
--- a/futility/cmd_vbutil_keyblock.c
+++ b/futility/cmd_vbutil_keyblock.c
@@ -19,7 +19,6 @@
 #include "host_key21.h"
 #include "util_misc.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /* Command line options */
 enum {
diff --git a/futility/dump_kernel_config_lib.c b/futility/dump_kernel_config_lib.c
index 4240e5e..ff39c41 100644
--- a/futility/dump_kernel_config_lib.c
+++ b/futility/dump_kernel_config_lib.c
@@ -10,7 +10,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
-#if !defined (__FreeBSD__)
+#if !defined (__FreeBSD__) && !defined(__OpenBSD__)
 #include <sys/sysmacros.h>
 #endif
 #include <sys/types.h>
@@ -125,7 +125,7 @@
 	char *newstr = NULL;
 
 	int fd = open(infile, O_RDONLY | O_CLOEXEC
-#if !defined(__FreeBSD__)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
 			| O_LARGEFILE
 #endif
 			);
diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c
index 7e805f5..fe0b223 100644
--- a/futility/file_type_bios.c
+++ b/futility/file_type_bios.c
@@ -16,7 +16,6 @@
 #include "futility_options.h"
 #include "host_common.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 static const char * const fmap_name[] = {
 	"GBB",					/* BIOS_FMAP_GBB */
diff --git a/futility/futility.h b/futility/futility.h
index 881189c..1f34713 100644
--- a/futility/futility.h
+++ b/futility/futility.h
@@ -116,14 +116,6 @@
 /* Copies a file or dies with an error message */
 void futil_copy_file_or_die(const char *infile, const char *outfile);
 
-/* Update ryu root key header in the image */
-int fill_ryu_root_header(uint8_t *ptr, size_t size,
-			 const struct vb2_gbb_header *gbb);
-
-/* Verify ryu root key header */
-int verify_ryu_root_header(uint8_t *ptr, size_t size,
-			   const struct vb2_gbb_header *gbb);
-
 /* Possible file operation errors */
 enum futil_file_err {
 	FILE_ERR_NONE,
diff --git a/futility/misc.c b/futility/misc.c
index 0c8a0e7..f3e7748 100644
--- a/futility/misc.c
+++ b/futility/misc.c
@@ -5,7 +5,7 @@
 
 #include <assert.h>
 #include <errno.h>
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <linux/fs.h>		/* For BLKGETSIZE64 */
 #endif
 #include <stdarg.h>
@@ -272,7 +272,7 @@
 		return FILE_ERR_STAT;
 	}
 
-#if !defined(HAVE_MACOS) && !defined(__FreeBSD__)
+#if !defined(HAVE_MACOS) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
 	if (S_ISBLK(sb.st_mode))
 		ioctl(fd, BLKGETSIZE64, &sb.st_size);
 #endif
diff --git a/futility/ryu_root_header.c b/futility/ryu_root_header.c
deleted file mode 100644
index ef00531..0000000
--- a/futility/ryu_root_header.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/* Copyright 2015 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <errno.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "2common.h"
-#include "2sha.h"
-#include "2sysincludes.h"
-#include "futility.h"
-
-#define SEARCH_STRIDE 4
-
-/**
- * Check if the pointer contains the magic string.  We need to use a
- * case-swapped version, so that the actual magic string doesn't appear in the
- * code, to avoid falsely finding it when searching for the struct.
- */
-static int is_magic(const void *ptr)
-{
-	const char magic_inv[RYU_ROOT_KEY_HASH_MAGIC_SIZE] =
-		RYU_ROOT_KEY_HASH_MAGIC_INVCASE;
-	const char *magic = ptr;
-	int i;
-
-	for (i = 0; i < RYU_ROOT_KEY_HASH_MAGIC_SIZE; i++) {
-		if (magic[i] != (magic_inv[i] ^ 0x20))
-			return 0;
-	}
-
-	return 1;
-}
-
-static int valid_ryu_root_header(struct vb2_ryu_root_key_hash *hash,
-				 size_t size)
-{
-	if (!is_magic(hash->magic))
-		return 0;  /* Wrong magic */
-
-	if (hash->header_version_major != RYU_ROOT_KEY_HASH_VERSION_MAJOR)
-		return 0;  /* Version we can't parse */
-
-	if (hash->struct_size < EXPECTED_VB2_RYU_ROOT_KEY_HASH_SIZE)
-		return 0;  /* Header too small */
-
-	if (hash->struct_size > size)
-		return 0;  /* Claimed size doesn't fit in buffer */
-
-	return 1;
-}
-
-/**
- * Find the root key hash struct and return it or NULL if error.
- */
-static struct vb2_ryu_root_key_hash *find_ryu_root_header(uint8_t *ptr,
-							  size_t size)
-{
-	size_t i;
-	struct vb2_ryu_root_key_hash *tmp, *hash = NULL;
-	int count = 0;
-
-	/* Look for the ryu root key hash header */
-	for (i = 0; i <= size - SEARCH_STRIDE; i += SEARCH_STRIDE) {
-		if (!is_magic(ptr + i))
-			continue;
-
-		/* Found something. See if it's any good. */
-		tmp = (struct vb2_ryu_root_key_hash *) (ptr + i);
-		if (valid_ryu_root_header(tmp, size - i))
-			if (!count++)
-				hash = tmp;
-	}
-
-	switch (count) {
-	case 0:
-		return NULL;
-	case 1:
-		return hash;
-	default:
-		fprintf(stderr,
-			"WARNING: multiple ryu root hash headers found\n");
-		/* But hey, it's only a warning.  Use the first one. */
-		return hash;
-	}
-}
-
-static void calculate_root_key_hash(uint8_t *digest, size_t digest_size,
-				    const struct vb2_gbb_header *gbb)
-{
-	const uint8_t *gbb_base = (const uint8_t *)gbb;
-
-	vb2_digest_buffer(gbb_base + gbb->rootkey_offset,
-			  gbb->rootkey_size,
-			  VB2_HASH_SHA256,
-			  digest,
-			  digest_size);
-}
-
-int fill_ryu_root_header(uint8_t *ptr, size_t size,
-			 const struct vb2_gbb_header *gbb)
-{
-	struct vb2_ryu_root_key_hash *hash;
-
-	/*
-	 * Find the ryu root header.  If not found, nothing we can do, but
-	 * that's ok because most images don't have the header.
-	 */
-	hash = find_ryu_root_header(ptr, size);
-	if (!hash)
-		return 0;
-
-	/* Update the hash stored in the header based on the root key */
-	calculate_root_key_hash(hash->root_key_hash_digest,
-				sizeof(hash->root_key_hash_digest),
-				gbb);
-
-	printf(" - calculate ryu root hash: success\n");
-	return 0;
-}
-
-int verify_ryu_root_header(uint8_t *ptr, size_t size,
-			   const struct vb2_gbb_header *gbb)
-{
-	uint8_t digest[VB2_SHA256_DIGEST_SIZE] = {0};
-
-	struct vb2_ryu_root_key_hash *hash;
-
-	/*
-	 * Find the ryu root header.  If not found, nothing we can do, but
-	 * that's ok because most images don't have the header.
-	 */
-	hash = find_ryu_root_header(ptr, size);
-	if (!hash) {
-		printf(" - ryu root hash not found\n");
-		return 0;
-	}
-
-	/* Check for all 0's, which means hash hasn't been set */
-	if (0 == memcmp(digest, hash->root_key_hash_digest, sizeof(digest))) {
-		printf(" - ryu root hash is unset\n");
-		return 0;
-	}
-
-	/* Update the hash stored in the header based on the root key */
-	calculate_root_key_hash(digest, sizeof(digest), gbb);
-
-	if (0 == memcmp(digest, hash->root_key_hash_digest, sizeof(digest))) {
-		printf(" - ryu root hash verified\n");
-		return 0;
-	} else {
-		printf(" - ryu root hash does not verify\n");
-		return -1;
-	}
-}
diff --git a/futility/updater.c b/futility/updater.c
index fa00854..87ac6fd 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -14,7 +14,6 @@
 #include "host_misc.h"
 #include "updater.h"
 #include "util_misc.h"
-#include "vb2_common.h"
 
 #define REMOVE_WP_URL "https://goo.gl/ces83U"
 
diff --git a/futility/updater_archive.c b/futility/updater_archive.c
index 218499e..4ad5287 100644
--- a/futility/updater_archive.c
+++ b/futility/updater_archive.c
@@ -8,6 +8,9 @@
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
+#if defined(__OpenBSD__)
+#include <sys/types.h>
+#endif
 #include <fts.h>
 #include <string.h>
 #include <stdio.h>
@@ -30,7 +33,6 @@
 #include "host_misc.h"
 #include "updater.h"
 #include "util_misc.h"
-#include "vb2_common.h"
 
 /*
  * A firmware update package (archive) is a file packed by either shar(1) or
@@ -1058,16 +1060,16 @@
 		return;
 	if (load_firmware_image(&image, fpath, archive))
 		return;
-	if (is_host)
-		gbb = find_gbb(&image);
-	else
+	if (!is_host)
 		printf(",\n");
 	printf("%*s\"%s\": { \"versions\": { \"ro\": \"%s\", \"rw\": \"%s\" },",
 	       indent, "", name, image.ro_version, image.rw_version_a);
 	indent += 2;
-	if (is_host && patch_image_by_model(&image, m, archive) != 0) {
+	if (!is_host) {
+		/* No extra information to be printed */
+        } else if (patch_image_by_model(&image, m, archive) != 0) {
 		ERROR("Failed to patch images by model: %s\n", m->name);
-	} else if (gbb) {
+	} else if (NULL != (gbb = find_gbb(&image))) {
 		printf("\n%*s\"keys\": { \"root\": \"%s\", ",
 		       indent, "",
 		       get_gbb_key_hash(gbb, gbb->rootkey_offset,
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c
index b9bdb2c..1d1ba62 100644
--- a/futility/updater_quirks.c
+++ b/futility/updater_quirks.c
@@ -46,7 +46,7 @@
 
 	{ .match = "Google_Poppy.", .quirks = "min_platform_version=6" },
 	{ .match = "Google_Scarlet.", .quirks = "min_platform_version=1" },
-	{ .match = "Google_Trogdor.", .quirks = "min_platform_version=1" },
+	{ .match = "Google_Trogdor.", .quirks = "min_platform_version=2" },
 
         /* Legacy white label units. */
         { .match = "Google_Enguarde.", .quirks = "allow_empty_wltag" },
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index a441e03..70ed396 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -10,7 +10,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#if defined (__FreeBSD__)
+#if defined (__FreeBSD__) || defined(__OpenBSD__)
 #include <sys/wait.h>
 #endif
 
@@ -681,7 +681,7 @@
 				diff_image, tempfiles);
 		if (!tmp_diff)
 			return -1;
-		ASPRINTF(&extra, "--noverify --diff=%s", tmp_diff);
+		ASPRINTF(&extra, "--noverify --flash-contents=%s", tmp_diff);
 	}
 
 	r = host_flashrom(FLASHROM_WRITE, tmp_path, programmer, verbosity,
diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c
index ecb193b..39bb16a 100644
--- a/futility/vb1_helper.c
+++ b/futility/vb1_helper.c
@@ -21,7 +21,6 @@
 #include "kernel_blob.h"
 #include "util_misc.h"
 #include "vb1_helper.h"
-#include "vb2_common.h"
 
 /****************************************************************************/
 /* Here are globals containing all the bits & pieces I'm working on.
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c
index 6a8f5a2..e805e2a 100644
--- a/host/arch/x86/lib/crossystem_arch.c
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -7,7 +7,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#if !defined(__FreeBSD__)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
 #include <linux/nvram.h>
 #include <linux/version.h>
 #endif
@@ -100,7 +100,7 @@
 
 static void VbFixCmosChecksum(FILE* file)
 {
-#if !defined(__FreeBSD__)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
 	int fd = fileno(file);
 	ioctl(fd, NVRAM_SETCKS);
 #endif
@@ -666,7 +666,7 @@
 
 	if (uname(&host) == 0) {
 		if (sscanf(host.release, "%u.%u.", &maj, &min) == 2) {
-#if !defined(__FreeBSD__)
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
 			if (KERNEL_VERSION(maj, min, 0) >= KERNEL_VERSION(4, 16, 0) &&
 			    *offset > 11)
 				*offset += 3;
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index bb10c39..9d23091 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -25,8 +25,14 @@
 #define KERNEL_CMDLINE_PATH "/proc/cmdline"
 
 /* Filename for the mount-encrypted key */
+/* TODO(b/174807059): Remove this after we land driver-level TPM simulator on
+ * all VM boards */
 #define MOUNT_ENCRYPTED_KEY_PATH "/mnt/stateful_partition/encrypted.key"
 
+/* Filename for the TPM simulator NV data */
+#define TPM_SIMULATOR_NVCHIP_PATH \
+	"/mnt/stateful_partition/unencrypted/tpm2-simulator/NVChip"
+
 /* Fields that GetVdatString() can get */
 typedef enum VdatStringField {
 	VDAT_STRING_DEPRECATED_TIMERS = 0,  /* Timer values */
@@ -63,7 +69,7 @@
 } VbBuildOption;
 
 static const char *fw_results[] = {"unknown", "trying", "success", "failure"};
-static const char *default_boot[] = {"disk", "usb", "legacy"};
+static const char *default_boot[] = {"disk", "usb", "altfw"};
 
 /* Masks for kern_nv usage by kernel. */
 #define KERN_NV_FWUPDATE_TRIES_MASK 0x000F
@@ -374,7 +380,10 @@
 	} else if (!strcasecmp(name,"disable_dev_request")) {
 		value = vb2_get_nv_storage(VB2_NV_DISABLE_DEV_REQUEST);
 	} else if (!strcasecmp(name,"clear_tpm_owner_request")) {
-		if (TPM2_SIMULATOR)
+		if (TPM2_SIMULATOR && VTPM_PROXY)
+			/* Check TPM simulator NVChip status */
+			value = access(TPM_SIMULATOR_NVCHIP_PATH, F_OK) != 0;
+		else if (TPM2_SIMULATOR)
 			/* Check mount-encrypted key status */
 			value = access(MOUNT_ENCRYPTED_KEY_PATH, F_OK) != 0;
 		else
@@ -411,8 +420,9 @@
 		value = vb2_get_nv_storage(VB2_NV_BACKUP_NVRAM_REQUEST);
 	} else if (!strcasecmp(name,"dev_boot_usb")) {
 		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_EXTERNAL);
-	} else if (!strcasecmp(name,"dev_boot_legacy")) {
-		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_LEGACY);
+	} else if (!strcasecmp(name,"dev_boot_altfw") ||
+		   !strcasecmp(name,"dev_boot_legacy")) {
+		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_ALTFW);
 	} else if (!strcasecmp(name,"dev_boot_signed_only")) {
 		value = vb2_get_nv_storage(VB2_NV_DEV_BOOT_SIGNED_ONLY);
 	} else if (!strcasecmp(name,"dev_enable_udc")) {
@@ -556,12 +566,13 @@
 			 * on simulator */
 			if (value == 0)
 				return -1;
-			/* Check mount-encrypted key status */
-			if (!access(MOUNT_ENCRYPTED_KEY_PATH, F_OK)) {
-				/* Remove the mount_encrypted key, and it would
-				 * also clear the TPM2.0 simulator NV space on
-				 * it. */
-				return remove(MOUNT_ENCRYPTED_KEY_PATH);
+			const char *tpm_path =
+				VTPM_PROXY ? TPM_SIMULATOR_NVCHIP_PATH
+					   : MOUNT_ENCRYPTED_KEY_PATH;
+			/* Check TPM simulator data status */
+			if (!access(tpm_path, F_OK)) {
+				/* Remove the TPM2.0 simulator data */
+				return remove(tpm_path);
 			} else {
 				/* Return success when the file is already
 				 * removed */
@@ -620,9 +631,10 @@
 	} else if (!strcasecmp(name,"dev_boot_usb")) {
 		return vb2_set_nv_storage_with_backup(
 			VB2_NV_DEV_BOOT_EXTERNAL, value);
-	} else if (!strcasecmp(name,"dev_boot_legacy")) {
+	} else if (!strcasecmp(name,"dev_boot_altfw") ||
+		   !strcasecmp(name,"dev_boot_legacy")) {
 		return vb2_set_nv_storage_with_backup(
-			VB2_NV_DEV_BOOT_LEGACY, value);
+			VB2_NV_DEV_BOOT_ALTFW, value);
 	} else if (!strcasecmp(name,"dev_boot_signed_only")) {
 		return vb2_set_nv_storage_with_backup(
 			VB2_NV_DEV_BOOT_SIGNED_ONLY, value);
@@ -671,6 +683,16 @@
 	} else if (!strcasecmp(name, "dev_default_boot")) {
 		int i;
 
+		/* "legacy" term deprecated in favour of "altfw"
+		   (see: b/179458327) */
+		if (!strcasecmp(value, "legacy")) {
+			fprintf(stderr,
+				"!!!\n"
+				"!!! PLEASE USE 'altfw' INSTEAD OF 'legacy'\n"
+				"!!!\n");
+			value = "altfw";
+		}
+
 		for (i = 0; i < ARRAY_SIZE(default_boot); i++) {
 			if (!strcasecmp(value, default_boot[i]))
 				return vb2_set_nv_storage(
diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c
index 62ab1bc..e83dfb2 100644
--- a/host/lib/flashrom.c
+++ b/host/lib/flashrom.c
@@ -155,7 +155,7 @@
 		FLASHROM_EXEC_NAME,
 		"-p",
 		programmer,
-		"--fast-verify",
+		"--noverify-all",
 		"-w",
 		region ? "-i" : tmpfile,
 		region ? region_param : NULL,
diff --git a/host/lib/host_common.c b/host/lib/host_common.c
index 63b45f2..82a5954 100644
--- a/host/lib/host_common.c
+++ b/host/lib/host_common.c
@@ -12,7 +12,6 @@
 #include "2sysincludes.h"
 #include "host_common.h"
 #include "host_key21.h"
-#include "vb2_common.h"
 
 struct vb2_fw_preamble *vb2_create_fw_preamble(
 	uint32_t firmware_version,
@@ -134,3 +133,22 @@
 	/* Return the header */
 	return h;
 }
+
+void vb2_kernel_get_vmlinuz_header(const struct vb2_kernel_preamble *preamble,
+				   uint64_t *vmlinuz_header_address,
+				   uint32_t *vmlinuz_header_size)
+{
+	if (preamble->header_version_minor < 1) {
+		*vmlinuz_header_address = 0;
+		*vmlinuz_header_size = 0;
+	} else {
+		/*
+		 * Set header and size only if the preamble header version is >
+		 * 2.1 as they don't exist in version 2.0 (Note that we don't
+		 * need to check header_version_major; if that's not 2 then
+		 * vb2_verify_kernel_preamble() would have already failed.
+		 */
+		*vmlinuz_header_address = preamble->vmlinuz_header_address;
+		*vmlinuz_header_size = preamble->vmlinuz_header_size;
+	}
+}
diff --git a/host/lib/host_key2.c b/host/lib/host_key2.c
index 913c6df..e2e3f31 100644
--- a/host/lib/host_key2.c
+++ b/host/lib/host_key2.c
@@ -19,7 +19,6 @@
 #include "host_key21.h"
 #include "host_key.h"
 #include "host_misc.h"
-#include "vb2_common.h"
 
 enum vb2_crypto_algorithm vb2_get_crypto_algorithm(
 	enum vb2_hash_algorithm hash_alg,
diff --git a/host/lib/host_keyblock.c b/host/lib/host_keyblock.c
index a7dbede..e5634ce 100644
--- a/host/lib/host_keyblock.c
+++ b/host/lib/host_keyblock.c
@@ -17,7 +17,6 @@
 #include "host_key21.h"
 #include "host_keyblock.h"
 #include "host_key.h"
-#include "vb2_common.h"
 
 struct vb2_keyblock *vb2_create_keyblock(
 		const struct vb2_packed_key *data_key,
diff --git a/host/lib/host_signature.c b/host/lib/host_signature.c
index db536c6..5b71d29 100644
--- a/host/lib/host_signature.c
+++ b/host/lib/host_signature.c
@@ -21,7 +21,6 @@
 #include "2sysincludes.h"
 #include "host_common.h"
 #include "host_signature21.h"
-#include "vb2_common.h"
 
 /* Invoke [external_signer] command with [pem_file] as an argument, contents of
  * [inbuf] passed redirected to stdin, and the stdout of the command is put
diff --git a/host/lib/host_signature2.c b/host/lib/host_signature2.c
index f7caa71..b6cd652 100644
--- a/host/lib/host_signature2.c
+++ b/host/lib/host_signature2.c
@@ -22,7 +22,6 @@
 #include "host_common.h"
 #include "host_key21.h"
 #include "host_signature21.h"
-#include "vb2_common.h"
 
 struct vb2_signature *vb2_alloc_signature(uint32_t sig_size,
 					  uint32_t data_size)
diff --git a/host/lib/include/host_common.h b/host/lib/include/host_common.h
index 55b15d3..a37a6c9 100644
--- a/host/lib/include/host_common.h
+++ b/host/lib/include/host_common.h
@@ -64,4 +64,18 @@
 	uint32_t desired_size,
 	const struct vb2_private_key *signing_key);
 
+/**
+ * Retrieve the 16-bit vmlinuz header address and size from the preamble.
+ *
+ * Size 0 means there is no 16-bit vmlinuz header present.  Old preamble
+ * versions (<2.1) return 0 for both fields.
+ *
+ * @param preamble	Preamble to check
+ * @param vmlinuz_header_address	Destination for header address
+ * @param vmlinuz_header_size		Destination for header size
+ */
+void vb2_kernel_get_vmlinuz_header(const struct vb2_kernel_preamble *preamble,
+				   uint64_t *vmlinuz_header_address,
+				   uint32_t *vmlinuz_header_size);
+
 #endif  /* VBOOT_REFERENCE_HOST_COMMON_H_ */
diff --git a/host/lib/util_misc.c b/host/lib/util_misc.c
index c99947f..26f7dac 100644
--- a/host/lib/util_misc.c
+++ b/host/lib/util_misc.c
@@ -20,7 +20,6 @@
 #include "host_key21.h"
 #include "openssl_compat.h"
 #include "util_misc.h"
-#include "vb2_common.h"
 
 const char *packed_key_sha1_string(const struct vb2_packed_key *key)
 {
diff --git a/scripts/image_signing/common.sh b/scripts/image_signing/common.sh
index 9541ca0..efa00a2 100644
--- a/scripts/image_signing/common.sh
+++ b/scripts/image_signing/common.sh
@@ -10,25 +10,6 @@
 . "$(dirname "$0")/common_minimal.sh"
 CROS_LOG_PREFIX="${PROG}: "
 
-# Array of actions that are executed during the clean up process.
-declare -a cleanup_actions
-
-# Adds an action to be executed during the clean up process.
-# Actions are executed in the reverse order of when they were added.
-# ARGS: ACTION
-add_cleanup_action() {
-  cleanup_actions[${#cleanup_actions[*]}]=$1
-}
-
-# Performs the latest clean up action and removes it from the list.
-perform_latest_cleanup_action() {
-  local num_actions=${#cleanup_actions[*]}
-  if [ "${num_actions}" -gt 0 ]; then
-    eval "${cleanup_actions[$num_actions-1]} || true" > /dev/null 2>&1
-    unset "cleanup_actions[$num_actions-1]"
-  fi
-}
-
 # Performs clean up by executing actions in the cleanup_actions array in
 # reversed order.
 cleanup() {
@@ -36,9 +17,8 @@
   rv=$?
   set +e
 
-  while [ ${#cleanup_actions[*]} -gt 0 ]; do
-    perform_latest_cleanup_action
-  done
+  cleanup_temps_and_mounts
+  cleanup_loopbacks
 
   set -e
   return $rv
@@ -158,6 +138,3 @@
 
 # This will override the trap set in common_minmal.sh
 trap "cleanup" INT TERM EXIT
-
-add_cleanup_action "cleanup_temps_and_mounts"
-add_cleanup_action "cleanup_loopbacks"
diff --git a/scripts/image_signing/ensure_no_nonrelease_files.sh b/scripts/image_signing/ensure_no_nonrelease_files.sh
index 48c75af..9e549ed 100755
--- a/scripts/image_signing/ensure_no_nonrelease_files.sh
+++ b/scripts/image_signing/ensure_no_nonrelease_files.sh
@@ -37,9 +37,14 @@
     # Either way, load test-expectations data from config.
     . "${configfile}" || return 1
 
-    local loopdev=$(loopback_partscan "${image}")
-    local rootfs=$(make_temp_dir)
-    mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+    local loopdev rootfs
+    if [[ -d "${image}" ]]; then
+        rootfs="${image}"
+    else
+        rootfs=$(make_temp_dir)
+        loopdev=$(loopback_partscan "${image}")
+        mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
+    fi
     # Pick the right set of test-expectation data to use.
     local brdvar=$(get_boardvar_from_lsb_release "${rootfs}")
     eval "release_file_blocklist=(\"\${RELEASE_FILE_BLOCKLIST_${brdvar}[@]}\")"
diff --git a/scripts/image_signing/ensure_not_ASAN.sh b/scripts/image_signing/ensure_not_ASAN.sh
index 16cc88c..f19b1dd 100755
--- a/scripts/image_signing/ensure_not_ASAN.sh
+++ b/scripts/image_signing/ensure_not_ASAN.sh
@@ -11,26 +11,31 @@
 . "$(dirname "$0")/common.sh"
 
 usage() {
-    echo "Usage $PROG image"
+  echo "Usage $PROG image"
 }
 
 main() {
-    if [ $# -ne 1 ]; then
-        usage
-        exit 1
-    fi
+  if [[ $# -ne 1 ]]; then
+    usage
+    exit 1
+  fi
 
-    local image="$1"
+  local image="$1"
 
-    local loopdev=$(loopback_partscan "${image}")
-    local rootfs=$(make_temp_dir)
+  local loopdev rootfs
+  if [[ -d "${image}" ]]; then
+    rootfs="${image}"
+  else
+    rootfs=$(make_temp_dir)
+    loopdev=$(loopback_partscan "${image}")
     mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+  fi
 
-    # This mirrors the check performed in the platform_ToolchainOptions
-    # autotest.
-    if readelf -s "$rootfs/opt/google/chrome/chrome" | \
-       grep -q __asan_init; then
-        exit 1
-    fi
+  # This mirrors the check performed in the platform_ToolchainOptions
+  # autotest.
+  if readelf -s "$rootfs/opt/google/chrome/chrome" | \
+     grep -q __asan_init; then
+    exit 1
+  fi
 }
 main "$@"
diff --git a/scripts/image_signing/ensure_not_tainted_license.sh b/scripts/image_signing/ensure_not_tainted_license.sh
index cd64049..7eab1c9 100755
--- a/scripts/image_signing/ensure_not_tainted_license.sh
+++ b/scripts/image_signing/ensure_not_tainted_license.sh
@@ -42,12 +42,16 @@
 
   license=$(find "${license_dir}" -name about_os_credits.html 2>/dev/null)
   if [[ -z "${license}" ]]; then
-    echo "License file about_os_credits.html not found in ${license_dir}"
-    exit 1
+    echo "License file about_os_credits.html not found in ${license_dir}."
+    echo "Skipping the check of tainted license."
+    exit 0
   fi
 
   tainted_tag="<!-- tainted -->"
-  tainted_status=$(grep "${tainted_tag}" "${license}")
+  # Add "|| :" to the grep command to prevent it from returning error code 1 if
+  # no match is found, which would cause the script to exit immediately with
+  # error code 1 due to set -e.
+  tainted_status=$(grep "${tainted_tag}" "${license}") || :
   if [[ -n "${tainted_status}" ]]; then
     echo "${license}:"
     echo "License file contains packages with LICENSE=TAINTED."
@@ -60,6 +64,7 @@
       /^[[:space:]]*$/d
       p
     }' "${license}"
+    exit 1
   fi
   exit 0
 }
diff --git a/scripts/image_signing/ensure_secure_kernelparams.sh b/scripts/image_signing/ensure_secure_kernelparams.sh
index 12bfbe5..b971ab4 100755
--- a/scripts/image_signing/ensure_secure_kernelparams.sh
+++ b/scripts/image_signing/ensure_secure_kernelparams.sh
@@ -100,9 +100,8 @@
     #                  which is the install kernel on the recovery image.
     #                  crosbug.com/24274
     local loop_kern="${loopdev}p4"
-    local loop_rootfs="${loopdev}p3"
     local rootfs=$(make_temp_dir)
-    sudo mount -o ro "${loop_rootfs}" "${rootfs}"
+    mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
 
     # Pick the right set of test-expectation data to use.
     local boardvar=$(get_boardvar_from_lsb_release "${rootfs}")
diff --git a/scripts/image_signing/ensure_update_verification.sh b/scripts/image_signing/ensure_update_verification.sh
index c72b0f6..e3929c5 100755
--- a/scripts/image_signing/ensure_update_verification.sh
+++ b/scripts/image_signing/ensure_update_verification.sh
@@ -23,10 +23,16 @@
   fi
 
   local image=$1
-  local loopdev=$(loopback_partscan "${image}")
-  local rootfs=$(make_temp_dir)
+
+  local loopdev rootfs
+  if [[ -d "${image}" ]]; then
+    rootfs="${image}"
+  else
+    rootfs=$(make_temp_dir)
+    loopdev=$(loopback_partscan "${image}")
+    mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+  fi
   local key_location="/usr/share/update_engine/update-payload-key.pub.pem"
-  mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
   if [ ! -e "$rootfs/$key_location" ]; then
     die "Update payload verification key not found at $key_location"
   fi
diff --git a/scripts/image_signing/gbb_flags_common.sh b/scripts/image_signing/gbb_flags_common.sh
index 100f37d..63c3f12 100755
--- a/scripts/image_signing/gbb_flags_common.sh
+++ b/scripts/image_signing/gbb_flags_common.sh
@@ -26,10 +26,10 @@
   VB2_GBB_FLAG_FORCE_DEV_BOOT_USB                0x00000010
   VB2_GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK         0x00000020
   VB2_GBB_FLAG_ENTER_TRIGGERS_TONORM             0x00000040
-  VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY             0x00000080
+  VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW              0x00000080
   VB2_GBB_FLAG_RUNNING_FAFT                      0x00000100
   VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC          0x00000200
-  VB2_GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY           0x00000400
+  VB2_GBB_FLAG_DEFAULT_DEV_BOOT_ALTFW            0x00000400
   VB2_GBB_FLAG_DISABLE_AUXFW_SOFTWARE_SYNC       0x00000800
   VB2_GBB_FLAG_DISABLE_LID_SHUTDOWN              0x00001000
   VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY             0x00004000
@@ -55,5 +55,5 @@
 }
 
 flashrom_write() {
-  flashrom -p host -i GBB --fast-verify -w "$@"
+  flashrom -p host -i GBB --noverify-all -w "$@"
 }
diff --git a/scripts/image_signing/insert_au_publickey.sh b/scripts/image_signing/insert_au_publickey.sh
index 9d1597d..fe0dbcc 100755
--- a/scripts/image_signing/insert_au_publickey.sh
+++ b/scripts/image_signing/insert_au_publickey.sh
@@ -21,10 +21,17 @@
 EOF
     exit 1
   fi
-  local loopdev=$(loopback_partscan "${image}")
-  local rootfs=$(make_temp_dir)
+
+  local loopdev rootfs
+  if [[ -d "${image}" ]]; then
+    rootfs="${image}"
+  else
+    rootfs=$(make_temp_dir)
+    loopdev=$(loopback_partscan "${image}")
+    mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
+  fi
+
   local key_location="/usr/share/update_engine/"
-  mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
   sudo mkdir -p "$rootfs/$key_location"
   sudo cp "$pub_key" "$rootfs/$key_location/update-payload-key.pub.pem"
   sudo chown root:root "$rootfs/$key_location/update-payload-key.pub.pem"
diff --git a/scripts/image_signing/set_channel.sh b/scripts/image_signing/set_channel.sh
index dc21246..d4e64ad 100755
--- a/scripts/image_signing/set_channel.sh
+++ b/scripts/image_signing/set_channel.sh
@@ -26,10 +26,14 @@
   local to=$2
   local loopdev rootfs lsb
 
-  loopdev=$(loopback_partscan "${image}")
-  rootfs=$(make_temp_dir)
+  if [[ -d "${image}" ]]; then
+    rootfs="${image}"
+  else
+    rootfs=$(make_temp_dir)
+    loopdev=$(loopback_partscan "${image}")
+    mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
+  fi
   lsb="${rootfs}/etc/lsb-release"
-  mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
   # Get the current channel on the image.
   local from=$(lsbval "${lsb}" 'CHROMEOS_RELEASE_TRACK')
   from=${from%"-channel"}
diff --git a/scripts/image_signing/set_lsb_release.sh b/scripts/image_signing/set_lsb_release.sh
index e847abb..55c1653 100755
--- a/scripts/image_signing/set_lsb_release.sh
+++ b/scripts/image_signing/set_lsb_release.sh
@@ -11,15 +11,17 @@
 
 set_lsb_release_keyval() {
   local rootfs=$1
+  local lsb="${rootfs}/etc/lsb-release"
   local key=$2
   local value=$3
-  local temp_lsb_release="$rootfs/etc/temp-lsb-release"
-  echo "$key=$value" | sudo tee "$temp_lsb_release" > /dev/null
-  grep -Ev "^$key=" "$rootfs/etc/lsb-release" \
-    | sudo tee -a "$temp_lsb_release" > /dev/null
-  sudo sort -o "$rootfs/etc/lsb-release" "$temp_lsb_release"
-  sudo rm -f "$temp_lsb_release"
-  restore_lsb_selinux "$rootfs/etc/lsb-release"
+  local data
+  data=$(
+    (
+    grep -Ev "^${key}=" "${lsb}"
+    echo "${key}=${value}"
+    ) | sort
+  )
+  sudo tee "${lsb}" <<<"${data}" >/dev/null
 }
 
 main() {
@@ -45,17 +47,25 @@
     exit 1
   fi
 
+  # If there are no key/value pairs to process, we don't need write access.
+  local ro=$([[ $# -eq 0 ]] && echo true || echo false)
+
   local image=$1
   shift
-  local loopdev=$(loopback_partscan "${image}")
-  local rootfs=$(make_temp_dir)
+  local loopdev rootfs
 
-  # If there are no key/value pairs to process, we don't need write access.
-  if [[ $# -eq 0 ]]; then
-    mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+  if [[ -d "${image}" ]]; then
+    rootfs="${image}"
   else
-    mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
-    touch "${image}"  # Updates the image modification time.
+    rootfs=$(make_temp_dir)
+    loopdev=$(loopback_partscan "${image}")
+
+    if ${ro}; then
+      mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+    else
+      mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
+      touch "${image}"  # Updates the image modification time.
+    fi
   fi
 
   # Process all the key/value pairs.
@@ -65,6 +75,9 @@
     shift 2
     set_lsb_release_keyval "${rootfs}" "${key}" "${value}"
   done
+  if ! ${ro}; then
+    restore_lsb_selinux "${rootfs}/etc/lsb-release"
+  fi
 
   # Dump the final state.
   cat "${rootfs}/etc/lsb-release"
diff --git a/scripts/image_signing/sign_gsc_firmware.sh b/scripts/image_signing/sign_gsc_firmware.sh
index 30e2795..af7b7da 100755
--- a/scripts/image_signing/sign_gsc_firmware.sh
+++ b/scripts/image_signing/sign_gsc_firmware.sh
@@ -25,7 +25,7 @@
 
 PRE_PVT_BID_FLAG=0x10
 MP_BID_FLAG=0x10000
-CR50_FACTORY_VERSION="0.3.22"
+CR50_NODE_LOCKED_VERSION="0.5.12"
 
 # Convert unsigned 32 bit value into a signed one.
 to_int32() {
@@ -151,9 +151,10 @@
 # that the manifest conforms to GSC version numbering and board ID flags
 # conventions for various build images:
 #
-# - only factory version binaries can be converted to node locked images,
-#   board IDs for node locked images come from signing instructions, and the
-#   config1 manifest field value must have the 0x80000000 bit set.
+# - only binaries where version is set to CR50_NODE_LOCKED_VERSION can be
+#   converted to node locked images. Board IDs for node locked images come
+#   from signing instructions, and the config1 manifest field value must have
+#   the 0x80000000 bit set.
 #
 # - when signing pre-pvt binaries (major version number is even) the 0x10
 #   flags bit must be set.
@@ -197,8 +198,9 @@
       if [[ -z ${INSN_DEVICE_ID:-} ]]; then
         die "Node locked target without Device ID value"
       fi
-      # Case of a node locked image, it must have the fixed factory version.
-      if [[ "${epoch}.${major}.${minor}" != "${CR50_FACTORY_VERSION}" ]];then
+      # Case of a node locked image, it must have the fixed version.
+      if [[ "${epoch}.${major}.${minor}" != "${CR50_NODE_LOCKED_VERSION}" ]]
+      then
         die "Won't create node locked images for version $epoch.$major.$minor"
       fi
 
@@ -492,6 +494,7 @@
   local output_file="$9"
   local generation="${10}"
   local temp_dir
+  local chip_name
 
   temp_dir="$(make_temp_dir)"
 
@@ -500,11 +503,13 @@
       # H1 flash size, image size must match.
       IMAGE_SIZE="$(( 512 * 1024 ))"
       IMAGE_BASE="0x40000"
+      chip_name="cr50"
       ;;
     (d)
       # D2 flash size, image size must match.
       IMAGE_SIZE="$(( 1024 * 1024 ))"
       IMAGE_BASE="0x80000"
+      chip_name="ti50"
       ;;
   esac
 
@@ -544,6 +549,9 @@
     paste_bin "${output_file}" "${bin}" "${IMAGE_BASE}" "${hex_base}"
   done
 
+  # Tell the signer how to rename the @CHIP@ portion of the output.
+  echo "${chip_name}" > "${output_file}.rename"
+
   info "Image successfully signed to ${output_file}"
 }
 
diff --git a/scripts/image_signing/tag_image.sh b/scripts/image_signing/tag_image.sh
index 8a01012..fb9492e 100755
--- a/scripts/image_signing/tag_image.sh
+++ b/scripts/image_signing/tag_image.sh
@@ -196,9 +196,13 @@
 fi
 
 # First round, mount as read-only and check if we need any modifications.
-loopdev=$(loopback_partscan "${IMAGE}")
-rootfs=$(make_temp_dir)
-mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+if [[ -d "${IMAGE}" ]]; then
+  rootfs="${IMAGE}"
+else
+  loopdev=$(loopback_partscan "${IMAGE}")
+  rootfs=$(make_temp_dir)
+  mount_loop_image_partition_ro "${loopdev}" 3 "${rootfs}"
+fi
 
 # we don't have tags in stateful partition yet...
 # stateful_dir=$(make_temp_dir)
@@ -210,8 +214,10 @@
 if [ ${g_modified} = ${FLAGS_TRUE} ]; then
   # Remount as RW.  We can't use `mount -o rw,remount` because of the bits in
   # the ext4 header we've set to block that.  See enable_rw_mount for details.
-  sudo umount "${rootfs}"
-  mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
+  if [[ ! -d "${IMAGE}" ]]; then
+    sudo umount "${rootfs}"
+    mount_loop_image_partition "${loopdev}" 3 "${rootfs}"
+  fi
 
   # second round, apply the modification to image.
   process_all_tags "${rootfs}" ${FLAGS_TRUE}
diff --git a/tests/devkeys/android/networkstack.pk8 b/tests/devkeys/android/networkstack.pk8
new file mode 100644
index 0000000..890d9d3
--- /dev/null
+++ b/tests/devkeys/android/networkstack.pk8
Binary files differ
diff --git a/tests/devkeys/android/networkstack.x509.pem b/tests/devkeys/android/networkstack.x509.pem
new file mode 100644
index 0000000..042c4e3
--- /dev/null
+++ b/tests/devkeys/android/networkstack.x509.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDxzCCAq+gAwIBAgIUcfGSt74kh+tpBdU4k71ijVm1/0cwDQYJKoZIhvcNAQEL
+BQAwdDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM
+DU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSBJbmMuMRAwDgYDVQQLDAdB
+bmRyb2lkMRAwDgYDVQQDDAdBbmRyb2lkMB4XDTIxMDQwNTIzMDk1NloXDTQ4MDgy
+MTIzMDk1NlowdDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAU
+BgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSBJbmMuMRAwDgYD
+VQQLDAdBbmRyb2lkMRAwDgYDVQQDDAdBbmRyb2lkMIIBIDANBgkqhkiG9w0BAQEF
+AAOCAQ0AMIIBCAKCAQEA0KHW5P5+dCq7OkVkGRmG0eYskcbgRK3DvTY7QPXCdnOm
+Fmq08S2l23mN1C+3+XMon0/Gh3DRr+lVLX3GZPoHX3e2ZTt8tu0Ee3k8T8VopfG9
+OpPlSzfazgI8sKtLe3wJ3RDalTlNd8Ne2YNRMY8RIkIwbySzUqkTixVk57NgMXpj
+tWmP19DOZPxXsGUa5m0qSS5/demnYAIoD+mg0Wd+xG2Y1ErT9O/j2l92ekm8+JKy
+jJ0W47el/mqO392JgNAEvcI9NbrnTaNi5Zq2PKhBhK0ohXOMyHUodUSmtBTWtW8n
+U+FK70ese+OzWQbjRryrmGYWB9ybc7YZ/FhH4US+rwIBA6NTMFEwHQYDVR0OBBYE
+FMGqz0YmVUA8iWBwLCMdoTFsidIiMB8GA1UdIwQYMBaAFMGqz0YmVUA8iWBwLCMd
+oTFsidIiMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKygSG3r
+7SHEb/nox88Pu31lxERrsjmNCtxJJMFlbf8sq1nWx59lmTLOW5sFKyWGH1Mf8f8O
+nXiZ6V+5obyAt05MJOBiSIGKBk21ds9r2ACCuFpJ+MAS3SNN7HlSfNvzRbGV3+gb
+V6FOH+2ndbqN3dkXUDctWXjNiq5QQlFFI4fIvvwiul45HZvDRrNRuexT1jzOlLVF
+Qe45E5QbJYVPMUe37kCVm1Ty3N+e/s2n1NsSHoD5BK+kvb+BPL3pK4dK62HzcdVp
+TB1EZFtrL8+aun1qhlEYNKlR/TNQdIPwZWH6ZmT7bF2GCfJcxshgWmajN/cW1rdc
+OEUdUtGkI9lgNiI=
+-----END CERTIFICATE-----
diff --git a/tests/vb20_api_kernel_tests.c b/tests/vb20_api_kernel_tests.c
index 676cb19..893cd4e 100644
--- a/tests/vb20_api_kernel_tests.c
+++ b/tests/vb20_api_kernel_tests.c
@@ -15,7 +15,6 @@
 #include "2secdata.h"
 #include "2sysincludes.h"
 #include "test_common.h"
-#include "vb2_common.h"
 #include "vboot_struct.h"
 
 /* Common context for tests */
diff --git a/tests/vb20_kernel_tests.c b/tests/vb20_kernel_tests.c
index 3f26549..8766114 100644
--- a/tests/vb20_kernel_tests.c
+++ b/tests/vb20_kernel_tests.c
@@ -15,7 +15,6 @@
 #include "2secdata.h"
 #include "2sysincludes.h"
 #include "test_common.h"
-#include "vb2_common.h"
 
 /* Common context for tests */
 static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
@@ -228,7 +227,7 @@
 	reset_common_data(FOR_KEYBLOCK);
 	mock_vblock.k.data_key_data[0] ^= 0xa0;
 	TEST_EQ(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
-		VB2_ERROR_KEYBLOCK_SIG_INVALID,
+		VB2_ERROR_KEYBLOCK_HASH_INVALID_IN_DEV_MODE,
 		"Keyblock check hash invalid");
 }
 
diff --git a/tests/vb20_rsa_padding_tests.c b/tests/vb20_rsa_padding_tests.c
index 03a38ee..90ff42a 100644
--- a/tests/vb20_rsa_padding_tests.c
+++ b/tests/vb20_rsa_padding_tests.c
@@ -6,13 +6,13 @@
 #include <stdint.h>
 #include <stdio.h>
 
+#include "2common.h"
 #include "2rsa.h"
 #include "2sysincludes.h"
 #include "file_keys.h"
 #include "host_key.h"
 #include "rsa_padding_test.h"
 #include "test_common.h"
-#include "vb2_common.h"
 
 vb2_error_t hwcrypto_modexp_return_value = VB2_SUCCESS;
 vb2_error_t vb2ex_hwcrypto_modexp(const struct vb2_public_key *key,
diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c
index 1fabb60..40fdf59 100644
--- a/tests/vb2_api_tests.c
+++ b/tests/vb2_api_tests.c
@@ -15,7 +15,6 @@
 #include "2secdata.h"
 #include "2sysincludes.h"
 #include "test_common.h"
-#include "vb2_common.h"
 
 /* Common context for tests */
 
diff --git a/tests/vb2_auxfw_sync_tests.c b/tests/vb2_auxfw_sync_tests.c
index f779ac0..48ce952 100644
--- a/tests/vb2_auxfw_sync_tests.c
+++ b/tests/vb2_auxfw_sync_tests.c
@@ -16,7 +16,6 @@
 #include "host_common.h"
 #include "load_kernel_fw.h"
 #include "test_common.h"
-#include "vboot_audio.h"
 #include "vboot_kernel.h"
 #include "vboot_struct.h"
 
diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c
index 89a560c..3f06289 100644
--- a/tests/vb2_common2_tests.c
+++ b/tests/vb2_common2_tests.c
@@ -9,36 +9,63 @@
 #include <stdio.h>
 #include <string.h>
 
+#include "2common.h"
 #include "2rsa.h"
 #include "2sysincludes.h"
 #include "file_keys.h"
 #include "host_common.h"
 #include "host_key21.h"
 #include "test_common.h"
-#include "vb2_common.h"
 
 static const uint8_t test_data[] = "This is some test data to sign.";
 static const uint32_t test_size = sizeof(test_data);
 
-static enum {
+static enum hwcrypto_state {
 	HWCRYPTO_OK,
 	HWCRYPTO_NOTSUPPORTED,
 	HWCRYPTO_ERROR,
-} hwcrypto_state;
+	HWCRYPTO_ABORT,
+} hwcrypto_state_rsa, hwcrypto_state_digest;
 
-vb2_error_t vb2ex_hwcrypto_rsa_verify_digest(const struct vb2_public_key *key,
-					     const uint8_t *sig, const uint8_t *digest)
+static vb2_error_t hwcrypto_mock(enum hwcrypto_state *state)
 {
-	switch (hwcrypto_state) {
+	switch (*state) {
 		case HWCRYPTO_OK:
 			return VB2_SUCCESS;
 		case HWCRYPTO_NOTSUPPORTED:
 			return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
 		case HWCRYPTO_ERROR:
-			return VB2_ERROR_RSA_VERIFY_DIGEST;
+			return VB2_ERROR_MOCK;
+		case HWCRYPTO_ABORT:
+			vb2ex_abort();
+			/* shouldn't reach here but added for compiler */
+			return VB2_ERROR_MOCK;
 	}
 }
 
+vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
+				       uint32_t data_size)
+{
+	return hwcrypto_mock(&hwcrypto_state_digest);
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
+{
+	return hwcrypto_mock(&hwcrypto_state_digest);
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest,
+					   uint32_t digest_size)
+{
+	return hwcrypto_mock(&hwcrypto_state_digest);
+}
+
+vb2_error_t vb2ex_hwcrypto_rsa_verify_digest(const struct vb2_public_key *key,
+					     const uint8_t *sig, const uint8_t *digest)
+{
+	return hwcrypto_mock(&hwcrypto_state_rsa);
+}
+
 
 static void test_unpack_key(const struct vb2_packed_key *key1)
 {
@@ -109,6 +136,9 @@
 	uint32_t sig_total_size = sig->sig_offset + sig->sig_size;
 	struct vb2_signature *sig2;
 
+	hwcrypto_state_rsa = HWCRYPTO_ABORT;
+	hwcrypto_state_digest = HWCRYPTO_ABORT;
+
 	vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
 
 	/* Allocate signature copy for tests */
@@ -155,18 +185,57 @@
 
 	pubk.allow_hwcrypto = 1;
 
-	hwcrypto_state = HWCRYPTO_OK;
+	hwcrypto_state_digest = HWCRYPTO_OK;
+	hwcrypto_state_rsa = HWCRYPTO_OK;
 	memcpy(sig2, sig, sig_total_size);
 	vb2_signature_data_mutable(sig2)[0] ^= 0x5A;
 	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
 		0, "vb2_verify_data() hwcrypto ok");
 
-	hwcrypto_state = HWCRYPTO_ERROR;
+	hwcrypto_state_rsa = HWCRYPTO_ERROR;
 	memcpy(sig2, sig, sig_total_size);
 	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
 		0, "vb2_verify_data() hwcrypto error");
 
-	hwcrypto_state = HWCRYPTO_NOTSUPPORTED;
+	hwcrypto_state_rsa = HWCRYPTO_NOTSUPPORTED;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto fallback ok");
+
+	memcpy(sig2, sig, sig_total_size);
+	sig2->sig_size -= 16;
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto fallback error");
+
+	hwcrypto_state_digest = HWCRYPTO_ERROR;
+	hwcrypto_state_rsa = HWCRYPTO_OK;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto error");
+
+	hwcrypto_state_rsa = HWCRYPTO_ERROR;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto error");
+
+	hwcrypto_state_rsa = HWCRYPTO_NOTSUPPORTED;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto fallback error");
+
+	hwcrypto_state_digest = HWCRYPTO_NOTSUPPORTED;
+	hwcrypto_state_rsa = HWCRYPTO_OK;
+	memcpy(sig2, sig, sig_total_size);
+	vb2_signature_data_mutable(sig2)[0] ^= 0x5A;
+	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto ok");
+
+	hwcrypto_state_rsa = HWCRYPTO_ERROR;
+	memcpy(sig2, sig, sig_total_size);
+	TEST_NEQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
+		0, "vb2_verify_data() hwcrypto error");
+
+	hwcrypto_state_rsa = HWCRYPTO_NOTSUPPORTED;
 	memcpy(sig2, sig, sig_total_size);
 	TEST_EQ(vb2_verify_data(test_data, test_size, sig2, &pubk, &wb),
 		0, "vb2_verify_data() hwcrypto fallback ok");
diff --git a/tests/vb2_common3_tests.c b/tests/vb2_common3_tests.c
index 4219222..5805204 100644
--- a/tests/vb2_common3_tests.c
+++ b/tests/vb2_common3_tests.c
@@ -7,6 +7,7 @@
 
 #include <stdio.h>
 
+#include "2common.h"
 #include "2rsa.h"
 #include "2sysincludes.h"
 #include "file_keys.h"
@@ -15,7 +16,6 @@
 #include "host_key.h"
 #include "host_signature.h"
 #include "test_common.h"
-#include "vb2_common.h"
 
 static void resign_keyblock(struct vb2_keyblock *h,
 			    const struct vb2_private_key *key)
diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c
index be86fbb..8881ea7 100644
--- a/tests/vb2_ec_sync_tests.c
+++ b/tests/vb2_ec_sync_tests.c
@@ -13,7 +13,6 @@
 #include "host_common.h"
 #include "load_kernel_fw.h"
 #include "test_common.h"
-#include "vboot_audio.h"
 #include "vboot_kernel.h"
 #include "vboot_struct.h"
 
diff --git a/tests/vb20_misc_tests.c b/tests/vb2_firmware_tests.c
similarity index 99%
rename from tests/vb20_misc_tests.c
rename to tests/vb2_firmware_tests.c
index fdab37e..681e5d6 100644
--- a/tests/vb20_misc_tests.c
+++ b/tests/vb2_firmware_tests.c
@@ -2,7 +2,7 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  *
- * Tests for misc library
+ * Tests for firmware verification library
  */
 
 #include <stdio.h>
@@ -15,7 +15,6 @@
 #include "2secdata.h"
 #include "2sysincludes.h"
 #include "test_common.h"
-#include "vb2_common.h"
 
 /* Common context for tests */
 static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
diff --git a/tests/vb2_host_flashrom_tests.c b/tests/vb2_host_flashrom_tests.c
index 9187e75..8552d0a 100644
--- a/tests/vb2_host_flashrom_tests.c
+++ b/tests/vb2_host_flashrom_tests.c
@@ -58,7 +58,7 @@
 	int captured_verify_int = FLASHROM_VERIFY_UNSPECIFIED;
 	struct option long_opts[] = {
 		{
-			.name = "fast-verify",
+			.name = "noverify-all",
 			.has_arg = no_argument,
 			.flag = &captured_verify_int,
 			.val = FLASHROM_VERIFY_FAST,
diff --git a/tests/vb2_kernel_tests.c b/tests/vb2_kernel_tests.c
index 4b0a249..0e1cb28 100644
--- a/tests/vb2_kernel_tests.c
+++ b/tests/vb2_kernel_tests.c
@@ -14,7 +14,6 @@
 #include "2secdata.h"
 #include "2sysincludes.h"
 #include "test_common.h"
-#include "vb2_common.h"
 #include "vboot_struct.h"
 
 /* Common context for tests */
@@ -140,7 +139,7 @@
 	return VB2_SUCCESS;
 }
 
-vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t get_info_flags)
+vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags)
 {
 	/*
 	 * TODO: Currently we don't have a good way of testing for an ordered
@@ -151,10 +150,10 @@
 		return mock_vbtlk_retval;
 
 	TEST_EQ(!!mock_vbtlk_expect_fixed,
-		!!(get_info_flags & VB_DISK_FLAG_FIXED),
+		!!(disk_flags & VB_DISK_FLAG_FIXED),
 		"  VbTryLoadKernel unexpected fixed disk call");
 	TEST_EQ(!!mock_vbtlk_expect_removable,
-		!!(get_info_flags & VB_DISK_FLAG_REMOVABLE),
+		!!(disk_flags & VB_DISK_FLAG_REMOVABLE),
 		"  VbTryLoadKernel unexpected removable disk call");
 
 	return mock_vbtlk_retval;
diff --git a/tests/vb2_keyblock_fuzzer.c b/tests/vb2_keyblock_fuzzer.c
index 6fabcd2..2aa83e1 100644
--- a/tests/vb2_keyblock_fuzzer.c
+++ b/tests/vb2_keyblock_fuzzer.c
@@ -7,6 +7,7 @@
 #include "2misc.h"
 #include "2nvstorage.h"
 #include "2rsa.h"
+#include "2rsa_private.h"
 #include "2secdata.h"
 #include "vboot_test.h"
 
diff --git a/tests/vb2_misc_tests.c b/tests/vb2_misc_tests.c
index c64552c..a7cc115 100644
--- a/tests/vb2_misc_tests.c
+++ b/tests/vb2_misc_tests.c
@@ -505,14 +505,14 @@
 	/* Any normal mode boot clears dev boot flags */
 	reset_common_data();
 	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
-	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 1);
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
 	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
 	vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, 1);
 	TEST_SUCC(vb2_check_dev_switch(ctx), "dev mode off");
 	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL),
 		0, "  cleared dev boot external");
-	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_LEGACY),
-		0, "  cleared dev boot legacy");
+	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_ALTFW),
+		0, "  cleared dev boot altfw");
 	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY),
 		0, "  cleared dev boot signed only");
 	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT),
@@ -892,14 +892,14 @@
 		VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
 		"no default boot, boot disk");
 
-	/* Set boot legacy by GBB */
+	/* Set boot altfw by GBB */
 	reset_common_data();
-	gbb.flags |= VB2_GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY;
+	gbb.flags |= VB2_GBB_FLAG_DEFAULT_DEV_BOOT_ALTFW;
 	vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
 		   VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL);
 	TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
-		VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY,
-		"GBB set default boot legacy");
+		VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW,
+		"GBB set default boot altfw");
 
 	/* Boot from internal disk */
 	reset_common_data();
@@ -926,36 +926,36 @@
 		VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
 		"default boot external not allowed");
 	reset_common_data();
-	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 1);
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
 	vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
 		   VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL);
 	TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
 		VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
 		"default boot external not allowed");
 
-	/* Boot legacy */
+	/* Boot altfw */
 	reset_common_data();
-	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 1);
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
 	vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
-		   VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY);
+		   VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW);
 	TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
-		VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY,
-		"set default boot legacy");
+		VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW,
+		"set default boot altfw");
 
-	/* Boot legacy not allowed */
+	/* Boot altfw not allowed */
 	reset_common_data();
 	vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
-		   VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY);
+		   VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW);
 	TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
 		VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
-		"default boot legacy not allowed");
+		"default boot altfw not allowed");
 	reset_common_data();
 	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
 	vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
-		   VB2_DEV_DEFAULT_BOOT_TARGET_LEGACY);
+		   VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW);
 	TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
 		VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
-		"default boot legacy not allowed");
+		"default boot altfw not allowed");
 }
 
 static void dev_boot_allowed_tests(void)
@@ -977,34 +977,34 @@
 
 	/* Legacy boot - not allowed by default */
 	reset_common_data();
-	TEST_EQ(vb2_dev_boot_legacy_allowed(ctx), 0,
-		"dev boot legacy - not allowed by default");
+	TEST_EQ(vb2_dev_boot_altfw_allowed(ctx), 0,
+		"dev boot altfw - not allowed by default");
 
 	/* Legacy boot - enabled by nvdata */
 	reset_common_data();
-	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 1);
-	TEST_EQ(vb2_dev_boot_legacy_allowed(ctx), 1,
-		"dev boot legacy - nvdata enabled");
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
+	TEST_EQ(vb2_dev_boot_altfw_allowed(ctx), 1,
+		"dev boot altfw - nvdata enabled");
 
 	/* Legacy boot - enabled by FWMP */
 	reset_common_data();
-	fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY;
-	TEST_EQ(vb2_dev_boot_legacy_allowed(ctx), 1,
-		"dev boot legacy - secdata enabled");
+	fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW;
+	TEST_EQ(vb2_dev_boot_altfw_allowed(ctx), 1,
+		"dev boot altfw - secdata enabled");
 
 	/* Legacy boot - force enabled by GBB */
 	reset_common_data();
-	gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY;
-	TEST_EQ(vb2_dev_boot_legacy_allowed(ctx), 1,
-		"dev boot legacy - GBB force enabled");
+	gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW;
+	TEST_EQ(vb2_dev_boot_altfw_allowed(ctx), 1,
+		"dev boot altfw - GBB force enabled");
 
 	/* Legacy boot - set all flags */
 	reset_common_data();
-	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 1);
-	fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY;
-	gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY;
-	TEST_EQ(vb2_dev_boot_legacy_allowed(ctx), 1,
-		"dev boot legacy - all flags set");
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
+	fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW;
+	gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW;
+	TEST_EQ(vb2_dev_boot_altfw_allowed(ctx), 1,
+		"dev boot altfw - all flags set");
 
 	/* External boot - not allowed by default */
 	reset_common_data();
diff --git a/tests/vb2_nvstorage_tests.c b/tests/vb2_nvstorage_tests.c
index a49f162..94bcfca 100644
--- a/tests/vb2_nvstorage_tests.c
+++ b/tests/vb2_nvstorage_tests.c
@@ -41,7 +41,7 @@
 	{VB2_NV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"},
 	{VB2_NV_KERNEL_FIELD, 0, 0x1234, 0xFEDC, "kernel field"},
 	{VB2_NV_DEV_BOOT_EXTERNAL, 0, 1, 0, "dev boot usb"},
-	{VB2_NV_DEV_BOOT_LEGACY, 0, 1, 0, "dev boot legacy"},
+	{VB2_NV_DEV_BOOT_ALTFW, 0, 1, 0, "dev boot altfw"},
 	{VB2_NV_DEV_BOOT_SIGNED_ONLY, 0, 1, 0, "dev boot custom"},
 	{VB2_NV_DEV_DEFAULT_BOOT, 0, 1, 2, "dev default boot"},
 	{VB2_NV_DIAG_REQUEST, 0, 1, 0, "diagnostic rom request"},
diff --git a/tests/vb2_preamble_fuzzer.c b/tests/vb2_preamble_fuzzer.c
index b29ccc7..186ee9f 100644
--- a/tests/vb2_preamble_fuzzer.c
+++ b/tests/vb2_preamble_fuzzer.c
@@ -7,6 +7,7 @@
 #include "2misc.h"
 #include "2nvstorage.h"
 #include "2rsa.h"
+#include "2rsa_private.h"
 #include "2secdata.h"
 #include "vboot_test.h"
 
diff --git a/tests/vb2_rsa_utility_tests.c b/tests/vb2_rsa_utility_tests.c
index cc856e8..4ad5a95 100644
--- a/tests/vb2_rsa_utility_tests.c
+++ b/tests/vb2_rsa_utility_tests.c
@@ -8,6 +8,7 @@
 
 #include "2common.h"
 #include "2rsa.h"
+#include "2rsa_private.h"
 #include "2sysincludes.h"
 #include "file_keys.h"
 #include "rsa_padding_test.h"
diff --git a/tests/vb2_ui_action_tests.c b/tests/vb2_ui_action_tests.c
index f6f18dc..6db75bf 100644
--- a/tests/vb2_ui_action_tests.c
+++ b/tests/vb2_ui_action_tests.c
@@ -19,8 +19,9 @@
 
 /* Mock screen index for testing screen utility functions. */
 #define MOCK_NO_SCREEN 0xef00
-#define MOCK_SCREEN_BASE 0xef10
-#define MOCK_SCREEN_MENU 0xef11
+#define MOCK_SCREEN_BLANK 0xef10
+#define MOCK_SCREEN_BASE 0xef11
+#define MOCK_SCREEN_MENU 0xef12
 #define MOCK_SCREEN_TARGET0 0xef20
 #define MOCK_SCREEN_TARGET1 0xef21
 #define MOCK_SCREEN_TARGET2 0xef22
@@ -65,11 +66,11 @@
 static uint32_t mock_vbtlk_expected_flag;
 
 static int mock_dev_boot_allowed;
-static int mock_dev_boot_legacy_allowed;
+static int mock_dev_boot_altfw_allowed;
 
-static int mock_vbexlegacy_called;
-static enum VbAltFwIndex_t mock_altfw_num_last;
-static uint32_t mock_bootloader_count;
+static int mock_run_altfw_called;
+static uint32_t mock_altfw_last;
+static uint32_t mock_altfw_count;
 
 static uint32_t mock_time_ms;
 static const uint32_t mock_time_start_ms = 31ULL * VB2_MSEC_PER_SEC;
@@ -80,8 +81,8 @@
 static vb2_error_t mock_action_countdown(struct vb2_ui_context *ui)
 {
 	if (++mock_action_called >= mock_action_countdown_limit)
-		return VB2_SUCCESS;
-	return VB2_REQUEST_UI_CONTINUE;
+		return VB2_REQUEST_UI_EXIT;
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t mock_action_screen_change(struct vb2_ui_context *ui)
@@ -99,35 +100,35 @@
 static vb2_error_t mock_action_flag0(struct vb2_ui_context *ui)
 {
 	if ((1 << 0) & mock_action_flags)
-		return VB2_SUCCESS;
-	return VB2_REQUEST_UI_CONTINUE;
+		return VB2_REQUEST_UI_EXIT;
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t mock_action_flag1(struct vb2_ui_context *ui)
 {
 	if ((1 << 1) & mock_action_flags)
-		return VB2_SUCCESS;
-	return VB2_REQUEST_UI_CONTINUE;
+		return VB2_REQUEST_UI_EXIT;
+	return VB2_SUCCESS;
 }
 
 static vb2_error_t mock_action_flag2(struct vb2_ui_context *ui)
 {
 	if ((1 << 2) & mock_action_flags)
-		return VB2_SUCCESS;
-	return VB2_REQUEST_UI_CONTINUE;
+		return VB2_REQUEST_UI_EXIT;
+	return VB2_SUCCESS;
 }
 
 static uint32_t mock_action_delay_ms;
 static vb2_error_t mock_action_msleep(struct vb2_ui_context *ui)
 {
 	vb2ex_msleep(mock_action_delay_ms);
-	return VB2_REQUEST_UI_CONTINUE;
+	return VB2_SUCCESS;
 }
 
 /* Mock screens */
 struct vb2_screen_info mock_screen_temp;
 const struct vb2_screen_info mock_screen_blank = {
-	.id = VB2_SCREEN_BLANK,
+	.id = MOCK_SCREEN_BLANK,
 	.name = "mock_screen_blank",
 };
 const struct vb2_screen_info mock_screen_base = {
@@ -234,10 +235,10 @@
 }
 
 
-static void set_mock_vbtlk(vb2_error_t retval, uint32_t get_info_flags)
+static void set_mock_vbtlk(vb2_error_t retval, uint32_t disk_flags)
 {
 	mock_vbtlk_retval = retval;
-	mock_vbtlk_expected_flag = get_info_flags;
+	mock_vbtlk_expected_flag = disk_flags;
 }
 
 static void displayed_eq(const char *text,
@@ -360,12 +361,12 @@
 
 	/* For dev_boot* in 2misc.h */
 	mock_dev_boot_allowed = 1;
-	mock_dev_boot_legacy_allowed = 0;
+	mock_dev_boot_altfw_allowed = 0;
 
-	/* For VbExLegacy */
-	mock_vbexlegacy_called = 0;
-	mock_altfw_num_last = -100;
-	mock_bootloader_count = 2;
+	/* For vb2ex_run_altfw */
+	mock_run_altfw_called = 0;
+	mock_altfw_last = -100;
+	mock_altfw_count = 2;
 
 	/* For vb2ex_mtime and vb2ex_msleep  */
 	mock_time_ms = mock_time_start_ms;
@@ -393,7 +394,7 @@
 	mock_get_screen_info_called++;
 
 	switch ((int)screen) {
-	case VB2_SCREEN_BLANK:
+	case MOCK_SCREEN_BLANK:
 		return &mock_screen_blank;
 	case MOCK_SCREEN_BASE:
 		return &mock_screen_base;
@@ -480,10 +481,10 @@
 	return 0;
 }
 
-vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t get_info_flags)
+vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags)
 {
-	TEST_EQ(mock_vbtlk_expected_flag, get_info_flags,
-		"  unexpected get_info_flags");
+	TEST_EQ(mock_vbtlk_expected_flag, disk_flags,
+		"  unexpected disk_flags");
 	return mock_vbtlk_retval;
 }
 
@@ -492,25 +493,25 @@
 	return mock_dev_boot_allowed;
 }
 
-int vb2_dev_boot_legacy_allowed(struct vb2_context *c)
+int vb2_dev_boot_altfw_allowed(struct vb2_context *c)
 {
-	return mock_dev_boot_legacy_allowed;
+	return mock_dev_boot_altfw_allowed;
 }
 
-vb2_error_t VbExLegacy(enum VbAltFwIndex_t altfw_num)
+vb2_error_t vb2ex_run_altfw(uint32_t altfw_id)
 {
-	mock_vbexlegacy_called++;
-	mock_altfw_num_last = altfw_num;
+	mock_run_altfw_called++;
+	mock_altfw_last = altfw_id;
 
-	if (altfw_num <= mock_bootloader_count)
+	if (altfw_id <= mock_altfw_count)
 		return VB2_SUCCESS;
 	else
 		return VB2_ERROR_UNKNOWN;
 }
 
-uint32_t vb2ex_get_bootloader_count(void)
+uint32_t vb2ex_get_altfw_count(void)
 {
-	return mock_bootloader_count;
+	return mock_altfw_count;
 }
 
 uint32_t vb2ex_mtime(void)
@@ -533,7 +534,7 @@
 	mock_ui_context.state->screen = &mock_screen_menu;
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.key = VB_KEY_UP;
-	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_SUCCESS,
 		"valid action");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 1,
 			MOCK_IGNORE);
@@ -544,7 +545,7 @@
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.state->hidden_item_mask = 0x0a;  /* 0b01010 */
 	mock_ui_context.key = VB_KEY_UP;
-	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_SUCCESS,
 		"valid action with hidden mask");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 0,
 			MOCK_IGNORE);
@@ -555,7 +556,7 @@
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.state->disabled_item_mask = 0x0a;  /* 0b01010 */
 	mock_ui_context.key = VB_KEY_UP;
-	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_SUCCESS,
 		"valid action with disabled mask");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 1,
 			MOCK_IGNORE);
@@ -565,7 +566,7 @@
 	mock_ui_context.state->screen = &mock_screen_menu;
 	mock_ui_context.state->selected_item = 0;
 	mock_ui_context.key = VB_KEY_UP;
-	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_SUCCESS,
 		"invalid action (blocked)");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 0,
 			MOCK_IGNORE);
@@ -576,7 +577,7 @@
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.state->hidden_item_mask = 0x0b;  /* 0b01011 */
 	mock_ui_context.key = VB_KEY_UP;
-	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_SUCCESS,
 		"invalid action (blocked by mask)");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
 			MOCK_IGNORE);
@@ -587,8 +588,7 @@
 		mock_ui_context.state->screen = &mock_screen_menu;
 		mock_ui_context.state->selected_item = 2;
 		mock_ui_context.key = VB_BUTTON_VOL_UP_SHORT_PRESS;
-		TEST_EQ(vb2_ui_menu_prev(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE,
+		TEST_EQ(vb2_ui_menu_prev(&mock_ui_context), VB2_SUCCESS,
 			"ignore volume-up when not DETACHABLE");
 		screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
 				MOCK_IGNORE);
@@ -606,7 +606,7 @@
 	mock_ui_context.state->screen = &mock_screen_menu;
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.key = VB_KEY_DOWN;
-	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_SUCCESS,
 		"valid action");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 3,
 			MOCK_IGNORE);
@@ -617,7 +617,7 @@
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.state->hidden_item_mask = 0x0a;  /* 0b01010 */
 	mock_ui_context.key = VB_KEY_DOWN;
-	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_SUCCESS,
 		"valid action with hidden mask");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 4,
 			MOCK_IGNORE);
@@ -628,7 +628,7 @@
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.state->disabled_item_mask = 0x0a;  /* 0b01010 */
 	mock_ui_context.key = VB_KEY_DOWN;
-	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_SUCCESS,
 		"valid action with disabled mask");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 3,
 			MOCK_IGNORE);
@@ -638,7 +638,7 @@
 	mock_ui_context.state->screen = &mock_screen_menu;
 	mock_ui_context.state->selected_item = 4;
 	mock_ui_context.key = VB_KEY_DOWN;
-	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_SUCCESS,
 		"invalid action (blocked)");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 4,
 			MOCK_IGNORE);
@@ -649,7 +649,7 @@
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.state->hidden_item_mask = 0x1a;  /* 0b11010 */
 	mock_ui_context.key = VB_KEY_DOWN;
-	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_SUCCESS,
 		"invalid action (blocked by mask)");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
 			MOCK_IGNORE);
@@ -660,8 +660,7 @@
 		mock_ui_context.state->screen = &mock_screen_menu;
 		mock_ui_context.state->selected_item = 2;
 		mock_ui_context.key = VB_BUTTON_VOL_DOWN_SHORT_PRESS;
-		TEST_EQ(vb2_ui_menu_next(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE,
+		TEST_EQ(vb2_ui_menu_next(&mock_ui_context), VB2_SUCCESS,
 			"ignore volume-down when not DETACHABLE");
 		screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
 				MOCK_IGNORE);
@@ -670,6 +669,12 @@
 	VB2_DEBUG("...done.\n");
 }
 
+static vb2_error_t try_menu_select_helper(void)
+{
+	VB2_TRY(vb2_ui_menu_select(&mock_ui_context));
+	return VB2_ERROR_MOCK;
+}
+
 static void menu_select_tests(void)
 {
 	VB2_DEBUG("Testing menu_select...\n");
@@ -678,19 +683,25 @@
 	reset_common_data();
 	mock_ui_context.state->screen = &mock_screen_base;
 	mock_ui_context.key = VB_KEY_ENTER;
-	TEST_EQ(vb2_ui_menu_select(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_select(&mock_ui_context), VB2_SUCCESS,
 		"vb2_ui_menu_select with no item screen");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_BASE, 0,
 			MOCK_IGNORE);
 
+	/* VB2_TRY around item selection should return right away */
+	reset_common_data();
+	mock_ui_context.state->screen = &mock_screen_menu;
+	mock_ui_context.key = VB_KEY_ENTER;
+	TEST_NEQ(try_menu_select_helper(), VB2_ERROR_MOCK,
+		"continued executing after VB2_TRY(menu_select)");
+
 	/* Try to select an item with a target (item 2) */
 	reset_common_data();
 	mock_ui_context.state->screen = &mock_screen_menu;
 	mock_ui_context.state->selected_item = 2;
 	mock_ui_context.key = VB_KEY_ENTER;
-	TEST_EQ(vb2_ui_menu_select(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE, "select an item with a target");
+	TEST_EQ(vb2_ui_menu_select(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
+		"select an item with a target");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_TARGET2, 0,
 			MOCK_IGNORE);
 
@@ -708,8 +719,7 @@
 	mock_ui_context.state->screen = &mock_screen_menu;
 	mock_ui_context.state->selected_item = 4;
 	mock_ui_context.key = VB_KEY_ENTER;
-	TEST_EQ(vb2_ui_menu_select(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_menu_select(&mock_ui_context), VB2_SUCCESS,
 		"select an item with neither targets nor actions");
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 4,
 			MOCK_IGNORE);
@@ -720,8 +730,8 @@
 	mock_ui_context.state->selected_item = 3;
 	mock_ui_context.state->disabled_item_mask = 0x08;  /* 0b01000 */
 	mock_ui_context.key = VB_KEY_ENTER;
-	TEST_EQ(vb2_ui_menu_select(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE, "cannot select a disabled item");
+	TEST_EQ(vb2_ui_menu_select(&mock_ui_context), VB2_SUCCESS,
+		"cannot select a disabled item");
 	TEST_EQ(mock_action_called, 0, "  no action called");
 
 	/* Ignore power button short press when not DETACHABLE */
@@ -730,8 +740,7 @@
 		mock_ui_context.state->screen = &mock_screen_menu;
 		mock_ui_context.state->selected_item = 1;
 		mock_ui_context.key = VB_BUTTON_POWER_SHORT_PRESS;
-		TEST_EQ(vb2_ui_menu_select(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE,
+		TEST_EQ(vb2_ui_menu_select(&mock_ui_context), VB2_SUCCESS,
 			"ignore power button short press when not DETACHABLE");
 		screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 1,
 				MOCK_IGNORE);
@@ -740,54 +749,63 @@
 	VB2_DEBUG("...done.\n");
 }
 
-static void vb2_ui_developer_mode_boot_alternate_action_tests(void)
+static void vb2_ui_developer_mode_boot_altfw_action_tests(void)
 {
 	VB2_DEBUG("Test developer mode boot alternate action...\n");
 
 	/* Not allowed: not in dev mode */
 	reset_common_data();
-	mock_dev_boot_legacy_allowed = 1;
-	TEST_EQ(vb2_ui_developer_mode_boot_alternate_action(&mock_ui_context),
+	mock_dev_boot_altfw_allowed = 1;
+	TEST_EQ(vb2_ui_developer_mode_boot_altfw_action(&mock_ui_context),
 		VB2_REQUEST_UI_CONTINUE, "not allowed: not in dev mode");
-	TEST_EQ(mock_vbexlegacy_called, 0, "  VbExLegacy not called");
+	TEST_EQ(mock_ui_context.error_code, VB2_UI_ERROR_ALTFW_DISABLED,
+		"ui_error code is set");
+	TEST_EQ(mock_run_altfw_called, 0, "  vb2ex_run_altfw not called");
 
 	/* Not allowed: dev boot not allowed */
 	reset_common_data();
 	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
 	mock_dev_boot_allowed = 0;
-	mock_dev_boot_legacy_allowed = 1;
-	TEST_EQ(vb2_ui_developer_mode_boot_alternate_action(&mock_ui_context),
+	mock_dev_boot_altfw_allowed = 1;
+	TEST_EQ(vb2_ui_developer_mode_boot_altfw_action(&mock_ui_context),
 		VB2_REQUEST_UI_CONTINUE, "not allowed: dev boot not allowed");
-	TEST_EQ(mock_vbexlegacy_called, 0, "  VbExLegacy not called");
+	TEST_EQ(mock_ui_context.error_code, VB2_UI_ERROR_ALTFW_DISABLED,
+		"ui_error code is set");
+	TEST_EQ(mock_run_altfw_called, 0, "  vb2ex_run_altfw not called");
 
-	/* Not allowed: boot legacy not allowed */
+	/* Not allowed: boot altfw not allowed */
 	reset_common_data();
 	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
-	TEST_EQ(vb2_ui_developer_mode_boot_alternate_action(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE,
-		"not allowed: boot legacy not allowed");
-	TEST_EQ(mock_vbexlegacy_called, 0, "  VbExLegacy not called");
+	TEST_EQ(vb2_ui_developer_mode_boot_altfw_action(&mock_ui_context),
+		VB2_REQUEST_UI_CONTINUE, "not allowed: boot altfw not allowed");
+	TEST_EQ(mock_ui_context.error_code, VB2_UI_ERROR_ALTFW_DISABLED,
+		"ui_error code is set");
+	TEST_EQ(mock_run_altfw_called, 0, "  vb2ex_run_altfw not called");
 
 	/* Allowed */
 	reset_common_data();
 	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	mock_ui_context.state->selected_item = 2;
-	TEST_EQ(vb2_ui_developer_mode_boot_alternate_action(&mock_ui_context),
+	TEST_EQ(vb2_ui_developer_mode_boot_altfw_action(&mock_ui_context),
 		VB2_REQUEST_UI_CONTINUE, "allowed");
-	TEST_EQ(mock_vbexlegacy_called, 1, "  VbExLegacy called once");
-	TEST_EQ(mock_altfw_num_last, 2, "  select bootloader #2");
+	TEST_EQ(mock_ui_context.error_code, VB2_UI_ERROR_ALTFW_FAILED,
+		"ui_error code is set");
+	TEST_EQ(mock_run_altfw_called, 1, "  vb2ex_run_altfw called once");
+	TEST_EQ(mock_altfw_last, 2, "  select bootloader #2");
 
 	/* CTRL+L = default bootloader */
 	reset_common_data();
 	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	mock_ui_context.key = VB_KEY_CTRL('L');
 	mock_ui_context.state->selected_item = 4;  /* Ignored */
-	TEST_EQ(vb2_ui_developer_mode_boot_alternate_action(&mock_ui_context),
+	TEST_EQ(vb2_ui_developer_mode_boot_altfw_action(&mock_ui_context),
 		VB2_REQUEST_UI_CONTINUE, "allowed: ctrl+l");
-	TEST_EQ(mock_vbexlegacy_called, 1, "  VbExLegacy called once");
-	TEST_EQ(mock_altfw_num_last, 0, "  select bootloader #0");
+	TEST_EQ(mock_ui_context.error_code, VB2_UI_ERROR_ALTFW_FAILED,
+		"ui_error code is set");
+	TEST_EQ(mock_run_altfw_called, 1, "  vb2ex_run_altfw called once");
+	TEST_EQ(mock_altfw_last, 0, "  select bootloader #0");
 
 	VB2_DEBUG("...done.\n");
 }
@@ -799,8 +817,8 @@
 	/* SUCCESS */
 	reset_common_data();
 	set_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
-	TEST_EQ(manual_recovery_action(&mock_ui_context),
-		VB2_SUCCESS, "SUCCESS");
+	TEST_EQ(manual_recovery_action(&mock_ui_context), VB2_REQUEST_UI_EXIT,
+		"EXIT");
 	TEST_EQ(mock_get_screen_info_called, 0, "  no change_screen");
 
 	/* NO_DISK_FOUND */
@@ -821,8 +839,8 @@
 	TEST_EQ(manual_recovery_action(&mock_ui_context),
 		VB2_REQUEST_UI_CONTINUE, "INVALID_KERNEL");
 	set_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
-	TEST_EQ(manual_recovery_action(&mock_ui_context),
-		VB2_SUCCESS, "SUCCESS");
+	TEST_EQ(manual_recovery_action(&mock_ui_context), VB2_REQUEST_UI_EXIT,
+		"EXIT");
 	screen_state_eq(mock_ui_context.state, VB2_SCREEN_RECOVERY_INVALID,
 			MOCK_IGNORE, MOCK_IGNORE);
 
@@ -845,8 +863,8 @@
 	TEST_EQ(manual_recovery_action(&mock_ui_context),
 		VB2_REQUEST_UI_CONTINUE, "NO_DISK_FOUND");
 	set_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
-	TEST_EQ(manual_recovery_action(&mock_ui_context),
-		VB2_SUCCESS, "SUCCESS");
+	TEST_EQ(manual_recovery_action(&mock_ui_context), VB2_REQUEST_UI_EXIT,
+		"EXIT");
 	screen_state_eq(mock_ui_context.state, VB2_SCREEN_RECOVERY_SELECT,
 			MOCK_IGNORE, MOCK_IGNORE);
 
@@ -891,13 +909,13 @@
 	reset_common_data();
 	mock_calls_until_shutdown = -1;
 	mock_action_countdown_limit = 10;
-	TEST_EQ(ui_loop(ctx, VB2_SCREEN_BLANK, mock_action_countdown),
+	TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BLANK, mock_action_countdown),
 		VB2_SUCCESS, "global action");
 	TEST_EQ(mock_action_called, 10, "  action called");
 
 	/* Global action can change screen */
 	reset_common_data();
-	TEST_EQ(ui_loop(ctx, VB2_SCREEN_BLANK, mock_action_screen_change),
+	TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BLANK, mock_action_screen_change),
 		VB2_REQUEST_SHUTDOWN, "global action can change screen");
 	DISPLAYED_PASS();
 	DISPLAYED_EQ("change to mock_screen_base", MOCK_SCREEN_BASE,
@@ -1054,7 +1072,7 @@
 	menu_select_tests();
 
 	/* Screen actions */
-	vb2_ui_developer_mode_boot_alternate_action_tests();
+	vb2_ui_developer_mode_boot_altfw_action_tests();
 
 	/* Global actions */
 	manual_recovery_action_tests();
diff --git a/tests/vb2_ui_tests.c b/tests/vb2_ui_tests.c
index bc95033..9a84a93 100644
--- a/tests/vb2_ui_tests.c
+++ b/tests/vb2_ui_tests.c
@@ -74,12 +74,12 @@
 
 static enum vb2_dev_default_boot_target mock_default_boot;
 static int mock_dev_boot_allowed;
-static int mock_dev_boot_legacy_allowed;
+static int mock_dev_boot_altfw_allowed;
 static int mock_dev_boot_external_allowed;
 
-static int mock_vbexlegacy_called;
-static enum VbAltFwIndex_t mock_altfw_num_last;
-static uint32_t mock_bootloader_count;
+static int mock_run_altfw_called;
+static uint32_t mock_altfw_last;
+static uint32_t mock_altfw_count;
 
 static vb2_error_t mock_vbtlk_retval[32];
 static uint32_t mock_vbtlk_expected_flag[32];
@@ -100,6 +100,8 @@
 static int mock_prepare_log_count;
 static uint32_t mock_log_page_count;
 
+static vb2_error_t mock_diag_storage_test_rv;
+
 static void add_mock_key(uint32_t press, int trusted)
 {
 	if (mock_key_total >= ARRAY_SIZE(mock_key) ||
@@ -118,7 +120,7 @@
 	add_mock_key(press, 0);
 }
 
-static void add_mock_vbtlk(vb2_error_t retval, uint32_t get_info_flags)
+static void add_mock_vbtlk(vb2_error_t retval, uint32_t disk_flags)
 {
 	if (mock_vbtlk_total >= ARRAY_SIZE(mock_vbtlk_retval) ||
 	    mock_vbtlk_total >= ARRAY_SIZE(mock_vbtlk_expected_flag)) {
@@ -127,7 +129,7 @@
 	}
 
 	mock_vbtlk_retval[mock_vbtlk_total] = retval;
-	mock_vbtlk_expected_flag[mock_vbtlk_total] = get_info_flags;
+	mock_vbtlk_expected_flag[mock_vbtlk_total] = disk_flags;
 	mock_vbtlk_total++;
 }
 
@@ -317,13 +319,13 @@
 	/* For dev_boot* in 2misc.h */
 	mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL;
 	mock_dev_boot_allowed = 1;
-	mock_dev_boot_legacy_allowed = 0;
+	mock_dev_boot_altfw_allowed = 0;
 	mock_dev_boot_external_allowed = 1;
 
-	/* For VbExLegacy */
-	mock_vbexlegacy_called = 0;
-	mock_altfw_num_last = -100;
-	mock_bootloader_count = 2;
+	/* For vb2ex_run_altfw */
+	mock_run_altfw_called = 0;
+	mock_altfw_last = -100;
+	mock_altfw_count = 2;
 
 	/* For VbTryLoadKernel */
 	memset(mock_vbtlk_retval, 0, sizeof(mock_vbtlk_retval));
@@ -353,6 +355,8 @@
 	else
 		add_mock_vbtlk(VB2_ERROR_MOCK, 0);
 	add_mock_pp_pressed(0);
+
+	mock_diag_storage_test_rv = VB2_SUCCESS;
 }
 
 /* Mock functions */
@@ -490,9 +494,9 @@
 	return mock_dev_boot_allowed;
 }
 
-int vb2_dev_boot_legacy_allowed(struct vb2_context *c)
+int vb2_dev_boot_altfw_allowed(struct vb2_context *c)
 {
-	return mock_dev_boot_legacy_allowed;
+	return mock_dev_boot_altfw_allowed;
 }
 
 int vb2_dev_boot_external_allowed(struct vb2_context *c)
@@ -500,20 +504,20 @@
 	return mock_dev_boot_external_allowed;
 }
 
-vb2_error_t VbExLegacy(enum VbAltFwIndex_t altfw_num)
+vb2_error_t vb2ex_run_altfw(uint32_t altfw_id)
 {
-	mock_vbexlegacy_called++;
-	mock_altfw_num_last = altfw_num;
+	mock_run_altfw_called++;
+	mock_altfw_last = altfw_id;
 
 	return VB2_SUCCESS;
 }
 
-uint32_t vb2ex_get_bootloader_count(void)
+uint32_t vb2ex_get_altfw_count(void)
 {
-	return mock_bootloader_count;
+	return mock_altfw_count;
 }
 
-vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t get_info_flags)
+vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags)
 {
 	int i = mock_iters;
 
@@ -521,8 +525,8 @@
 	if (i >= mock_vbtlk_total)
 		i = mock_vbtlk_total - 1;
 
-	TEST_EQ(mock_vbtlk_expected_flag[i], get_info_flags,
-		"  unexpected get_info_flags");
+	TEST_EQ(mock_vbtlk_expected_flag[i], disk_flags,
+		"  unexpected disk_flags");
 
 	return mock_vbtlk_retval[i];
 }
@@ -571,6 +575,11 @@
 	return mock_log_page_count;
 }
 
+vb2_error_t vb2ex_diag_get_storage_test_log(const char **log)
+{
+	return mock_diag_storage_test_rv;
+}
+
 /* Tests */
 static void developer_tests(void)
 {
@@ -598,6 +607,14 @@
 	TEST_EQ(mock_beep_count, 2, "  beeped twice");
 	TEST_TRUE(mock_iters >= mock_vbtlk_total, "  used up mock_vbtlk");
 
+	/* Don't proceed to internal disk after timeout (dev mode disallowed) */
+	reset_common_data(FOR_DEVELOPER);
+	mock_dev_boot_allowed = 0;
+	TEST_EQ(ui_loop(ctx, VB2_SCREEN_DEVELOPER_MODE, NULL),
+		VB2_REQUEST_SHUTDOWN,
+		"do not proceed to internal disk after timeout "
+		"(dev mode disallowed)");
+
 	/* Use short delay */
 	reset_common_data(FOR_DEVELOPER);
 	gbb.flags |= VB2_GBB_FLAG_DEV_SCREEN_SHORT_DELAY;
@@ -687,6 +704,15 @@
 	TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
 		"default boot from external disk not allowed, don't boot");
 
+	/* Don't proceed to external disk after timeout (dev mode disallowed) */
+	reset_common_data(FOR_DEVELOPER);
+	mock_dev_boot_allowed = 0;
+	mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
+	TEST_EQ(ui_loop(ctx, VB2_SCREEN_DEVELOPER_MODE, NULL),
+		VB2_REQUEST_SHUTDOWN,
+		"do not proceed to external disk after timeout "
+		"(dev mode disallowed)");
+
 	/* If no external disk, don't boot */
 	reset_common_data(FOR_DEVELOPER);
 	add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
@@ -702,20 +728,21 @@
 	TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
 		"select boot external in dev menu");
 
-	/* Ctrl+L = boot legacy (allowed) */
+	/* Ctrl+L = boot altfw (allowed) */
 	reset_common_data(FOR_DEVELOPER);
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	add_mock_keypress(VB_KEY_CTRL('L'));
 	TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
-		"ctrl+l = boot legacy");
-	TEST_EQ(mock_vbexlegacy_called, 1, "  VbExLegacy called");
+		"ctrl+l = boot altfw");
+	TEST_EQ(mock_run_altfw_called, 1, "  vb2ex_run_altfw called");
 
-	/* Ctrl+L = boot legacy (disallowed) */
+	/* Ctrl+L = boot altfw (disallowed) */
 	reset_common_data(FOR_DEVELOPER);
 	add_mock_keypress(VB_KEY_CTRL('L'));
 	TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
-		"ctrl+l = boot legacy");
-	TEST_EQ(mock_vbexlegacy_called, 0, "  VbExLegacy not called");
+		"ctrl+l = boot altfw");
+	TEST_EQ(mock_run_altfw_called, 0,
+		"  vb2ex_run_altfw not called");
 
 	/* VB_BUTTON_VOL_UP_LONG_PRESS = boot external */
 	if (DETACHABLE) {
@@ -726,19 +753,6 @@
 			"VB_BUTTON_VOL_UP_LONG_PRESS = boot external");
 	}
 
-	/* If dev mode is disabled, goes to to_norm screen repeatedly */
-	reset_common_data(FOR_DEVELOPER);
-	add_mock_keypress(VB_KEY_ESC);
-	mock_dev_boot_allowed = 0;
-	TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
-		"if dev mode is disabled, goes to to_norm screen repeatedly");
-	DISPLAYED_EQ("to_norm", VB2_SCREEN_DEVELOPER_TO_NORM, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-	DISPLAYED_PASS();
-	DISPLAYED_EQ("to_norm", VB2_SCREEN_DEVELOPER_TO_NORM, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-	DISPLAYED_NO_EXTRA();
-
 	/* Select to_norm in dev menu and confirm */
 	reset_common_data(FOR_DEVELOPER);
 	add_mock_keypress(VB_KEY_UP);
@@ -749,6 +763,18 @@
 	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), 1,
 		"  disable dev request");
 
+	/* Select to_norm in dev menu and confirm (dev mode disallowed) */
+	reset_common_data(FOR_DEVELOPER);
+	mock_dev_boot_allowed = 0;
+	add_mock_keypress(VB_KEY_UP);
+	add_mock_keypress(VB_KEY_ENTER);
+	add_mock_keypress(VB_KEY_ENTER);
+	TEST_EQ(ui_loop(ctx, VB2_SCREEN_DEVELOPER_MODE, NULL),
+		VB2_REQUEST_REBOOT,
+		"select to_norm in dev menu and confirm (dev mode disallowed)");
+	TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), 1,
+		"  disable dev request");
+
 	/* Select to_norm in dev menu and cancel */
 	reset_common_data(FOR_DEVELOPER);
 	add_mock_keypress(VB_KEY_UP);
@@ -1286,7 +1312,7 @@
 
 	/* Dev mode: disabled and hidden item mask */
 	reset_common_data(FOR_DEVELOPER);
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
 	TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
 		"dev mode screen: no disabled or hidden item");
@@ -1294,7 +1320,7 @@
 		     MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE);
 
 	reset_common_data(FOR_DEVELOPER);
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON;
 	add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
 	TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
@@ -1305,7 +1331,7 @@
 	reset_common_data(FOR_DEVELOPER);
 	add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
 	mock_dev_boot_external_allowed = 0;
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
 		"dev mode screen: hide boot external");
 	DISPLAYED_EQ("dev mode screen", VB2_SCREEN_DEVELOPER_MODE,
@@ -1364,7 +1390,7 @@
 	DISPLAYED_NO_EXTRA();
 
 	reset_common_data(FOR_DEVELOPER);  /* Select #2 by default */
-	mock_dev_boot_legacy_allowed = 1;
+	mock_dev_boot_altfw_allowed = 1;
 	/* #4: Alternate boot */
 	add_mock_keypress(VB_KEY_DOWN);
 	add_mock_keypress(VB_KEY_DOWN);
@@ -1372,7 +1398,7 @@
 	add_mock_keypress(VB_KEY_ENTER);
 	TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
 		"dev mode screen");
-	TEST_EQ(mock_vbexlegacy_called, 1, "  VbExLegacy called");
+	TEST_EQ(mock_run_altfw_called, 1, "  vb2ex_run_altfw called");
 
 	reset_common_data(FOR_DEVELOPER);  /* Select #2 by default */
 	add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
@@ -1777,8 +1803,8 @@
 	reset_common_data(FOR_DIAGNOSTICS);
 	TEST_EQ(vb2_diagnostic_menu(ctx), VB2_REQUEST_SHUTDOWN,
 		"diagnostic screen: no disabled or hidden item");
-	DISPLAYED_EQ("diagnostic menu", VB2_SCREEN_DIAGNOSTICS,
-		     MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE);
+	DISPLAYED_EQ("diagnostic menu", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE,
+		     MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE);
 
 	/* Diagnostics screen */
 	reset_common_data(FOR_DIAGNOSTICS);
@@ -1786,67 +1812,94 @@
 	/* #0: Language menu */
 	add_mock_keypress(VB_KEY_UP);
 	add_mock_keypress(VB_KEY_ENTER);
-	/* #1: Storage screen */
 	add_mock_keypress(VB_KEY_ESC);
+	/* #1: Storage health screen */
 	add_mock_keypress(VB_KEY_DOWN);
 	add_mock_keypress(VB_KEY_ENTER);
-	/* #2: Quick memory test screen */
 	add_mock_keypress(VB_KEY_ESC);
+	/* #2: Short storage self-test screen */
 	add_mock_keypress(VB_KEY_DOWN);
 	add_mock_keypress(VB_KEY_ENTER);
-	/* #3: Full memory test screen */
 	add_mock_keypress(VB_KEY_ESC);
+	/* #3: Extended storage self-test screen */
 	add_mock_keypress(VB_KEY_DOWN);
 	add_mock_keypress(VB_KEY_ENTER);
-	/* #4: Power off (End of menu) */
 	add_mock_keypress(VB_KEY_ESC);
+	/* #4: Quick memory test screen */
+	add_mock_keypress(VB_KEY_DOWN);
+	add_mock_keypress(VB_KEY_ENTER);
+	add_mock_keypress(VB_KEY_ESC);
+	/* #5: Full memory test screen */
+	add_mock_keypress(VB_KEY_DOWN);
+	add_mock_keypress(VB_KEY_ENTER);
+	add_mock_keypress(VB_KEY_ESC);
+	/* #6: Power off (End of menu) */
 	add_mock_keypress(VB_KEY_DOWN);
 	add_mock_keypress(VB_KEY_ENTER);
 	mock_calls_until_shutdown = -1;
 	TEST_EQ(vb2_diagnostic_menu(ctx), VB2_REQUEST_SHUTDOWN,
 		"diagnostic screen");
 
-	DISPLAYED_EQ("default on first button of menu",
-		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 1, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_EQ("default on first button of menu", VB2_SCREEN_DIAGNOSTICS,
+		     MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
 	/* #0: Language menu */
-	DISPLAYED_EQ("language selection",
-		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 0, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_EQ("language selection", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE,
+		     0, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
 	DISPLAYED_EQ("#0: language menu", VB2_SCREEN_LANGUAGE_SELECT,
 		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
 		     MOCK_IGNORE);
-	/* #1: Storage screen */
 	DISPLAYED_PASS();
-	DISPLAYED_EQ("storage button",
-		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 1, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE);
-	DISPLAYED_EQ("#1: storage screen", VB2_SCREEN_DIAGNOSTICS_STORAGE,
-		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
-		     MOCK_IGNORE);
-	/* #2: Quick memory test screen */
-	DISPLAYED_PASS();
-	DISPLAYED_EQ("quick memory test button",
-		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 2, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE);
-	DISPLAYED_EQ("#1: quick memory test screen",
-		     VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK, MOCK_IGNORE,
+	/* #1: Storage health screen */
+	DISPLAYED_EQ("storage health button", VB2_SCREEN_DIAGNOSTICS,
+		     MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_EQ("#1: storage screen",
+		     VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH, MOCK_IGNORE,
 		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-	/* #3: Full memory test screen */
 	DISPLAYED_PASS();
-	DISPLAYED_EQ("full memory test button",
+	/* #2: Short storage self-test screen */
+	DISPLAYED_EQ("short storage self-test button", VB2_SCREEN_DIAGNOSTICS,
+		     MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_EQ("#2: short storage self-test screen",
+		     VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT, MOCK_IGNORE,
+		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_PASS();
+	/* #3: Extended storage self-test screen */
+	DISPLAYED_EQ("extended storage self-test button",
 		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 3, MOCK_IGNORE,
 		     MOCK_IGNORE, MOCK_IGNORE);
-	DISPLAYED_EQ("#3: full memory test screen",
+	DISPLAYED_EQ("#3: extended storage self-test screen",
+		     VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED, MOCK_IGNORE,
+		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_PASS();
+	/* #4: Quick memory test screen */
+	DISPLAYED_EQ("quick memory test button", VB2_SCREEN_DIAGNOSTICS,
+		     MOCK_IGNORE, 4, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_EQ("#4: quick memory test screen",
+		     VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK, MOCK_IGNORE,
+		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_PASS();
+	/* #5: Full memory test screen */
+	DISPLAYED_EQ("full memory test button", VB2_SCREEN_DIAGNOSTICS,
+		     MOCK_IGNORE, 5, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
+	DISPLAYED_EQ("#5: full memory test screen",
 		     VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL, MOCK_IGNORE,
 		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-	/* #4: Power of (End of menu) */
 	DISPLAYED_PASS();
-	DISPLAYED_EQ("power off",
-		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 4, MOCK_IGNORE,
-		     MOCK_IGNORE, MOCK_IGNORE);
+	/* #6: Power of (End of menu) */
+	DISPLAYED_EQ("power off", VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, 6,
+		     MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
 	DISPLAYED_NO_EXTRA();
 
+	/* Diagnostics screen: no nvme */
+	reset_common_data(FOR_DIAGNOSTICS);
+	/* Non-nvme storage returns UNIMPLEMENTED. */
+	mock_diag_storage_test_rv = VB2_ERROR_EX_UNIMPLEMENTED;
+	TEST_EQ(vb2_diagnostic_menu(ctx), VB2_REQUEST_SHUTDOWN,
+		"diagnostic screen: check disabled item");
+	DISPLAYED_EQ("diagnostic menu: self-test disabled",
+		     VB2_SCREEN_DIAGNOSTICS, MOCK_IGNORE, MOCK_IGNORE, 0xc, 0x0,
+		     MOCK_IGNORE);
+
 	VB2_DEBUG("...done.\n");
 }
 
diff --git a/tests/vb2_ui_utility_tests.c b/tests/vb2_ui_utility_tests.c
index 821402a..1a7b19e 100644
--- a/tests/vb2_ui_utility_tests.c
+++ b/tests/vb2_ui_utility_tests.c
@@ -43,10 +43,6 @@
 }
 
 /* Mock screens */
-struct vb2_screen_info mock_screen_blank = {
-	.id = VB2_SCREEN_BLANK,
-	.name = "mock_screen_blank",
-};
 struct vb2_screen_info mock_screen_base = {
 	.id = MOCK_SCREEN_BASE,
 	.name = "mock_screen_base: menuless screen",
@@ -125,8 +121,6 @@
 	mock_action_called = 0;
 
 	/* Reset init and action functions */
-	mock_screen_blank.init = NULL;
-	mock_screen_blank.action = NULL;
 	mock_screen_base.init = NULL;
 	mock_screen_base.action = NULL;
 	mock_screen_menu.init = NULL;
@@ -157,8 +151,6 @@
 const struct vb2_screen_info *vb2_get_screen_info(enum vb2_screen screen)
 {
 	switch ((int)screen) {
-	case VB2_SCREEN_BLANK:
-		return &mock_screen_blank;
 	case MOCK_SCREEN_BASE:
 		return &mock_screen_base;
 	case MOCK_SCREEN_MENU:
@@ -179,14 +171,13 @@
 	if (!DETACHABLE) {
 		reset_common_data();
 		mock_shutdown_request = 0;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE,
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
 			"release, press, hold, and release");
 		mock_shutdown_request = VB_SHUTDOWN_REQUEST_POWER_BUTTON;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE, "  press");
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE, "  hold");
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+			"  press");
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+			"  hold");
 		mock_shutdown_request = 0;
 		TEST_EQ(check_shutdown_request(&mock_ui_context),
 			VB2_REQUEST_SHUTDOWN, "  release");
@@ -196,8 +187,8 @@
 	if (!DETACHABLE) {
 		reset_common_data();
 		mock_shutdown_request = VB_SHUTDOWN_REQUEST_POWER_BUTTON;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE, "press is ignored");
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+			"press is ignored");
 	}
 
 	/* Power button short press from key */
@@ -222,13 +213,13 @@
 	reset_common_data();
 	gbb.flags |= VB2_GBB_FLAG_DISABLE_LID_SHUTDOWN;
 	mock_shutdown_request = VB_SHUTDOWN_REQUEST_LID_CLOSED;
-	TEST_EQ(check_shutdown_request(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE, "lid ignored");
+	TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+		"lid ignored");
 	if (!DETACHABLE) {  /* Power button works for non DETACHABLE */
 		mock_shutdown_request = VB_SHUTDOWN_REQUEST_LID_CLOSED |
 					VB_SHUTDOWN_REQUEST_POWER_BUTTON;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE, "  lidsw + pwdsw");
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+			"  lidsw + pwdsw");
 		mock_shutdown_request = 0;
 		TEST_EQ(check_shutdown_request(&mock_ui_context),
 			VB2_REQUEST_SHUTDOWN, "  pwdsw release");
@@ -250,24 +241,35 @@
 		/* Flag pwdsw */
 		reset_common_data();
 		mock_shutdown_request = VB_SHUTDOWN_REQUEST_POWER_BUTTON;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE, "DETACHABLE: ignore pwdsw");
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+			"DETACHABLE: ignore pwdsw");
 		mock_shutdown_request = 0;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE, "  ignore on release");
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
+			"  ignore on release");
 
 		/* Power button short press */
 		reset_common_data();
 		mock_shutdown_request = 0;
 		mock_ui_context.key = VB_BUTTON_POWER_SHORT_PRESS;
-		TEST_EQ(check_shutdown_request(&mock_ui_context),
-			VB2_REQUEST_UI_CONTINUE,
+		TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
 			"DETACHABLE: ignore power button short press");
 	}
 
 	VB2_DEBUG("...done.\n");
 }
 
+static vb2_error_t try_back_helper(void)
+{
+	VB2_TRY(vb2_ui_screen_back(&mock_ui_context));
+	return VB2_ERROR_MOCK;
+}
+
+static vb2_error_t try_screen_change_helper(enum vb2_screen screen_id)
+{
+	VB2_TRY(vb2_ui_screen_change(&mock_ui_context, screen_id));
+	return VB2_ERROR_MOCK;
+}
+
 static void screen_stack_tests(void)
 {
 	VB2_DEBUG("Testing screen stack functionality...\n");
@@ -281,8 +283,7 @@
 
 	/* Screen back with empty stack */
 	reset_common_data();
-	TEST_EQ(vb2_ui_screen_back(&mock_ui_context),
-		VB2_REQUEST_UI_CONTINUE,
+	TEST_EQ(vb2_ui_screen_back(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
 		"screen back with empty stack");
 	TEST_PTR_EQ(mock_ui_context.state, NULL, "  stack is empty");
 
@@ -299,6 +300,16 @@
 	screen_state_eq(mock_ui_context.state, MOCK_SCREEN_BASE, 2, 0x10);
 	TEST_EQ(mock_action_called, 1, "  action called once");
 
+	/* VB2_TRY around back should return right away */
+	reset_common_data();
+	TEST_NEQ(try_back_helper(), VB2_ERROR_MOCK,
+		 "continued executing after VB2_TRY(back)");
+
+	/* VB2_TRY around screen_change should return right away */
+	reset_common_data();
+	TEST_NEQ(try_screen_change_helper(MOCK_SCREEN_ROOT), VB2_ERROR_MOCK,
+		 "continued executing after VB2_TRY(screen_change)");
+
 	/* Change to target screen already in stack, restoring the state */
 	reset_common_data();
 	mock_screen_base.init = mock_action_base;
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
index 5229ee5..32eaf02 100644
--- a/tests/vboot_api_kernel4_tests.c
+++ b/tests/vboot_api_kernel4_tests.c
@@ -17,7 +17,6 @@
 #include "test_common.h"
 #include "tlcl.h"
 #include "tss_constants.h"
-#include "vboot_audio.h"
 #include "vboot_kernel.h"
 #include "vboot_struct.h"
 #include "vboot_test.h"
@@ -121,7 +120,7 @@
 	kernel_version = value;
 }
 
-vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t get_info_flags)
+vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags)
 {
 	sd->kernel_version = new_version;
 
diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c
index bcb5d04..9294fd7 100644
--- a/tests/vboot_api_kernel_tests.c
+++ b/tests/vboot_api_kernel_tests.c
@@ -29,6 +29,7 @@
 	const char *name;
 
 	/* inputs for test case */
+	uint32_t ctx_flags;
 	uint32_t want_flags;
 	vb2_error_t diskgetinfo_return_val;
 	disk_desc_t disks_to_provide[MAX_TEST_DISKS];
@@ -52,7 +53,44 @@
 
 test_case_t test[] = {
 	{
+		.name = "first drive (removable)",
+		.ctx_flags = 0,
+		.want_flags = VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_FIXED,
+		.disks_to_provide = {
+			{4096, 100, VB_DISK_FLAG_REMOVABLE, pickme},
+			{4096, 100, VB_DISK_FLAG_FIXED, "holygrail"},
+		},
+		.disk_count_to_return = DEFAULT_COUNT,
+		.diskgetinfo_return_val = VB2_SUCCESS,
+		.loadkernel_return_val = {0},
+		.external_expected = {0},
+
+		.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
+		.expected_to_find_disk = pickme,
+		.expected_to_load_disk = pickme,
+		.expected_return_val = VB2_SUCCESS
+	},
+	{
+		.name = "first drive (fixed)",
+		.ctx_flags = 0,
+		.want_flags = VB_DISK_FLAG_REMOVABLE | VB_DISK_FLAG_FIXED,
+		.disks_to_provide = {
+			{4096, 100, VB_DISK_FLAG_FIXED, pickme},
+			{4096, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"},
+		},
+		.disk_count_to_return = DEFAULT_COUNT,
+		.diskgetinfo_return_val = VB2_SUCCESS,
+		.loadkernel_return_val = {0},
+		.external_expected = {0},
+
+		.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
+		.expected_to_find_disk = pickme,
+		.expected_to_load_disk = pickme,
+		.expected_return_val = VB2_SUCCESS
+	},
+	{
 		.name = "first removable drive",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_REMOVABLE,
 		.disks_to_provide = {
 			/* too small */
@@ -83,6 +121,7 @@
 	},
 	{
 		.name = "first removable drive (skip external GPT)",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_REMOVABLE,
 		.disks_to_provide = {
 			/* too small */
@@ -115,6 +154,7 @@
 	},
 	{
 		.name = "second removable drive",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_REMOVABLE,
 		.disks_to_provide = {
 			/* wrong flags */
@@ -133,6 +173,7 @@
 	},
 	{
 		.name = "first fixed drive",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_FIXED,
 		.disks_to_provide = {
 			/* too small */
@@ -165,6 +206,7 @@
 	},
 	{
 		.name = "no drives at all",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_FIXED,
 		.disks_to_provide = {},
 		.disk_count_to_return = DEFAULT_COUNT,
@@ -177,6 +219,7 @@
 	},
 	{
 		.name = "VbExDiskGetInfo() error",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_FIXED,
 		.disks_to_provide = {
 			{512,  10, VB_DISK_FLAG_REMOVABLE, 0},
@@ -192,6 +235,7 @@
 	},
 	{
 		.name = "invalid kernel",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_FIXED,
 		.disks_to_provide = {
 			/* too small */
@@ -223,6 +267,7 @@
 	},
 	{
 		.name = "invalid kernel, order flipped",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_FIXED,
 		.disks_to_provide = {
 			{512, 1000, VB_DISK_FLAG_FIXED, "stateful partition"},
@@ -240,6 +285,7 @@
 	},
 	{
 		.name = "no Chrome OS partitions",
+		.ctx_flags = 0,
 		.want_flags = VB_DISK_FLAG_FIXED,
 		.disks_to_provide = {
 			{512, 100, VB_DISK_FLAG_FIXED, "stateful partition"},
@@ -257,6 +303,43 @@
 	},
 	{
 		.name = "invalid kernel (removable)",
+		.ctx_flags = 0,
+		.want_flags = VB_DISK_FLAG_REMOVABLE,
+		.disks_to_provide = {
+			{512,  100,  VB_DISK_FLAG_REMOVABLE, "corrupted"},
+			{512,  100,  VB_DISK_FLAG_REMOVABLE, "data"},
+		},
+		.disk_count_to_return = DEFAULT_COUNT,
+		.diskgetinfo_return_val = VB2_SUCCESS,
+		.loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+					  VB2_ERROR_LK_NO_KERNEL_FOUND},
+
+		.expected_recovery_request_val = VB2_RECOVERY_RW_INVALID_OS,
+		.expected_to_find_disk = DONT_CARE,
+		.expected_to_load_disk = 0,
+		.expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+	},
+	{
+		.name = "invalid kernel (removable, rec mode)",
+		.ctx_flags = VB2_CONTEXT_RECOVERY_MODE,
+		.want_flags = VB_DISK_FLAG_REMOVABLE,
+		.disks_to_provide = {
+			{512,  100,  VB_DISK_FLAG_REMOVABLE, "corrupted"},
+			{512,  100,  VB_DISK_FLAG_REMOVABLE, "data"},
+		},
+		.disk_count_to_return = DEFAULT_COUNT,
+		.diskgetinfo_return_val = VB2_SUCCESS,
+		.loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+					  VB2_ERROR_LK_NO_KERNEL_FOUND},
+
+		.expected_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED,
+		.expected_to_find_disk = DONT_CARE,
+		.expected_to_load_disk = 0,
+		.expected_return_val = VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+	},
+	{
+		.name = "invalid kernel (removable, dev mode)",
+		.ctx_flags = VB2_CONTEXT_DEVELOPER_MODE,
 		.want_flags = VB_DISK_FLAG_REMOVABLE,
 		.disks_to_provide = {
 			{512,  100,  VB_DISK_FLAG_REMOVABLE, "corrupted"},
@@ -274,6 +357,23 @@
 	},
 	{
 		.name = "no kernel (removable)",
+		.ctx_flags = 0,
+		.want_flags = VB_DISK_FLAG_REMOVABLE,
+		.disks_to_provide = {
+			{512,  100,  VB_DISK_FLAG_REMOVABLE, "data"},
+		},
+		.disk_count_to_return = DEFAULT_COUNT,
+		.diskgetinfo_return_val = VB2_SUCCESS,
+		.loadkernel_return_val = {VB2_ERROR_LK_NO_KERNEL_FOUND},
+
+		.expected_recovery_request_val = VB2_RECOVERY_RW_NO_KERNEL,
+		.expected_to_find_disk = DONT_CARE,
+		.expected_to_load_disk = 0,
+		.expected_return_val = VB2_ERROR_LK_NO_KERNEL_FOUND,
+	},
+	{
+		.name = "no kernel (removable, rec mode)",
+		.ctx_flags = VB2_CONTEXT_RECOVERY_MODE,
 		.want_flags = VB_DISK_FLAG_REMOVABLE,
 		.disks_to_provide = {
 			{512,  100,  VB_DISK_FLAG_REMOVABLE, "data"},
@@ -312,7 +412,7 @@
 	TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
 		  "vb2api_init failed");
 
-	memset(VbApiKernelGetParams(), 0, sizeof(LoadKernelParams));
+	memset(VbApiKernelGetParams(), 0, sizeof(VbSelectAndLoadKernelParams));
 
 	memset(&mock_disks, 0, sizeof(mock_disks));
 	load_kernel_calls = 0;
@@ -395,14 +495,16 @@
 	return VB2_SUCCESS;
 }
 
-vb2_error_t LoadKernel(struct vb2_context *c, LoadKernelParams *params)
+vb2_error_t LoadKernel(struct vb2_context *c,
+		       VbSelectAndLoadKernelParams *params,
+		       VbDiskInfo *disk_info)
 {
 	got_find_disk = (const char *)params->disk_handle;
 	VB2_DEBUG("%s(%d): got_find_disk = %s\n", __FUNCTION__,
 		  load_kernel_calls,
 		  got_find_disk ? got_find_disk : "0");
 	if (t->external_expected[load_kernel_calls] !=
-			!!(params->boot_flags & BOOT_FLAG_EXTERNAL_GPT))
+			!!(disk_info->flags & VB_DISK_FLAG_EXTERNAL_GPT))
 		got_external_mismatch++;
 	return t->loadkernel_return_val[load_kernel_calls++];
 }
@@ -428,7 +530,8 @@
 	for (i = 0; i < num_tests; i++) {
 		printf("Test case: %s ...\n", test[i].name);
 		ResetMocks(i);
-		TEST_EQ(VbTryLoadKernel(ctx, test[i].want_flags),
+		ctx->flags = t->ctx_flags;
+		TEST_EQ(VbTryLoadKernel(ctx, t->want_flags),
 			t->expected_return_val, "  return value");
 		TEST_EQ(got_recovery_request_val,
 			t->expected_recovery_request_val, "  recovery_request");
diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c
index 87056ad..486602c 100644
--- a/tests/vboot_kernel_tests.c
+++ b/tests/vboot_kernel_tests.c
@@ -20,7 +20,6 @@
 #include "host_common.h"
 #include "load_kernel_fw.h"
 #include "test_common.h"
-#include "vb2_common.h"
 #include "vboot_api.h"
 #include "vboot_kernel.h"
 
@@ -55,7 +54,8 @@
 
 static struct vb2_gbb_header gbb;
 static VbExDiskHandle_t handle;
-static LoadKernelParams lkp;
+static VbSelectAndLoadKernelParams lkp;
+static VbDiskInfo disk_info;
 static struct vb2_keyblock kbh;
 static struct vb2_kernel_preamble kph;
 static struct vb2_secdata_fwmp *fwmp;
@@ -137,13 +137,16 @@
 	gbb.flags = 0;
 
 	memset(&lkp, 0, sizeof(lkp));
-	lkp.bytes_per_lba = 512;
-	lkp.streaming_lba_count = 1024;
-	lkp.gpt_lba_count = 1024;
 	lkp.kernel_buffer = kernel_buffer;
 	lkp.kernel_buffer_size = sizeof(kernel_buffer);
 	lkp.disk_handle = (VbExDiskHandle_t)1;
 
+	memset(&disk_info, 0, sizeof(disk_info));
+	disk_info.bytes_per_lba = 512;
+	disk_info.streaming_lba_count = 1024;
+	disk_info.lba_count = 1024;
+	disk_info.handle = lkp.disk_handle;
+
 	memset(&kbh, 0, sizeof(kbh));
 	kbh.data_key.key_version = 2;
 	kbh.keyblock_flags = -1;
@@ -168,14 +171,19 @@
 	vb2_nv_init(ctx);
 
 	sd = vb2_get_sd(ctx);
-	sd->kernel_version = 0x20001;
+	sd->kernel_version_secdata = 0x20001;
 
 	/* CRC will be invalid after here, but nobody's checking */
 	sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT;
 	fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp;
 	memcpy(&fwmp->dev_key_hash, mock_digest, sizeof(fwmp->dev_key_hash));
 
-	// TODO: more workbuf fields - flags, secdata_firmware, secdata_kernel
+	// TODO: more workbuf fields - flags, secdata_firmware
+
+	vb2api_secdata_kernel_create(ctx);
+	vb2_secdata_kernel_init(ctx);
+	vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_FLAGS,
+			VB2_SECDATA_KERNEL_FLAG_HWCRYPTO_ALLOWED);
 }
 
 /* Mocks */
@@ -588,7 +596,7 @@
 
 static void TestLoadKernel(int expect_retval, const char *test_name)
 {
-	TEST_EQ(LoadKernel(ctx, &lkp), expect_retval, test_name);
+	TEST_EQ(LoadKernel(ctx, &lkp, &disk_info), expect_retval, test_name);
 }
 
 /**
@@ -603,6 +611,7 @@
 	/* This causes the stream open call to fail */
 	ResetMocks();
 	lkp.disk_handle = NULL;
+	disk_info.handle = NULL;
 	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Bad disk handle");
 }
 
@@ -700,6 +709,24 @@
 	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
 		       "Keyblock rec!dev flag mismatch");
 
+	/* Check keyblock flag mismatches (dev mode + signed kernel required) */
+	ResetMocks();
+	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
+	kbh.keyblock_flags =
+		VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0;
+	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+		       "Keyblock dev flag mismatch (signed kernel required)");
+
+	ResetMocks();
+	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+	fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY;
+	kbh.keyblock_flags =
+		VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0;
+	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+		       "Keyblock dev flag mismatch (signed kernel required)");
+
+	/* Check kernel key version */
 	ResetMocks();
 	kbh.data_key.key_version = 1;
 	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
@@ -756,6 +783,23 @@
 	ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
 	TestLoadKernel(0, "Kernel version ignored in rec mode");
 
+	/* Check kernel version (dev mode + signed kernel required) */
+	ResetMocks();
+	kbh.data_key.key_version = 0;
+	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+	vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
+	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+		       "Keyblock key version checked in dev mode "
+		       "(signed kernel required)");
+
+	ResetMocks();
+	kbh.data_key.key_version = 0;
+	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+	fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY;
+	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+		       "Keyblock key version checked in dev mode "
+		       "(signed kernel required)");
+
 	/* Check developer key hash - bad */
 	ResetMocks();
 	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
@@ -764,6 +808,14 @@
 	TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
 		       "Fail keyblock dev fwmp hash");
 
+	/* Check developer key hash - bad (recovery mode) */
+	ResetMocks();
+	ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+	fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH;
+	fwmp->dev_key_hash[0]++;
+	TestLoadKernel(0, "Bad keyblock dev fwmp hash ignored in rec mode");
+
 	/* Check developer key hash - good */
 	ResetMocks();
 	ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
@@ -814,7 +866,7 @@
 
 	/* Check that EXTERNAL_GPT flag makes it down */
 	ResetMocks();
-	lkp.boot_flags |= BOOT_FLAG_EXTERNAL_GPT;
+	disk_info.flags |= VB_DISK_FLAG_EXTERNAL_GPT;
 	TestLoadKernel(0, "Succeed external GPT");
 	TEST_EQ(gpt_flag_external, 1, "GPT was external");
 
diff --git a/tests/verify_kernel.c b/tests/verify_kernel.c
index 9aaad72..8fe969e 100644
--- a/tests/verify_kernel.c
+++ b/tests/verify_kernel.c
@@ -10,6 +10,7 @@
 #include "2common.h"
 #include "2misc.h"
 #include "2nvstorage.h"
+#include "2secdata.h"
 #include "host_common.h"
 #include "util_misc.h"
 #include "vboot_api.h"
@@ -22,16 +23,17 @@
 
 static uint8_t *diskbuf;
 
-static LoadKernelParams params;
+static VbSelectAndLoadKernelParams params;
+static VbDiskInfo disk_info;
 
 vb2_error_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
 			 uint64_t lba_count, void *buffer)
 {
 	if (handle != (VbExDiskHandle_t)1)
 		return VB2_ERROR_UNKNOWN;
-	if (lba_start >= params.streaming_lba_count)
+	if (lba_start >= disk_info.streaming_lba_count)
 		return VB2_ERROR_UNKNOWN;
-	if (lba_start + lba_count > params.streaming_lba_count)
+	if (lba_start + lba_count > disk_info.streaming_lba_count)
 		return VB2_ERROR_UNKNOWN;
 
 	memcpy(buffer, diskbuf + lba_start * 512, lba_count * 512);
@@ -43,9 +45,9 @@
 {
 	if (handle != (VbExDiskHandle_t)1)
 		return VB2_ERROR_UNKNOWN;
-	if (lba_start >= params.streaming_lba_count)
+	if (lba_start >= disk_info.streaming_lba_count)
 		return VB2_ERROR_UNKNOWN;
-	if (lba_start + lba_count > params.streaming_lba_count)
+	if (lba_start + lba_count > disk_info.streaming_lba_count)
 		return VB2_ERROR_UNKNOWN;
 
 	memcpy(diskbuf + lba_start * 512, buffer, lba_count * 512);
@@ -86,9 +88,10 @@
 
 	/* Set up params */
 	params.disk_handle = (VbExDiskHandle_t)1;
-	params.bytes_per_lba = 512;
-	params.streaming_lba_count = disk_bytes / 512;
-	params.gpt_lba_count = params.streaming_lba_count;
+	disk_info.handle = (VbExDiskHandle_t)1;
+	disk_info.bytes_per_lba = 512;
+	disk_info.streaming_lba_count = disk_bytes / 512;
+	disk_info.lba_count = disk_info.streaming_lba_count;
 
 	params.kernel_buffer_size = 16 * 1024 * 1024;
 	params.kernel_buffer = malloc(params.kernel_buffer_size);
@@ -98,7 +101,7 @@
 	}
 
 	/* TODO(chromium:441893): support dev-mode flag and external gpt flag */
-	params.boot_flags = 0;
+	disk_info.flags = 0;
 
 	if (vb2api_init(&workbuf, sizeof(workbuf), &ctx)) {
 		fprintf(stderr, "Can't initialize workbuf\n");
@@ -124,9 +127,14 @@
 	 * dev mode.  So just use defaults for nv storage.
 	 */
 	vb2_nv_init(ctx);
+	/* We need to init kernel secdata for
+	 * VB2_SECDATA_KERNEL_FLAG_HWCRYPTO_ALLOWED.
+	 */
+	vb2api_secdata_kernel_create(ctx);
+	vb2_secdata_kernel_init(ctx);
 
 	/* Try loading kernel */
-	rv = LoadKernel(ctx, &params);
+	rv = LoadKernel(ctx, &params, &disk_info);
 	if (rv != VB2_SUCCESS) {
 		fprintf(stderr, "LoadKernel() failed with code %d\n", rv);
 		return 1;
diff --git a/utility/crossystem.c b/utility/crossystem.c
index 384c671..079bf32 100644
--- a/utility/crossystem.c
+++ b/utility/crossystem.c
@@ -37,13 +37,13 @@
   {"cros_debug", 0, "OS should allow debug features"},
   {"dbg_reset", CAN_WRITE, "Debug reset mode request"},
   {"debug_build", 0, "OS image built for debug features"},
-  {"dev_boot_legacy", CAN_WRITE, "Enable developer mode boot Legacy OSes"},
+  {"dev_boot_altfw", CAN_WRITE, "Enable developer mode alternate bootloader"},
   {"dev_boot_signed_only", CAN_WRITE,
    "Enable developer mode boot only from official kernels"},
   {"dev_boot_usb", CAN_WRITE,
    "Enable developer mode boot from external disk (USB/SD)"},
   {"dev_default_boot", IS_STRING|CAN_WRITE,
-   "Default boot from disk, legacy or usb"},
+   "Default boot from disk, altfw or usb"},
   {"dev_enable_udc", CAN_WRITE, "Enable USB Device Controller"},
   {"devsw_boot", 0, "Developer switch position at boot"},
   {"devsw_cur",  0, "Developer switch current position"},
@@ -106,7 +106,7 @@
 static void PrintHelp(const char *progname) {
   const Param *p;
 
-  printf("\nUsage:\n"
+  printf("Usage:\n"
          "  %s [--all]\n"
          "    Prints all parameters with descriptions and current values.\n"
          "    If --all is specified, prints even normally hidden fields.\n"
@@ -116,7 +116,7 @@
          "    Sets the parameter(s) to the specified value(s).\n"
          "  %s [param1?value1] [param2?value2 [...]]]\n"
          "    Checks if the parameter(s) all contain the specified value(s).\n"
-         "Stops at the first error."
+         "    Stops at the first error.\n"
          "\n"
          "Valid parameters:\n", progname, progname, progname, progname);
   for (p = sys_param_list; p->name; p++) {
@@ -125,6 +125,10 @@
            (p->flags & IS_STRING) ? "str" : "int",
            p->desc);
   }
+  printf("\n"
+         "For more information, please see:\n"
+         "https://chromium.googlesource.com/chromiumos/docs/+/HEAD/"
+         "os_config.md#crossystem\n");
 }
 
 
@@ -135,6 +139,14 @@
   const Param* p;
   if (!name)
     return NULL;
+  /* "legacy" term deprecated in favour of "altfw" (see: b/179458327) */
+  if (!strcasecmp(name, "dev_boot_legacy")) {
+    fprintf(stderr,
+            "!!!\n"
+            "!!! PLEASE USE 'dev_boot_altfw' INSTEAD OF 'dev_boot_legacy'\n"
+            "!!!\n");
+    name = "dev_boot_altfw";
+  }
   for (p = sys_param_list; p->name; p++) {
     if (!strcasecmp(p->name, name))
       return p;
@@ -308,13 +320,13 @@
       case PARAM_SUCCESS:
         break;
       case PARAM_ERROR_READ_ONLY:
-        fprintf(stderr, "Parameter %s is read-only\n", name);
+        fprintf(stderr, "Parameter %s is read-only\n", p->name);
         break;
       case PARAM_ERROR_INVALID_INT:
         fprintf(stderr, "Value %s is not a valid integer\n", value);
         break;
       default:
-        fprintf(stderr, "Failed to set parameter %s\n", name);
+        fprintf(stderr, "Failed to set parameter %s\n", p->name);
         break;
       }
     } else if (has_expect)
diff --git a/utility/load_kernel_test.c b/utility/load_kernel_test.c
index c5dc7cb..cad82fd 100644
--- a/utility/load_kernel_test.c
+++ b/utility/load_kernel_test.c
@@ -26,7 +26,8 @@
 static struct vb2_shared_data *sd;
 
 /* Global variables for stub functions */
-static LoadKernelParams lkp;
+static VbSelectAndLoadKernelParams lkp;
+static VbDiskInfo disk_info;
 static FILE *image_file = NULL;
 
 
@@ -36,17 +37,19 @@
 {
 	printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
 
-	if (lba_start >= lkp.streaming_lba_count ||
-	    lba_start + lba_count > lkp.streaming_lba_count) {
+	if (lba_start >= disk_info.streaming_lba_count ||
+	    lba_start + lba_count > disk_info.streaming_lba_count) {
 		fprintf(stderr,
 			"Read overrun: %" PRIu64 " + %" PRIu64
 			" > %" PRIu64 "\n", lba_start,
-			lba_count, lkp.streaming_lba_count);
+			lba_count, disk_info.streaming_lba_count);
 		return 1;
 	}
 
-	if (0 != fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET) ||
-	    1 != fread(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) {
+	if (0 != fseek(image_file, lba_start * disk_info.bytes_per_lba,
+		       SEEK_SET) ||
+	    1 != fread(buffer, lba_count * disk_info.bytes_per_lba, 1,
+		       image_file)) {
 		fprintf(stderr, "Read error.");
 		return 1;
 	}
@@ -59,12 +62,12 @@
 {
 	printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
 
-	if (lba_start >= lkp.streaming_lba_count ||
-	    lba_start + lba_count > lkp.streaming_lba_count) {
+	if (lba_start >= disk_info.streaming_lba_count ||
+	    lba_start + lba_count > disk_info.streaming_lba_count) {
 		fprintf(stderr,
 			"Read overrun: %" PRIu64 " + %" PRIu64
 			" > %" PRIu64 "\n", lba_start, lba_count,
-			lkp.streaming_lba_count);
+			disk_info.streaming_lba_count);
 		return 1;
 	}
 
@@ -72,8 +75,9 @@
 	   our example file */
 	return VB2_SUCCESS;
 
-	fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET);
-	if (1 != fwrite(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) {
+	fseek(image_file, lba_start * disk_info.bytes_per_lba, SEEK_SET);
+	if (1 != fwrite(buffer, lba_count * disk_info.bytes_per_lba, 1,
+			image_file)) {
 		fprintf(stderr, "Read error.");
 		return 1;
 	}
@@ -96,8 +100,8 @@
 	int errorcnt = 0;
 	char *e = 0;
 
-	memset(&lkp, 0, sizeof(LoadKernelParams));
-	lkp.bytes_per_lba = LBA_BYTES;
+	memset(&lkp, 0, sizeof(VbSelectAndLoadKernelParams));
+	disk_info.bytes_per_lba = LBA_BYTES;
 	int boot_flags = BOOT_FLAG_RECOVERY;
 
 	/* Parse options */
@@ -186,7 +190,6 @@
 	}
 
 	printf("bootflags = %d\n", boot_flags);
-	lkp.boot_flags = boot_flags;
 
 	/* Get image size */
 	printf("Reading from image: %s\n", image_name);
@@ -196,10 +199,11 @@
 		return 1;
 	}
 	fseek(image_file, 0, SEEK_END);
-	lkp.streaming_lba_count = (ftell(image_file) / LBA_BYTES);
-	lkp.gpt_lba_count = lkp.streaming_lba_count;
+	disk_info.streaming_lba_count = (ftell(image_file) / LBA_BYTES);
+	disk_info.lba_count = disk_info.streaming_lba_count;
 	rewind(image_file);
-	printf("Streaming LBA count: %" PRIu64 "\n", lkp.streaming_lba_count);
+	printf("Streaming LBA count: %" PRIu64 "\n",
+	       disk_info.streaming_lba_count);
 
 	/* Allocate a buffer for the kernel */
 	lkp.kernel_buffer = malloc(KERNEL_BUFFER_SIZE);
@@ -241,7 +245,7 @@
 		ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
 
 	/* Call LoadKernel() */
-	rv = LoadKernel(ctx, &lkp);
+	rv = LoadKernel(ctx, &lkp, &disk_info);
 	printf("LoadKernel() returned %d\n", rv);
 
 	if (VB2_SUCCESS == rv) {
diff --git a/utility/tpmc.c b/utility/tpmc.c
index 5723edf..841551c 100644
--- a/utility/tpmc.c
+++ b/utility/tpmc.c
@@ -66,10 +66,10 @@
  * success, non-zero for failure.
  */
 static int HexStringToUint32(const char* string, uint32_t* value) {
-  char tail[1];
+  char tail;
   /* strtoul is not as good because it overflows silently */
-  const char* format = strncmp(string, "0x", 2) ? "%8x%s" : "0x%8x%s";
-  int n = sscanf(string, format, value, tail);
+  const char* format = strncmp(string, "0x", 2) ? "%8x%c" : "0x%8x%c";
+  int n = sscanf(string, format, value, &tail);
   return n != 1;
 }
 
diff --git a/utility/verify_data.c b/utility/verify_data.c
index 8440b3a..6d3ea15 100644
--- a/utility/verify_data.c
+++ b/utility/verify_data.c
@@ -21,7 +21,6 @@
 #include "2sysincludes.h"
 #include "file_keys.h"
 #include "host_common.h"
-#include "vb2_common.h"
 
 /* ANSI Color coding sequences. */
 #define COL_GREEN "\e[1;32m"