Merge commit '1269365169791c65a6bf6f364583209195874138' into cros_sdk
Updated vboot_reference to CrOS version 14283.0.0
BUG=b/202788640
TEST=local BE run
RELEASE_NOTE=Updated ChromeOS base to ChromeOS version 14283.0.0.
Change-Id: I7d97e04ac7e527d86cffe43a5edae39be555e908
diff --git a/.checkpatch.conf b/.checkpatch.conf
new file mode 100644
index 0000000..1f93e0e
--- /dev/null
+++ b/.checkpatch.conf
@@ -0,0 +1,21 @@
+# Not Linux, so don't expect a Linux tree.
+--no-tree
+
+# Ignore aspects we don't follow here.
+--ignore BLOCK_COMMENT_STYLE
+--ignore C99_COMMENTS
+--ignore CAMELCASE
+--ignore CONFIG_DESCRIPTION
+--ignore GLOBAL_INITIALISERS
+--ignore INITIALISED_STATIC
+--ignore LINE_SPACING
+--ignore MACRO_WITH_FLOW_CONTROL
+--ignore NEW_TYPEDEFS
+--ignore OPEN_BRACE
+--ignore PREFER_ALIGNED
+--ignore PREFER_PACKED
+--ignore PREFER_PRINTF
+--ignore SPACING
+--ignore SPDX_LICENSE_TAG
+--ignore SPLIT_STRING
+--ignore TRAILING_STATEMENTS
diff --git a/Makefile b/Makefile
index 327b753..82d6a44 100644
--- a/Makefile
+++ b/Makefile
@@ -123,7 +123,7 @@
# Provide default CC and CFLAGS for firmware builds; if you have any -D flags,
# please add them after this point (e.g., -DVBOOT_DEBUG).
-DEBUG_FLAGS := $(if ${DEBUG},-g -O0,-g -Os)
+DEBUG_FLAGS := $(if ${DEBUG},-g -Og,-g -Os)
WERROR := -Werror
FIRMWARE_FLAGS := -nostdinc -ffreestanding -fno-builtin -fno-stack-protector
COMMON_FLAGS := -pipe ${WERROR} -Wall -Wstrict-prototypes -Wtype-limits \
@@ -171,7 +171,7 @@
# Needs -Wl because LD is actually set to CC by default.
LDFLAGS += -Wl,--gc-sections
-ifneq (${DEBUG},)
+ifneq (${DEBUG}$(filter-out 0,${TEST_PRINT}),)
CFLAGS += -DVBOOT_DEBUG
endif
@@ -235,13 +235,6 @@
CFLAGS += -DDETACHABLE=0
endif
-# pass DIAGNOSTIC_UI= (or =0) to make to disable feature
-ifneq ($(filter-out 0,${DIAGNOSTIC_UI}),)
-CFLAGS += -DDIAGNOSTIC_UI=1
-else
-CFLAGS += -DDIAGNOSTIC_UI=0
-endif
-
# Confirm physical presence using keyboard
ifneq ($(filter-out 0,${PHYSICAL_PRESENCE_KEYBOARD}),)
CFLAGS += -DPHYSICAL_PRESENCE_KEYBOARD=1
@@ -422,12 +415,6 @@
firmware/lib20/api_kernel.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 \
-
# TPM lightweight command library
ifeq (${TPM2_MODE},)
TLCL_SRCS = \
@@ -445,6 +432,14 @@
firmware/lib/tpm_lite/mocked_tlcl.c
endif
+ifneq ($(filter-out 0,${X86_SHA_EXT}),)
+CFLAGS += -DX86_SHA_EXT
+FWLIB_SRCS += \
+ firmware/2lib/2sha256_x86.c
+endif
+# Even if X86_SHA_EXT is 0 we need cflags since this will be compiled for tests
+${BUILD}/firmware/2lib/2sha256_x86.o: CFLAGS += -mssse3 -mno-avx -msha
+
ifeq (${FIRMWARE_ARCH},)
# Include BIOS stubs in the firmware library when compiling for host
# TODO: split out other stub funcs too
@@ -709,11 +704,13 @@
TEST_NAMES = \
tests/cgptlib_test \
tests/chromeos_config_tests \
+ tests/gpt_misc_tests \
tests/sha_benchmark \
tests/subprocess_tests \
tests/vboot_api_kernel4_tests \
tests/vboot_api_kernel_tests \
tests/vboot_kernel_tests \
+ tests/vboot_kernel2_tests \
tests/verify_kernel
ifeq (${MOCK_TPM}${TPM2_MODE},)
@@ -753,9 +750,6 @@
tests/vb2_secdata_kernel_tests \
tests/vb2_sha_api_tests \
tests/vb2_sha_tests \
- tests/vb2_ui_tests \
- tests/vb2_ui_action_tests \
- tests/vb2_ui_utility_tests \
tests/hmac_test
TEST20_NAMES = \
@@ -774,6 +768,11 @@
TEST_NAMES += ${TEST2X_NAMES} ${TEST20_NAMES} ${TEST21_NAMES}
+# This is build-only test since we can't run this without
+# sha-ni extension on x86. To run this test, you have to
+# manually copy executable into compatible machine and run it.
+TEST_NAMES += tests/vb2_sha256_x86_tests
+
# And a few more...
ifeq (${TPM2_MODE},)
TLCL_TEST_NAMES = \
@@ -1095,6 +1094,11 @@
${TEST20_BINS}: LIBS += ${FWLIB}
${TEST20_BINS}: LDLIBS += ${CRYPTO_LIBS}
+# Special build for sha256_x86 test
+X86_SHA256_TEST = ${BUILD_RUN}/tests/vb2_sha256_x86_tests
+${X86_SHA256_TEST}: ${BUILD}/firmware/2lib/2sha256_x86.o
+${X86_SHA256_TEST}: LIBS += ${BUILD}/firmware/2lib/2sha256_x86.o
+
${TESTLIB}: ${TESTLIB_OBJS}
@${PRINTF} " RM $(subst ${BUILD}/,,$@)\n"
${Q}rm -f $@
@@ -1255,6 +1259,7 @@
.PHONY: runmisctests
runmisctests: install_for_test
+ ${RUNTEST} ${BUILD_RUN}/tests/gpt_misc_tests
${RUNTEST} ${BUILD_RUN}/tests/subprocess_tests
ifeq (${MOCK_TPM}${TPM2_MODE},)
# tlcl_tests only works when MOCK_TPM is disabled
@@ -1263,6 +1268,7 @@
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel4_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel2_tests
.PHONY: run2tests
run2tests: install_for_test
@@ -1285,9 +1291,6 @@
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_api_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
- ${RUNTEST} ${BUILD_RUN}/tests/vb2_ui_tests
- ${RUNTEST} ${BUILD_RUN}/tests/vb2_ui_action_tests
- ${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/vb21_host_common_tests
diff --git a/OWNERS b/OWNERS
index 2f14d72..74ba71a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,5 @@
-kitching@chromium.org
jwerner@chromium.org
-rspangler@chromium.org
+yupingso@chromium.org
+furquan@chromium.org
+hungte@chromium.org
*
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg
index 8770083..54d538d 100644
--- a/PRESUBMIT.cfg
+++ b/PRESUBMIT.cfg
@@ -1,8 +1,12 @@
[Hook Overrides]
branch_check: true
+checkpatch_check: true
+long_line_check: false
signoff_check: true
# We are using Linux style indentation with tabs
# The indentation is checked by checkpatch not the python script
tab_check: false
+[Hook Overrides Options]
+cros_license_check: --exclude_regex=^\.checkpatch\.conf$
diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c
index c3edd0f..2f888fd 100644
--- a/cgpt/cgpt_common.c
+++ b/cgpt/cgpt_common.c
@@ -672,6 +672,8 @@
const Guid guid_chromeos_reserved = GPT_ENT_TYPE_CHROMEOS_RESERVED;
const Guid guid_efi = GPT_ENT_TYPE_EFI;
const Guid guid_unused = GPT_ENT_TYPE_UNUSED;
+const Guid guid_chromeos_minios = GPT_ENT_TYPE_CHROMEOS_MINIOS;
+const Guid guid_chromeos_hibernate = GPT_ENT_TYPE_CHROMEOS_HIBERNATE;
const static struct {
const Guid *type;
@@ -686,6 +688,8 @@
{&guid_chromeos_reserved, "reserved", "ChromeOS reserved"},
{&guid_efi, "efi", "EFI System Partition"},
{&guid_unused, "unused", "Unused (nonexistent) partition"},
+ {&guid_chromeos_minios, "minios", "ChromeOS miniOS"},
+ {&guid_chromeos_hibernate, "hibernate", "ChromeOS hibernate"},
};
/* Resolves human-readable GPT type.
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c
index aa1d25d..593a12c 100644
--- a/firmware/2lib/2api.c
+++ b/firmware/2lib/2api.c
@@ -59,6 +59,11 @@
if (rv)
vb2api_fail(ctx, VB2_RECOVERY_GBB_HEADER, rv);
+ /* Check for dev switch */
+ rv = vb2_check_dev_switch(ctx);
+ if (rv)
+ vb2api_fail(ctx, VB2_RECOVERY_DEV_SWITCH, rv);
+
/*
* Check for recovery. Note that this function returns void, since any
* errors result in requesting recovery. That's also why we don't
@@ -67,20 +72,6 @@
*/
vb2_check_recovery(ctx);
- /* Check for dev switch */
- rv = vb2_check_dev_switch(ctx);
- if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
- /*
- * Error in dev switch processing, and we weren't already
- * headed for recovery mode. Reboot into recovery mode, since
- * it's too late to handle those errors this boot, and we need
- * to take a different path through the dev switch checking
- * code in that case.
- */
- vb2api_fail(ctx, VB2_RECOVERY_DEV_SWITCH, rv);
- return rv;
- }
-
/*
* Check for possible reasons to ask the firmware to make display
* available. VB2_CONTEXT_RECOVERY_MODE may have been set above by
diff --git a/firmware/2lib/2ec_sync.c b/firmware/2lib/2ec_sync.c
index 9c49ceb..20490e0 100644
--- a/firmware/2lib/2ec_sync.c
+++ b/firmware/2lib/2ec_sync.c
@@ -212,6 +212,10 @@
return VB2_REQUEST_REBOOT_EC_TO_RO;
}
+ /* We no longer trust the EC once it is already in RW or tries to jump
+ to RW. */
+ ctx->flags &= ~VB2_CONTEXT_EC_TRUSTED;
+
/* Tell EC to jump to RW. It should already be in RW for EFS2. */
if (!(sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW)) {
VB2_DEBUG("jumping to EC-RW\n");
diff --git a/firmware/2lib/2kernel.c b/firmware/2lib/2kernel.c
index 763214d..86fb286 100644
--- a/firmware/2lib/2kernel.c
+++ b/firmware/2lib/2kernel.c
@@ -11,7 +11,7 @@
#include "2nvstorage.h"
#include "2rsa.h"
#include "2secdata.h"
-#include "vboot_kernel.h"
+#include "vboot_api.h"
/**
* Reset any NVRAM requests.
@@ -157,12 +157,14 @@
vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
sd->kernel_version = sd->kernel_version_secdata;
+ vb2_fill_dev_boot_flags(ctx);
+
/* Find the key to use to verify the kernel keyblock */
if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
/* Load recovery key from GBB. */
rv = vb2_gbb_read_recovery_key(ctx, &packed_key, NULL, &wb);
if (rv) {
- if (vb2_allow_recovery(ctx))
+ if (vb2api_allow_recovery(ctx))
VB2_DIE("GBB read recovery key failed.\n");
else
/*
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index 75a9f36..efa33a8 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -375,8 +375,14 @@
return VB2_SUCCESS;
}
-void vb2_enable_developer_mode(struct vb2_context *ctx)
+vb2_error_t vb2api_enable_developer_mode(struct vb2_context *ctx)
{
+ if (!vb2api_allow_recovery(ctx)) {
+ VB2_DEBUG("ERROR: Can only enable developer mode from manual "
+ "recovery mode\n");
+ return VB2_ERROR_API_ENABLE_DEV_NOT_ALLOWED;
+ }
+
uint32_t flags;
VB2_DEBUG("Enabling developer mode...\n");
@@ -389,10 +395,29 @@
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
VB2_DEBUG("Mode change will take effect on next reboot\n");
+
+ return VB2_SUCCESS;
+}
+
+vb2_error_t vb2api_disable_developer_mode(struct vb2_context *ctx)
+{
+ if (vb2api_gbb_get_flags(ctx) & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) {
+ VB2_DEBUG("ERROR: dev mode forced by GBB flag\n");
+ return VB2_ERROR_API_DISABLE_DEV_NOT_ALLOWED;
+ }
+
+ VB2_DEBUG("Leaving dev mode\n");
+ vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 1);
+ return VB2_SUCCESS;
+}
+
+void vb2api_request_diagnostics(struct vb2_context *ctx) {
+ vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
+ VB2_DEBUG("Diagnostics requested\n");
}
test_mockable
-int vb2_allow_recovery(struct vb2_context *ctx)
+int vb2api_allow_recovery(struct vb2_context *ctx)
{
if (ctx->flags & VB2_CONTEXT_NO_BOOT)
return 0;
@@ -432,7 +457,7 @@
/* But stow recovery reason as subcode for non-manual recovery. */
if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE) &&
- !vb2_allow_recovery(ctx)) {
+ !vb2api_allow_recovery(ctx)) {
VB2_DEBUG("Stow recovery reason as subcode (%#x)\n",
sd->recovery_reason);
vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, sd->recovery_reason);
@@ -459,6 +484,11 @@
return vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX);
}
+void vb2api_set_locale_id(struct vb2_context *ctx, uint32_t locale_id)
+{
+ vb2_nv_set(ctx, VB2_NV_LOCALIZATION_INDEX, locale_id);
+}
+
void vb2api_export_vbsd(struct vb2_context *ctx, void *dest)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
@@ -532,12 +562,12 @@
switch (vb2_nv_get(ctx, VB2_NV_DEV_DEFAULT_BOOT)) {
case VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL:
- if (vb2_dev_boot_external_allowed(ctx))
+ if (ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED)
return VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
break;
case VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW:
- if (vb2_dev_boot_altfw_allowed(ctx))
+ if (ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED)
return VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW;
break;
}
@@ -545,33 +575,25 @@
return VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL;
}
-int vb2_dev_boot_allowed(struct vb2_context *ctx)
+void vb2_fill_dev_boot_flags(struct vb2_context *ctx)
{
struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
- if (vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_DISABLE_BOOT))
- return !!(gbb->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON);
+ if (!vb2_secdata_fwmp_get_flag(ctx,
+ VB2_SECDATA_FWMP_DEV_DISABLE_BOOT) ||
+ (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON))
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_ALLOWED;
- return 1;
-}
+ if (vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL) ||
+ (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_USB) ||
+ vb2_secdata_fwmp_get_flag(ctx,
+ VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL))
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED;
-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_ALTFW) ||
- (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW) ||
- vb2_secdata_fwmp_get_flag(ctx,
- VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW);
-}
-
-int vb2_dev_boot_external_allowed(struct vb2_context *ctx)
-{
- struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
-
- return vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL) ||
- (gbb->flags & VB2_GBB_FLAG_FORCE_DEV_BOOT_USB) ||
- vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL);
+ if (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_ALTFW))
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED;
}
int vb2api_use_short_dev_screen_delay(struct vb2_context *ctx)
diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c
index 1cd5ba2..4fd9808 100644
--- a/firmware/2lib/2nvstorage.c
+++ b/firmware/2lib/2nvstorage.c
@@ -80,6 +80,11 @@
sd->status |= VB2_SD_STATUS_NV_REINIT;
/* TODO: unit test for status flag being set */
+ } else {
+#ifndef CHROMEOS_ENVIRONMENT
+ /* Always clear this on first reboot that didn't need reinit. */
+ vb2_nv_set(ctx, VB2_NV_FIRMWARE_SETTINGS_RESET, 0);
+#endif
}
sd->status |= VB2_SD_STATUS_NV_INIT;
@@ -209,6 +214,9 @@
return GETBIT(VB2_NV_OFFS_MISC,
VB2_NV_MISC_POST_EC_SYNC_DELAY);
+ case VB2_NV_MINIOS_PRIORITY:
+ return GETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_MINIOS_PRIORITY);
+
case VB2_NV_DEPRECATED_DEV_BOOT_FASTBOOT_FULL_CAP:
case VB2_NV_DEPRECATED_FASTBOOT_UNLOCK_IN_FW:
case VB2_NV_DEPRECATED_ENABLE_ALT_OS_REQUEST:
@@ -416,6 +424,10 @@
SETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_POST_EC_SYNC_DELAY);
break;
+ case VB2_NV_MINIOS_PRIORITY:
+ SETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_MINIOS_PRIORITY);
+ break;
+
case VB2_NV_DEPRECATED_DEV_BOOT_FASTBOOT_FULL_CAP:
case VB2_NV_DEPRECATED_FASTBOOT_UNLOCK_IN_FW:
case VB2_NV_DEPRECATED_ENABLE_ALT_OS_REQUEST:
diff --git a/firmware/2lib/2sha256.c b/firmware/2lib/2sha256.c
index c361237..0044113 100644
--- a/firmware/2lib/2sha256.c
+++ b/firmware/2lib/2sha256.c
@@ -1,3 +1,8 @@
+/* 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.
+ */
+
/* SHA-256 and SHA-512 implementation based on code by Oliver Gay
* <olivier.gay@a3.epfl.ch> under a BSD-style license. See below.
*/
@@ -37,6 +42,7 @@
#include "2common.h"
#include "2sha.h"
+#include "2sha_private.h"
#include "2sysincludes.h"
#define SHFR(x, n) (x >> n)
@@ -50,22 +56,6 @@
#define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3))
#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
-#define UNPACK32(x, str) \
- { \
- *((str) + 3) = (uint8_t) ((x) ); \
- *((str) + 2) = (uint8_t) ((x) >> 8); \
- *((str) + 1) = (uint8_t) ((x) >> 16); \
- *((str) + 0) = (uint8_t) ((x) >> 24); \
- }
-
-#define PACK32(str, x) \
- { \
- *(x) = ((uint32_t) *((str) + 3) ) \
- | ((uint32_t) *((str) + 2) << 8) \
- | ((uint32_t) *((str) + 1) << 16) \
- | ((uint32_t) *((str) + 0) << 24); \
- }
-
/* Macros used for loops unrolling */
#define SHA256_SCR(i) \
@@ -77,13 +67,13 @@
#define SHA256_EXP(a, b, c, d, e, f, g, h, j) \
{ \
t1 = wv[h] + SHA256_F2(wv[e]) + CH(wv[e], wv[f], wv[g]) \
- + sha256_k[j] + w[j]; \
+ + vb2_sha256_k[j] + w[j]; \
t2 = SHA256_F1(wv[a]) + MAJ(wv[a], wv[b], wv[c]); \
wv[d] += t1; \
wv[h] = t1 + t2; \
}
-static const uint32_t sha256_h0[8] = {
+const uint32_t vb2_sha256_h0[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
@@ -93,7 +83,7 @@
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
};
-static const uint32_t sha256_k[64] = {
+const uint32_t vb2_sha256_k[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
@@ -116,7 +106,7 @@
void vb2_sha256_init(struct vb2_sha256_context *ctx,
enum vb2_hash_algorithm algo)
{
- const uint32_t *h0 = algo == VB2_HASH_SHA224 ? sha224_h0 : sha256_h0;
+ const uint32_t *h0 = algo == VB2_HASH_SHA224 ? sha224_h0 : vb2_sha256_h0;
#ifndef UNROLL_LOOPS
int i;
@@ -167,7 +157,7 @@
for (j = 0; j < 64; j++) {
t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
- + sha256_k[j] + w[j];
+ + vb2_sha256_k[j] + w[j];
t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
wv[7] = wv[6];
wv[6] = wv[5];
diff --git a/firmware/2lib/2sha256_x86.c b/firmware/2lib/2sha256_x86.c
new file mode 100644
index 0000000..e80477e
--- /dev/null
+++ b/firmware/2lib/2sha256_x86.c
@@ -0,0 +1,255 @@
+/* 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.
+ *
+ * SHA256 implementation using x86 SHA extension.
+ * Mainly from https://github.com/noloader/SHA-Intrinsics/blob/master/sha256-x86.c,
+ * Written and place in public domain by Jeffrey Walton
+ * Based on code from Intel, and by Sean Gulley for
+ * the miTLS project.
+ */
+#include "2common.h"
+#include "2sha.h"
+#include "2sha_private.h"
+#include "2api.h"
+
+static struct vb2_sha256_context sha_ctx;
+
+typedef int vb2_m128i __attribute__ ((vector_size(16)));
+
+static inline vb2_m128i vb2_loadu_si128(vb2_m128i *ptr)
+{
+ vb2_m128i result;
+ asm volatile ("movups %1, %0" : "=x"(result) : "m"(*ptr));
+ return result;
+}
+
+static inline void vb2_storeu_si128(vb2_m128i *to, vb2_m128i from)
+{
+ asm volatile ("movups %1, %0" : "=m"(*to) : "x"(from));
+}
+
+static inline vb2_m128i vb2_add_epi32(vb2_m128i a, vb2_m128i b)
+{
+ return a + b;
+}
+
+static inline vb2_m128i vb2_shuffle_epi8(vb2_m128i value, vb2_m128i mask)
+{
+ asm ("pshufb %1, %0" : "+x"(value) : "xm"(mask));
+ return value;
+}
+
+static inline vb2_m128i vb2_shuffle_epi32(vb2_m128i value, int mask)
+{
+ vb2_m128i result;
+ asm ("pshufd %2, %1, %0" : "=x"(result) : "xm"(value), "i" (mask));
+ return result;
+}
+
+static inline vb2_m128i vb2_alignr_epi8(vb2_m128i a, vb2_m128i b, int imm8)
+{
+ asm ("palignr %2, %1, %0" : "+x"(a) : "xm"(b), "i"(imm8));
+ return a;
+}
+
+static inline vb2_m128i vb2_sha256msg1_epu32(vb2_m128i a, vb2_m128i b)
+{
+ asm ("sha256msg1 %1, %0" : "+x"(a) : "xm"(b));
+ return a;
+}
+
+static inline vb2_m128i vb2_sha256msg2_epu32(vb2_m128i a, vb2_m128i b)
+{
+ asm ("sha256msg2 %1, %0" : "+x"(a) : "xm"(b));
+ return a;
+}
+
+static inline vb2_m128i vb2_sha256rnds2_epu32(vb2_m128i a, vb2_m128i b,
+ vb2_m128i k)
+{
+ asm ("sha256rnds2 %1, %0" : "+x"(a) : "xm"(b), "Yz"(k));
+ return a;
+}
+
+#define SHA256_X86_PUT_STATE1(j, i) \
+ { \
+ msgtmp[j] = vb2_loadu_si128((vb2_m128i *) \
+ (message + (i << 6) + (j * 16))); \
+ msgtmp[j] = vb2_shuffle_epi8(msgtmp[j], shuf_mask); \
+ msg = vb2_add_epi32(msgtmp[j], \
+ vb2_loadu_si128((vb2_m128i *)&vb2_sha256_k[j * 4])); \
+ state1 = vb2_sha256rnds2_epu32(state1, state0, msg); \
+ }
+
+#define SHA256_X86_PUT_STATE0() \
+ { \
+ msg = vb2_shuffle_epi32(msg, 0x0E); \
+ state0 = vb2_sha256rnds2_epu32(state0, state1, msg); \
+ }
+
+#define SHA256_X86_LOOP(j) \
+ { \
+ int k = j & 3; \
+ int prev_k = (k + 3) & 3; \
+ int next_k = (k + 1) & 3; \
+ msg = vb2_add_epi32(msgtmp[k], \
+ vb2_loadu_si128((vb2_m128i *)&vb2_sha256_k[j * 4])); \
+ state1 = vb2_sha256rnds2_epu32(state1, state0, msg); \
+ tmp = vb2_alignr_epi8(msgtmp[k], msgtmp[prev_k], 4); \
+ msgtmp[next_k] = vb2_add_epi32(msgtmp[next_k], tmp); \
+ msgtmp[next_k] = vb2_sha256msg2_epu32(msgtmp[next_k], \
+ msgtmp[k]); \
+ SHA256_X86_PUT_STATE0(); \
+ msgtmp[prev_k] = vb2_sha256msg1_epu32(msgtmp[prev_k], \
+ msgtmp[k]); \
+ }
+
+static void vb2_sha256_transform_x86ext(const uint8_t *message,
+ unsigned int block_nb)
+{
+ vb2_m128i state0, state1, msg, abef_save, cdgh_save;
+ vb2_m128i msgtmp[4];
+ vb2_m128i tmp;
+ int i;
+ const vb2_m128i shuf_mask = {0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f};
+
+ state0 = vb2_loadu_si128((vb2_m128i *)&sha_ctx.h[0]);
+ state1 = vb2_loadu_si128((vb2_m128i *)&sha_ctx.h[4]);
+ for (i = 0; i < (int) block_nb; i++) {
+ abef_save = state0;
+ cdgh_save = state1;
+
+ SHA256_X86_PUT_STATE1(0, i);
+ SHA256_X86_PUT_STATE0();
+
+ SHA256_X86_PUT_STATE1(1, i);
+ SHA256_X86_PUT_STATE0();
+ msgtmp[0] = vb2_sha256msg1_epu32(msgtmp[0], msgtmp[1]);
+
+ SHA256_X86_PUT_STATE1(2, i);
+ SHA256_X86_PUT_STATE0();
+ msgtmp[1] = vb2_sha256msg1_epu32(msgtmp[1], msgtmp[2]);
+
+ SHA256_X86_PUT_STATE1(3, i);
+ tmp = vb2_alignr_epi8(msgtmp[3], msgtmp[2], 4);
+ msgtmp[0] = vb2_add_epi32(msgtmp[0], tmp);
+ msgtmp[0] = vb2_sha256msg2_epu32(msgtmp[0], msgtmp[3]);
+ SHA256_X86_PUT_STATE0();
+ msgtmp[2] = vb2_sha256msg1_epu32(msgtmp[2], msgtmp[3]);
+
+ SHA256_X86_LOOP(4);
+ SHA256_X86_LOOP(5);
+ SHA256_X86_LOOP(6);
+ SHA256_X86_LOOP(7);
+ SHA256_X86_LOOP(8);
+ SHA256_X86_LOOP(9);
+ SHA256_X86_LOOP(10);
+ SHA256_X86_LOOP(11);
+ SHA256_X86_LOOP(12);
+ SHA256_X86_LOOP(13);
+ SHA256_X86_LOOP(14);
+
+ msg = vb2_add_epi32(msgtmp[3],
+ vb2_loadu_si128((vb2_m128i *)&vb2_sha256_k[15 * 4]));
+ state1 = vb2_sha256rnds2_epu32(state1, state0, msg);
+ SHA256_X86_PUT_STATE0();
+
+ state0 = vb2_add_epi32(state0, abef_save);
+ state1 = vb2_add_epi32(state1, cdgh_save);
+
+ }
+
+ vb2_storeu_si128((vb2_m128i *)&sha_ctx.h[0], state0);
+ vb2_storeu_si128((vb2_m128i *)&sha_ctx.h[4], state1);
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
+ uint32_t data_size)
+{
+ if (hash_alg != VB2_HASH_SHA256)
+ return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
+
+ sha_ctx.h[0] = vb2_sha256_h0[5];
+ sha_ctx.h[1] = vb2_sha256_h0[4];
+ sha_ctx.h[2] = vb2_sha256_h0[1];
+ sha_ctx.h[3] = vb2_sha256_h0[0];
+ sha_ctx.h[4] = vb2_sha256_h0[7];
+ sha_ctx.h[5] = vb2_sha256_h0[6];
+ sha_ctx.h[6] = vb2_sha256_h0[3];
+ sha_ctx.h[7] = vb2_sha256_h0[2];
+ sha_ctx.size = 0;
+ sha_ctx.total_size = 0;
+ memset(sha_ctx.block, 0, sizeof(sha_ctx.block));
+
+ return VB2_SUCCESS;
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
+{
+ unsigned int remaining_blocks;
+ unsigned int new_size, rem_size, tmp_size;
+ const uint8_t *shifted_data;
+
+ tmp_size = VB2_SHA256_BLOCK_SIZE - sha_ctx.size;
+ rem_size = size < tmp_size ? size : tmp_size;
+
+ memcpy(&sha_ctx.block[sha_ctx.size], buf, rem_size);
+
+ if (sha_ctx.size + size < VB2_SHA256_BLOCK_SIZE) {
+ sha_ctx.size += size;
+ return VB2_SUCCESS;
+ }
+
+ new_size = size - rem_size;
+ remaining_blocks = new_size / VB2_SHA256_BLOCK_SIZE;
+
+ shifted_data = buf + rem_size;
+
+ vb2_sha256_transform_x86ext(sha_ctx.block, 1);
+ vb2_sha256_transform_x86ext(shifted_data, remaining_blocks);
+
+ rem_size = new_size % VB2_SHA256_BLOCK_SIZE;
+
+ memcpy(sha_ctx.block, &shifted_data[remaining_blocks * VB2_SHA256_BLOCK_SIZE],
+ rem_size);
+
+ sha_ctx.size = rem_size;
+ sha_ctx.total_size += (remaining_blocks + 1) * VB2_SHA256_BLOCK_SIZE;
+ return VB2_SUCCESS;
+}
+
+vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest,
+ uint32_t digest_size)
+{
+ unsigned int block_nb;
+ unsigned int pm_size;
+ unsigned int size_b;
+ unsigned int block_rem_size = sha_ctx.size % VB2_SHA256_BLOCK_SIZE;
+ if (digest_size != VB2_SHA256_DIGEST_SIZE) {
+ VB2_DEBUG("ERROR: Digest size does not match expected length.\n");
+ return VB2_ERROR_SHA_FINALIZE_DIGEST_SIZE;
+ }
+
+ block_nb = (1 + ((VB2_SHA256_BLOCK_SIZE - SHA256_MIN_PAD_LEN)
+ < block_rem_size));
+
+ size_b = (sha_ctx.total_size + sha_ctx.size) * 8;
+ pm_size = block_nb * VB2_SHA256_BLOCK_SIZE;
+
+ memset(sha_ctx.block + sha_ctx.size, 0, pm_size - sha_ctx.size);
+ sha_ctx.block[sha_ctx.size] = SHA256_PAD_BEGIN;
+ UNPACK32(size_b, sha_ctx.block + pm_size - 4);
+
+ vb2_sha256_transform_x86ext(sha_ctx.block, block_nb);
+
+ UNPACK32(sha_ctx.h[3], &digest[ 0]);
+ UNPACK32(sha_ctx.h[2], &digest[ 4]);
+ UNPACK32(sha_ctx.h[7], &digest[ 8]);
+ UNPACK32(sha_ctx.h[6], &digest[12]);
+ UNPACK32(sha_ctx.h[1], &digest[16]);
+ UNPACK32(sha_ctx.h[0], &digest[20]);
+ UNPACK32(sha_ctx.h[5], &digest[24]);
+ UNPACK32(sha_ctx.h[4], &digest[28]);
+ return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/2stub.c b/firmware/2lib/2stub.c
index 7cec2e5..956b4bb 100644
--- a/firmware/2lib/2stub.c
+++ b/firmware/2lib/2stub.c
@@ -50,7 +50,7 @@
enum vb2_resource_index index, uint32_t offset,
void *buf, uint32_t size)
{
- fprintf(stderr, "%s: function not implemented\n", __func__);
+ VB2_DEBUG("function not implemented\n");
return VB2_ERROR_EX_UNIMPLEMENTED;
}
@@ -60,14 +60,14 @@
__attribute__((weak))
vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *ctx)
{
- fprintf(stderr, "%s: function not implemented\n", __func__);
+ VB2_DEBUG("function not implemented\n");
return VB2_ERROR_EX_UNIMPLEMENTED;
}
__attribute__((weak))
vb2_error_t vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val)
{
- fprintf(stderr, "%s: function not implemented\n", __func__);
+ VB2_DEBUG("function not implemented\n");
return VB2_ERROR_EX_UNIMPLEMENTED;
}
@@ -201,12 +201,6 @@
}
__attribute__((weak))
-vb2_error_t vb2ex_diag_storage_test_control(enum vb2_diag_storage_test ops)
-{
- return VB2_SUCCESS;
-}
-
-__attribute__((weak))
vb2_error_t vb2ex_diag_memory_quick_test(int reset, const char **out)
{
*out = "mock";
@@ -256,3 +250,27 @@
ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
return VB2_SUCCESS;
}
+
+__attribute__((weak))
+vb2_error_t vb2ex_broken_screen_ui(struct vb2_context *ctx)
+{
+ return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_manual_recovery_ui(struct vb2_context *ctx)
+{
+ return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_developer_ui(struct vb2_context *ctx)
+{
+ return VB2_SUCCESS;
+}
+
+__attribute__((weak))
+vb2_error_t vb2ex_diagnostic_ui(struct vb2_context *ctx)
+{
+ return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/2stub_hwcrypto.c b/firmware/2lib/2stub_hwcrypto.c
index 56272ad..87fb733 100644
--- a/firmware/2lib/2stub_hwcrypto.c
+++ b/firmware/2lib/2stub_hwcrypto.c
@@ -7,6 +7,7 @@
#include "2api.h"
+#ifndef X86_SHA_EXT
__attribute__((weak))
vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
uint32_t data_size)
@@ -26,6 +27,7 @@
{
return VB2_ERROR_SHA_FINALIZE_ALGORITHM; /* Should not be called. */
}
+#endif
__attribute__((weak))
vb2_error_t vb2ex_hwcrypto_rsa_verify_digest(const struct vb2_public_key *key,
diff --git a/firmware/2lib/2ui.c b/firmware/2lib/2ui.c
deleted file mode 100644
index 7173450..0000000
--- a/firmware/2lib/2ui.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/* Copyright 2020 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.
- *
- * User interfaces for developer and recovery mode menus.
- */
-
-#include "2api.h"
-#include "2common.h"
-#include "2misc.h"
-#include "2nvstorage.h"
-#include "2return_codes.h"
-#include "2ui.h"
-#include "2ui_private.h"
-#include "vboot_api.h" /* For VB_SHUTDOWN_REQUEST_POWER_BUTTON */
-#include "vboot_kernel.h"
-
-/*****************************************************************************/
-/* Utility functions */
-
-/**
- * Check GBB flags against VbExIsShutdownRequested() shutdown request,
- * and check for VB_BUTTON_POWER_SHORT_PRESS key, to determine if a
- * shutdown is required.
- *
- * @param ui UI context pointer
- * @return VB2_REQUEST_SHUTDOWN if shutdown needed, or VB2_SUCCESS
- */
-vb2_error_t check_shutdown_request(struct vb2_ui_context *ui)
-{
- struct vb2_gbb_header *gbb = vb2_get_gbb(ui->ctx);
- uint32_t shutdown_request = VbExIsShutdownRequested();
-
- /*
- * Ignore power button push until after we have seen it released.
- * This avoids shutting down immediately if the power button is still
- * being held on startup. After we've recognized a valid power button
- * push then don't report the event until after the button is released.
- */
- if (shutdown_request & VB_SHUTDOWN_REQUEST_POWER_BUTTON) {
- shutdown_request &= ~VB_SHUTDOWN_REQUEST_POWER_BUTTON;
- if (ui->power_button == VB2_POWER_BUTTON_RELEASED)
- ui->power_button = VB2_POWER_BUTTON_PRESSED;
- } else {
- if (ui->power_button == VB2_POWER_BUTTON_PRESSED)
- shutdown_request |= VB_SHUTDOWN_REQUEST_POWER_BUTTON;
- ui->power_button = VB2_POWER_BUTTON_RELEASED;
- }
-
- if (ui->key == VB_BUTTON_POWER_SHORT_PRESS)
- shutdown_request |= VB_SHUTDOWN_REQUEST_POWER_BUTTON;
-
- /* If desired, ignore shutdown request due to lid closure. */
- if (gbb->flags & VB2_GBB_FLAG_DISABLE_LID_SHUTDOWN)
- shutdown_request &= ~VB_SHUTDOWN_REQUEST_LID_CLOSED;
-
- /*
- * In detachables, disable shutdown due to power button.
- * It is used for menu selection instead.
- */
- if (DETACHABLE)
- shutdown_request &= ~VB_SHUTDOWN_REQUEST_POWER_BUTTON;
-
- if (shutdown_request)
- return VB2_REQUEST_SHUTDOWN;
-
- return VB2_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Error action functions */
-
-vb2_error_t error_exit_action(struct vb2_ui_context *ui)
-{
- /*
- * If an error message is currently shown on the screen, any
- * key press clears that error. Unset the key so that it is
- * not processed by other action functions.
- */
- if (ui->key && ui->error_code) {
- ui->error_code = VB2_UI_ERROR_NONE;
- ui->key = 0;
- }
- return VB2_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Menu navigation functions */
-
-const struct vb2_menu *get_menu(struct vb2_ui_context *ui)
-{
- const struct vb2_menu *menu;
- static const struct vb2_menu empty_menu = {
- .num_items = 0,
- .items = NULL,
- };
- if (ui->state->screen->get_menu) {
- menu = ui->state->screen->get_menu(ui);
- return menu ? menu : &empty_menu;
- } else {
- return &ui->state->screen->menu;
- }
-}
-
-vb2_error_t menu_navigation_action(struct vb2_ui_context *ui)
-{
- uint32_t key = ui->key;
-
- /* Map detachable button presses for simplicity. */
- if (DETACHABLE) {
- if (key == VB_BUTTON_VOL_UP_SHORT_PRESS)
- key = VB_KEY_UP;
- else if (key == VB_BUTTON_VOL_DOWN_SHORT_PRESS)
- key = VB_KEY_DOWN;
- else if (key == VB_BUTTON_POWER_SHORT_PRESS)
- key = VB_KEY_ENTER;
- }
-
- switch (key) {
- case VB_KEY_UP:
- return vb2_ui_menu_prev(ui);
- case VB_KEY_DOWN:
- return vb2_ui_menu_next(ui);
- case VB_KEY_ENTER:
- return vb2_ui_menu_select(ui);
- case VB_KEY_ESC:
- return vb2_ui_screen_back(ui);
- default:
- if (key != 0)
- VB2_DEBUG("Pressed key %#x, trusted? %d\n",
- ui->key, ui->key_trusted);
- }
-
- return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_ui_menu_prev(struct vb2_ui_context *ui)
-{
- int item;
-
- if (!DETACHABLE && ui->key == VB_BUTTON_VOL_UP_SHORT_PRESS)
- return VB2_SUCCESS;
-
- item = ui->state->selected_item - 1;
- while (item >= 0 && VB2_GET_BIT(ui->state->hidden_item_mask, item))
- item--;
- /* Only update if item is valid */
- if (item >= 0)
- ui->state->selected_item = item;
-
- return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_ui_menu_next(struct vb2_ui_context *ui)
-{
- int item;
- const struct vb2_menu *menu;
-
- if (!DETACHABLE && ui->key == VB_BUTTON_VOL_DOWN_SHORT_PRESS)
- return VB2_SUCCESS;
-
- menu = get_menu(ui);
- item = ui->state->selected_item + 1;
- while (item < menu->num_items &&
- VB2_GET_BIT(ui->state->hidden_item_mask, item))
- item++;
- /* Only update if item is valid */
- if (item < menu->num_items)
- ui->state->selected_item = item;
-
- return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_ui_menu_select(struct vb2_ui_context *ui)
-{
- const struct vb2_menu *menu;
- const struct vb2_menu_item *menu_item;
-
- if (!DETACHABLE && ui->key == VB_BUTTON_POWER_SHORT_PRESS)
- return VB2_SUCCESS;
-
- menu = get_menu(ui);
- if (menu->num_items == 0)
- return VB2_SUCCESS;
-
- menu_item = &menu->items[ui->state->selected_item];
-
- /* Cannot select a disabled menu item */
- if (VB2_GET_BIT(ui->state->disabled_item_mask,
- ui->state->selected_item)) {
- VB2_DEBUG("Menu item <%s> disabled; ignoring\n",
- menu_item->text);
- return VB2_SUCCESS;
- }
-
- if (menu_item->action) {
- VB2_DEBUG("Menu item <%s> run action\n", menu_item->text);
- return menu_item->action(ui);
- } else if (menu_item->target) {
- VB2_DEBUG("Menu item <%s> to target screen %#x\n",
- menu_item->text, menu_item->target);
- return vb2_ui_screen_change(ui, menu_item->target);
- }
-
- VB2_DEBUG("Menu item <%s> no action or target screen\n",
- menu_item->text);
- return VB2_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Screen navigation functions */
-
-vb2_error_t vb2_ui_screen_back(struct vb2_ui_context *ui)
-{
- struct vb2_screen_state *tmp;
-
- if (ui->state && ui->state->prev) {
- tmp = ui->state->prev;
- free(ui->state);
- ui->state = tmp;
- if (ui->state->screen->reinit)
- VB2_TRY(ui->state->screen->reinit(ui));
- } else {
- VB2_DEBUG("ERROR: No previous screen; ignoring\n");
- }
-
- return VB2_REQUEST_UI_CONTINUE;
-}
-
-static vb2_error_t default_screen_init(struct vb2_ui_context *ui)
-{
- const struct vb2_menu *menu = get_menu(ui);
- ui->state->selected_item = 0;
- if (menu->num_items > 1 && menu->items[0].is_language_select)
- ui->state->selected_item = 1;
- return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_ui_screen_change(struct vb2_ui_context *ui, enum vb2_screen id)
-{
- const struct vb2_screen_info *new_screen_info;
- struct vb2_screen_state *cur_state;
- int state_exists = 0;
-
- new_screen_info = vb2_get_screen_info(id);
- if (new_screen_info == NULL) {
- VB2_DEBUG("ERROR: Screen entry %#x not found; ignoring\n", id);
- return VB2_REQUEST_UI_CONTINUE;
- }
-
- /* Check to see if the screen state already exists in our stack. */
- cur_state = ui->state;
- while (cur_state != NULL) {
- if (cur_state->screen->id == id) {
- state_exists = 1;
- break;
- }
- cur_state = cur_state->prev;
- }
-
- if (state_exists) {
- /* Pop until the requested screen is at the top of stack. */
- while (ui->state->screen->id != id) {
- cur_state = ui->state;
- ui->state = cur_state->prev;
- free(cur_state);
- }
- if (ui->state->screen->reinit)
- VB2_TRY(ui->state->screen->reinit(ui));
- } else {
- /* Allocate the requested screen on top of the stack. */
- cur_state = malloc(sizeof(*ui->state));
- memset(cur_state, 0, sizeof(*ui->state));
- if (cur_state == NULL) {
- VB2_DEBUG("WARNING: malloc failed; ignoring\n");
- return VB2_REQUEST_UI_CONTINUE;
- }
- cur_state->prev = ui->state;
- cur_state->screen = new_screen_info;
- ui->state = cur_state;
- if (ui->state->screen->init)
- VB2_TRY(ui->state->screen->init(ui));
- else
- VB2_TRY(default_screen_init(ui));
- }
-
- return VB2_REQUEST_UI_CONTINUE;
-}
-
-/*****************************************************************************/
-/* Core UI loop */
-
-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;
- int prev_disable_timer;
- enum vb2_ui_error prev_error_code;
- const struct vb2_menu *menu;
- const struct vb2_screen_info *root_info;
- uint32_t key_flags;
- uint32_t start_time_ms, elapsed_ms;
- vb2_error_t rv;
-
- memset(&ui, 0, sizeof(ui));
- ui.ctx = ctx;
- root_info = vb2_get_screen_info(root_screen_id);
- 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 && 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;
-
- while (1) {
- start_time_ms = vb2ex_mtime();
-
- /* Draw if there are state changes. */
- if (memcmp(&prev_state, ui.state, sizeof(*ui.state)) ||
- /* Redraw when timer is disabled. */
- prev_disable_timer != ui.disable_timer ||
- /* Redraw/beep on a transition. */
- prev_error_code != ui.error_code ||
- /* Beep. */
- ui.error_beep != 0 ||
- /* Redraw on a screen request to refresh. */
- ui.force_display) {
-
- menu = get_menu(&ui);
- VB2_DEBUG("<%s> menu item <%s>\n",
- ui.state->screen->name,
- menu->num_items ?
- menu->items[ui.state->selected_item].text :
- "null");
- vb2ex_display_ui(ui.state->screen->id, ui.locale_id,
- ui.state->selected_item,
- ui.state->disabled_item_mask,
- ui.state->hidden_item_mask,
- ui.disable_timer,
- ui.state->current_page,
- ui.error_code);
- if (ui.error_beep ||
- (ui.error_code &&
- prev_error_code != ui.error_code)) {
- vb2ex_beep(250, 400);
- ui.error_beep = 0;
- }
-
- /* Reset refresh flag. */
- ui.force_display = 0;
-
- /* Update prev variables. */
- memcpy(&prev_state, ui.state, sizeof(*ui.state));
- prev_disable_timer = ui.disable_timer;
- prev_error_code = ui.error_code;
- }
-
- /* Grab new keyboard input. */
- ui.key = VbExKeyboardReadWithFlags(&key_flags);
- ui.key_trusted = !!(key_flags & VB_KEY_FLAG_TRUSTED_KEYBOARD);
-
- /* Check for shutdown request. */
- rv = check_shutdown_request(&ui);
- 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 && rv != VB2_REQUEST_UI_CONTINUE)
- return rv;
-
- /* Run screen action. */
- if (ui.state->screen->action) {
- rv = ui.state->screen->action(&ui);
- if (rv && rv != VB2_REQUEST_UI_CONTINUE)
- return rv;
- }
-
- /* Run menu navigation action. */
- rv = menu_navigation_action(&ui);
- if (rv && rv != VB2_REQUEST_UI_CONTINUE)
- return rv;
-
- /* Run global action function if available. */
- if (global_action) {
- rv = global_action(&ui);
- if (rv && rv != VB2_REQUEST_UI_CONTINUE)
- return rv;
- }
-
- /* Delay. */
- elapsed_ms = vb2ex_mtime() - start_time_ms;
- if (elapsed_ms < KEY_DELAY_MS)
- vb2ex_msleep(KEY_DELAY_MS - elapsed_ms);
- }
-
- 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)
-{
- 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') ||
- (DETACHABLE && ui->key == VB_BUTTON_VOL_UP_LONG_PRESS))
- return vb2_ui_developer_mode_boot_external_action(ui);
- 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')) /* L for aLtfw (formerly Legacy) */
- return vb2_ui_developer_mode_boot_altfw_action(ui);
-
- return VB2_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Broken recovery */
-
-vb2_error_t vb2_broken_recovery_menu(struct vb2_context *ctx)
-{
- return ui_loop(ctx, VB2_SCREEN_RECOVERY_BROKEN, broken_recovery_action);
-}
-
-vb2_error_t broken_recovery_action(struct vb2_ui_context *ui)
-{
- /* Broken recovery keyboard shortcuts */
- if (ui->key == '\t')
- return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO);
-
- return VB2_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Manual recovery */
-
-vb2_error_t vb2_manual_recovery_menu(struct vb2_context *ctx)
-{
- return ui_loop(ctx, VB2_SCREEN_RECOVERY_SELECT, manual_recovery_action);
-}
-
-vb2_error_t manual_recovery_action(struct vb2_ui_context *ui)
-{
- /* 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 VB2_REQUEST_UI_EXIT;
-
- /* If disk validity state changed, switch to appropriate screen. */
- if (ui->recovery_rv != rv) {
- VB2_DEBUG("Recovery VbTryLoadKernel %#x --> %#x\n",
- ui->recovery_rv, rv);
- ui->recovery_rv = rv;
- return vb2_ui_screen_change(ui,
- rv == VB2_ERROR_LK_NO_DISK_FOUND ?
- VB2_SCREEN_RECOVERY_SELECT :
- VB2_SCREEN_RECOVERY_INVALID);
- }
-
- /* Manual recovery keyboard shortcuts */
- if (ui->key == VB_KEY_CTRL('D') ||
- (DETACHABLE && ui->key == VB_BUTTON_VOL_UP_DOWN_COMBO_PRESS))
- return vb2_ui_screen_change(ui, VB2_SCREEN_RECOVERY_TO_DEV);
-
- if (ui->key == '\t')
- return vb2_ui_screen_change(ui, VB2_SCREEN_DEBUG_INFO);
-
- return VB2_SUCCESS;
-}
-
-/*****************************************************************************/
-/* Diagnostics */
-
-vb2_error_t vb2_diagnostic_menu(struct vb2_context *ctx)
-{
- return ui_loop(ctx, VB2_SCREEN_DIAGNOSTICS, NULL);
-}
diff --git a/firmware/2lib/2ui_screens.c b/firmware/2lib/2ui_screens.c
deleted file mode 100644
index a9359b5..0000000
--- a/firmware/2lib/2ui_screens.c
+++ /dev/null
@@ -1,1407 +0,0 @@
-/* Copyright 2020 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.
- *
- * Firmware screen definitions.
- */
-
-#include "2api.h"
-#include "2common.h"
-#include "2misc.h"
-#include "2nvstorage.h"
-#include "2ui.h"
-#include "2ui_private.h"
-#include "vboot_api.h"
-#include "vboot_kernel.h"
-
-#define MENU_ITEMS(a) ((struct vb2_menu){ \
- .num_items = ARRAY_SIZE(a), \
- .items = a, \
-})
-
-#define LANGUAGE_SELECT_ITEM ((struct vb2_menu_item){ \
- .text = "Language selection", \
- .target = VB2_SCREEN_LANGUAGE_SELECT, \
- .is_language_select = 1, \
-})
-
-#define NEXT_ITEM(target_screen) ((struct vb2_menu_item){ \
- .text = "Next", \
- .target = (target_screen), \
-})
-
-#define BACK_ITEM ((struct vb2_menu_item){ \
- .text = "Back", \
- .action = vb2_ui_screen_back, \
-})
-
-#define ADVANCED_OPTIONS_ITEM ((struct vb2_menu_item){ \
- .text = "Advanced options", \
- .target = VB2_SCREEN_ADVANCED_OPTIONS, \
-})
-
-/* Action that will power off the device. */
-static vb2_error_t power_off_action(struct vb2_ui_context *ui)
-{
- return VB2_REQUEST_SHUTDOWN;
-}
-
-#define POWER_OFF_ITEM ((struct vb2_menu_item){ \
- .text = "Power off", \
- .action = power_off_action, \
-})
-
-/******************************************************************************/
-/*
- * 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
- * assigned to correct menu item indices in all three functions, the
- * current_page is valid in prev and next actions, and the back_item is assigned
- * to a correct menu item index.
- */
-
-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);
-}
-
-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->hidden_item_mask, cancel_item);
- if (ui->state->selected_item == cancel_item)
- ui->state->selected_item = back_item;
- }
- return VB2_SUCCESS;
-}
-
-static vb2_error_t log_page_prev_action(struct vb2_ui_context *ui)
-{
- /* Validity check. */
- if (ui->state->current_page == 0)
- return VB2_SUCCESS;
-
- ui->state->current_page--;
- return log_page_update(ui, NULL);
-}
-
-static vb2_error_t log_page_next_action(struct vb2_ui_context *ui)
-{
- /* Validity check. */
- if (ui->state->current_page == ui->state->page_count - 1)
- return VB2_SUCCESS;
-
- ui->state->current_page++;
- return log_page_update(ui, NULL);
-}
-
-#define PAGE_UP_ITEM ((struct vb2_menu_item){ \
- .text = "Page up", \
- .action = log_page_prev_action, \
-})
-
-#define PAGE_DOWN_ITEM ((struct vb2_menu_item){ \
- .text = "Page down", \
- .action = log_page_next_action, \
-})
-
-/******************************************************************************/
-/* VB2_SCREEN_LANGUAGE_SELECT */
-
-static vb2_error_t language_select_action(struct vb2_ui_context *ui)
-{
- vb2_error_t rv;
- ui->locale_id = ui->state->selected_item;
- VB2_DEBUG("Locale changed to %u\n", ui->locale_id);
-
- /* Write locale id back to nvdata. */
- vb2_nv_set(ui->ctx, VB2_NV_LOCALIZATION_INDEX, ui->locale_id);
-
- /* Commit nvdata changes immediately, in case of three-finger salute
- reboot. Ignore commit errors in recovery mode. */
- rv = vb2ex_commit_data(ui->ctx);
- if (rv && !(ui->ctx->flags & VB2_CONTEXT_RECOVERY_MODE))
- return rv;
-
- return vb2_ui_screen_back(ui);
-}
-
-const struct vb2_menu *get_language_menu(struct vb2_ui_context *ui)
-{
- int i;
- uint32_t num_locales;
- struct vb2_menu_item *items;
-
- if (ui->language_menu.num_items > 0)
- return &ui->language_menu;
-
- num_locales = vb2ex_get_locale_count();
- if (num_locales == 0) {
- VB2_DEBUG("WARNING: No locales available; assuming 1 locale\n");
- num_locales = 1;
- }
-
- items = malloc(num_locales * sizeof(struct vb2_menu_item));
- if (!items) {
- VB2_DEBUG("ERROR: malloc failed for language items\n");
- return NULL;
- }
-
- for (i = 0; i < num_locales; i++) {
- items[i].text = "Some language";
- items[i].action = language_select_action;
- }
-
- ui->language_menu.num_items = num_locales;
- ui->language_menu.items = items;
- return &ui->language_menu;
-}
-
-static vb2_error_t language_select_init(struct vb2_ui_context *ui)
-{
- const struct vb2_menu *menu = get_menu(ui);
- if (menu->num_items == 0) {
- VB2_DEBUG("ERROR: No menu items found; "
- "rejecting entering language selection screen\n");
- return vb2_ui_screen_back(ui);
- }
- if (ui->locale_id < menu->num_items) {
- ui->state->selected_item = ui->locale_id;
- } else {
- VB2_DEBUG("WARNING: Current locale not found in menu items; "
- "initializing selected_item to 0\n");
- ui->state->selected_item = 0;
- }
- return VB2_SUCCESS;
-}
-
-static const struct vb2_screen_info language_select_screen = {
- .id = VB2_SCREEN_LANGUAGE_SELECT,
- .name = "Language selection screen",
- .init = language_select_init,
- .get_menu = get_language_menu,
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_BROKEN */
-
-static const struct vb2_menu_item recovery_broken_items[] = {
- LANGUAGE_SELECT_ITEM,
- ADVANCED_OPTIONS_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_broken_screen = {
- .id = VB2_SCREEN_RECOVERY_BROKEN,
- .name = "Recover broken device",
- .menu = MENU_ITEMS(recovery_broken_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_ADVANCED_OPTIONS */
-
-#define ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE 1
-#define ADVANCED_OPTIONS_ITEM_DEBUG_INFO 2
-
-vb2_error_t advanced_options_init(struct vb2_ui_context *ui)
-{
- ui->state->selected_item = ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE;
- if (vb2_get_sd(ui->ctx)->flags & VB2_SD_FLAG_DEV_MODE_ENABLED ||
- !vb2_allow_recovery(ui->ctx)) {
- VB2_SET_BIT(ui->state->hidden_item_mask,
- ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE);
- ui->state->selected_item = ADVANCED_OPTIONS_ITEM_DEBUG_INFO;
- }
-
- return VB2_SUCCESS;
-}
-
-static const struct vb2_menu_item advanced_options_items[] = {
- LANGUAGE_SELECT_ITEM,
- [ADVANCED_OPTIONS_ITEM_DEVELOPER_MODE] = {
- .text = "Enable developer mode",
- .target = VB2_SCREEN_RECOVERY_TO_DEV,
- },
- [ADVANCED_OPTIONS_ITEM_DEBUG_INFO] = {
- .text = "Debug info",
- .target = VB2_SCREEN_DEBUG_INFO,
- },
- {
- .text = "Firmware log",
- .target = VB2_SCREEN_FIRMWARE_LOG,
- },
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info advanced_options_screen = {
- .id = VB2_SCREEN_ADVANCED_OPTIONS,
- .name = "Advanced options",
- .init = advanced_options_init,
- .menu = MENU_ITEMS(advanced_options_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_DEBUG_INFO */
-
-#define DEBUG_INFO_ITEM_PAGE_UP 1
-#define DEBUG_INFO_ITEM_PAGE_DOWN 2
-#define DEBUG_INFO_ITEM_BACK 3
-
-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)
- 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;
-}
-
-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)
-{
- return debug_info_set_content(ui);
-}
-
-static const struct vb2_menu_item debug_info_items[] = {
- LANGUAGE_SELECT_ITEM,
- [DEBUG_INFO_ITEM_PAGE_UP] = PAGE_UP_ITEM,
- [DEBUG_INFO_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM,
- [DEBUG_INFO_ITEM_BACK] = BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info debug_info_screen = {
- .id = VB2_SCREEN_DEBUG_INFO,
- .name = "Debug info",
- .init = debug_info_init,
- .reinit = debug_info_reinit,
- .menu = MENU_ITEMS(debug_info_items),
- .page_up_item = DEBUG_INFO_ITEM_PAGE_UP,
- .page_down_item = DEBUG_INFO_ITEM_PAGE_DOWN,
- .back_item = DEBUG_INFO_ITEM_BACK,
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_FIRMWARE_LOG */
-
-#define FIRMWARE_LOG_ITEM_PAGE_UP 1
-#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)
-{
- 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)
-{
- return firmware_log_set_content(ui, 0);
-}
-
-static const struct vb2_menu_item firmware_log_items[] = {
- LANGUAGE_SELECT_ITEM,
- [FIRMWARE_LOG_ITEM_PAGE_UP] = PAGE_UP_ITEM,
- [FIRMWARE_LOG_ITEM_PAGE_DOWN] = PAGE_DOWN_ITEM,
- [FIRMWARE_LOG_ITEM_BACK] = BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info firmware_log_screen = {
- .id = VB2_SCREEN_FIRMWARE_LOG,
- .name = "Firmware log",
- .init = firmware_log_init,
- .reinit = firmware_log_reinit,
- .menu = MENU_ITEMS(firmware_log_items),
- .page_up_item = FIRMWARE_LOG_ITEM_PAGE_UP,
- .page_down_item = FIRMWARE_LOG_ITEM_PAGE_DOWN,
- .back_item = FIRMWARE_LOG_ITEM_BACK,
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_SELECT */
-
-#define RECOVERY_SELECT_ITEM_PHONE 1
-#define RECOVERY_SELECT_ITEM_EXTERNAL_DISK 2
-#define RECOVERY_SELECT_ITEM_DIAGNOSTICS 3
-
-/* Set VB2_NV_DIAG_REQUEST and reboot. */
-static vb2_error_t launch_diagnostics_action(struct vb2_ui_context *ui)
-{
- vb2_nv_set(ui->ctx, VB2_NV_DIAG_REQUEST, 1);
- VB2_DEBUG("Diagnostics requested, rebooting\n");
- return VB2_REQUEST_REBOOT;
-}
-
-vb2_error_t recovery_select_init(struct vb2_ui_context *ui)
-{
- ui->state->selected_item = RECOVERY_SELECT_ITEM_PHONE;
- if (!vb2api_phone_recovery_ui_enabled(ui->ctx)) {
- VB2_DEBUG("WARNING: Phone recovery not available\n");
- VB2_SET_BIT(ui->state->hidden_item_mask,
- RECOVERY_SELECT_ITEM_PHONE);
- ui->state->selected_item = RECOVERY_SELECT_ITEM_EXTERNAL_DISK;
- }
-
- if (!DIAGNOSTIC_UI || !vb2api_diagnostic_ui_enabled(ui->ctx))
- VB2_SET_BIT(ui->state->hidden_item_mask,
- RECOVERY_SELECT_ITEM_DIAGNOSTICS);
-
- return VB2_SUCCESS;
-}
-
-static const struct vb2_menu_item recovery_select_items[] = {
- LANGUAGE_SELECT_ITEM,
- [RECOVERY_SELECT_ITEM_PHONE] = {
- .text = "Recovery using phone",
- .target = VB2_SCREEN_RECOVERY_PHONE_STEP1,
- },
- [RECOVERY_SELECT_ITEM_EXTERNAL_DISK] = {
- .text = "Recovery using external disk",
- .target = VB2_SCREEN_RECOVERY_DISK_STEP1,
- },
- [RECOVERY_SELECT_ITEM_DIAGNOSTICS] = {
- .text = "Launch diagnostics",
- .action = launch_diagnostics_action,
- },
- ADVANCED_OPTIONS_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_select_screen = {
- .id = VB2_SCREEN_RECOVERY_SELECT,
- .name = "Recovery method selection",
- .init = recovery_select_init,
- .menu = MENU_ITEMS(recovery_select_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_INVALID */
-
-static const struct vb2_menu_item recovery_invalid_items[] = {
- LANGUAGE_SELECT_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_invalid_screen = {
- .id = VB2_SCREEN_RECOVERY_INVALID,
- .name = "Invalid recovery inserted",
- .menu = MENU_ITEMS(recovery_invalid_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_TO_DEV */
-
-#define RECOVERY_TO_DEV_ITEM_CONFIRM 1
-#define RECOVERY_TO_DEV_ITEM_CANCEL 2
-
-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)
- /* We're in dev mode, so let user know they can't transition */
- 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");
- return vb2_ui_screen_back(ui);
- }
-
- ui->state->selected_item = RECOVERY_TO_DEV_ITEM_CONFIRM;
-
- /* Disable "Confirm" button for other physical presence types. */
- if (!PHYSICAL_PRESENCE_KEYBOARD) {
- VB2_SET_BIT(ui->state->hidden_item_mask,
- RECOVERY_TO_DEV_ITEM_CONFIRM);
- ui->state->selected_item = RECOVERY_TO_DEV_ITEM_CANCEL;
- }
-
- ui->physical_presence_button_pressed = 0;
-
- return VB2_SUCCESS;
-}
-
-static vb2_error_t recovery_to_dev_finalize(struct vb2_ui_context *ui)
-{
- VB2_DEBUG("Physical presence confirmed!\n");
-
- /* Validity check, should never happen. */
- if (ui->state->screen->id != VB2_SCREEN_RECOVERY_TO_DEV ||
- (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_SUCCESS;
- }
-
- VB2_DEBUG("Enabling dev mode and rebooting...\n");
- vb2_enable_developer_mode(ui->ctx);
- return VB2_REQUEST_REBOOT_EC_TO_RO;
-}
-
-vb2_error_t recovery_to_dev_confirm_action(struct vb2_ui_context *ui)
-{
- if (!ui->key_trusted) {
- VB2_DEBUG("Reject untrusted %s confirmation\n",
- ui->key == VB_KEY_ENTER ? "ENTER" : "POWER");
- /*
- * If physical presence is confirmed using the keyboard,
- * beep and notify the user when the ENTER key comes
- * from an untrusted keyboard.
- */
- if (PHYSICAL_PRESENCE_KEYBOARD && ui->key == VB_KEY_ENTER)
- return set_ui_error(
- ui, VB2_UI_ERROR_UNTRUSTED_CONFIRMATION);
- return VB2_SUCCESS;
- }
- return recovery_to_dev_finalize(ui);
-}
-
-vb2_error_t recovery_to_dev_action(struct vb2_ui_context *ui)
-{
- int pressed;
-
- if (ui->key == ' ') {
- VB2_DEBUG("SPACE means cancel dev mode transition\n");
- return vb2_ui_screen_back(ui);
- }
-
- /* Keyboard physical presence case covered by "Confirm" action. */
- if (PHYSICAL_PRESENCE_KEYBOARD)
- 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_SUCCESS;
- }
- if (!ui->physical_presence_button_pressed)
- return VB2_SUCCESS;
- VB2_DEBUG("Physical presence button released\n");
-
- return recovery_to_dev_finalize(ui);
-}
-
-static const struct vb2_menu_item recovery_to_dev_items[] = {
- LANGUAGE_SELECT_ITEM,
- [RECOVERY_TO_DEV_ITEM_CONFIRM] = {
- .text = "Confirm",
- .action = recovery_to_dev_confirm_action,
- },
- [RECOVERY_TO_DEV_ITEM_CANCEL] = {
- .text = "Cancel",
- .action = vb2_ui_screen_back,
- },
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_to_dev_screen = {
- .id = VB2_SCREEN_RECOVERY_TO_DEV,
- .name = "Transition to developer mode",
- .init = recovery_to_dev_init,
- .action = recovery_to_dev_action,
- .menu = MENU_ITEMS(recovery_to_dev_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_PHONE_STEP1 */
-
-static const struct vb2_menu_item recovery_phone_step1_items[] = {
- LANGUAGE_SELECT_ITEM,
- NEXT_ITEM(VB2_SCREEN_RECOVERY_PHONE_STEP2),
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_phone_step1_screen = {
- .id = VB2_SCREEN_RECOVERY_PHONE_STEP1,
- .name = "Phone recovery step 1",
- .menu = MENU_ITEMS(recovery_phone_step1_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_PHONE_STEP2 */
-
-static const struct vb2_menu_item recovery_phone_step2_items[] = {
- LANGUAGE_SELECT_ITEM,
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_phone_step2_screen = {
- .id = VB2_SCREEN_RECOVERY_PHONE_STEP2,
- .name = "Phone recovery step 2",
- .menu = MENU_ITEMS(recovery_phone_step2_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_DISK_STEP1 */
-
-static const struct vb2_menu_item recovery_disk_step1_items[] = {
- LANGUAGE_SELECT_ITEM,
- NEXT_ITEM(VB2_SCREEN_RECOVERY_DISK_STEP2),
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_disk_step1_screen = {
- .id = VB2_SCREEN_RECOVERY_DISK_STEP1,
- .name = "Disk recovery step 1",
- .menu = MENU_ITEMS(recovery_disk_step1_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_DISK_STEP2 */
-
-static const struct vb2_menu_item recovery_disk_step2_items[] = {
- LANGUAGE_SELECT_ITEM,
- NEXT_ITEM(VB2_SCREEN_RECOVERY_DISK_STEP3),
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_disk_step2_screen = {
- .id = VB2_SCREEN_RECOVERY_DISK_STEP2,
- .name = "Disk recovery step 2",
- .menu = MENU_ITEMS(recovery_disk_step2_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_RECOVERY_DISK_STEP3 */
-
-static const struct vb2_menu_item recovery_disk_step3_items[] = {
- LANGUAGE_SELECT_ITEM,
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info recovery_disk_step3_screen = {
- .id = VB2_SCREEN_RECOVERY_DISK_STEP3,
- .name = "Disk recovery step 3",
- .menu = MENU_ITEMS(recovery_disk_step3_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_DEVELOPER_MODE */
-
-#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_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);
-
- /* 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,
- DEVELOPER_MODE_ITEM_RETURN_TO_SECURE);
-
- /* Don't show "Boot from external disk" button if not allowed. */
- if (!vb2_dev_boot_external_allowed(ui->ctx))
- VB2_SET_BIT(ui->state->hidden_item_mask,
- DEVELOPER_MODE_ITEM_BOOT_EXTERNAL);
-
- /* Don't show "Select alternate bootloader" button if not allowed. */
- if (!vb2_dev_boot_altfw_allowed(ui->ctx))
- VB2_SET_BIT(ui->state->hidden_item_mask,
- 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_ALTFW:
- ui->state->selected_item =
- DEVELOPER_MODE_ITEM_SELECT_ALTFW;
- break;
- default:
- ui->state->selected_item = DEVELOPER_MODE_ITEM_BOOT_INTERNAL;
- break;
- }
-
- ui->start_time_ms = vb2ex_mtime();
-
- return VB2_SUCCESS;
-}
-
-vb2_error_t vb2_ui_developer_mode_boot_internal_action(
- struct vb2_ui_context *ui)
-{
- 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_SUCCESS;
- }
-
- VB2_TRY(VbTryLoadKernel(ui->ctx, VB_DISK_FLAG_FIXED));
- return VB2_REQUEST_UI_EXIT;
-}
-
-vb2_error_t vb2_ui_developer_mode_boot_external_action(
- struct vb2_ui_context *ui)
-{
- vb2_error_t rv;
-
- /* Validity check, should never happen. */
- if (!(ui->ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ||
- !vb2_dev_boot_allowed(ui->ctx) ||
- !vb2_dev_boot_external_allowed(ui->ctx)) {
- VB2_DEBUG("ERROR: Dev mode external boot not allowed\n");
- ui->error_beep = 1;
- 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_REQUEST_UI_EXIT;
- } else if (rv == VB2_ERROR_LK_NO_DISK_FOUND) {
- if (ui->state->screen->id !=
- VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL) {
- VB2_DEBUG("No external disk found\n");
- ui->error_beep = 1;
- }
- return vb2_ui_screen_change(
- ui, VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL);
- } else {
- if (ui->state->screen->id !=
- VB2_SCREEN_DEVELOPER_INVALID_DISK) {
- VB2_DEBUG("Invalid external disk: %#x\n", rv);
- ui->error_beep = 1;
- }
- return vb2_ui_screen_change(
- ui, VB2_SCREEN_DEVELOPER_INVALID_DISK);
- }
-}
-
-vb2_error_t developer_mode_action(struct vb2_ui_context *ui)
-{
- const int use_short = vb2api_use_short_dev_screen_delay(ui->ctx);
- uint64_t elapsed_ms;
-
- /* Once any user interaction occurs, stop the timer. */
- if (ui->key)
- ui->disable_timer = 1;
- if (ui->disable_timer)
- return VB2_SUCCESS;
-
- elapsed_ms = vb2ex_mtime() - ui->start_time_ms;
-
- /* If we're using short delay, wait 2 seconds and don't beep. */
- if (use_short && elapsed_ms > DEV_DELAY_SHORT_MS) {
- VB2_DEBUG("Booting default target after 2s\n");
- ui->disable_timer = 1;
- return vb2_ui_menu_select(ui);
- }
-
- /* Otherwise, beep at 20 and 20.5 seconds. */
- if ((ui->beep_count == 0 && elapsed_ms > DEV_DELAY_BEEP1_MS) ||
- (ui->beep_count == 1 && elapsed_ms > DEV_DELAY_BEEP2_MS)) {
- vb2ex_beep(250, 400);
- ui->beep_count++;
- }
-
- /* Stop after 30 seconds. */
- if (elapsed_ms > DEV_DELAY_NORMAL_MS) {
- VB2_DEBUG("Booting default target after 30s\n");
- ui->disable_timer = 1;
- return vb2_ui_menu_select(ui);
- }
-
- return VB2_SUCCESS;
-}
-
-static const struct vb2_menu_item developer_mode_items[] = {
- LANGUAGE_SELECT_ITEM,
- [DEVELOPER_MODE_ITEM_RETURN_TO_SECURE] = {
- .text = "Return to secure mode",
- .target = VB2_SCREEN_DEVELOPER_TO_NORM,
- },
- [DEVELOPER_MODE_ITEM_BOOT_INTERNAL] = {
- .text = "Boot from internal disk",
- .action = vb2_ui_developer_mode_boot_internal_action,
- },
- [DEVELOPER_MODE_ITEM_BOOT_EXTERNAL] = {
- .text = "Boot from external disk",
- .action = vb2_ui_developer_mode_boot_external_action,
- },
- [DEVELOPER_MODE_ITEM_SELECT_ALTFW] = {
- .text = "Select alternate bootloader",
- .target = VB2_SCREEN_DEVELOPER_SELECT_ALTFW,
- },
- ADVANCED_OPTIONS_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info developer_mode_screen = {
- .id = VB2_SCREEN_DEVELOPER_MODE,
- .name = "Developer mode",
- .init = developer_mode_init,
- .action = developer_mode_action,
- .menu = MENU_ITEMS(developer_mode_items),
-};
-
-/******************************************************************************/
-/* 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");
- return set_ui_error_and_go_back(
- ui, VB2_UI_ERROR_TO_NORM_NOT_ALLOWED);
- }
- ui->state->selected_item = DEVELOPER_TO_NORM_ITEM_CONFIRM;
- /* 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_SUCCESS;
- }
-
- VB2_DEBUG("Leaving dev mode\n");
- vb2_nv_set(ui->ctx, VB2_NV_DISABLE_DEV_REQUEST, 1);
- return VB2_REQUEST_REBOOT;
-}
-
-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,
- },
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info developer_to_norm_screen = {
- .id = VB2_SCREEN_DEVELOPER_TO_NORM,
- .name = "Transition to normal mode",
- .init = developer_to_norm_init,
- .menu = MENU_ITEMS(developer_to_norm_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL */
-
-static const struct vb2_menu_item developer_boot_external_items[] = {
- LANGUAGE_SELECT_ITEM,
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info developer_boot_external_screen = {
- .id = VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL,
- .name = "Developer boot from external disk",
- .action = vb2_ui_developer_mode_boot_external_action,
- .menu = MENU_ITEMS(developer_boot_external_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_DEVELOPER_INVALID_DISK */
-
-static const struct vb2_menu_item developer_invalid_disk_items[] = {
- LANGUAGE_SELECT_ITEM,
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info developer_invalid_disk_screen = {
- .id = VB2_SCREEN_DEVELOPER_INVALID_DISK,
- .name = "Invalid external disk in dev mode",
- .action = vb2_ui_developer_mode_boot_external_action,
- .menu = MENU_ITEMS(developer_invalid_disk_items),
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_DEVELOPER_SELECT_ALTFW */
-
-static const struct vb2_menu_item developer_select_bootloader_items_before[] = {
- LANGUAGE_SELECT_ITEM,
-};
-
-static const struct vb2_menu_item developer_select_bootloader_items_after[] = {
- BACK_ITEM,
- POWER_OFF_ITEM,
-};
-
-static vb2_error_t developer_select_bootloader_init(struct vb2_ui_context *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_SUCCESS;
-}
-
-vb2_error_t vb2_ui_developer_mode_boot_altfw_action(
- struct vb2_ui_context *ui)
-{
- 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_altfw_allowed(ui->ctx)) {
- VB2_DEBUG("ERROR: Dev mode alternate bootloader not allowed\n");
- return set_ui_error(ui, VB2_UI_ERROR_ALTFW_DISABLED);
- }
-
- if (vb2ex_get_altfw_count() == 0) {
- VB2_DEBUG("ERROR: No alternate bootloader was found\n");
- return set_ui_error(ui, VB2_UI_ERROR_ALTFW_EMPTY);
- }
-
- if (ui->key == VB_KEY_CTRL('L')) {
- altfw_id = 0;
- VB2_DEBUG("Try booting from default bootloader\n");
- } else {
- altfw_id = ui->state->selected_item - menu_before_len + 1;
- VB2_DEBUG("Try booting from bootloader #%u\n", altfw_id);
- }
-
- /* vb2ex_run_altfw will not return if successful */
- vb2ex_run_altfw(altfw_id);
-
- VB2_DEBUG("ERROR: Alternate bootloader failed\n");
- return set_ui_error(ui, VB2_UI_ERROR_ALTFW_FAILED);
-}
-
-static const struct vb2_menu *get_bootloader_menu(struct vb2_ui_context *ui)
-{
- int i;
- uint32_t num_bootloaders, num_items;
- struct vb2_menu_item *items;
- const size_t menu_before_len =
- ARRAY_SIZE(developer_select_bootloader_items_before);
- const size_t menu_after_len =
- ARRAY_SIZE(developer_select_bootloader_items_after);
-
- if (ui->bootloader_menu.num_items > 0)
- return &ui->bootloader_menu;
-
- num_bootloaders = vb2ex_get_altfw_count();
- if (num_bootloaders == 0) {
- VB2_DEBUG("ERROR: No bootloader was found\n");
- return NULL;
- }
- VB2_DEBUG("num_bootloaders: %u\n", num_bootloaders);
- num_items = num_bootloaders + menu_before_len + menu_after_len;
- items = malloc(num_items * sizeof(struct vb2_menu_item));
- if (!items) {
- VB2_DEBUG("ERROR: malloc failed for bootloader items\n");
- return NULL;
- }
-
- /* Copy prefix items to the begin. */
- memcpy(&items[0],
- developer_select_bootloader_items_before,
- menu_before_len * sizeof(struct vb2_menu_item));
-
- /* Copy bootloaders. */
- 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_altfw_action;
- }
-
- /* Copy postfix items to the end. */
- memcpy(&items[num_items - menu_after_len],
- developer_select_bootloader_items_after,
- menu_after_len * sizeof(struct vb2_menu_item));
-
- ui->bootloader_menu.num_items = num_items;
- ui->bootloader_menu.items = items;
-
- return &ui->bootloader_menu;
-}
-
-static const struct vb2_screen_info developer_select_bootloader_screen = {
- .id = VB2_SCREEN_DEVELOPER_SELECT_ALTFW,
- .name = "Select alternate bootloader",
- .init = developer_select_bootloader_init,
- .get_menu = get_bootloader_menu,
-};
-
-/******************************************************************************/
-/* 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,
- [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 = "Memory check (quick)",
- .target = VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK,
- },
- {
- .text = "Memory check (full)",
- .target = VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL,
- },
- POWER_OFF_ITEM,
-};
-
-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_HEALTH */
-
-#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_health_init_impl(
- struct vb2_ui_context *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 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_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,
-};
-
-/******************************************************************************/
-/* VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK
- VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL */
-
-#define DIAGNOSTICS_MEMORY_ITEM_PAGE_UP 0
-#define DIAGNOSTICS_MEMORY_ITEM_PAGE_DOWN 1
-#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)
-{
- 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_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_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)
-{
- return diagnostics_memory_update_screen(
- ui, &vb2ex_diag_memory_quick_test, 0);
-}
-
-static vb2_error_t diagnostics_memory_update_full(struct vb2_ui_context *ui)
-{
- return diagnostics_memory_update_screen(
- ui, &vb2ex_diag_memory_full_test, 0);
-}
-
-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",
- .action = vb2_ui_screen_back,
- },
- POWER_OFF_ITEM,
-};
-
-static const struct vb2_screen_info diagnostics_memory_quick_screen = {
- .id = VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK,
- .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_BACK,
- .cancel_item = DIAGNOSTICS_MEMORY_ITEM_CANCEL,
-};
-
-static const struct vb2_screen_info diagnostics_memory_full_screen = {
- .id = VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL,
- .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_BACK,
- .cancel_item = DIAGNOSTICS_MEMORY_ITEM_CANCEL,
-};
-
-/******************************************************************************/
-/*
- * TODO(chromium:1035800): Refactor UI code across vboot and depthcharge.
- * Currently vboot and depthcharge maintain their own copies of menus/screens.
- * vboot detects keyboard input and controls the navigation among different menu
- * items and screens, while depthcharge performs the actual rendering of each
- * screen, based on the menu information passed from vboot.
- */
-static const struct vb2_screen_info *screens[] = {
- &language_select_screen,
- &recovery_broken_screen,
- &advanced_options_screen,
- &debug_info_screen,
- &firmware_log_screen,
- &recovery_select_screen,
- &recovery_invalid_screen,
- &recovery_to_dev_screen,
- &recovery_phone_step1_screen,
- &recovery_phone_step2_screen,
- &recovery_disk_step1_screen,
- &recovery_disk_step2_screen,
- &recovery_disk_step3_screen,
- &developer_mode_screen,
- &developer_to_norm_screen,
- &developer_boot_external_screen,
- &developer_invalid_disk_screen,
- &developer_select_bootloader_screen,
- &diagnostics_screen,
- &diagnostics_storage_health_screen,
- &diagnostics_storage_test_short_screen,
- &diagnostics_storage_test_extended_screen,
- &diagnostics_memory_quick_screen,
- &diagnostics_memory_full_screen,
-};
-
-const struct vb2_screen_info *vb2_get_screen_info(enum vb2_screen id)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(screens); i++) {
- if (screens[i]->id == id)
- return screens[i];
- }
- return NULL;
-}
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index fb656da..1f9d70f 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -240,6 +240,23 @@
* it doesn't jump to RW when this flag is set.
*/
VB2_CONTEXT_EC_TRUSTED = (1 << 24),
+
+ /*
+ * Boot into developer mode is allowed by FWMP or GBB flags.
+ */
+ VB2_CONTEXT_DEV_BOOT_ALLOWED = (1 << 25),
+
+ /*
+ * Boot into developer mode from external disk is allowed by nvdata,
+ * FWMP or GBB flags.
+ */
+ VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED = (1 << 26),
+
+ /*
+ * Boot into developer mode from alternate bootloader is allowed by
+ * nvdata, FWMP or GBB flags.
+ */
+ VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED = (1 << 27),
};
/* Helper for aligning fields in vb2_context. */
@@ -283,8 +300,8 @@
/*
* Secure data for firmware verification stage. Caller must fill this
* from some secure non-volatile location before calling
- * vb2api_fw_phase1. If the VB2_CONTEXT_SECDATA_CHANGED flag is set
- * when a function returns, caller must save the data back to the
+ * vb2api_fw_phase1. If the VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED flag
+ * is set when a function returns, caller must save the data back to the
* secure non-volatile location and then clear the flag.
*/
uint8_t secdata_firmware[VB2_SECDATA_FIRMWARE_SIZE];
@@ -871,6 +888,14 @@
uint32_t vb2api_get_locale_id(struct vb2_context *ctx);
/**
+ * Set the locale id in nvdata.
+ *
+ * @param ctx Vboot context
+ * @param locale_id The locale id to be set
+ */
+void vb2api_set_locale_id(struct vb2_context *ctx, uint32_t locale_id);
+
+/**
* Whether phone recovery functionality is enabled or not.
*
* @param ctx Vboot context
@@ -907,7 +932,8 @@
};
/**
- * Get the default boot target in developer mode.
+ * Get the default boot target in developer mode. This function must be called
+ * after vb2api_kernel_phase1.
*
* @param ctx Vboot context
* @return The developer mode default boot target.
@@ -923,6 +949,50 @@
*/
int vb2api_use_short_dev_screen_delay(struct vb2_context *ctx);
+/**
+ * Check whether recovery is allowed or not.
+ *
+ * The only way to pass this check and proceed to the recovery process is to
+ * physically request a recovery (a.k.a. manual recovery). All other recovery
+ * requests including manual recovery requested by a (compromised) host will
+ * end up with 'broken' screen.
+ *
+ * @param ctx Vboot context
+ * @return 1 if recovery is allowed; 0 if no or uncertain.
+ */
+int vb2api_allow_recovery(struct vb2_context *ctx);
+
+/**
+ * Request to enable developer mode.
+ *
+ * Enables the developer flag in vb2_context firmware secdata. Note that
+ * modified secdata must be saved for change to apply on reboot.
+ *
+ * NOTE: Doesn't update the LAST_BOOT_DEVELOPER secdata flag. That should be
+ * done on the next boot.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS if success; error if enabling developer mode is not
+ * allowed.
+ */
+vb2_error_t vb2api_enable_developer_mode(struct vb2_context *ctx);
+
+/**
+ * Request to disable developer mode by setting VB2_NV_DIAG_REQUEST.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS if success; other errors if the check of
+ * VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON failed.
+ */
+vb2_error_t vb2api_disable_developer_mode(struct vb2_context *ctx);
+
+/**
+ * Request diagnostics by setting VB2_NV_DIAG_REQUEST.
+ *
+ * @param ctx Vboot context
+ */
+void vb2api_request_diagnostics(struct vb2_context *ctx);
+
/*****************************************************************************/
/* APIs provided by the caller to verified boot */
@@ -1324,6 +1394,53 @@
/*****************************************************************************/
/* Functions for UI display. */
+/**
+ * UI for a non-manual recovery ("BROKEN").
+ *
+ * Enter the broken screen UI, which shows that an unrecoverable error was
+ * encountered last boot. Wait for the user to physically reset or shut down.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS, or non-zero error code.
+ */
+vb2_error_t vb2ex_broken_screen_ui(struct vb2_context *ctx);
+
+/**
+ * UI for a manual recovery-mode boot.
+ *
+ * Enter the recovery menu, which prompts the user to insert recovery media,
+ * navigate the step-by-step recovery, or enter developer mode if allowed.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS, or non-zero error code.
+ */
+vb2_error_t vb2ex_manual_recovery_ui(struct vb2_context *ctx);
+
+/**
+ * UI for a developer-mode boot.
+ *
+ * Enter the developer menu, which provides options to switch out of developer
+ * mode, boot from external media, use legacy bootloader, or boot Chrome OS from
+ * disk.
+ *
+ * If a timeout occurs, take the default boot action.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS, or non-zero error code.
+ */
+vb2_error_t vb2ex_developer_ui(struct vb2_context *ctx);
+
+/**
+ * UI for a diagnostic tools boot.
+ *
+ * Enter the diagnostic tools menu, which provides debug information and
+ * diagnostic tests of various hardware components.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS, or non-zero error code.
+ */
+vb2_error_t vb2ex_diagnostic_ui(struct vb2_context *ctx);
+
/* Helpers for bitmask operations */
#define VB2_SET_BIT(mask, index) ((mask) |= ((uint32_t)1 << (index)))
#define VB2_CLR_BIT(mask, index) ((mask) &= ~((uint32_t)1 << (index)))
@@ -1386,6 +1503,8 @@
VB2_UI_ERROR_UNTRUSTED_CONFIRMATION,
/* To-norm not allowed */
VB2_UI_ERROR_TO_NORM_NOT_ALLOWED,
+ /* Internal boot failed */
+ VB2_UI_ERROR_INTERNAL_BOOT_FAILED,
/* External boot is disabled */
VB2_UI_ERROR_EXTERNAL_BOOT_DISABLED,
/* Alternate bootloader is disabled */
@@ -1589,17 +1708,6 @@
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 918c50d..695f50d 100644
--- a/firmware/2lib/include/2common.h
+++ b/firmware/2lib/include/2common.h
@@ -86,10 +86,10 @@
#endif
#if (defined(__GNUC__) && __GNUC__ >= 7)
-#define VBOOT_FALLTHROUGH __attribute__((fallthrough))
+#define VBOOT_FALLTHROUGH __attribute__((__fallthrough__))
#elif defined(__clang__)
-#if __has_attribute(fallthrough)
-#define VBOOT_FALLTHROUGH __attribute__((fallthrough))
+#if __has_attribute(__fallthrough__)
+#define VBOOT_FALLTHROUGH __attribute__((__fallthrough__))
#endif
#else
#define VBOOT_FALLTHROUGH ((void)0)
@@ -298,7 +298,7 @@
static inline const uint8_t *vb2_packed_key_data(
const struct vb2_packed_key *key)
{
- return (const uint8_t *)key + key->key_offset;
+ return (const uint8_t *)((uintptr_t)key + key->key_offset);
}
/**
@@ -331,7 +331,7 @@
static inline const uint8_t *vb2_signature_data(
const struct vb2_signature *sig)
{
- return (const uint8_t *)sig + sig->sig_offset;
+ return (const uint8_t *)((uintptr_t)sig + sig->sig_offset);
}
/**
diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h
index 3d96293..b36e127 100644
--- a/firmware/2lib/include/2misc.h
+++ b/firmware/2lib/include/2misc.h
@@ -162,32 +162,6 @@
vb2_error_t vb2_load_kernel_preamble(struct vb2_context *ctx);
/**
- * Utility function to enable developer mode.
- *
- * Enables the developer flag in vb2_context firmware secdata. Note that
- * modified secdata must be saved for change to apply on reboot.
- *
- * NOTE: Doesn't update the LAST_BOOT_DEVELOPER secdata flag. That should be
- * done on the next boot.
- *
- * @param ctx Vboot context
- */
-void vb2_enable_developer_mode(struct vb2_context *ctx);
-
-/**
- * Check whether recovery is allowed or not.
- *
- * The only way to pass this check and proceed to the recovery process is to
- * physically request a recovery (a.k.a. manual recovery). All other recovery
- * requests including manual recovery requested by a (compromised) host will
- * end up with 'broken' screen.
- *
- * @param ctx Vboot context
- * @return 1 if recovery is allowed; 0 if no or uncertain.
- */
-int vb2_allow_recovery(struct vb2_context *ctx);
-
-/**
* Clear recovery request appropriately.
*
* To avoid the recovery request "sticking" and the user being in a permanent
@@ -210,38 +184,11 @@
void vb2_clear_recovery(struct vb2_context *ctx);
/**
- * Determine if developer mode is allowed.
+ * Fill VB2_CONTEXT_DEV_BOOT_ALLOWED, VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED and
+ * VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED flags in ctx->flags.
*
- * Developer boot is not allowed if and only if FWMP_DEV_DISABLE_BOOT is set and
- * GBB_FORCE_DEV_SWITCH_ON is not set.
- *
- * @param ctx Vboot context
- * @return 1 if allowed, or 0 otherwise.
+ * @param ctx Vboot context.
*/
-int vb2_dev_boot_allowed(struct vb2_context *ctx);
-
-/**
- * Determine if booting from legacy BIOS is allowed.
- *
- * Legacy BIOS is allowed if any of these flags are set:
- * 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_altfw_allowed(struct vb2_context *ctx);
-
-/**
- * Determine if booting from external disk is allowed.
- *
- * Booting from external disk is allowed if any of these flags are set:
- * VB2_NV_DEV_BOOT_EXTERNAL, VB2_GBB_FLAG_FORCE_DEV_BOOT_USB, and
- * VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL.
- *
- * @param ctx Vboot context
- * @return 1 if allowed, or 0 otherwise.
- */
-int vb2_dev_boot_external_allowed(struct vb2_context *ctx);
+void vb2_fill_dev_boot_flags(struct vb2_context *ctx);
#endif /* VBOOT_REFERENCE_2MISC_H_ */
diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h
index 2f40b23..fe75823 100644
--- a/firmware/2lib/include/2nvstorage.h
+++ b/firmware/2lib/include/2nvstorage.h
@@ -125,6 +125,8 @@
VB2_NV_POST_EC_SYNC_DELAY,
/* Request booting of diagnostic rom. 0=no, 1=yes. */
VB2_NV_DIAG_REQUEST,
+ /* Priority of miniOS partition to load: 0=MINIOS-A, 1=MINIOS-B. */
+ VB2_NV_MINIOS_PRIORITY,
};
/* Firmware result codes for VB2_NV_FW_RESULT and VB2_NV_FW_PREV_RESULT */
diff --git a/firmware/2lib/include/2nvstorage_fields.h b/firmware/2lib/include/2nvstorage_fields.h
index 9575e87..449b8fd 100644
--- a/firmware/2lib/include/2nvstorage_fields.h
+++ b/firmware/2lib/include/2nvstorage_fields.h
@@ -79,7 +79,7 @@
#define VB2_NV_BOOT_DISABLE_DEV 0x40
#define VB2_NV_BOOT_DEBUG_RESET 0x80
-/* Fields in VB2_NV_OFFS_BOOT2 (unused = 0x00) */
+/* Fields in VB2_NV_OFFS_BOOT2 */
#define VB2_NV_BOOT2_RESULT_MASK 0x03
#define VB2_NV_BOOT2_TRIED 0x04
#define VB2_NV_BOOT2_TRY_NEXT 0x08
@@ -102,11 +102,12 @@
#define VB2_NV_TPM_CLEAR_OWNER_DONE 0x02
#define VB2_NV_TPM_REBOOTED 0x04
-/* Fields in VB2_NV_OFFS_MISC (unused = 0x80) */
+/* Fields in VB2_NV_OFFS_MISC (unused = 0xa0) */
#define VB2_NV_MISC_DEPRECATED_UNLOCK_FASTBOOT 0x01
#define VB2_NV_MISC_BOOT_ON_AC_DETECT 0x02
#define VB2_NV_MISC_TRY_RO_SYNC 0x04
#define VB2_NV_MISC_BATTERY_CUTOFF 0x08
+#define VB2_NV_MISC_MINIOS_PRIORITY 0x10
#define VB2_NV_MISC_POST_EC_SYNC_DELAY 0x40
#endif /* VBOOT_REFERENCE_2NVSTORAGE_FIELDS_H_ */
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 4512ff8..0dc7c44 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -454,168 +454,174 @@
VB2_ERROR_MISC = VB2_ERROR_BASE + 0x080000,
/* Work buffer too small (see vb2api_init and vb2api_reinit) */
- VB2_ERROR_WORKBUF_SMALL,
+ VB2_ERROR_WORKBUF_SMALL = 0x10080001,
/* Work buffer unaligned (see vb2api_init and vb2api_reinit) */
- VB2_ERROR_WORKBUF_ALIGN,
+ VB2_ERROR_WORKBUF_ALIGN = 0x10080002,
/* Work buffer too small in GBB-related function */
- VB2_ERROR_GBB_WORKBUF,
+ VB2_ERROR_GBB_WORKBUF = 0x10080003,
/* Bad magic number in vb2_read_gbb_header() */
- VB2_ERROR_GBB_MAGIC,
+ VB2_ERROR_GBB_MAGIC = 0x10080004,
/* Incompatible version in vb2_read_gbb_header() */
- VB2_ERROR_GBB_VERSION,
+ VB2_ERROR_GBB_VERSION = 0x10080005,
/* Old version in vb2_read_gbb_header() */
- VB2_ERROR_GBB_TOO_OLD,
+ VB2_ERROR_GBB_TOO_OLD = 0x10080006,
/* Header size too small in vb2_read_gbb_header() */
- VB2_ERROR_GBB_HEADER_SIZE,
+ VB2_ERROR_GBB_HEADER_SIZE = 0x10080007,
/* Work buffer too small for root key in vb2_load_fw_keyblock() */
- VB2_ERROR_FW_KEYBLOCK_WORKBUF_ROOT_KEY,
+ VB2_ERROR_FW_KEYBLOCK_WORKBUF_ROOT_KEY = 0x10080008,
/* Work buffer too small for header in vb2_load_fw_keyblock() */
- VB2_ERROR_FW_KEYBLOCK_WORKBUF_HEADER,
+ VB2_ERROR_FW_KEYBLOCK_WORKBUF_HEADER = 0x10080009,
/* Work buffer too small for keyblock in vb2_load_fw_keyblock() */
- VB2_ERROR_FW_KEYBLOCK_WORKBUF,
+ VB2_ERROR_FW_KEYBLOCK_WORKBUF = 0x1008000a,
/* Keyblock version out of range in vb2_load_fw_keyblock() */
- VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE,
+ VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE = 0x1008000b,
/* Keyblock version rollback in vb2_load_fw_keyblock() */
- VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK,
+ VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK = 0x1008000c,
/* Missing firmware data key in vb2_load_fw_preamble() */
- VB2_ERROR_FW_PREAMBLE2_DATA_KEY,
+ VB2_ERROR_FW_PREAMBLE2_DATA_KEY = 0x1008000d,
/* Work buffer too small for header in vb2_load_fw_preamble() */
- VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER,
+ VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER = 0x1008000e,
/* Work buffer too small for preamble in vb2_load_fw_preamble() */
- VB2_ERROR_FW_PREAMBLE2_WORKBUF,
+ VB2_ERROR_FW_PREAMBLE2_WORKBUF = 0x1008000f,
/* Firmware version out of range in vb2_load_fw_preamble() */
- VB2_ERROR_FW_PREAMBLE_VERSION_RANGE,
+ VB2_ERROR_FW_PREAMBLE_VERSION_RANGE = 0x10080010,
/* Firmware version rollback in vb2_load_fw_preamble() */
- VB2_ERROR_FW_PREAMBLE_VERSION_ROLLBACK,
+ VB2_ERROR_FW_PREAMBLE_VERSION_ROLLBACK = 0x10080011,
/* Not enough space in work buffer for resource object */
- VB2_ERROR_READ_RESOURCE_OBJECT_BUF,
+ VB2_ERROR_READ_RESOURCE_OBJECT_BUF = 0x10080012,
/* Work buffer too small for header in vb2_load_kernel_keyblock() */
- VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF_HEADER,
+ VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF_HEADER = 0x10080013,
/* Work buffer too small for keyblock in vb2_load_kernel_keyblock() */
- VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF,
+ VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF = 0x10080014,
/* Keyblock version out of range in vb2_load_kernel_keyblock() */
- VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE,
+ VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE = 0x10080015,
/* Keyblock version rollback in vb2_load_kernel_keyblock() */
- VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK,
+ VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK = 0x10080016,
/*
* Keyblock flags don't match current mode in
* vb2_load_kernel_keyblock().
*/
- VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG,
- VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG,
+ VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG = 0x10080017,
+ VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG = 0x10080018,
/* Missing firmware data key in vb2_load_kernel_preamble() */
- VB2_ERROR_KERNEL_PREAMBLE2_DATA_KEY,
+ VB2_ERROR_KERNEL_PREAMBLE2_DATA_KEY = 0x10080019,
/* Work buffer too small for header in vb2_load_kernel_preamble() */
- VB2_ERROR_KERNEL_PREAMBLE2_WORKBUF_HEADER,
+ VB2_ERROR_KERNEL_PREAMBLE2_WORKBUF_HEADER = 0x1008001a,
/* Work buffer too small for preamble in vb2_load_kernel_preamble() */
- VB2_ERROR_KERNEL_PREAMBLE2_WORKBUF,
+ VB2_ERROR_KERNEL_PREAMBLE2_WORKBUF = 0x1008001b,
/* Kernel version out of range in vb2_load_kernel_preamble() */
- VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE,
+ VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE = 0x1008001c,
/* Kernel version rollback in vb2_load_kernel_preamble() */
- VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK,
+ VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK = 0x1008001d,
/* Kernel preamble not loaded before calling vb2api_get_kernel_size() */
- VB2_ERROR_API_GET_KERNEL_SIZE_PREAMBLE,
+ VB2_ERROR_API_GET_KERNEL_SIZE_PREAMBLE = 0x1008001e,
/* Unable to unpack kernel subkey in vb2_verify_vblock();
* deprecated and replaced with VB2_ERROR_UNPACK_KEY_* */
- VB2_ERROR_DEPRECATED_VBLOCK_KERNEL_SUBKEY,
+ VB2_ERROR_DEPRECATED_VBLOCK_KERNEL_SUBKEY = 0x1008001f,
/*
* Got a self-signed kernel in vb2_verify_vblock(), but need an
* officially signed one; deprecated and replaced with
* VB2_ERROR_KERNEL_KEYBLOCK_*.
*/
- VB2_ERROR_DEPRECATED_VBLOCK_SELF_SIGNED,
+ VB2_ERROR_DEPRECATED_VBLOCK_SELF_SIGNED = 0x10080020,
/* Invalid keyblock hash in vb2_verify_vblock();
* deprecated and replaced with VB2_ERROR_KERNEL_KEYBLOCK_* */
- VB2_ERROR_DEPRECATED_VBLOCK_KEYBLOCK_HASH,
+ VB2_ERROR_DEPRECATED_VBLOCK_KEYBLOCK_HASH = 0x10080021,
/* Invalid keyblock in vb2_verify_vblock();
* deprecated and replaced with VB2_ERROR_KERNEL_KEYBLOCK_* */
- VB2_ERROR_DEPRECATED_VBLOCK_KEYBLOCK,
+ VB2_ERROR_DEPRECATED_VBLOCK_KEYBLOCK = 0x10080022,
/* Wrong dev key hash in vb2_verify_kernel_vblock_dev_key_hash() */
- VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH,
+ VB2_ERROR_KERNEL_KEYBLOCK_DEV_KEY_HASH = 0x10080023,
/* Work buffer too small in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_WORKBUF,
+ VB2_ERROR_LOAD_PARTITION_WORKBUF = 0x10080024,
/* Unable to read vblock in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_READ_VBLOCK,
+ VB2_ERROR_LOAD_PARTITION_READ_VBLOCK = 0x10080025,
/* Unable to verify vblock in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_VERIFY_VBLOCK,
+ VB2_ERROR_LOAD_PARTITION_VERIFY_VBLOCK = 0x10080026,
/* Kernel body offset too large in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_BODY_OFFSET,
+ VB2_ERROR_LOAD_PARTITION_BODY_OFFSET = 0x10080027,
/* Kernel body too big in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_BODY_SIZE,
+ VB2_ERROR_LOAD_PARTITION_BODY_SIZE = 0x10080028,
/* Unable to read kernel body in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_READ_BODY,
+ VB2_ERROR_LOAD_PARTITION_READ_BODY = 0x10080029,
/* Unable to unpack data key in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_DATA_KEY,
+ VB2_ERROR_LOAD_PARTITION_DATA_KEY = 0x1008002a,
/* Unable to verify body in vb2_load_partition() */
- VB2_ERROR_LOAD_PARTITION_VERIFY_BODY,
+ VB2_ERROR_LOAD_PARTITION_VERIFY_BODY = 0x1008002b,
/* Unable to get EC image hash in ec_sync_phase1() */
- VB2_ERROR_EC_HASH_IMAGE,
+ VB2_ERROR_EC_HASH_IMAGE = 0x1008002c,
/* Unable to get expected EC image hash in ec_sync_phase1() */
- VB2_ERROR_EC_HASH_EXPECTED,
+ VB2_ERROR_EC_HASH_EXPECTED = 0x1008002d,
/* Expected and image hashes are different size in ec_sync_phase1() */
- VB2_ERROR_EC_HASH_SIZE,
+ VB2_ERROR_EC_HASH_SIZE = 0x1008002e,
/* Incompatible version for vb2_shared_data structure being loaded */
- VB2_ERROR_SHARED_DATA_VERSION,
+ VB2_ERROR_SHARED_DATA_VERSION = 0x1008002f,
/* Bad magic number in vb2_shared_data structure */
- VB2_ERROR_SHARED_DATA_MAGIC,
+ VB2_ERROR_SHARED_DATA_MAGIC = 0x10080030,
/* Some part of GBB data is invalid */
- VB2_ERROR_GBB_INVALID,
+ VB2_ERROR_GBB_INVALID = 0x10080031,
/* Invalid parameter */
- VB2_ERROR_INVALID_PARAMETER,
+ VB2_ERROR_INVALID_PARAMETER = 0x10080032,
/* Problem with workbuf validity (see vb2api_init and vb2api_reinit) */
- VB2_ERROR_WORKBUF_INVALID,
+ VB2_ERROR_WORKBUF_INVALID = 0x10080033,
- /* Escape from NO_BOOT mode is detected. */
- VB2_ERROR_ESCAPE_NO_BOOT,
+ /* Escape from NO_BOOT mode is detected */
+ VB2_ERROR_ESCAPE_NO_BOOT = 0x10080034,
+
+ /*
+ * Keyblock flags don't match current mode in
+ * vb2_load_kernel_keyblock().
+ */
+ VB2_ERROR_KERNEL_KEYBLOCK_MINIOS_FLAG = 0x10080035,
/**********************************************************************
* API-level errors
@@ -701,6 +707,12 @@
/* Digest buffer passed into vb2api_check_hash incorrect. */
VB2_ERROR_API_CHECK_DIGEST_SIZE,
+ /* Disabling developer mode is not allowed by GBB flags */
+ VB2_ERROR_API_DISABLE_DEV_NOT_ALLOWED,
+
+ /* Enabling developer mode is not allowed in non-recovery mode */
+ VB2_ERROR_API_ENABLE_DEV_NOT_ALLOWED,
+
/**********************************************************************
* Errors which may be generated by implementations of vb2ex functions.
* Implementation may also return its own specific errors, which should
diff --git a/firmware/2lib/include/2sha_private.h b/firmware/2lib/include/2sha_private.h
new file mode 100644
index 0000000..ffa79f2
--- /dev/null
+++ b/firmware/2lib/include/2sha_private.h
@@ -0,0 +1,38 @@
+/* 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.
+ *
+ * Constants & macro for sha algorithms.
+ */
+
+#ifndef VBOOT_REFERENCE_2SHA_PRIVATE_H_
+#define VBOOT_REFERENCE_2SHA_PRIVATE_H_
+
+/* Sha256 padding is consisted of 0x80 + zeros + length of message (8 byte).
+ * So minimum length for padding is 9.
+ */
+#define SHA256_MIN_PAD_LEN 9
+
+/* Beginning of sha256 padding is always 0x80 when messages are in bytes
+ */
+#define SHA256_PAD_BEGIN 0x80
+
+extern const uint32_t vb2_sha256_h0[8];
+extern const uint32_t vb2_sha256_k[64];
+
+#define UNPACK32(x, str) \
+ { \
+ *((str) + 3) = (uint8_t) ((x) ); \
+ *((str) + 2) = (uint8_t) ((x) >> 8); \
+ *((str) + 1) = (uint8_t) ((x) >> 16); \
+ *((str) + 0) = (uint8_t) ((x) >> 24); \
+ }
+
+#define PACK32(str, x) \
+ { \
+ *(x) = ((uint32_t) *((str) + 3) ) \
+ | ((uint32_t) *((str) + 2) << 8) \
+ | ((uint32_t) *((str) + 1) << 16) \
+ | ((uint32_t) *((str) + 0) << 24); \
+ }
+#endif /* VBOOT_REFERENCE_2SHA_PRIVATE_H_ */
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index b79bbd0..ea193d7 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -364,6 +364,8 @@
#define VB2_KEYBLOCK_FLAG_DEVELOPER_1 0x2 /* Developer switch on */
#define VB2_KEYBLOCK_FLAG_RECOVERY_0 0x4 /* Not recovery mode */
#define VB2_KEYBLOCK_FLAG_RECOVERY_1 0x8 /* Recovery mode */
+#define VB2_KEYBLOCK_FLAG_MINIOS_0 0x10 /* Not miniOS boot */
+#define VB2_KEYBLOCK_FLAG_MINIOS_1 0x20 /* miniOS boot */
/*
* Keyblock, containing the public key used to sign some other chunk of data.
diff --git a/firmware/2lib/include/2sysincludes.h b/firmware/2lib/include/2sysincludes.h
index 0671772..1e671e9 100644
--- a/firmware/2lib/include/2sysincludes.h
+++ b/firmware/2lib/include/2sysincludes.h
@@ -21,9 +21,4 @@
#include <stdlib.h>
#include <string.h>
-#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
-#include <byteswap.h>
-#include <memory.h>
-#endif
-
#endif /* VBOOT_REFERENCE_2SYSINCLUDES_H_ */
diff --git a/firmware/2lib/include/2ui.h b/firmware/2lib/include/2ui.h
deleted file mode 100644
index bfb2b8b..0000000
--- a/firmware/2lib/include/2ui.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/* Copyright 2020 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.
- *
- * User interfaces for developer and recovery mode menus.
- */
-
-#ifndef VBOOT_REFERENCE_2UI_H_
-#define VBOOT_REFERENCE_2UI_H_
-
-#include <2api.h>
-#include <2sysincludes.h>
-
-/*****************************************************************************/
-/* Data structures */
-
-struct vb2_ui_context; /* Forward declaration */
-
-struct vb2_menu_item {
- /* Text description */
- const char *text;
- /* Target screen */
- enum vb2_screen target;
- /* Action function takes precedence over target screen if non-NULL. */
- vb2_error_t (*action)(struct vb2_ui_context *ui);
- /* Whether the item is language selection */
- int is_language_select;
-};
-
-struct vb2_menu {
- /* Number of menu items */
- uint16_t num_items;
- /* List of menu items */
- const struct vb2_menu_item *items;
-};
-
-struct vb2_screen_info {
- /* Screen id */
- enum vb2_screen id;
- /* Screen name for printing to console only */
- const char *name;
- /*
- * Init function runs once when changing to the screen which is not in
- * the history stack.
- */
- vb2_error_t (*init)(struct vb2_ui_context *ui);
- /*
- * Re-init function runs once when changing to the screen which is
- * already in the history stack, for example, when going back to the
- * screen. Exactly one of init() and reinit() will be called.
- */
- vb2_error_t (*reinit)(struct vb2_ui_context *ui);
- /* Action function runs repeatedly while on the screen. */
- vb2_error_t (*action)(struct vb2_ui_context *ui);
- /* Menu items. */
- struct vb2_menu menu;
- /*
- * Custom function for getting menu items. If non-null, field 'menu'
- * will be ignored.
- */
- const struct vb2_menu *(*get_menu)(struct vb2_ui_context *ui);
- /*
- * Indices of menu items;
- * used by log_page_* functions in 2ui_screens.c.
- */
- uint32_t page_up_item;
- uint32_t page_down_item;
- uint32_t back_item;
- uint32_t cancel_item;
-};
-
-struct vb2_screen_state {
- const struct vb2_screen_info *screen;
- uint32_t selected_item;
- uint32_t disabled_item_mask;
- uint32_t hidden_item_mask;
-
- /* For log screen. */
- uint32_t page_count;
- uint32_t current_page;
-
- /* For minidiag test screens. */
- int test_finished; /* Do not update screen if the content is done */
-
- struct vb2_screen_state *prev;
-};
-
-enum vb2_power_button {
- VB2_POWER_BUTTON_HELD_SINCE_BOOT = 0,
- VB2_POWER_BUTTON_RELEASED,
- VB2_POWER_BUTTON_PRESSED, /* Must have been previously released */
-};
-
-struct vb2_ui_context {
- struct vb2_context *ctx;
- struct vb2_screen_state *state;
- uint32_t locale_id;
- uint32_t key;
- int key_trusted;
-
- /* For check_shutdown_request. */
- enum vb2_power_button power_button;
-
- /* For developer mode. */
- int disable_timer;
- uint32_t start_time_ms;
- int beep_count;
-
- /* For manual recovery. */
- vb2_error_t recovery_rv;
-
- /* For to_dev transition flow. */
- int physical_presence_button_pressed;
-
- /* For language selection screen. */
- struct vb2_menu language_menu;
-
- /* For bootloader selection screen. */
- struct vb2_menu bootloader_menu;
-
- /* For error beep sound. */
- int error_beep;
-
- /* For displaying error messages. */
- enum vb2_ui_error error_code;
-
- /* Force calling vb2ex_display_ui for refreshing the screen. This flag
- will be reset after done. */
- int force_display;
-};
-
-vb2_error_t vb2_ui_developer_mode_boot_internal_action(
- 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_altfw_action(
- struct vb2_ui_context *ui);
-
-/**
- * Get info struct of a screen.
- *
- * @param id Screen from enum vb2_screen
- *
- * @return screen info struct on success, NULL on error.
- */
-const struct vb2_screen_info *vb2_get_screen_info(enum vb2_screen id);
-
-/*****************************************************************************/
-/* Menu navigation functions */
-
-/**
- * Move selection to the previous menu item.
- *
- * Update selected_item, taking into account hidden indices (from
- * hidden_item_mask). The selection does not wrap, meaning that we block
- * on 0 when we hit the start of the menu.
- *
- * @param ui UI context pointer
- * @return VB2_SUCCESS, or error code on error.
- */
-vb2_error_t vb2_ui_menu_prev(struct vb2_ui_context *ui);
-
-/**
- * Move selection to the next menu item.
- *
- * Update selected_item, taking into account hidden indices (from
- * hidden_item_mask). The selection does not wrap, meaning that we block
- * on the max index when we hit the end of the menu.
- *
- * @param ui UI context pointer
- * @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_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.
- *
- * 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.
- */
-vb2_error_t vb2_ui_screen_back(struct vb2_ui_context *ui);
-
-/**
- * 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);
-
-/*****************************************************************************/
-/* UI loops */
-
-/**
- * UI for a developer-mode boot.
- *
- * Enter the developer menu, which provides options to switch out of developer
- * mode, boot from external media, use legacy bootloader, or boot Chrome OS from
- * disk.
- *
- * If a timeout occurs, take the default boot action.
- *
- * @param ctx Vboot context
- * @return VB2_SUCCESS, or non-zero error code.
- */
-vb2_error_t vb2_developer_menu(struct vb2_context *ctx);
-
-/**
- * UI for a non-manual recovery ("BROKEN").
- *
- * Enter the recovery menu, which shows that an unrecoverable error was
- * encountered last boot. Wait for the user to physically reset or shut down.
- *
- * @param ctx Vboot context
- * @return VB2_SUCCESS, or non-zero error code.
- */
-vb2_error_t vb2_broken_recovery_menu(struct vb2_context *ctx);
-
-/**
- * UI for a manual recovery-mode boot.
- *
- * Enter the recovery menu, which prompts the user to insert recovery media,
- * navigate the step-by-step recovery, or enter developer mode if allowed.
- *
- * @param ctx Vboot context
- * @return VB2_SUCCESS, or non-zero error code.
- */
-vb2_error_t vb2_manual_recovery_menu(struct vb2_context *ctx);
-
-/**
- * UI for a diagnostic tools boot.
- *
- * Enter the diagnostic tools menu, which provides debug information and
- * diagnostic tests of various hardware components.
- *
- * @param ctx Vboot context
- * @return VB2_SUCCESS, or non-zero error code.
- */
-vb2_error_t vb2_diagnostic_menu(struct vb2_context *ctx);
-
-#endif /* VBOOT_REFERENCE_2UI_H_ */
diff --git a/firmware/2lib/include/2ui_private.h b/firmware/2lib/include/2ui_private.h
deleted file mode 100644
index 6ce6cf8..0000000
--- a/firmware/2lib/include/2ui_private.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright 2020 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.
- *
- * Private declarations for 2ui.c. Defined here for testing purposes.
- */
-
-#include "2api.h"
-#include "2common.h"
-
-#ifndef VBOOT_REFERENCE_2UI_PRIVATE_H_
-#define VBOOT_REFERENCE_2UI_PRIVATE_H_
-
-/* Time-related constants */
-#define KEY_DELAY_MS 20 /* Delay between key scans in UI loops */
-#define DEV_DELAY_SHORT_MS (2 * VB2_MSEC_PER_SEC) /* 2 seconds */
-#define DEV_DELAY_NORMAL_MS (30 * VB2_MSEC_PER_SEC) /* 30 seconds */
-#define DEV_DELAY_BEEP1_MS (20 * VB2_MSEC_PER_SEC) /* 20 seconds */
-#define DEV_DELAY_BEEP2_MS (20 * VB2_MSEC_PER_SEC + 500) /* 20.5 seconds */
-
-/* From 2ui.c */
-vb2_error_t check_shutdown_request(struct vb2_ui_context *ui);
-const struct vb2_menu *get_menu(struct vb2_ui_context *ui);
-vb2_error_t error_exit_action(struct vb2_ui_context *ui);
-vb2_error_t menu_navigation_action(struct vb2_ui_context *ui);
-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 developer_action(struct vb2_ui_context *ui);
-vb2_error_t broken_recovery_action(struct vb2_ui_context *ui);
-vb2_error_t manual_recovery_action(struct vb2_ui_context *ui);
-
-/* From 2ui_screens.c */
-const struct vb2_menu *get_language_menu(struct vb2_ui_context *ui);
-vb2_error_t advanced_options_init(struct vb2_ui_context *ui);
-vb2_error_t recovery_select_init(struct vb2_ui_context *ui);
-vb2_error_t recovery_to_dev_init(struct vb2_ui_context *ui);
-vb2_error_t recovery_to_dev_confirm_action(struct vb2_ui_context *ui);
-vb2_error_t recovery_to_dev_action(struct vb2_ui_context *ui);
-vb2_error_t developer_mode_init(struct vb2_ui_context *ui);
-vb2_error_t developer_mode_action(struct vb2_ui_context *ui);
-vb2_error_t developer_to_norm_action(struct vb2_ui_context *ui);
-
-#endif /* VBOOT_REFERENCE_2UI_PRIVATE_H_ */
diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h
index ff6ee32..9f50509 100644
--- a/firmware/include/gpt.h
+++ b/firmware/include/gpt.h
@@ -53,6 +53,10 @@
{{{0xebd0a0a2,0xb9e5,0x4433,0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}}}}
#define GPT_ENT_TYPE_LINUX_FS \
{{{0x0fc63daf,0x8483,0x4772,0x8e,0x79,{0x3d,0x69,0xd8,0x47,0x7d,0xe4}}}}
+#define GPT_ENT_TYPE_CHROMEOS_MINIOS \
+ {{{0x09845860,0x705f,0x4bb5,0xb1,0x6c,{0x8a,0x8a,0x09,0x9c,0xaf,0x52}}}}
+#define GPT_ENT_TYPE_CHROMEOS_HIBERNATE \
+ {{{0x3f0f8318,0xf146,0x4e6b,0x82,0x22,{0xc2,0x8c,0x8f,0x02,0xe0,0xd5}}}}
#define UUID_NODE_LEN 6
#define GUID_SIZE 16
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 2b1d838..f19ee74 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -77,6 +77,33 @@
vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx,
VbSelectAndLoadKernelParams *kparams);
+/**
+ * Attempt loading a kernel from the specified type(s) of disks.
+ *
+ * If successful, sets kparams.disk_handle to the disk for the kernel and
+ * returns VB2_SUCCESS.
+ *
+ * @param ctx Vboot context
+ * @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 disk_flags);
+
+/**
+ * Attempt loading a miniOS kernel from internal disk.
+ *
+ * Scans sectors at the start and end of the disk, and looks for miniOS kernels
+ * starting at the beginning of the sector. Attempts loading any miniOS
+ * kernels found.
+ *
+ * If successful, sets lkp.disk_handle to the disk for the kernel and returns
+ * VB2_SUCCESS.
+ *
+ * @param ctx Vboot context
+ * @return VB2_SUCCESS or the most specific VB2_ERROR_LK error.
+ */
+vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx);
+
/*****************************************************************************/
/* Disk access (previously in boot_device.h) */
@@ -255,82 +282,6 @@
void VbExStreamClose(VbExStream_t stream);
/*****************************************************************************/
-/* Keyboard and switches */
-
-/* Key code for CTRL + letter */
-#define VB_KEY_CTRL(letter) (letter & 0x1f)
-
-/* Key code for fn keys */
-#define VB_KEY_F(num) (num + 0x108)
-
-/* Key codes for required non-printable-ASCII characters. */
-enum VbKeyCode_t {
- VB_KEY_ENTER = '\r',
- VB_KEY_ESC = 0x1b,
- VB_KEY_BACKSPACE = 0x8,
- VB_KEY_UP = 0x100,
- VB_KEY_DOWN = 0x101,
- VB_KEY_LEFT = 0x102,
- VB_KEY_RIGHT = 0x103,
- VB_KEY_CTRL_ENTER = 0x104,
-};
-
-/*
- * WARNING!!! Before updating the codes in enum VbButtonCode_t, ensure that the
- * code does not overlap the values in VbKeyCode_t unless the button action is
- * the same as key action.
- */
-enum VbButtonCode_t {
- /* Volume up/down short press match the values in 8042 driver. */
- VB_BUTTON_VOL_UP_SHORT_PRESS = 0x62,
- VB_BUTTON_VOL_DOWN_SHORT_PRESS = 0x63,
- /* Dummy values used below. */
- VB_BUTTON_POWER_SHORT_PRESS = 0x90,
- VB_BUTTON_VOL_UP_LONG_PRESS = 0x91,
- VB_BUTTON_VOL_DOWN_LONG_PRESS = 0x92,
- VB_BUTTON_VOL_UP_DOWN_COMBO_PRESS = 0x93,
-};
-
-/* Flags for additional information.
- * TODO(semenzato): consider adding flags for modifiers instead of
- * making up some of the key codes above.
- */
-enum VbKeyFlags_t {
- VB_KEY_FLAG_TRUSTED_KEYBOARD = 1 << 0,
-};
-
-/**
- * Read the next keypress from the keyboard buffer.
- *
- * Returns the keypress, or zero if no keypress is pending or error.
- *
- * The following keys must be returned as ASCII character codes:
- * 0x08 Backspace
- * 0x09 Tab
- * 0x0D Enter (carriage return)
- * 0x01 - 0x1A Ctrl+A - Ctrl+Z (yes, those alias with backspace/tab/enter)
- * 0x1B Esc (VB_KEY_ESC)
- * 0x20 Space
- * 0x30 - 0x39 '0' - '9'
- * 0x60 - 0x7A 'a' - 'z'
- *
- * Some extended keys must also be supported; see the VB_KEY_* defines above.
- *
- * Keys ('/') or key-chords (Fn+Q) not defined above may be handled in any of
- * the following ways:
- * 1. Filter (don't report anything if one of these keys is pressed).
- * 2. Report as ASCII (if a well-defined ASCII value exists for the key).
- * 3. Report as any other value in the range 0x200 - 0x2FF.
- * It is not permitted to report a key as a multi-byte code (for example,
- * sending an arrow key as the sequence of keys '\x1b', '[', '1', 'A'). */
-uint32_t VbExKeyboardRead(void);
-
-/**
- * Same as VbExKeyboardRead(), but return extra information.
- */
-uint32_t VbExKeyboardReadWithFlags(uint32_t *flags_ptr);
-
-/*****************************************************************************/
/* Misc */
/**
diff --git a/firmware/lib/include/load_kernel_fw.h b/firmware/lib/include/load_kernel_fw.h
index 96c8f86..af45470 100644
--- a/firmware/lib/include/load_kernel_fw.h
+++ b/firmware/lib/include/load_kernel_fw.h
@@ -12,10 +12,11 @@
#include "vboot_api.h"
/**
- * Attempt to load the kernel from the current device.
+ * Attempt to load kernel from the specified device.
*
* @param ctx Vboot context
* @param params Params specific to loading the kernel
+ * @param disk_info Disk from which to read kernel
*
* Returns VB2_SUCCESS if successful. If unsuccessful, returns an error code.
*/
@@ -23,4 +24,17 @@
VbSelectAndLoadKernelParams *params,
VbDiskInfo *disk_info);
+/**
+ * Attempt to load miniOS kernel from the specified device.
+ *
+ * @param ctx Vboot context
+ * @param params Params specific to loading the kernel
+ * @param disk_info Disk from which to read kernel
+ *
+ * Returns VB2_SUCCESS if successful. If unsuccessful, returns an error code.
+ */
+vb2_error_t LoadMiniOsKernel(struct vb2_context *ctx,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info);
+
#endif /* VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ */
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h
deleted file mode 100644
index a9dc824..0000000
--- a/firmware/lib/include/vboot_kernel.h
+++ /dev/null
@@ -1,31 +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.
- *
- * Data structure and API definitions for a verified boot kernel image.
- * (Firmware Portion)
- */
-
-#ifndef VBOOT_REFERENCE_VBOOT_KERNEL_H_
-#define VBOOT_REFERENCE_VBOOT_KERNEL_H_
-
-#include "cgptlib.h"
-#include "gpt_misc.h"
-#include "load_kernel_fw.h"
-#include "vboot_api.h"
-
-struct vb2_context;
-
-/**
- * Attempt loading a kernel from the specified type(s) of disks.
- *
- * If successful, sets lkp.disk_handle to the disk for the kernel and returns
- * VB2_SUCCESS.
- *
- * @param ctx Vboot context
- * @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 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 8a06892..374dfd4 100644
--- a/firmware/lib/include/vboot_struct.h
+++ b/firmware/lib/include/vboot_struct.h
@@ -10,7 +10,7 @@
#include <stdint.h>
-#include "vboot_kernel.h"
+#include "2sysincludes.h"
#ifdef __cplusplus
extern "C" {
diff --git a/firmware/lib/include/vboot_test.h b/firmware/lib/include/vboot_test.h
index 41e8e5d..fb1f52a 100644
--- a/firmware/lib/include/vboot_test.h
+++ b/firmware/lib/include/vboot_test.h
@@ -12,6 +12,6 @@
* vboot_api_kernel.c */
struct VbSelectAndLoadKernelParams;
-struct VbSelectAndLoadKernelParams *VbApiKernelGetParams(void);
+struct VbSelectAndLoadKernelParams **VbApiKernelGetParamsPtr(void);
#endif /* VBOOT_REFERENCE_TEST_API_H_ */
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 93de040..2abd57e 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -13,21 +13,19 @@
#include "2rsa.h"
#include "2secdata.h"
#include "2sysincludes.h"
-#include "2ui.h"
#include "load_kernel_fw.h"
#include "vboot_api.h"
-#include "vboot_kernel.h"
#include "vboot_struct.h"
#include "vboot_test.h"
/* Global variables */
-static VbSelectAndLoadKernelParams lkp;
+static VbSelectAndLoadKernelParams *kparams_ptr;
#ifdef CHROMEOS_ENVIRONMENT
/* Global variable accessor for unit tests */
-struct VbSelectAndLoadKernelParams *VbApiKernelGetParams(void)
+struct VbSelectAndLoadKernelParams **VbApiKernelGetParamsPtr(void)
{
- return &lkp;
+ return &kparams_ptr;
}
#endif
@@ -63,15 +61,20 @@
((info->flags & VB_DISK_FLAG_SELECT_MASK) - 1)) == 0;
}
-test_mockable
-vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags)
+static vb2_error_t VbTryLoadKernelImpl(struct vb2_context *ctx,
+ uint32_t disk_flags, int minios)
{
vb2_error_t rv = VB2_ERROR_LK_NO_DISK_FOUND;
VbDiskInfo* disk_info = NULL;
uint32_t disk_count = 0;
uint32_t i;
+ vb2_error_t new_rv;
- lkp.disk_handle = NULL;
+ /* TODO: Should have been set by VbSelectAndLoadKernel. Remove when
+ this global is no longer needed. */
+ VB2_ASSERT(kparams_ptr);
+
+ kparams_ptr->disk_handle = NULL;
/* Find disks */
if (VB2_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count, disk_flags))
@@ -89,10 +92,16 @@
disk_info[i].flags);
continue;
}
+ kparams_ptr->disk_handle = disk_info[i].handle;
- 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);
+ if (minios) {
+ new_rv = LoadMiniOsKernel(ctx, kparams_ptr,
+ &disk_info[i]);
+ VB2_DEBUG("LoadMiniOsKernel() = %#x\n", new_rv);
+ } else {
+ new_rv = LoadKernel(ctx, kparams_ptr, &disk_info[i]);
+ VB2_DEBUG("LoadKernel() = %#x\n", new_rv);
+ }
/* Stop now if we found a kernel. */
if (VB2_SUCCESS == new_rv) {
@@ -130,38 +139,16 @@
return rv;
}
-static vb2_error_t vb2_kernel_init_kparams(struct vb2_context *ctx,
- VbSelectAndLoadKernelParams *kparams)
+test_mockable
+vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags)
{
- /* Fill in params for calls to LoadKernel() */
- memset(&lkp, 0, sizeof(lkp));
- lkp.kernel_buffer = kparams->kernel_buffer;
- lkp.kernel_buffer_size = kparams->kernel_buffer_size;
-
- /* Clear output params in case we fail */
- kparams->disk_handle = NULL;
- kparams->partition_number = 0;
- kparams->bootloader_address = 0;
- kparams->bootloader_size = 0;
- kparams->flags = 0;
- memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
-
- return VB2_SUCCESS;
+ return VbTryLoadKernelImpl(ctx, disk_flags, 0);
}
-static void vb2_kernel_fill_kparams(struct vb2_context *ctx,
- VbSelectAndLoadKernelParams *kparams)
+test_mockable
+vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx)
{
- /* Save disk parameters */
- kparams->disk_handle = lkp.disk_handle;
- kparams->partition_number = lkp.partition_number;
- kparams->bootloader_address = lkp.bootloader_address;
- kparams->bootloader_size = lkp.bootloader_size;
- kparams->flags = lkp.flags;
- kparams->kernel_buffer = lkp.kernel_buffer;
- kparams->kernel_buffer_size = lkp.kernel_buffer_size;
- memcpy(kparams->partition_guid, lkp.partition_guid,
- sizeof(kparams->partition_guid));
+ return VbTryLoadKernelImpl(ctx, VB_DISK_FLAG_FIXED, 1);
}
vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx,
@@ -170,12 +157,14 @@
struct vb2_shared_data *sd = vb2_get_sd(ctx);
vb2_gbb_flags_t gbb_flags = vb2api_gbb_get_flags(ctx);
+ /* TODO: Send this argument through subsequent function calls, rather
+ than relying on a global to pass it to VbTryLoadKernel. */
+ kparams_ptr = kparams;
+
/* Init nvstorage space. TODO(kitching): Remove once we add assertions
to vb2_nv_get and vb2_nv_set. */
vb2_nv_init(ctx);
- VB2_TRY(vb2_kernel_init_kparams(ctx, kparams));
-
VB2_TRY(vb2api_kernel_phase1(ctx));
VB2_DEBUG("GBB flags are %#x\n", gbb_flags);
@@ -222,11 +211,11 @@
VB2_DEBUG("NO_BOOT in RECOVERY mode\n");
/* Recovery boot. This has UI. */
- if (vb2_allow_recovery(ctx))
- VB2_TRY(vb2_manual_recovery_menu(ctx));
+ if (vb2api_allow_recovery(ctx))
+ VB2_TRY(vb2ex_manual_recovery_ui(ctx));
else
- VB2_TRY(vb2_broken_recovery_menu(ctx));
- } else if (DIAGNOSTIC_UI && vb2api_diagnostic_ui_enabled(ctx) &&
+ VB2_TRY(vb2ex_broken_screen_ui(ctx));
+ } else if (vb2api_diagnostic_ui_enabled(ctx) &&
vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) {
/*
* Need to clear the request flag and commit nvdata changes
@@ -237,7 +226,7 @@
vb2ex_commit_data(ctx);
/* Diagnostic boot. This has UI. */
- VB2_TRY(vb2_diagnostic_menu(ctx));
+ VB2_TRY(vb2ex_diagnostic_ui(ctx));
/*
* The diagnostic menu should either boot a rom, or
* return either of reboot or shutdown.
@@ -245,7 +234,7 @@
return VB2_REQUEST_REBOOT;
} else if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) {
/* Developer boot. This has UI. */
- VB2_TRY(vb2_developer_menu(ctx));
+ VB2_TRY(vb2ex_developer_ui(ctx));
} else {
/* Normal boot */
VB2_TRY(vb2_normal_boot(ctx));
@@ -262,6 +251,5 @@
return VB2_ERROR_ESCAPE_NO_BOOT;
}
- vb2_kernel_fill_kparams(ctx, kparams);
return VB2_SUCCESS;
}
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 05458b0..34a8a42 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -18,6 +18,17 @@
#include "load_kernel_fw.h"
#include "vboot_api.h"
+enum vb2_load_partition_flags {
+ VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY = (1 << 0),
+ VB2_LOAD_PARTITION_FLAG_MINIOS = (1 << 1),
+};
+
+#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
+
+/* Minimum context work buffer size needed for vb2_load_partition() */
+#define VB2_LOAD_PARTITION_WORKBUF_BYTES \
+ (VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES + KBUF_SIZE)
+
#define LOWEST_TPM_VERSION 0xffffffff
enum vb2_boot_mode {
@@ -163,15 +174,17 @@
/**
* Verify a kernel vblock.
*
+ * @param ctx Vboot context
* @param kbuf Buffer containing the vblock
* @param kbuf_size Size of the buffer in bytes
+ * @param lpflags Flags (one or more of vb2_load_partition_flags)
* @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,
- struct vb2_workbuf *wb)
+ uint32_t lpflags, struct vb2_workbuf *wb)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
@@ -240,6 +253,15 @@
if (need_keyblock_valid)
return VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG;
}
+ if (!(keyblock->keyblock_flags &
+ ((lpflags & VB2_LOAD_PARTITION_FLAG_MINIOS) ?
+ VB2_KEYBLOCK_FLAG_MINIOS_1 :
+ VB2_KEYBLOCK_FLAG_MINIOS_0))) {
+ VB2_DEBUG("Keyblock miniOS flag mismatch.\n");
+ keyblock_valid = 0;
+ if (need_keyblock_valid)
+ return VB2_ERROR_KERNEL_KEYBLOCK_MINIOS_FLAG;
+ }
/* Check for rollback of key version except in recovery mode. */
enum vb2_boot_mode boot_mode = get_boot_mode(ctx);
@@ -299,6 +321,29 @@
return rv;
}
+ /* Rollback check for miniOS */
+ if (need_keyblock_valid && (lpflags & VB2_LOAD_PARTITION_FLAG_MINIOS)) {
+ if (preamble->kernel_version <
+ (sd->kernel_version_secdata >> 24)) {
+ keyblock_valid = 0;
+ if (need_keyblock_valid) {
+ VB2_DEBUG("miniOS kernel version too old.\n");
+ return VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK;
+ }
+ }
+ if (preamble->kernel_version > 0xff) {
+ /*
+ * Key version is stored in the top 8 bits of 16 bits
+ * in the TPM, so key versions greater than 0xFF can't
+ * be stored properly.
+ */
+ VB2_DEBUG("Key version > 0xFF.\n");
+ keyblock_valid = 0;
+ if (need_keyblock_valid)
+ return VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE;
+ }
+ }
+
/*
* Kernel preamble version is the lower 16 bits of the composite
* kernel version.
@@ -321,29 +366,18 @@
return VB2_SUCCESS;
}
-enum vb2_load_partition_flags {
- /* Only check the vblock to */
- VB2_LOAD_PARTITION_VBLOCK_ONLY = (1 << 0),
-};
-
-#define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */
-
-/* Minimum context work buffer size needed for vb2_load_partition() */
-#define VB2_LOAD_PARTITION_WORKBUF_BYTES \
- (VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES + KBUF_SIZE)
-
/**
* Load and verify a partition from the stream.
*
* @param ctx Vboot context
- * @param stream Stream to load kernel from
- * @param flags Flags (one or more of vb2_load_partition_flags)
* @param params Load-kernel parameters
+ * @param stream Stream to load kernel from
+ * @param lpflags Flags (one or more of vb2_load_partition_flags)
* @return VB2_SUCCESS, or non-zero error code.
*/
static vb2_error_t vb2_load_partition(
- struct vb2_context *ctx, VbExStream_t stream, uint32_t flags,
- VbSelectAndLoadKernelParams *params)
+ struct vb2_context *ctx, VbSelectAndLoadKernelParams *params,
+ VbExStream_t stream, uint32_t lpflags)
{
uint32_t read_ms = 0, start_ts;
struct vb2_workbuf wb;
@@ -362,11 +396,10 @@
}
read_ms += vb2ex_mtime() - start_ts;
- if (vb2_verify_kernel_vblock(ctx, kbuf, KBUF_SIZE, &wb)) {
+ if (vb2_verify_kernel_vblock(ctx, kbuf, KBUF_SIZE, lpflags, &wb))
return VB2_ERROR_LOAD_PARTITION_VERIFY_VBLOCK;
- }
- if (flags & VB2_LOAD_PARTITION_VBLOCK_ONLY)
+ if (lpflags & VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY)
return VB2_SUCCESS;
struct vb2_keyblock *keyblock = get_keyblock(kbuf);
@@ -456,6 +489,143 @@
return VB2_SUCCESS;
}
+static vb2_error_t try_minios_kernel(struct vb2_context *ctx,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info,
+ uint64_t sector) {
+ VbExStream_t stream;
+ uint64_t sectors_left = disk_info->lba_count - sector;
+ const uint32_t lpflags = VB2_LOAD_PARTITION_FLAG_MINIOS;
+ vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
+
+ /* Re-open stream at correct offset to pass to vb2_load_partition. */
+ if (VbExStreamOpen(params->disk_handle, sector, sectors_left,
+ &stream)) {
+ VB2_DEBUG("Unable to open disk handle.\n");
+ return rv;
+ }
+
+ rv = vb2_load_partition(ctx, params, stream, lpflags);
+ VB2_DEBUG("vb2_load_partition returned: %d\n", rv);
+
+ VbExStreamClose(stream);
+
+ if (rv)
+ return VB2_ERROR_LK_NO_KERNEL_FOUND;
+ return rv;
+}
+
+static vb2_error_t try_minios_sectors(struct vb2_context *ctx,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info,
+ uint64_t start, uint64_t count)
+{
+ const uint32_t buf_size = count * disk_info->bytes_per_lba;
+ char *buf;
+ VbExStream_t stream;
+ uint64_t isector;
+ vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
+
+ buf = malloc(buf_size);
+ if (buf == NULL) {
+ VB2_DEBUG("Unable to allocate disk read buffer.\n");
+ return rv;
+ }
+
+ if (VbExStreamOpen(params->disk_handle, start, count, &stream)) {
+ VB2_DEBUG("Unable to open disk handle.\n");
+ free(buf);
+ return rv;
+ }
+ if (VbExStreamRead(stream, buf_size, buf)) {
+ VB2_DEBUG("Unable to read disk.\n");
+ free(buf);
+ VbExStreamClose(stream);
+ return rv;
+ }
+ VbExStreamClose(stream);
+
+ for (isector = 0; isector < count; isector++) {
+ if (memcmp(buf + isector * disk_info->bytes_per_lba,
+ VB2_KEYBLOCK_MAGIC, VB2_KEYBLOCK_MAGIC_SIZE))
+ continue;
+ VB2_DEBUG("Match on sector %" PRIu64 " / %" PRIu64 "\n",
+ start + isector,
+ disk_info->lba_count - 1);
+ rv = try_minios_kernel(ctx, params, disk_info, start + isector);
+ if (rv == VB2_SUCCESS)
+ break;
+ }
+
+ free(buf);
+ return rv;
+}
+
+static vb2_error_t try_minios_sector_region(struct vb2_context *ctx,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info,
+ int end_region)
+{
+ const uint64_t disk_count_half = (disk_info->lba_count + 1) / 2;
+ const uint64_t check_count_256 = 256 * 1024
+ * 1024 / disk_info->bytes_per_lba; // 256 MB
+ const uint64_t batch_count_1 = 1024
+ * 1024 / disk_info->bytes_per_lba; // 1 MB
+ const uint64_t check_count = VB2_MIN(disk_count_half, check_count_256);
+ const uint64_t batch_count = VB2_MIN(disk_count_half, batch_count_1);
+ uint64_t sector;
+ uint64_t start;
+ uint64_t end;
+ const char *region_name;
+ vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
+
+ if (!end_region) {
+ start = 0;
+ end = check_count;
+ region_name = "start";
+ } else {
+ start = disk_info->lba_count - check_count;
+ end = disk_info->lba_count;
+ region_name = "end";
+ }
+
+ VB2_DEBUG("Checking %s of disk for kernels...\n", region_name);
+ for (sector = start; sector < end; sector += batch_count) {
+ rv = try_minios_sectors(ctx, params, disk_info, sector,
+ batch_count);
+ if (rv == VB2_SUCCESS)
+ return rv;
+ }
+
+ return rv;
+}
+
+/*
+ * Search for kernels by sector, rather than by partition. Only sectors near
+ * the start and end of disks are considered, and the kernel must start exactly
+ * at the first byte of the sector.
+ */
+vb2_error_t LoadMiniOsKernel(struct vb2_context *ctx,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info)
+{
+ vb2_error_t rv;
+ int end_region_first = vb2_nv_get(ctx, VB2_NV_MINIOS_PRIORITY);
+
+ rv = try_minios_sector_region(ctx, params, disk_info, end_region_first);
+ if (rv)
+ rv = try_minios_sector_region(ctx, params, disk_info,
+ !end_region_first);
+ if (rv)
+ return rv;
+
+ rv = vb2ex_tpm_set_mode(VB2_TPM_MODE_DISABLED);
+ if (rv)
+ VB2_DEBUG("Failed to disable TPM\n");
+
+ return rv;
+}
+
vb2_error_t LoadKernel(struct vb2_context *ctx,
VbSelectAndLoadKernelParams *params,
VbDiskInfo *disk_info)
@@ -465,11 +635,8 @@
uint32_t lowest_version = LOWEST_TPM_VERSION;
vb2_error_t rv;
- /* Clear output params in case we fail */
+ /* Clear output params */
params->partition_number = 0;
- params->bootloader_address = 0;
- params->bootloader_size = 0;
- params->flags = 0;
/* Read GPT data */
GptData gpt;
@@ -518,14 +685,14 @@
* If we already have a good kernel, we only needed to
* look at the vblock versions to check for rollback.
*/
- lpflags |= VB2_LOAD_PARTITION_VBLOCK_ONLY;
+ lpflags |= VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY;
}
- rv = vb2_load_partition(ctx, stream, lpflags, params);
+ rv = vb2_load_partition(ctx, params, stream, lpflags);
VbExStreamClose(stream);
if (rv) {
- VB2_DEBUG("Marking kernel as invalid.\n");
+ VB2_DEBUG("Marking kernel as invalid (err=%x).\n", rv);
GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
continue;
}
@@ -542,7 +709,7 @@
* If we're only looking at headers, we're done with this
* partition.
*/
- if (lpflags & VB2_LOAD_PARTITION_VBLOCK_ONLY)
+ if (lpflags & VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY)
continue;
/*
diff --git a/firmware/stub/tpm_lite_stub.c b/firmware/stub/tpm_lite_stub.c
index b59db33..01704f8 100644
--- a/firmware/stub/tpm_lite_stub.c
+++ b/firmware/stub/tpm_lite_stub.c
@@ -43,15 +43,8 @@
*/
static int exit_on_failure = 1;
-/* Similar to VbExError, only handle the non-exit case.
- */
-static int DoError(int result, const char* format, ...)
+static inline uint32_t try_exit(uint32_t result)
{
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, format, ap);
- va_end(ap);
if (exit_on_failure)
exit(1);
return result;
@@ -62,13 +55,13 @@
__attribute__((unused)) static void DbgPrintBytes(const uint8_t* a, int n)
{
int i;
- fprintf(stderr, "DEBUG: ");
+ VB2_DEBUG_RAW("DEBUG: ");
for (i = 0; i < n; i++) {
if (i && i % 16 == 0)
- fprintf(stderr, "\nDEBUG: ");
- fprintf(stderr, "%02x ", a[i]);
+ VB2_DEBUG_RAW("\nDEBUG: ");
+ VB2_DEBUG_RAW("%02x ", a[i]);
}
- fprintf(stderr, "\n");
+ VB2_DEBUG_RAW("\n");
}
@@ -79,13 +72,13 @@
{
uint8_t response[TPM_MAX_COMMAND_SIZE];
if (in_len <= 0) {
- return DoError(TPM_E_INPUT_TOO_SMALL,
- "invalid command length %d for command %#x\n",
- in_len, in[9]);
+ VB2_DEBUG("ERROR: invalid command length %d for command %#x\n",
+ in_len, in[9]);
+ return try_exit(TPM_E_INPUT_TOO_SMALL);
} else if (tpm_fd < 0) {
- return DoError(TPM_E_NO_DEVICE,
- "the TPM device was not opened. " \
- "Forgot to call TlclLibInit?\n");
+ VB2_DEBUG("ERROR: the TPM device was not opened. "
+ "Forgot to call TlclLibInit?\n");
+ return try_exit(TPM_E_NO_DEVICE);
} else {
int n;
int retries = 0;
@@ -105,15 +98,15 @@
retries + 1, strerror(errno));
}
if (n < 0) {
- return DoError(TPM_E_WRITE_FAILURE,
- "write failure to TPM device: %s "
- "(first error %d)\n",
- strerror(errno), first_errno);
+ VB2_DEBUG("ERROR: write failure to TPM device: %s "
+ "(first error %d)\n",
+ strerror(errno), first_errno);
+ return try_exit(TPM_E_WRITE_FAILURE);
} else if (n != in_len) {
- return DoError(TPM_E_WRITE_FAILURE,
- "bad write size to TPM device: %d vs %u "
- "(%d retries, first error %d)\n",
- n, in_len, retries, first_errno);
+ VB2_DEBUG("ERROR: bad write size to TPM device: "
+ "%d vs %u (%d retries, first error %d)\n",
+ n, in_len, retries, first_errno);
+ return try_exit(TPM_E_WRITE_FAILURE);
}
/* Read response. Retry in case of communication errors.
@@ -131,18 +124,18 @@
retries + 1, strerror(errno));
}
if (n == 0) {
- return DoError(TPM_E_READ_EMPTY,
- "null read from TPM device\n");
+ VB2_DEBUG("ERROR: null read from TPM device\n");
+ return try_exit(TPM_E_READ_EMPTY);
} else if (n < 0) {
- return DoError(TPM_E_READ_FAILURE,
- "read failure from TPM device: %s "
- "(first error %d)\n",
- strerror(errno), first_errno);
+ VB2_DEBUG("ERROR: read failure from TPM device: %s "
+ "(first error %d)\n",
+ strerror(errno), first_errno);
+ return try_exit(TPM_E_READ_FAILURE);
} else {
if (n > *pout_len) {
- return DoError(TPM_E_RESPONSE_TOO_LARGE,
- "TPM response too long for "
- "output buffer\n");
+ VB2_DEBUG("ERROR: TPM response too long for "
+ "output buffer\n");
+ return try_exit(TPM_E_RESPONSE_TOO_LARGE);
} else {
*pout_len = n;
memcpy(out, response, n);
@@ -221,9 +214,9 @@
delay.tv_nsec = OPEN_RETRY_DELAY_NS;
nanosleep(&delay, NULL);
}
- return DoError(VB2_ERROR_UNKNOWN,
- "TPM: Cannot open TPM device %s: %s\n",
- device_path, strerror(saved_errno));
+ VB2_DEBUG("ERROR: TPM: Cannot open TPM device %s: %s\n",
+ device_path, strerror(saved_errno));
+ return try_exit(VB2_ERROR_UNKNOWN);
}
uint32_t vb2ex_tpm_send_recv(const uint8_t* request, uint32_t request_length,
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c
index bc5f2fe..5e08556 100644
--- a/firmware/stub/vboot_api_stub.c
+++ b/firmware/stub/vboot_api_stub.c
@@ -19,18 +19,6 @@
#include "vboot_test.h"
__attribute__((weak))
-uint32_t VbExKeyboardRead(void)
-{
- return 0;
-}
-
-__attribute__((weak))
-uint32_t VbExKeyboardReadWithFlags(uint32_t *flags_ptr)
-{
- return 0;
-}
-
-__attribute__((weak))
uint32_t VbExIsShutdownRequested(void)
{
return 0;
diff --git a/futility/cmd_show.c b/futility/cmd_show.c
index 716b2b2..dbe6edd 100644
--- a/futility/cmd_show.c
+++ b/futility/cmd_show.c
@@ -72,6 +72,10 @@
printf(" !REC");
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_RECOVERY_1)
printf(" REC");
+ if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_0)
+ printf(" !MINIOS");
+ if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_1)
+ printf(" MINIOS");
printf("\n");
struct vb2_packed_key *data_key = &keyblock->data_key;
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index 9bfa7fd..be8b634 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -20,7 +20,6 @@
#include "2common.h"
#include "file_type.h"
#include "file_type_bios.h"
-#include "fmap.h"
#include "futility.h"
#include "futility_options.h"
#include "host_common.h"
diff --git a/futility/cmd_vbutil_keyblock.c b/futility/cmd_vbutil_keyblock.c
index bec23c3..28a3ccd 100644
--- a/futility/cmd_vbutil_keyblock.c
+++ b/futility/cmd_vbutil_keyblock.c
@@ -222,6 +222,10 @@
printf(" !REC");
if (block->keyblock_flags & VB2_KEYBLOCK_FLAG_RECOVERY_1)
printf(" REC");
+ if (block->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_0)
+ printf(" !MINIOS");
+ if (block->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_1)
+ printf(" MINIOS");
printf("\n");
struct vb2_packed_key *data_key = &block->data_key;
diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c
index 39bb16a..2a0e87a 100644
--- a/futility/vb1_helper.c
+++ b/futility/vb1_helper.c
@@ -548,6 +548,10 @@
printf(" !REC");
if (g_keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_RECOVERY_1)
printf(" REC");
+ if (g_keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_0)
+ printf(" !MINIOS");
+ if (g_keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_1)
+ printf(" MINIOS");
printf("\n");
printf(" Data key algorithm: %u %s\n", data_key->algorithm,
vb2_get_crypto_algorithm_name(data_key->algorithm));
diff --git a/host/arch/arm/lib/crossystem_arch.c b/host/arch/arm/lib/crossystem_arch.c
index 0223b70..116f8fc 100644
--- a/host/arch/arm/lib/crossystem_arch.c
+++ b/host/arch/arm/lib/crossystem_arch.c
@@ -35,7 +35,9 @@
#define PLATFORM_DEV_PATH "/sys/devices/platform/chromeos_arm"
/* These should match the Linux GPIO name (i.e., 'gpio-line-names'). */
#define GPIO_NAME_RECOVERY_SW_L "RECOVERY_SW_L"
+#define GPIO_NAME_RECOVERY_SW "RECOVERY_SW"
#define GPIO_NAME_WP_L "AP_FLASH_WP_L"
+#define GPIO_NAME_WP "AP_FLASH_WP"
/* Device for NVCTX write */
#define NVCTX_PATH "/dev/mmcblk%d"
/* Base name for GPIO files */
@@ -481,6 +483,9 @@
value = gpiod_read(GPIO_NAME_RECOVERY_SW_L, true);
if (value != -1)
return value;
+ value = gpiod_read(GPIO_NAME_RECOVERY_SW, false);
+ if (value != -1)
+ return value;
/* Try the deprecated chromeos_arm platform device next. */
return VbGetPlatformGpioStatus("recovery");
} else if (!strcasecmp(name, "wpsw_cur")) {
@@ -489,6 +494,9 @@
value = gpiod_read(GPIO_NAME_WP_L, true);
if (value != -1)
return value;
+ value = gpiod_read(GPIO_NAME_WP, false);
+ if (value != -1)
+ return value;
/* Try the deprecated chromeos_arm platform device next. */
return VbGetPlatformGpioStatus("write-protect");
} else if (!strcasecmp(name, "recoverysw_ec_boot")) {
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index 9d23091..02443b1 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -13,6 +13,7 @@
#include "2common.h"
#include "2nvstorage.h"
#include "2sysincludes.h"
+#include "chromeos_config.h"
#include "crossystem_arch.h"
#include "crossystem.h"
#include "crossystem_vbnv.h"
@@ -490,7 +491,19 @@
const char *VbGetSystemPropertyString(const char *name, char *dest,
size_t size)
{
- /* Check architecture-dependent properties first */
+ /* Check for HWID override via cros_config */
+ if (!strcasecmp(name, "hwid")) {
+ char *hwid_override;
+
+ if (chromeos_config_get_string("/", "hwid-override",
+ &hwid_override) == VB2_SUCCESS) {
+ StrCopy(dest, hwid_override, size);
+ free(hwid_override);
+ return dest;
+ }
+ }
+
+ /* Check architecture-dependent properties */
if (VbGetArchPropertyString(name, dest, size))
return dest;
@@ -532,6 +545,8 @@
return default_boot[v];
else
return "unknown";
+ } else if (!strcasecmp(name, "minios_priority")) {
+ return vb2_get_nv_storage(VB2_NV_MINIOS_PRIORITY) ? "B" : "A";
}
return NULL;
@@ -671,7 +686,13 @@
return vb2_set_nv_storage(VB2_NV_TRY_NEXT, 1);
else
return -1;
-
+ } else if (!strcasecmp(name, "minios_priority")) {
+ if (!strcasecmp(value, "A"))
+ return vb2_set_nv_storage(VB2_NV_MINIOS_PRIORITY, 0);
+ else if (!strcasecmp(value, "B"))
+ return vb2_set_nv_storage(VB2_NV_MINIOS_PRIORITY, 1);
+ else
+ return -1;
} else if (!strcasecmp(name, "fw_result")) {
int i;
diff --git a/host/lib/include/host_misc.h b/host/lib/include/host_misc.h
index 0249420..298e742 100644
--- a/host/lib/include/host_misc.h
+++ b/host/lib/include/host_misc.h
@@ -9,6 +9,7 @@
#define VBOOT_REFERENCE_HOST_MISC_H_
#include "vboot_struct.h"
+#include "vboot_api.h"
/* Copy up to dest_size-1 characters from src to dest, ensuring null
* termination (which strncpy() doesn't do). Returns the destination
diff --git a/scripts/image_signing/sign_android_image.sh b/scripts/image_signing/sign_android_image.sh
index cb45fe9..a7d0fc6 100755
--- a/scripts/image_signing/sign_android_image.sh
+++ b/scripts/image_signing/sign_android_image.sh
@@ -54,8 +54,10 @@
info "Start signing framework apks"
- image_content_integrity_check "${system_mnt}" "${working_dir}" \
- "Prepare apks signing"
+ if ! image_content_integrity_check "${system_mnt}" "${working_dir}" \
+ "Prepare apks signing"; then
+ return 1
+ fi
# Counters for validity check.
local counter_platform=0
@@ -120,8 +122,10 @@
--in "${temp_apk}" --out "${signed_apk}" \
${extra_flags}
fi
- image_content_integrity_check "${system_mnt}" "${working_dir}" \
- "sign apk ${signed_apk}"
+ if ! image_content_integrity_check "${system_mnt}" "${working_dir}" \
+ "sign apk ${signed_apk}"; then
+ return 1
+ fi
# Copy the content instead of mv to avoid owner/mode changes.
sudo cp "${signed_apk}" "${apk}" && rm -f "${signed_apk}"
@@ -133,8 +137,10 @@
: $(( counter_${keyname} += 1 ))
: $(( counter_total += 1 ))
- image_content_integrity_check "${system_mnt}" "${working_dir}" \
- "update re-signed apk ${apk}"
+ if ! image_content_integrity_check "${system_mnt}" "${working_dir}" \
+ "update re-signed apk ${apk}"; then
+ return 1
+ fi
done < <(find "${system_mnt}/system" -type f -name '*.apk' -print0)
info "Found ${counter_platform} platform APKs."
@@ -149,6 +155,8 @@
${counter_total} -lt 25 ]]; then
die "Number of re-signed package seems to be wrong"
fi
+
+ return 0
}
# Extracts certificate from the provided public key.
@@ -250,11 +258,14 @@
snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.new"
local d
if ! d=$(diff "${working_dir}"/properties.{orig,new}); then
- die "Unexpected change of file property, diff due to ${reason}\n${d}"
+ error "Unexpected change of file property, diff due to ${reason}\n${d}"
+ return 1
fi
+
+ return 0
}
-main() {
+sign_android_internal() {
local root_fs_dir=$1
local key_dir=$2
@@ -262,7 +273,6 @@
# Keep this aligned with
# src/private-overlays/project-cheets-private/scripts/board_specific_setup.sh
local system_image=""
- local compression_flags=""
local selinux_dir="${root_fs_dir}/etc/selinux"
local file_contexts=""
local vm_candidate="${root_fs_dir}/opt/google/vms/android/system.raw.img"
@@ -270,11 +280,9 @@
"${root_fs_dir}/opt/google/containers/android/system.raw.img")
if [[ -f "${vm_candidate}" ]]; then
system_image="${vm_candidate}"
- compression_flags="-comp lz4 -Xhc -b 256K"
file_contexts="${selinux_dir}/arc/contexts/files/android_file_contexts_vm"
elif [[ -f "${container_candidate}" ]]; then
system_image="${container_candidate}"
- compression_flags="-comp gzip"
file_contexts="${selinux_dir}/arc/contexts/files/android_file_contexts"
else
die "System image does not exist"
@@ -297,6 +305,21 @@
die "System image does not exist: ${system_img}"
fi
+ # NOTE: Keep compression_flags aligned with
+ # src/private-overlays/project-cheets-private/scripts/board_specific_setup.sh
+ local compression_flags=""
+ local compression=$(sudo "${unsquashfs}" -s "${system_img}" \
+ | grep -e ^"Compression\s")
+ if [[ "${compression}" == "Compression gzip" ]]; then
+ compression_flags="-comp gzip"
+ elif [[ "${compression}" == "Compression lz4" ]]; then
+ compression_flags="-comp lz4 -Xhc -b 256K"
+ elif [[ "${compression}" == "Compression zstd" ]]; then
+ compression_flags="-comp zstd"
+ else
+ die "Unexpected compression type: ${compression}"
+ fi
+
if ! type -P zipalign &>/dev/null || ! type -P signapk &>/dev/null \
|| ! type -P apksigner &>/dev/null; then
# TODO(victorhsieh): Make this an error. This is not treating as error
@@ -313,17 +336,26 @@
snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.orig"
- sign_framework_apks "${system_mnt}" "${key_dir}" "${working_dir}"
- image_content_integrity_check "${system_mnt}" "${working_dir}" \
- "sign_framework_apks"
+ if ! sign_framework_apks "${system_mnt}" "${key_dir}" "${working_dir}"; then
+ return 1
+ fi
+
+ if ! image_content_integrity_check "${system_mnt}" "${working_dir}" \
+ "sign_framework_apks"; then
+ return 1
+ fi
update_sepolicy "${system_mnt}" "${key_dir}"
- image_content_integrity_check "${system_mnt}" "${working_dir}" \
- "update_sepolicy"
+ if ! image_content_integrity_check "${system_mnt}" "${working_dir}" \
+ "update_sepolicy"; then
+ return 1
+ fi
replace_ota_cert "${system_mnt}" "${key_dir}/releasekey.x509.pem"
- image_content_integrity_check "${system_mnt}" "${working_dir}" \
- "replace_ota_cert"
+ if ! image_content_integrity_check "${system_mnt}" "${working_dir}" \
+ "replace_ota_cert"; then
+ return 1
+ fi
# Packages cache needs to be regenerated when the key and timestamp are
# changed for apks.
@@ -367,17 +399,33 @@
info "Packages cache ${packages_cache} does not exist. Skip regeneration."
fi
- info "Repacking squashfs image"
+ info "Repacking squashfs image with compression flags '${compression_flags}'"
local old_size=$(stat -c '%s' "${system_img}")
# Remove old system image to prevent mksquashfs tries to merge both images.
sudo rm -rf "${system_img}"
- # Note, compression_flags is a combination of flags. Keep this aligned with
- # src/private-overlays/project-cheets-private/scripts/board_specific_setup.sh
sudo mksquashfs "${system_mnt}" "${system_img}" \
${compression_flags} -context-file "${file_contexts}" -mount-point "/" \
-no-progress
local new_size=$(stat -c '%s' "${system_img}")
info "Android system image size change: ${old_size} -> ${new_size}"
+ return 0
+}
+
+main() {
+ # TODO(b/175081695): Remove retries once root problem is fixed.
+ local attempts
+ for (( attempts = 1; attempts <= 3; ++attempts )); do
+ if sign_android_internal "$@"; then
+ exit 0
+ fi
+ warn "Could not sign android image due to recoverable error, will retry," \
+ "attempt # ${attempts}."
+ warn "@@@ALERT@@@"
+ lsof -n
+ dmesg
+ mount
+ done
+ die "Unable to sign Android image; giving up."
}
main "$@"
diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh
index 6167f0b..53a9264 100755
--- a/scripts/image_signing/sign_official_build.sh
+++ b/scripts/image_signing/sign_official_build.sh
@@ -9,15 +9,13 @@
# Prerequisite tools needed in the system path:
#
# futility (from src/platform/vboot_reference)
-# vbutil_kernel (from src/platform/vboot_reference)
-# vbutil_key (from src/platform/vboot_reference)
-# cgpt (from src/platform/vboot_reference)
-# dump_kernel_config (from src/platform/vboot_reference)
-# verity (from src/platform/verity)
+# verity (from src/platform2/verity)
# load_kernel_test (from src/platform/vboot_reference)
# dumpe2fs
+# e2fsck
# sha1sum
-# cbfstool (from src/third_party/coreboot)
+
+MINIOS_KERNEL_GUID="09845860-705f-4bb5-b16c-8a8a099caf52"
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
@@ -27,15 +25,11 @@
cat <<EOF
Usage: $PROG <type> input_image /path/to/keys/dir [output_image] [version_file]
where <type> is one of:
- ssd (sign an SSD image)
- base (sign a base image, similar to an SSD image)
+ base (sign a base image)
recovery (sign a USB recovery image)
factory (sign a factory install image)
update_payload (sign a delta update hash)
- kernel (sign a kernel image)
- recovery_kernel (sign a recovery_kernel image)
firmware (sign a firmware image)
- usb (sign an image to boot directly from USB)
verify (verify an image including rootfs hashes)
accessory_usbpd (sign USB-PD accessory firmware)
accessory_rwsig (sign accessory RW firmware)
@@ -84,8 +78,7 @@
PATH=$PATH:/usr/sbin:/sbin
# Make sure the tools we need are available.
-for prereqs in ${FUTILITY} vbutil_kernel cgpt dump_kernel_config verity \
- cbfstool load_kernel_test dumpe2fs sha1sum e2fsck; do
+for prereqs in ${FUTILITY} verity load_kernel_test dumpe2fs e2fsck sha1sum; do
type -P "${prereqs}" &>/dev/null || \
die "${prereqs} tool not found."
done
@@ -214,7 +207,7 @@
info "Updating rootfs hash and updating config for Kernel partitions"
# If we can't find dm parameters in the kernel config, bail out now.
- local kernel_config=$(sudo dump_kernel_config "${loop_kern}")
+ local kernel_config=$(sudo ${FUTILITY} dump_kernel_config "${loop_kern}")
local dm_config=$(get_dmparams_from_config "${kernel_config}")
if [ -z "${dm_config}" ]; then
error "Couldn't grab dm_config from kernel ${loop_kern}"
@@ -265,7 +258,7 @@
for kernelpart in 2 4; do
loop_kern="${loopdev}p${kernelpart}"
if ! new_kernel_config="$(
- sudo dump_kernel_config "${loop_kern}" 2>/dev/null)" &&
+ sudo ${FUTILITY} dump_kernel_config "${loop_kern}" 2>/dev/null)" &&
[[ "${kernelpart}" == 4 ]]; then
# Legacy images don't have partition 4.
info "Skipping empty kernel partition 4 (legacy images)."
@@ -283,7 +276,7 @@
keyblock="${kern_b_keyblock}"
priv_key="${kern_b_privkey}"
fi
- sudo vbutil_kernel --repack "${loop_kern}" \
+ sudo ${FUTILITY} vbutil_kernel --repack "${loop_kern}" \
--keyblock ${keyblock} \
--signprivate ${priv_key} \
--version "${KERNEL_VERSION}" \
@@ -302,13 +295,13 @@
local temp_out_vb="$(make_temp_file)"
local loop_kern="${loopdev}p4"
- if [[ -z "$(sudo dump_kernel_config "${loop_kern}" 2>/dev/null)" ]]; then
+ if [[ -z "$(sudo ${FUTILITY} dump_kernel_config "${loop_kern}" 2>/dev/null)" ]]; then
info "Building vmlinuz_hd.vblock from legacy image partition 2."
loop_kern="${loopdev}p2"
fi
# vblock should always use kernel keyblock.
- sudo vbutil_kernel --repack "${temp_out_vb}" \
+ sudo ${FUTILITY} vbutil_kernel --repack "${temp_out_vb}" \
--keyblock "${KEY_DIR}/kernel.keyblock" \
--signprivate "${KEY_DIR}/kernel_data_key.vbprivk" \
--oldblob "${loop_kern}" \
@@ -402,52 +395,6 @@
info "Signed firmware image output to ${image}"
}
-# Sign a kernel in-place with the given keys.
-# Args: KERNEL_IMAGE KEY_DIR KERNEL_VERSION
-sign_kernel() {
- local image=$1
- local key_dir=$2
- local kernel_version=$3
-
- # Note: Although vbutil_kernel may correctly handle specifying the same
- # output file as the input file, we do not want to rely on it correctly
- # handing that. Hence, the use of a temporary file.
- local temp_kernel=$(make_temp_file)
-
- # Resign the kernel with new keys.
- vbutil_kernel --repack "${temp_kernel}" \
- --keyblock "${key_dir}/kernel.keyblock" \
- --signprivate "${key_dir}/kernel_data_key.vbprivk" \
- --version "${kernel_version}" \
- --oldblob "${image}"
-
- mv "${temp_kernel}" "${image}"
- info "Signed kernel image output to ${image}"
-}
-
-# Sign a recovery kernel in-place with the given keys.
-# Args: KERNEL_IMAGE KEY_DIR KERNEL_VERSION
-sign_recovery_kernel() {
- local image=$1
- local key_dir=$2
- local kernel_version=$3
-
- # Note: Although vbutil_kernel may correctly handle specifying the same
- # output file as the input file, we do not want to rely on it correctly
- # handing that. Hence, the use of a temporary file.
- local temp_kernel=$(make_temp_file)
-
- # Resign the kernel with new recovery keys.
- vbutil_kernel --repack "${temp_kernel}" \
- --keyblock "${key_dir}/recovery_kernel.keyblock" \
- --signprivate "${key_dir}/recovery_kernel_data_key.vbprivk" \
- --version "${kernel_version}" \
- --oldblob "${image}"
-
- mv "${temp_kernel}" "${image}"
- info "Signed recovery_kernel image output to ${image}"
-}
-
# Sign a delta update payload (usually created by paygen).
# Args: INPUT_IMAGE KEY_DIR OUTPUT_IMAGE
sign_update_payload() {
@@ -464,7 +411,7 @@
[8192]=10
)
- key_output=$(futility show "${key_file}")
+ key_output=$(${FUTILITY} show "${key_file}")
key_size=$(echo "${key_output}" | sed -n '/Key length/s/[^0-9]*//p')
algo=${algos[${key_size}]}
if [[ -z ${algo} ]]; then
@@ -681,20 +628,23 @@
echo "Signed with keyset in $(readlink -f "${KEY_DIR}") ." >>"${signer_notes}"
# record recovery_key
key="${KEY_DIR}/recovery_key.vbpubk"
- sha1=$(vbutil_key --unpack "${key}" | grep sha1sum | cut -d" " -f9)
+ sha1=$(${FUTILITY} vbutil_key --unpack "${key}" \
+ | grep sha1sum | cut -d" " -f9)
echo "recovery: ${sha1}" >>"${signer_notes}"
# record root_key(s)
if [[ -d "${shellball_keyset_dir}" ]]; then
echo "List sha1sum of all loem/model's signatures:" >>"${signer_notes}"
for key in "${shellball_keyset_dir}"/rootkey.*; do
model="${key##*.}"
- sha1=$(vbutil_key --unpack "${key}" | grep sha1sum | cut -d" " -f9)
+ sha1=$(${FUTILITY} vbutil_key --unpack "${key}" \
+ | grep sha1sum | cut -d" " -f9)
echo " ${model}: ${sha1}" >>"${signer_notes}"
done
else
echo "List sha1sum of single key's signature:" >>"${signer_notes}"
key="${KEY_DIR}/root_key.vbpubk"
- sha1=$(vbutil_key --unpack "${key}" | grep sha1sum | cut -d" " -f9)
+ sha1=$(${FUTILITY} vbutil_key --unpack "${key}" \
+ | grep sha1sum | cut -d" " -f9)
echo " root: ${sha1}" >>"${signer_notes}"
fi
@@ -771,7 +721,11 @@
elif [[ -z "${esp_dir}" ]]; then
return 0
fi
- "${SCRIPT_DIR}/install_gsetup_certs.sh" "${esp_dir}" "${KEY_DIR}/uefi"
+ # TODO(b/199136347): First class this as an arg and pass from config
+ # in the signing repo. This is a temporary fix to unblock reven-release.
+ if [[ "${KEY_DIR}" != *"Reven"* ]]; then
+ "${SCRIPT_DIR}/install_gsetup_certs.sh" "${esp_dir}" "${KEY_DIR}/uefi"
+ fi
"${SCRIPT_DIR}/sign_uefi.sh" "${esp_dir}" "${KEY_DIR}/uefi"
sudo umount "${esp_dir}"
@@ -843,7 +797,7 @@
local partnum
for partnum in 2 4; do
info "Considering Kernel partition ${partnum}"
- kernel_config=$(sudo dump_kernel_config "${loopdev}p${partnum}")
+ kernel_config=$(sudo ${FUTILITY} dump_kernel_config "${loopdev}p${partnum}")
local hash_image=$(make_temp_file)
if ! calculate_rootfs_hash "${loop_rootfs}" "${kernel_config}" \
"${hash_image}"; then
@@ -911,7 +865,8 @@
local loop_kernb="${loopdev}p4"
# Update the Kernel B hash in Kernel A command line
- local old_kerna_config="$(sudo dump_kernel_config "${loop_kerna}")"
+ local old_kerna_config="$(sudo ${FUTILITY} \
+ dump_kernel_config "${loop_kerna}")"
local old_kernb_hash="$(echo "$old_kerna_config" |
sed -nEe "s#.*kern_b_hash=([a-z0-9]*).*#\1#p")"
if [[ "${#old_kernb_hash}" -lt 64 ]]; then
@@ -928,7 +883,7 @@
cat ${new_kerna_config}
# Re-calculate kernel partition signature and command line.
- sudo vbutil_kernel --repack "${loop_kerna}" \
+ sudo ${FUTILITY} vbutil_kernel --repack "${loop_kerna}" \
--keyblock ${KEY_DIR}/recovery_kernel.keyblock \
--signprivate ${KEY_DIR}/recovery_kernel_data_key.vbprivk \
--version "${KERNEL_VERSION}" \
@@ -936,6 +891,58 @@
--config ${new_kerna_config}
}
+# Re-sign miniOS kernels with new keys.
+# Args: LOOPDEV KEYBLOCK PRIVKEY
+resign_minios_kernels() {
+ local loopdev="$1"
+ local keyblock="$2"
+ local priv_key="$3"
+
+ info "Searching for miniOS kernels to resign..."
+
+ local loop_minios
+ for loop_minios in "${loopdev}p"*; do
+ local part_type_guid
+ part_type_guid=$(sudo lsblk -rnb -o PARTTYPE "${loop_minios}")
+ if [[ "${part_type_guid}" != "${MINIOS_KERNEL_GUID}" ]]; then
+ continue
+ fi
+
+ # Skip miniOS partitions which are empty. This happens when miniOS
+ # kernels aren't written to the partitions because the feature is not
+ # enabled.
+ if ! sudo "${FUTILITY}" dump_kernel_config "${loop_minios}"; then
+ info "Skipping empty miniOS partition ${loop_minios}."
+ continue
+ fi
+
+ # Delay checking that keyblock and private key exist until we are certain
+ # of a valid miniOS partition. Images that don't support miniOS might not
+ # provide these. (This check is repeated twice, but that's okay.)
+ if [[ ! -e "${keyblock}" ]]; then
+ error "Resign miniOS: keyblock doesn't exist: ${keyblock}"
+ return 1
+ fi
+ if [[ ! -e "${priv_key}" ]]; then
+ error "Resign miniOS: private key doesn't exist: ${priv_key}"
+ return 1
+ fi
+
+ # Assume this is a miniOS kernel.
+ local minios_kernel_version=$((KERNEL_VERSION >> 24))
+ if sudo ${FUTILITY} vbutil_kernel --repack "${loop_minios}" \
+ --keyblock "${keyblock}" \
+ --signprivate "${priv_key}" \
+ --version "${minios_kernel_version}" \
+ --oldblob "${loop_minios}"; then
+ info "Resign miniOS ${loop_minios}: done"
+ else
+ error "Resign miniOS ${loop_minios}: failed"
+ return 1
+ fi
+ done
+}
+
# Update the legacy bootloader templates in EFI partition if available.
# Args: LOOPDEV KERNEL
update_legacy_bootloader() {
@@ -952,7 +959,7 @@
fi
# If we can't find the dm parameter in the kernel config, bail out now.
- local kernel_config=$(sudo dump_kernel_config "${loop_kern}")
+ local kernel_config=$(sudo ${FUTILITY} dump_kernel_config "${loop_kern}")
local root_hexdigest="$(get_hash_from_config "${kernel_config}")"
if [[ -z "${root_hexdigest}" ]]; then
error "Couldn't grab root_digest from kernel partition ${loop_kern}"
@@ -983,7 +990,7 @@
# Sign an image file with proper keys.
# Args: IMAGE_TYPE INPUT OUTPUT DM_PARTNO KERN_A_KEYBLOCK KERN_A_PRIVKEY \
-# KERN_B_KEYBLOCK KERN_B_PRIVKEY
+# KERN_B_KEYBLOCK KERN_B_PRIVKEY MINIOS_KEYBLOCK MINIOS_PRIVKEY
#
# A ChromiumOS image file (INPUT) always contains 2 partitions (kernel A & B).
# This function will rebuild hash data by DM_PARTNO, resign kernel partitions by
@@ -1000,6 +1007,8 @@
local kernA_privkey="$6"
local kernB_keyblock="$7"
local kernB_privkey="$8"
+ local minios_keyblock="$9"
+ local minios_privkey="${10}"
info "Preparing ${image_type} image..."
cp --sparse=always "${input}" "${output}"
@@ -1020,7 +1029,7 @@
# /boot in rootfs to update kernel. We infer the BIOS type from the kernel
# config.
local loop_kerna="${loopdev}p2"
- local kerna_config="$(sudo dump_kernel_config "${loop_kerna}")"
+ local kerna_config="$(sudo ${FUTILITY} dump_kernel_config "${loop_kerna}")"
if [[ "${image_type}" != "factory_install" &&
" ${kerna_config} " != *" cros_legacy "* &&
" ${kerna_config} " != *" cros_efi "* ]]; then
@@ -1033,6 +1042,10 @@
if [[ "${image_type}" == "recovery" ]]; then
update_recovery_kernel_hash "${loopdev}"
fi
+ if ! resign_minios_kernels "${loopdev}" "${minios_keyblock}" \
+ "${minios_privkey}"; then
+ return 1
+ fi
if ! update_legacy_bootloader "${loopdev}" "${loop_kern}"; then
# Error is already logged.
return 1
@@ -1047,7 +1060,7 @@
loopdev=$(loopback_partscan "${INPUT_IMAGE}")
for partnum in 2 4; do
info "kernel config in partition number ${partnum}:"
- sudo dump_kernel_config "${loopdev}p${partnum}"
+ sudo ${FUTILITY} dump_kernel_config "${loopdev}p${partnum}"
echo
done
exit 0
@@ -1077,46 +1090,36 @@
info "Using kernel version: ${KERNEL_VERSION}"
# Make all modifications on output copy.
-if [[ "${TYPE}" == "ssd" || "${TYPE}" == "base" ]]; then
- sign_image_file "SSD" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
- "${KEY_DIR}/kernel.keyblock" "${KEY_DIR}/kernel_data_key.vbprivk" \
- "${KEY_DIR}/kernel.keyblock" "${KEY_DIR}/kernel_data_key.vbprivk"
-elif [[ "${TYPE}" == "usb" ]]; then
- sign_image_file "USB" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
- "${KEY_DIR}/recovery_kernel.keyblock" \
- "${KEY_DIR}/recovery_kernel_data_key.vbprivk" \
+if [[ "${TYPE}" == "base" ]]; then
+ sign_image_file "base" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
"${KEY_DIR}/kernel.keyblock" \
- "${KEY_DIR}/kernel_data_key.vbprivk"
+ "${KEY_DIR}/kernel_data_key.vbprivk" \
+ "${KEY_DIR}/kernel.keyblock" \
+ "${KEY_DIR}/kernel_data_key.vbprivk" \
+ "${KEY_DIR}/minios_kernel.keyblock" \
+ "${KEY_DIR}/minios_kernel_data_key.vbprivk"
elif [[ "${TYPE}" == "recovery" ]]; then
sign_image_file "recovery" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 4 \
"${KEY_DIR}/recovery_kernel.keyblock" \
"${KEY_DIR}/recovery_kernel_data_key.vbprivk" \
"${KEY_DIR}/kernel.keyblock" \
- "${KEY_DIR}/kernel_data_key.vbprivk"
+ "${KEY_DIR}/kernel_data_key.vbprivk" \
+ "${KEY_DIR}/minios_kernel.keyblock" \
+ "${KEY_DIR}/minios_kernel_data_key.vbprivk"
elif [[ "${TYPE}" == "factory" ]]; then
sign_image_file "factory_install" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
"${KEY_DIR}/installer_kernel.keyblock" \
"${KEY_DIR}/installer_kernel_data_key.vbprivk" \
"${KEY_DIR}/kernel.keyblock" \
- "${KEY_DIR}/kernel_data_key.vbprivk"
+ "${KEY_DIR}/kernel_data_key.vbprivk" \
+ "${KEY_DIR}/minios_kernel.keyblock" \
+ "${KEY_DIR}/minios_kernel_data_key.vbprivk"
elif [[ "${TYPE}" == "firmware" ]]; then
if [[ -e "${KEY_DIR}/loem.ini" ]]; then
die "LOEM signing not implemented yet for firmware images"
fi
cp ${INPUT_IMAGE} ${OUTPUT_IMAGE}
sign_firmware ${OUTPUT_IMAGE} ${KEY_DIR} ${FIRMWARE_VERSION}
-elif [[ "${TYPE}" == "kernel" ]]; then
- if [[ -e "${KEY_DIR}/loem.ini" ]]; then
- die "LOEM signing not implemented yet for kernel images"
- fi
- cp "${INPUT_IMAGE}" "${OUTPUT_IMAGE}"
- sign_kernel "${OUTPUT_IMAGE}" "${KEY_DIR}" "${KERNEL_VERSION}"
-elif [[ "${TYPE}" == "recovery_kernel" ]]; then
- if [[ -e "${KEY_DIR}/loem.ini" ]]; then
- die "LOEM signing not implemented yet for recovery_kernel images"
- fi
- cp "${INPUT_IMAGE}" "${OUTPUT_IMAGE}"
- sign_recovery_kernel "${OUTPUT_IMAGE}" "${KEY_DIR}" "${KERNEL_VERSION}"
elif [[ "${TYPE}" == "update_payload" ]]; then
sign_update_payload ${INPUT_IMAGE} ${KEY_DIR} ${OUTPUT_IMAGE}
elif [[ "${TYPE}" == "accessory_usbpd" ]]; then
@@ -1125,7 +1128,7 @@
KEY_NAME="${KEY_DIR}/key"
fi
cp "${INPUT_IMAGE}" "${OUTPUT_IMAGE}"
- futility sign --type usbpd1 --pem "${KEY_NAME}.pem" "${OUTPUT_IMAGE}"
+ ${FUTILITY} sign --type usbpd1 --pem "${KEY_NAME}.pem" "${OUTPUT_IMAGE}"
elif [[ "${TYPE}" == "accessory_rwsig" ]]; then
# If one key is present in this container, assume it's the right one.
# See crbug.com/863464
@@ -1138,7 +1141,7 @@
fi
fi
cp "${INPUT_IMAGE}" "${OUTPUT_IMAGE}"
- futility sign --type rwsig --prikey "${KEY_NAME}" \
+ ${FUTILITY} sign --type rwsig --prikey "${KEY_NAME}" \
--version "${FIRMWARE_VERSION}" "${OUTPUT_IMAGE}"
elif [[ "${TYPE}" == "gsc_firmware" ]]; then
sign_gsc_firmware "${INPUT_IMAGE}" "${KEY_DIR}" "${OUTPUT_IMAGE}"
diff --git a/scripts/image_signing/strip_boot_from_image.sh b/scripts/image_signing/strip_boot_from_image.sh
index 2971b08..0f36390 100755
--- a/scripts/image_signing/strip_boot_from_image.sh
+++ b/scripts/image_signing/strip_boot_from_image.sh
@@ -27,7 +27,7 @@
local rootfs="$1"
info "Zeroing freespace in ${rootfs}"
- sudo fstrim -v "${rootfs}"
+ sudo sfill -llz "${rootfs}"
}
diff --git a/scripts/keygeneration/common.sh b/scripts/keygeneration/common.sh
index 21d5334..da06f3c 100644
--- a/scripts/keygeneration/common.sh
+++ b/scripts/keygeneration/common.sh
@@ -58,18 +58,32 @@
DEV_FIRMWARE_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID}
RECOVERY_KERNEL_ALGOID=${RSA4096_SHA512_ALGOID}
+MINIOS_KERNEL_ALGOID=${RSA4096_SHA512_ALGOID}
INSTALLER_KERNEL_ALGOID=${RSA4096_SHA512_ALGOID}
KERNEL_SUBKEY_ALGOID=${RSA4096_SHA256_ALGOID}
KERNEL_DATAKEY_ALGOID=${RSA2048_SHA256_ALGOID}
# Keyblock modes determine which boot modes a signing key is valid for use
# in verification.
-EC_KEYBLOCK_MODE=7 # Only allow RW EC firmware in non-recovery.
-FIRMWARE_KEYBLOCK_MODE=7 # Only allow RW firmware in non-recovery.
-DEV_FIRMWARE_KEYBLOCK_MODE=6 # Only allow in dev mode.
-RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode.
-KERNEL_KEYBLOCK_MODE=7 # Only allow in non-recovery.
-INSTALLER_KERNEL_KEYBLOCK_MODE=10 # Only allow in Dev + Recovery.
+# !DEV 0x1 DEV 0x2
+# !REC 0x4 REC 0x8
+# !MINIOS 0x10 MINIOS 0x20
+# Note that firmware keyblock modes are not used. Consider deprecating.
+
+# Only allow RW EC firmware in non-recovery + non-miniOS.
+EC_KEYBLOCK_MODE=$((0x1 | 0x2 | 0x4 | 0x10))
+# Only allow RW firmware in non-recovery + non-miniOS.
+FIRMWARE_KEYBLOCK_MODE=$((0x1 | 0x2 | 0x4 | 0x10))
+# Only allow in dev mode + non-recovery + non-miniOS.
+DEV_FIRMWARE_KEYBLOCK_MODE=$((0x2 | 0x4 | 0x10))
+# Only allow in recovery mode + non-miniOS.
+RECOVERY_KERNEL_KEYBLOCK_MODE=$((0x1 | 0x2 | 0x8 | 0x10))
+# Only allow in recovery mode + miniOS.
+MINIOS_KERNEL_KEYBLOCK_MODE=$((0x1 | 0x2 | 0x8 | 0x20))
+# Only allow in non-recovery + non-miniOS.
+KERNEL_KEYBLOCK_MODE=$((0x1 | 0x2 | 0x4 | 0x10))
+# Only allow in dev + recovery + non-miniOS.
+INSTALLER_KERNEL_KEYBLOCK_MODE=$((0x2 | 0x8 | 0x10))
# Emit .vbpubk and .vbprivk using given basename and algorithm
# NOTE: This function also appears in ../../utility/dev_make_keypair. Making
@@ -125,6 +139,8 @@
# 0x02 Developer switch on
# 0x04 Not recovery mode
# 0x08 Recovery mode
+# 0x10 Not miniOS mode
+# 0x20 miniOS mode
make_keyblock() {
local base=$1
local flags=$2
diff --git a/scripts/keygeneration/create_new_keys.sh b/scripts/keygeneration/create_new_keys.sh
index 40cccbc..11aedc1 100755
--- a/scripts/keygeneration/create_new_keys.sh
+++ b/scripts/keygeneration/create_new_keys.sh
@@ -43,6 +43,7 @@
local root_key_algoid=${ROOT_KEY_ALGOID}
local recovery_key_algoid=${RECOVERY_KEY_ALGOID}
local recovery_kernel_algoid=${RECOVERY_KERNEL_ALGOID}
+ local minios_kernel_algoid=${MINIOS_KERNEL_ALGOID}
local installer_kernel_algoid=${INSTALLER_KERNEL_ALGOID}
local keyname
local output_dir="${PWD}" setperms="false"
@@ -166,6 +167,7 @@
# Create the recovery and factory installer keypairs
make_pair recovery_key ${recovery_key_algoid}
make_pair recovery_kernel_data_key ${recovery_kernel_algoid}
+ make_pair minios_kernel_data_key ${minios_kernel_algoid}
make_pair installer_kernel_data_key ${installer_kernel_algoid}
# Create the firmware keyblock for use only in Normal mode. This is redundant,
@@ -182,6 +184,9 @@
# Create the recovery kernel keyblock for use only in Recovery mode.
make_keyblock recovery_kernel ${RECOVERY_KERNEL_KEYBLOCK_MODE} recovery_kernel_data_key recovery_key
+ # Create the miniOS kernel keyblock for use only in miniOS mode.
+ make_keyblock minios_kernel ${MINIOS_KERNEL_KEYBLOCK_MODE} minios_kernel_data_key recovery_key
+
# Create the normal kernel keyblock for use only in Normal mode.
make_keyblock kernel ${KERNEL_KEYBLOCK_MODE} kernel_data_key kernel_subkey
diff --git a/tests/devkeys/ec.keyblock b/tests/devkeys/ec.keyblock
index 6b088f3..d934291 100644
--- a/tests/devkeys/ec.keyblock
+++ b/tests/devkeys/ec.keyblock
Binary files differ
diff --git a/tests/devkeys/firmware.keyblock b/tests/devkeys/firmware.keyblock
index 1e2273e..e3653f8 100644
--- a/tests/devkeys/firmware.keyblock
+++ b/tests/devkeys/firmware.keyblock
Binary files differ
diff --git a/tests/devkeys/installer_kernel.keyblock b/tests/devkeys/installer_kernel.keyblock
index cfa3bd1..282e1d6 100644
--- a/tests/devkeys/installer_kernel.keyblock
+++ b/tests/devkeys/installer_kernel.keyblock
Binary files differ
diff --git a/tests/devkeys/kernel.keyblock b/tests/devkeys/kernel.keyblock
index 9740be4..6bb7213 100644
--- a/tests/devkeys/kernel.keyblock
+++ b/tests/devkeys/kernel.keyblock
Binary files differ
diff --git a/tests/devkeys/minios_kernel.keyblock b/tests/devkeys/minios_kernel.keyblock
new file mode 100644
index 0000000..3675690
--- /dev/null
+++ b/tests/devkeys/minios_kernel.keyblock
Binary files differ
diff --git a/tests/devkeys/minios_kernel_data_key.vbprivk b/tests/devkeys/minios_kernel_data_key.vbprivk
new file mode 100644
index 0000000..da3a15b
--- /dev/null
+++ b/tests/devkeys/minios_kernel_data_key.vbprivk
Binary files differ
diff --git a/tests/devkeys/minios_kernel_data_key.vbpubk b/tests/devkeys/minios_kernel_data_key.vbpubk
new file mode 100644
index 0000000..34ff93b
--- /dev/null
+++ b/tests/devkeys/minios_kernel_data_key.vbpubk
Binary files differ
diff --git a/tests/devkeys/recovery_kernel.keyblock b/tests/devkeys/recovery_kernel.keyblock
index ad16e39..c1c8eff 100644
--- a/tests/devkeys/recovery_kernel.keyblock
+++ b/tests/devkeys/recovery_kernel.keyblock
Binary files differ
diff --git a/tests/futility/expect_output/show.tests_devkeys_kernel.keyblock b/tests/futility/expect_output/show.tests_devkeys_kernel.keyblock
index 6505d91..2266424 100644
--- a/tests/futility/expect_output/show.tests_devkeys_kernel.keyblock
+++ b/tests/futility/expect_output/show.tests_devkeys_kernel.keyblock
@@ -1,7 +1,7 @@
Keyblock: tests/devkeys/kernel.keyblock
Signature: ignored
Size: 0x4b8
- Flags: 7 !DEV DEV !REC
+ Flags: 23 !DEV DEV !REC !MINIOS
Data key algorithm: 4 RSA2048 SHA256
Data key version: 1
Data key sha1sum: d6170aa480136f1f29cf339a5ab1b960585fa444
diff --git a/tests/futility/expect_output/vbutil_firmware.verify b/tests/futility/expect_output/vbutil_firmware.verify
index edc9c65..e23c169 100644
--- a/tests/futility/expect_output/vbutil_firmware.verify
+++ b/tests/futility/expect_output/vbutil_firmware.verify
@@ -1,6 +1,6 @@
Keyblock:
Size: 2232
- Flags: 7 (ignored)
+ Flags: 23 (ignored)
Data key algorithm: 7 RSA4096 SHA256
Data key version: 1
Data key sha1sum: e2c1c92d7d7aa7dfed5e8375edd30b7ae52b7450
diff --git a/tests/futility/expect_output/vbutil_keyblock.tests_devkeys_kernel.keyblock b/tests/futility/expect_output/vbutil_keyblock.tests_devkeys_kernel.keyblock
index d55fce3..afb0faf 100644
--- a/tests/futility/expect_output/vbutil_keyblock.tests_devkeys_kernel.keyblock
+++ b/tests/futility/expect_output/vbutil_keyblock.tests_devkeys_kernel.keyblock
@@ -1,6 +1,6 @@
Keyblock file: tests/devkeys/kernel.keyblock
Signature valid
-Flags: 7 !DEV DEV !REC
+Flags: 23 !DEV DEV !REC !MINIOS
Data key algorithm: 4 RSA2048 SHA256
Data key version: 1
Data key sha1sum: d6170aa480136f1f29cf339a5ab1b960585fa444
diff --git a/tests/futility/test_sign_keyblocks.sh b/tests/futility/test_sign_keyblocks.sh
index 7ba43af..f689c89 100755
--- a/tests/futility/test_sign_keyblocks.sh
+++ b/tests/futility/test_sign_keyblocks.sh
@@ -18,7 +18,7 @@
# Create a copy of an existing keyblock, using the old way
${FUTILITY} vbutil_keyblock --pack ${TMP}.keyblock0 \
--datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \
- --flags 7 \
+ --flags 23 \
--signprivate ${DEVKEYS}/root_key.vbprivk
# Check it.
@@ -32,7 +32,7 @@
# Now create it the new way
${FUTILITY} --debug sign \
--datapubkey ${DEVKEYS}/firmware_data_key.vbpubk \
- --flags 7 \
+ --flags 23 \
--signprivate ${DEVKEYS}/root_key.vbprivk \
--outfile ${TMP}.keyblock1
diff --git a/tests/gpt_misc_tests.c b/tests/gpt_misc_tests.c
new file mode 100644
index 0000000..e0a8d56
--- /dev/null
+++ b/tests/gpt_misc_tests.c
@@ -0,0 +1,378 @@
+/* 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.
+ *
+ * Tests for vboot_kernel.c
+ */
+
+#include "2api.h"
+#include "cgptlib.h"
+#include "cgptlib_internal.h"
+#include "gpt.h"
+#include "test_common.h"
+
+#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
+#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
+
+/* Assumes 512-byte disk sectors */
+#define MOCK_SECTOR_SIZE 512
+#define MOCK_SECTOR_COUNT 1024
+
+/* Mock kernel partition */
+struct mock_part {
+ uint32_t start;
+ uint32_t size;
+};
+
+/* Mock data */
+static char call_log[4096];
+static int disk_read_to_fail;
+static int disk_write_to_fail;
+
+static VbExDiskHandle_t handle;
+static uint8_t mock_disk[MOCK_SECTOR_SIZE * MOCK_SECTOR_COUNT];
+static GptHeader *mock_gpt_primary =
+ (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * 1];
+static GptHeader *mock_gpt_secondary =
+ (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * (MOCK_SECTOR_COUNT - 1)];
+
+/**
+ * Prepare a valid GPT header that will pass CheckHeader() tests
+ */
+static void SetupGptHeader(GptHeader *h, int is_secondary)
+{
+ memset(h, '\0', MOCK_SECTOR_SIZE);
+
+ /* "EFI PART" */
+ memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
+ h->revision = GPT_HEADER_REVISION;
+ h->size = MIN_SIZE_OF_HEADER;
+
+ /* 16KB: 128 entries of 128 bytes */
+ h->size_of_entry = sizeof(GptEntry);
+ h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
+
+ /* Set LBA pointers for primary or secondary header */
+ if (is_secondary) {
+ h->my_lba = MOCK_SECTOR_COUNT - GPT_HEADER_SECTORS;
+ h->entries_lba = h->my_lba - CalculateEntriesSectors(h,
+ MOCK_SECTOR_SIZE);
+ } else {
+ h->my_lba = GPT_PMBR_SECTORS;
+ h->entries_lba = h->my_lba + 1;
+ }
+
+ h->first_usable_lba = 2 + CalculateEntriesSectors(h, MOCK_SECTOR_SIZE);
+ h->last_usable_lba = MOCK_SECTOR_COUNT - 2 - CalculateEntriesSectors(h,
+ MOCK_SECTOR_SIZE);
+
+ h->header_crc32 = HeaderCrc(h);
+}
+
+static void ResetCallLog(void)
+{
+ *call_log = 0;
+}
+
+/**
+ * Reset mock data (for use before each test)
+ */
+static void ResetMocks(void)
+{
+ ResetCallLog();
+
+ memset(&mock_disk, 0, sizeof(mock_disk));
+ SetupGptHeader(mock_gpt_primary, 0);
+ SetupGptHeader(mock_gpt_secondary, 1);
+
+ disk_read_to_fail = -1;
+ disk_write_to_fail = -1;
+}
+
+/* Mocks */
+
+vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start,
+ uint64_t lba_count, void *buffer)
+{
+ LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
+
+ if ((int)lba_start == disk_read_to_fail)
+ return VB2_ERROR_MOCK;
+
+ memcpy(buffer, &mock_disk[lba_start * MOCK_SECTOR_SIZE],
+ lba_count * MOCK_SECTOR_SIZE);
+
+ return VB2_SUCCESS;
+}
+
+vb2_error_t VbExDiskWrite(VbExDiskHandle_t h, uint64_t lba_start,
+ uint64_t lba_count, const void *buffer)
+{
+ LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
+
+ if ((int)lba_start == disk_write_to_fail)
+ return VB2_ERROR_MOCK;
+
+ memcpy(&mock_disk[lba_start * MOCK_SECTOR_SIZE], buffer,
+ lba_count * MOCK_SECTOR_SIZE);
+
+ return VB2_SUCCESS;
+}
+
+/**
+ * Test reading/writing GPT
+ */
+static void ReadWriteGptTest(void)
+{
+ GptData g;
+ GptHeader *h;
+
+ g.sector_bytes = MOCK_SECTOR_SIZE;
+ g.streaming_drive_sectors = g.gpt_drive_sectors = MOCK_SECTOR_COUNT;
+ g.valid_headers = g.valid_entries = MASK_BOTH;
+
+ ResetMocks();
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskRead(h, 991, 32)\n");
+ ResetCallLog();
+ /*
+ * Valgrind complains about access to uninitialized memory here, so
+ * zero the primary header before each test.
+ */
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
+ TEST_CALLS("");
+
+ /*
+ * Invalidate primary GPT header,
+ * check that AllocAndReadGptData still succeeds
+ */
+ ResetMocks();
+ memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "AllocAndRead primary invalid");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Primary header is invalid");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Secondary header is valid");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskRead(h, 991, 32)\n");
+ WriteAndFreeGptData(handle, &g);
+
+ /*
+ * Invalidate secondary GPT header,
+ * check that AllocAndReadGptData still succeeds
+ */
+ ResetMocks();
+ memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "AllocAndRead secondary invalid");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Primary header is valid");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Secondary header is invalid");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n");
+ WriteAndFreeGptData(handle, &g);
+
+ /*
+ * Invalidate primary AND secondary GPT header,
+ * check that AllocAndReadGptData fails.
+ */
+ ResetMocks();
+ memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
+ memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 1,
+ "AllocAndRead primary and secondary invalid");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Primary header is invalid");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 1, "Secondary header is invalid");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 1023, 1)\n");
+ WriteAndFreeGptData(handle, &g);
+
+ /*
+ * Invalidate primary GPT header and check that it is
+ * repaired by GptRepair().
+ *
+ * This would normally be called by LoadKernel()->GptInit()
+ * but this callback is mocked in these tests.
+ */
+ ResetMocks();
+ memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "Fix Primary GPT: AllocAndRead");
+ /* Call GptRepair() with input indicating secondary GPT is valid */
+ g.valid_headers = g.valid_entries = MASK_SECONDARY;
+ GptRepair(&g);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
+ "Fix Primary GPT: WriteAndFreeGptData");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskRead(h, 991, 32)\n"
+ "VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+ TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Fix Primary GPT: Primary header is valid");
+
+ /*
+ * Invalidate secondary GPT header and check that it can be
+ * repaired by GptRepair().
+ *
+ * This would normally be called by LoadKernel()->GptInit()
+ * but this callback is mocked in these tests.
+ */
+ ResetMocks();
+ memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0,
+ "Fix Secondary GPT: AllocAndRead");
+ /* Call GptRepair() with input indicating primary GPT is valid */
+ g.valid_headers = g.valid_entries = MASK_PRIMARY;
+ GptRepair(&g);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
+ "Fix Secondary GPT: WriteAndFreeGptData");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+ TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
+ g.gpt_drive_sectors, 0, g.sector_bytes),
+ 0, "Fix Secondary GPT: Secondary header is valid");
+
+ /* Data which is changed is written */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
+ ResetCallLog();
+ memset(g.primary_header, '\0', g.sector_bytes);
+ h = (GptHeader*)g.primary_header;
+ h->entries_lba = 2;
+ h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
+ h->size_of_entry = sizeof(GptEntry);
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+
+ /* Data which is changed is written */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ ResetCallLog();
+ memset(g.primary_header, '\0', g.sector_bytes);
+ h = (GptHeader*)g.primary_header;
+ h->entries_lba = 2;
+ h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
+ h->size_of_entry = sizeof(GptEntry);
+ h = (GptHeader*)g.secondary_header;
+ h->entries_lba = 991;
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n"
+ "VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+
+ /* If legacy signature, don't modify GPT header/entries 1 */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ h = (GptHeader *)g.primary_header;
+ memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
+ g.modified = -1;
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
+ TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+
+ /* Error reading */
+ ResetMocks();
+ disk_read_to_fail = 1;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = g.valid_entries = MASK_SECONDARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+
+ ResetMocks();
+ disk_read_to_fail = 2;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = MASK_BOTH;
+ g.valid_entries = MASK_SECONDARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 2, 32)\n");
+
+ ResetMocks();
+ disk_read_to_fail = 991;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = MASK_BOTH;
+ g.valid_entries = MASK_PRIMARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
+ TEST_CALLS("VbExDiskWrite(h, 991, 32)\n");
+
+ ResetMocks();
+ disk_read_to_fail = 1023;
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ g.valid_headers = g.valid_entries = MASK_PRIMARY;
+ GptRepair(&g);
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
+ TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
+ "VbExDiskWrite(h, 991, 32)\n");
+
+ /* Error writing */
+ ResetMocks();
+ disk_write_to_fail = 1;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 2;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ h = (GptHeader*)g.primary_header;
+ h->entries_lba = 2;
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 991;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 1023;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ memset(g.primary_header, '\0', g.sector_bytes);
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+}
+
+int main(void)
+{
+ ReadWriteGptTest();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/load_kernel_tests.sh b/tests/load_kernel_tests.sh
index d5f41f2..45eedf4 100755
--- a/tests/load_kernel_tests.sh
+++ b/tests/load_kernel_tests.sh
@@ -31,10 +31,10 @@
--key ${TESTKEY_DIR}/key_rsa2048.keyb --algorithm 4
# Keyblock with kernel data key is signed by kernel subkey
-# Flags=5 means dev=0 rec=0
+# Flags=21 means dev=0 rec=0 minios=0
${FUTILITY} vbutil_keyblock --pack keyblock.test \
--datapubkey datakey.test \
- --flags 5 \
+ --flags 21 \
--signprivate ${SCRIPT_DIR}/devkeys/kernel_subkey.vbprivk
# Kernel preamble is signed with the kernel data key
diff --git a/tests/test_common.c b/tests/test_common.c
index 7e994f3..2ce3a5d 100644
--- a/tests/test_common.c
+++ b/tests/test_common.c
@@ -147,6 +147,20 @@
return !result;
}
+int test_fail(int result,
+ const char *preamble, const char *desc, const char *comment)
+{
+ if (result != 0) {
+ print_passed(preamble, desc, comment);
+ } else {
+ print_failed(preamble, desc, comment);
+ fprintf(stderr,
+ " Didn't expect SUCCESS (0), but got it\n");
+ gTestSuccess = 0;
+ }
+ return result;
+}
+
int test_true(int result,
const char *preamble, const char *desc, const char *comment)
{
diff --git a/tests/test_common.h b/tests/test_common.h
index e0d8ef3..c3da880 100644
--- a/tests/test_common.h
+++ b/tests/test_common.h
@@ -120,6 +120,17 @@
#result " == 0", \
comment)
+/* Return 1 if result is not 0 (VB2_SUCCESS or other), else return 1.
+ * Also update the global gTestSuccess flag if test fails. */
+int test_fail(int result,
+ const char *preamble, const char *desc, const char *comment);
+
+#define TEST_FAIL(result, comment) \
+ test_fail(result, \
+ __FILE__ ":" TOSTRING(__LINE__), \
+ #result " != 0", \
+ comment)
+
/* Return 1 if vb2ex_abort() was called, else return 0.
* Also update the global gTestSuccess flag if test fails. */
int test_abort(int aborted,
diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c
index 40fdf59..beab239 100644
--- a/tests/vb2_api_tests.c
+++ b/tests/vb2_api_tests.c
@@ -384,20 +384,14 @@
TEST_NEQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE, 0, " recovery flag");
TEST_NEQ(ctx->flags & VB2_CONTEXT_CLEAR_RAM, 0, " clear ram flag");
- /* Dev switch error in normal mode reboots to recovery */
+ /* Dev switch error proceeds to a recovery boot */
reset_common_data(FOR_MISC);
retval_vb2_check_dev_switch = VB2_ERROR_MOCK;
- TEST_EQ(vb2api_fw_phase1(ctx), VB2_ERROR_MOCK, "phase1 dev switch");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
- VB2_RECOVERY_DEV_SWITCH, " recovery request");
-
- /* Dev switch error already in recovery mode just proceeds */
- reset_common_data(FOR_MISC);
- vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, VB2_RECOVERY_RO_UNSPECIFIED);
- retval_vb2_check_dev_switch = VB2_ERROR_MOCK;
TEST_EQ(vb2api_fw_phase1(ctx), VB2_ERROR_API_PHASE1_RECOVERY,
- "phase1 dev switch error in recovery");
- TEST_EQ(sd->recovery_reason, VB2_RECOVERY_RO_UNSPECIFIED,
+ "phase1 dev switch error proceeds to recovery");
+ TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
+ VB2_RECOVERY_DEV_SWITCH, " recovery request");
+ TEST_EQ(sd->recovery_reason, VB2_RECOVERY_DEV_SWITCH,
" recovery reason");
/* Check that DISPLAY_AVAILABLE gets set on recovery mode. */
TEST_NEQ(ctx->flags & VB2_CONTEXT_DISPLAY_INIT,
diff --git a/tests/vb2_auxfw_sync_tests.c b/tests/vb2_auxfw_sync_tests.c
index 48ce952..3987d64 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_kernel.h"
#include "vboot_struct.h"
/* Mock data */
diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c
index 3f06289..5f065f8 100644
--- a/tests/vb2_common2_tests.c
+++ b/tests/vb2_common2_tests.c
@@ -41,6 +41,7 @@
/* shouldn't reach here but added for compiler */
return VB2_ERROR_MOCK;
}
+ return VB2_ERROR_MOCK;
}
vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c
index 11d183c..d76c402 100644
--- a/tests/vb2_common_tests.c
+++ b/tests/vb2_common_tests.c
@@ -276,9 +276,11 @@
{
struct vb2_packed_key k = {.key_offset = sizeof(k),
.key_size = 128};
+ const void *lower_base;
TEST_SUCC(vb2_verify_packed_key_inside(&k, sizeof(k)+128, &k),
"vb2_packed_key_inside() ok 1");
- TEST_SUCC(vb2_verify_packed_key_inside(&k - 1,
+ lower_base = (const void *)((uintptr_t)&k - sizeof(k));
+ TEST_SUCC(vb2_verify_packed_key_inside(lower_base,
2*sizeof(k)+128, &k),
"vb2_packed_key_inside() ok 2");
TEST_EQ(vb2_verify_packed_key_inside(&k, 128, &k),
@@ -297,9 +299,11 @@
{
struct vb2_signature s = {.sig_offset = sizeof(s),
.sig_size = 128};
+ const void *lower_base;
TEST_SUCC(vb2_verify_signature_inside(&s, sizeof(s)+128, &s),
"vb2_verify_signature_inside() ok 1");
- TEST_SUCC(vb2_verify_signature_inside(&s - 1,
+ lower_base = (const void *)((uintptr_t)&s - sizeof(s));
+ TEST_SUCC(vb2_verify_signature_inside(lower_base,
2*sizeof(s)+128, &s),
"vb2_verify_signature_inside() ok 2");
TEST_EQ(vb2_verify_signature_inside(&s, 128, &s),
diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c
index 8881ea7..16496e4 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_kernel.h"
#include "vboot_struct.h"
/* Mock data */
@@ -97,6 +96,13 @@
memset(hmir, 0, sizeof(hmir));
hmir[0] = 42;
vb2_secdata_kernel_set_ec_hash(ctx, hmir);
+
+ /*
+ * This flag should not involve in the steps deciding whether EC is
+ * running RW. The only concern here is we need to clear this flag after
+ * attempting a jump to RW.
+ */
+ ctx->flags |= VB2_CONTEXT_EC_TRUSTED;
}
/* Mock functions */
@@ -516,6 +522,8 @@
TEST_EQ(ec_ro_protected, 1, "ec ro protected");
TEST_EQ(ec_rw_protected, 1, "ec rw protected");
TEST_EQ(ec_run_image, 1, "ec run image");
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_EC_TRUSTED,
+ " VB2_CONTEXT_EC_TRUSTED is cleared");
ResetMocks();
test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW");
@@ -524,6 +532,8 @@
TEST_EQ(ec_ro_protected, 1, " ec ro protected");
TEST_EQ(ec_rw_protected, 1, " ec rw protected");
TEST_EQ(ec_run_image, 1, " ec run image");
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_EC_TRUSTED,
+ " VB2_CONTEXT_EC_TRUSTED is cleared");
ResetMocks();
jump_retval = VB2_ERROR_MOCK;
@@ -534,6 +544,8 @@
TEST_EQ(ec_ro_protected, 0, " ec ro protected");
TEST_EQ(ec_rw_protected, 0, " ec rw protected");
TEST_EQ(ec_run_image, 0, " ec run image");
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_EC_TRUSTED,
+ " VB2_CONTEXT_EC_TRUSTED is cleared");
ResetMocks();
jump_retval = VB2_REQUEST_REBOOT_EC_TO_RO;
@@ -544,6 +556,8 @@
TEST_EQ(ec_ro_protected, 0, " ec ro protected");
TEST_EQ(ec_rw_protected, 0, " ec rw protected");
TEST_EQ(ec_run_image, 0, " ec run image");
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_EC_TRUSTED,
+ " VB2_CONTEXT_EC_TRUSTED is cleared");
ResetMocks();
protect_retval = VB2_ERROR_MOCK;
@@ -553,6 +567,8 @@
TEST_EQ(ec_ro_protected, 0, "ec ro protected");
TEST_EQ(ec_rw_protected, 0, "ec rw protected");
TEST_EQ(ec_run_image, 1, "ec run image");
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_EC_TRUSTED,
+ " VB2_CONTEXT_EC_TRUSTED is cleared");
/* No longer check for shutdown requested */
ResetMocks();
diff --git a/tests/vb2_kernel_tests.c b/tests/vb2_kernel_tests.c
index 0e1cb28..0dc0e74 100644
--- a/tests/vb2_kernel_tests.c
+++ b/tests/vb2_kernel_tests.c
@@ -15,6 +15,7 @@
#include "2sysincludes.h"
#include "test_common.h"
#include "vboot_struct.h"
+#include "vboot_api.h"
/* Common context for tests */
static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
diff --git a/tests/vb2_misc_tests.c b/tests/vb2_misc_tests.c
index a7cc115..c4b3ce4 100644
--- a/tests/vb2_misc_tests.c
+++ b/tests/vb2_misc_tests.c
@@ -58,7 +58,7 @@
/* Mocked functions */
-int vb2_allow_recovery(struct vb2_context *c)
+int vb2api_allow_recovery(struct vb2_context *c)
{
return allow_recovery_retval;
}
@@ -640,24 +640,35 @@
static void enable_dev_tests(void)
{
reset_common_data();
- vb2_enable_developer_mode(ctx);
+ allow_recovery_retval = 0;
+ TEST_FAIL(vb2api_enable_developer_mode(ctx),
+ "vb2api_enable_developer_mode - failed");
+ TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) &
+ VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0,
+ " dev mode flag not set");
+
+ reset_common_data();
+ allow_recovery_retval = 1;
+ TEST_SUCC(vb2api_enable_developer_mode(ctx),
+ "vb2api_enable_developer_mode - success");
TEST_NEQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) &
VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0,
- "dev mode flag set");
+ " dev mode flag set");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL), BOOT_EXTERNAL_ON_DEV,
- "NV_DEV_BOOT_EXTERNAL set according to compile-time flag");
+ " NV_DEV_BOOT_EXTERNAL set according to compile-time flag");
/* secdata_firmware not initialized, aborts */
reset_common_data();
+ allow_recovery_retval = 1;
sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
- TEST_ABORT(vb2_enable_developer_mode(ctx),
+ TEST_ABORT(vb2api_enable_developer_mode(ctx),
"secdata_firmware no init, enable dev mode aborted");
sd->status |= VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_FLAGS) &
VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE, 0,
- "dev mode flag not set");
+ " dev mode flag not set");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_DEV_BOOT_EXTERNAL), 0,
- "NV_DEV_BOOT_EXTERNAL not set");
+ " NV_DEV_BOOT_EXTERNAL not set");
}
static void tpm_clear_tests(void)
@@ -911,7 +922,7 @@
/* Boot from external disk */
reset_common_data();
- vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED;
vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL);
TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
@@ -926,7 +937,7 @@
VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
"default boot external not allowed");
reset_common_data();
- vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED;
vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL);
TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
@@ -935,7 +946,7 @@
/* Boot altfw */
reset_common_data();
- vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED;
vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW);
TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
@@ -950,7 +961,7 @@
VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL,
"default boot altfw not allowed");
reset_common_data();
- vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
+ ctx->flags |= VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED;
vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT,
VB2_DEV_DEFAULT_BOOT_TARGET_ALTFW);
TEST_EQ(vb2api_get_dev_default_boot_target(ctx),
@@ -958,84 +969,100 @@
"default boot altfw not allowed");
}
-static void dev_boot_allowed_tests(void)
+static void fill_dev_boot_flags_tests(void)
{
/* Dev boot - allowed by default */
reset_common_data();
- TEST_EQ(vb2_dev_boot_allowed(ctx), 1, "dev boot - allowed by default");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED,
+ "dev boot - allowed by default");
/* Dev boot - disabled by FWMP */
reset_common_data();
fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT;
- TEST_EQ(vb2_dev_boot_allowed(ctx), 0, "dev boot - FWMP disabled");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED,
+ "dev boot - FWMP disabled");
/* Dev boot - force enabled by GBB */
reset_common_data();
fwmp->flags |= VB2_SECDATA_FWMP_DEV_DISABLE_BOOT;
gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON;
- TEST_EQ(vb2_dev_boot_allowed(ctx), 1, "dev boot - GBB force dev on");
-
- /* Legacy boot - not allowed by default */
- reset_common_data();
- 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_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_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_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_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");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALLOWED,
+ "dev boot - GBB force dev on");
/* External boot - not allowed by default */
reset_common_data();
- TEST_EQ(vb2_dev_boot_external_allowed(ctx), 0,
- "dev boot external - not allowed by default");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED,
+ "dev boot external - not allowed by default");
/* External boot - enabled by nvdata */
reset_common_data();
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
- TEST_EQ(vb2_dev_boot_external_allowed(ctx), 1,
- "dev boot external - nvdata enabled");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED,
+ "dev boot external - nvdata enabled");
/* External boot - enabled by FWMP */
reset_common_data();
fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL;
- TEST_EQ(vb2_dev_boot_external_allowed(ctx), 1,
- "dev boot external - secdata enabled");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED,
+ "dev boot external - secdata enabled");
/* External boot - force enabled by GBB */
reset_common_data();
gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_USB;
- TEST_EQ(vb2_dev_boot_external_allowed(ctx), 1,
- "dev boot external - GBB force enabled");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED,
+ "dev boot external - GBB force enabled");
/* External boot - set all flags */
reset_common_data();
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_EXTERNAL;
gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_USB;
- TEST_EQ(vb2_dev_boot_external_allowed(ctx), 1,
- "dev boot external - all flags set");
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_EXTERNAL_ALLOWED,
+ "dev boot external - all flags set");
+
+ /* Alternate boot - not allowed by default */
+ reset_common_data();
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_FALSE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED,
+ "dev boot altfw - not allowed by default");
+
+ /* Alternate boot - enabled by nvdata */
+ reset_common_data();
+ vb2_nv_set(ctx, VB2_NV_DEV_BOOT_ALTFW, 1);
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED,
+ "dev boot altfw - nvdata enabled");
+
+ /* Alternate boot - enabled by FWMP */
+ reset_common_data();
+ fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_ALTFW;
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED,
+ "dev boot altfw - secdata enabled");
+
+ /* Alternate boot - force enabled by GBB */
+ reset_common_data();
+ gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW;
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED,
+ "dev boot altfw - GBB force enabled");
+
+ /* Alternate boot - set all flags */
+ reset_common_data();
+ 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;
+ vb2_fill_dev_boot_flags(ctx);
+ TEST_TRUE(ctx->flags & VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED,
+ "dev boot altfw - all flags set");
}
static void use_dev_screen_short_delay_tests(void)
@@ -1068,7 +1095,7 @@
phone_recovery_enabled_tests();
diagnostic_ui_enabled_tests();
dev_default_boot_tests();
- dev_boot_allowed_tests();
+ fill_dev_boot_flags_tests();
use_dev_screen_short_delay_tests();
return gTestSuccess ? 0 : 255;
diff --git a/tests/vb2_sha256_x86_tests.c b/tests/vb2_sha256_x86_tests.c
new file mode 100644
index 0000000..06ba12e
--- /dev/null
+++ b/tests/vb2_sha256_x86_tests.c
@@ -0,0 +1,137 @@
+/* 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.
+ */
+
+/* FIPS 180-2 Tests for message digest functions. */
+
+#include <cpuid.h>
+#include <stdio.h>
+
+#include "2api.h"
+#include "2sha.h"
+#include "sha_test_vectors.h"
+#include "test_common.h"
+
+vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size,
+ enum vb2_hash_algorithm hash_alg, uint8_t *digest,
+ uint32_t digest_size)
+{
+ VB2_TRY(vb2ex_hwcrypto_digest_init(hash_alg, size));
+ VB2_TRY(vb2ex_hwcrypto_digest_extend(buf, size));
+
+ return vb2ex_hwcrypto_digest_finalize(digest, digest_size);
+
+}
+
+static void sha256_tests(void)
+{
+ uint8_t digest[VB2_SHA256_DIGEST_SIZE];
+ uint8_t *test_inputs[3];
+ const uint8_t expect_multiple[VB2_SHA256_DIGEST_SIZE] = {
+ 0x07, 0x08, 0xb4, 0xca, 0x46, 0x4c, 0x40, 0x39,
+ 0x07, 0x06, 0x88, 0x80, 0x30, 0x55, 0x5d, 0x86,
+ 0x0e, 0x4a, 0x0d, 0x2b, 0xc6, 0xc4, 0x87, 0x39,
+ 0x2c, 0x16, 0x55, 0xb0, 0x82, 0x13, 0x16, 0x29 };
+ int i;
+
+ test_inputs[0] = (uint8_t *) oneblock_msg;
+ test_inputs[1] = (uint8_t *) multiblock_msg1;
+ test_inputs[2] = (uint8_t *) long_msg;
+
+ for (i = 0; i < 3; i++) {
+ TEST_SUCC(vb2_digest_buffer(test_inputs[i],
+ strlen((char *)test_inputs[i]),
+ VB2_HASH_SHA256,
+ digest, sizeof(digest)),
+ "vb2_digest_buffer() SHA256");
+ TEST_EQ(memcmp(digest, sha256_results[i], sizeof(digest)),
+ 0, "SHA-256 digest");
+ }
+
+ TEST_EQ(vb2_digest_buffer(test_inputs[0],
+ strlen((char *)test_inputs[0]),
+ VB2_HASH_SHA256, digest, sizeof(digest) - 1),
+ VB2_ERROR_SHA_FINALIZE_DIGEST_SIZE,
+ "vb2_digest_buffer() too small");
+
+ /* Test multiple small extends */
+ vb2ex_hwcrypto_digest_init(VB2_HASH_SHA256, 15);
+ vb2ex_hwcrypto_digest_extend((uint8_t *)"test1", 5);
+ vb2ex_hwcrypto_digest_extend((uint8_t *)"test2", 5);
+ vb2ex_hwcrypto_digest_extend((uint8_t *)"test3", 5);
+ vb2ex_hwcrypto_digest_finalize(digest, VB2_SHA256_DIGEST_SIZE);
+ TEST_EQ(memcmp(digest, expect_multiple, sizeof(digest)), 0,
+ "SHA-256 multiple extends");
+
+ TEST_EQ(vb2_hash_block_size(VB2_HASH_SHA256), VB2_SHA256_BLOCK_SIZE,
+ "vb2_hash_block_size(VB2_HASH_SHA256)");
+
+}
+
+static void known_value_tests(void)
+{
+ const char sentinel[] = "keepme";
+ union {
+ struct vb2_hash hash;
+ char overflow[sizeof(struct vb2_hash) + 8];
+ } test;
+
+#define TEST_KNOWN_VALUE(algo, str, value) \
+ TEST_EQ(vb2_digest_size(algo), sizeof(value) - 1, \
+ "Known hash size " #algo ": " #str); \
+ { \
+ char *sent_base = test.overflow + \
+ offsetof(struct vb2_hash, raw) + sizeof(value) - 1; \
+ strcpy(sent_base, sentinel); \
+ strcpy(sent_base, sentinel); \
+ TEST_SUCC(vb2_digest_buffer((const uint8_t *)str, \
+ sizeof(str) - 1, \
+ algo, test.hash.raw, \
+ vb2_digest_size(algo)), \
+ "Calculate known hash " #algo ": " #str); \
+ TEST_EQ(memcmp(test.hash.raw, value, sizeof(value) - 1), 0, \
+ "Known hash " #algo ": " #str); \
+ TEST_EQ(strcmp(sent_base, sentinel), 0, \
+ "Overflow known hash " #algo ": " #str); \
+ }
+
+ TEST_KNOWN_VALUE(VB2_HASH_SHA256, "",
+ "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9"
+ "\x24\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52"
+ "\xb8\x55");
+
+ const char long_test_string[] = "abcdefghbcdefghicdefghijdefghijkefgh"
+ "ijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrs"
+ "mnopqrstnopqrstu";
+ TEST_KNOWN_VALUE(VB2_HASH_SHA256, long_test_string,
+ "\xcf\x5b\x16\xa7\x78\xaf\x83\x80\x03\x6c\xe5\x9e\x7b\x04\x92"
+ "\x37\x0b\x24\x9b\x11\xe8\xf0\x7a\x51\xaf\xac\x45\x03\x7a\xfe"
+ "\xe9\xd1");
+
+ /* vim helper to escape hex: <Shift+V>:s/\([a-f0-9]\{2\}\)/\\x\1/g */
+#undef TEST_KNOWN_VALUE
+}
+
+int main(int argc, char *argv[])
+{
+ uint32_t a, b = 0, c, d;
+ /* EAX = 07H, sub-leaf 0 */
+ __get_cpuid_count(7, 0, &a, &b, &c, &d);
+ if ((b & bit_SHA) == 0) {
+ fprintf(stderr, "SHA-NI not supported.\n");
+ return 254;
+ }
+
+ /* Initialize long_msg with 'a' x 1,000,000 */
+ long_msg = (char *) malloc(1000001);
+ memset(long_msg, 'a', 1000000);
+ long_msg[1000000]=0;
+
+ sha256_tests();
+ known_value_tests();
+
+ free(long_msg);
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vb2_sha_tests.c b/tests/vb2_sha_tests.c
index b4a4bd0..a14af65 100644
--- a/tests/vb2_sha_tests.c
+++ b/tests/vb2_sha_tests.c
@@ -172,21 +172,27 @@
static void known_value_tests(void)
{
const char sentinel[] = "keepme";
- struct {
+ union {
struct vb2_hash hash;
- uint8_t overflow[8];
+ char overflow[sizeof(struct vb2_hash) + 8];
} test;
+
#define TEST_KNOWN_VALUE(algo, str, value) \
TEST_EQ(vb2_digest_size(algo), sizeof(value) - 1, \
"Known hash size " #algo ": " #str); \
- strcpy((char *)&test.hash.raw[sizeof(value) - 1], sentinel); \
- TEST_SUCC(vb2_hash_calculate(str, sizeof(str) - 1, algo, &test.hash), \
- "Calculate known hash " #algo ": " #str); \
- TEST_EQ(memcmp(test.hash.raw, value, sizeof(value) - 1), 0, \
- "Known hash " #algo ": " #str); \
- TEST_EQ(strcmp((char *)&test.hash.raw[sizeof(value) - 1], sentinel), 0,\
- "Overflow known hash " #algo ": " #str);
+ { \
+ char *sent_base = test.overflow + \
+ offsetof(struct vb2_hash, raw) + sizeof(value) - 1; \
+ strcpy(sent_base, sentinel); \
+ TEST_SUCC(vb2_hash_calculate(str, sizeof(str) - 1, \
+ algo, &test.hash), \
+ "Calculate known hash " #algo ": " #str); \
+ TEST_EQ(memcmp(test.hash.raw, value, sizeof(value) - 1), 0, \
+ "Known hash " #algo ": " #str); \
+ TEST_EQ(strcmp(sent_base, sentinel), 0, \
+ "Overflow known hash " #algo ": " #str); \
+ }
TEST_KNOWN_VALUE(VB2_HASH_SHA1, "",
"\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18"
diff --git a/tests/vb2_ui_action_tests.c b/tests/vb2_ui_action_tests.c
deleted file mode 100644
index 6db75bf..0000000
--- a/tests/vb2_ui_action_tests.c
+++ /dev/null
@@ -1,1085 +0,0 @@
-/* Copyright 2020 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.
- *
- * Tests for UI related actions.
- */
-
-#include "2api.h"
-#include "2common.h"
-#include "2misc.h"
-#include "2nvstorage.h"
-#include "2ui.h"
-#include "2ui_private.h"
-#include "test_common.h"
-#include "vboot_kernel.h"
-
-/* Fixed value for ignoring some checks. */
-#define MOCK_IGNORE 0xffffu
-
-/* Mock screen index for testing screen utility functions. */
-#define MOCK_NO_SCREEN 0xef00
-#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
-#define MOCK_SCREEN_ACTION 0xef30
-#define MOCK_SCREEN_ALL_ACTION 0xef32
-
-/* Mock data */
-/* TODO(b/156448738): Add tests for timer_disabled and error_code */
-struct display_call {
- const struct vb2_screen_info *screen;
- uint32_t locale_id;
- uint32_t selected_item;
- uint32_t disabled_item_mask;
- uint32_t hidden_item_mask;
- int timer_disabled;
- uint32_t current_page;
- enum vb2_ui_error error_code;
-} __attribute__((packed));
-
-static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
- __attribute__((aligned(VB2_WORKBUF_ALIGN)));
-static struct vb2_context *ctx;
-static struct vb2_shared_data *sd;
-static struct vb2_gbb_header gbb;
-
-static int mock_calls_until_shutdown;
-
-static struct vb2_ui_context mock_ui_context;
-
-static struct display_call mock_displayed[64];
-static int mock_displayed_count;
-static int mock_displayed_i;
-
-static uint32_t mock_key[64];
-static int mock_key_trusted[64];
-static int mock_key_count;
-static int mock_key_total;
-
-static int mock_get_screen_info_called;
-
-static vb2_error_t mock_vbtlk_retval;
-static uint32_t mock_vbtlk_expected_flag;
-
-static int mock_dev_boot_allowed;
-static int mock_dev_boot_altfw_allowed;
-
-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;
-
-/* Mock actions */
-static uint32_t mock_action_called;
-static uint32_t mock_action_countdown_limit;
-static vb2_error_t mock_action_countdown(struct vb2_ui_context *ui)
-{
- if (++mock_action_called >= mock_action_countdown_limit)
- return VB2_REQUEST_UI_EXIT;
- return VB2_SUCCESS;
-}
-
-static vb2_error_t mock_action_screen_change(struct vb2_ui_context *ui)
-{
- return vb2_ui_screen_change(ui, MOCK_SCREEN_BASE);
-}
-
-static vb2_error_t mock_action_base(struct vb2_ui_context *ui)
-{
- mock_action_called++;
- return VB2_SUCCESS;
-}
-
-static int mock_action_flags;
-static vb2_error_t mock_action_flag0(struct vb2_ui_context *ui)
-{
- if ((1 << 0) & mock_action_flags)
- 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_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_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_SUCCESS;
-}
-
-/* Mock screens */
-struct vb2_screen_info mock_screen_temp;
-const struct vb2_screen_info mock_screen_blank = {
- .id = MOCK_SCREEN_BLANK,
- .name = "mock_screen_blank",
-};
-const struct vb2_screen_info mock_screen_base = {
- .id = MOCK_SCREEN_BASE,
- .name = "mock_screen_base: menuless screen",
-};
-const struct vb2_menu_item mock_screen_menu_items[] = {
- {
- .text = "item 0",
- .target = MOCK_SCREEN_TARGET0,
- },
- {
- .text = "item 1",
- .target = MOCK_SCREEN_TARGET1,
- },
- {
- .text = "item 2",
- .target = MOCK_SCREEN_TARGET2,
- },
- {
- .text = "item 3",
- .action = mock_action_base,
- },
- {
- .text = "item 4 (no target)",
- },
-};
-const struct vb2_screen_info mock_screen_menu = {
- .id = MOCK_SCREEN_MENU,
- .name = "mock_screen_menu: screen with 5 items",
- .menu = {
- .num_items = ARRAY_SIZE(mock_screen_menu_items),
- .items = mock_screen_menu_items,
- },
-};
-const struct vb2_screen_info mock_screen_target0 = {
- .id = MOCK_SCREEN_TARGET0,
- .name = "mock_screen_target0",
-};
-const struct vb2_screen_info mock_screen_target1 = {
- .id = MOCK_SCREEN_TARGET1,
- .name = "mock_screen_target1",
-};
-const struct vb2_screen_info mock_screen_target2 = {
- .id = MOCK_SCREEN_TARGET2,
- .name = "mock_screen_target2",
-};
-const struct vb2_screen_info mock_screen_action = {
- .id = MOCK_SCREEN_ACTION,
- .name = "mock_screen_action",
- .action = mock_action_countdown,
-};
-const struct vb2_menu_item mock_screen_all_action_items[] = {
- {
- .text = "all_action_screen_item",
- .action = mock_action_flag1,
- },
-};
-const struct vb2_screen_info mock_screen_all_action = {
- .id = MOCK_SCREEN_ALL_ACTION,
- .name = "mock_screen_all_action",
- .action = mock_action_flag0,
- .menu = {
- .num_items = ARRAY_SIZE(mock_screen_all_action_items),
- .items = mock_screen_all_action_items,
- },
-};
-
-static void screen_state_eq(const struct vb2_screen_state *state,
- enum vb2_screen screen,
- uint32_t selected_item,
- uint32_t hidden_item_mask)
-{
- if (screen != MOCK_IGNORE) {
- if (state->screen == NULL)
- TEST_TRUE(0, " state.screen does not exist");
- else
- TEST_EQ(state->screen->id, screen, " state.screen");
- }
- if (selected_item != MOCK_IGNORE)
- TEST_EQ(state->selected_item,
- selected_item, " state.selected_item");
- if (hidden_item_mask != MOCK_IGNORE)
- TEST_EQ(state->hidden_item_mask,
- hidden_item_mask, " state.hidden_item_mask");
-}
-
-static void add_mock_key(uint32_t press, int trusted)
-{
- if (mock_key_total >= ARRAY_SIZE(mock_key) ||
- mock_key_total >= ARRAY_SIZE(mock_key_trusted)) {
- TEST_TRUE(0, " mock_key ran out of entries!");
- return;
- }
-
- mock_key[mock_key_total] = press;
- mock_key_trusted[mock_key_total] = trusted;
- mock_key_total++;
-}
-
-static void add_mock_keypress(uint32_t press)
-{
- add_mock_key(press, 0);
-}
-
-
-static void set_mock_vbtlk(vb2_error_t retval, uint32_t disk_flags)
-{
- mock_vbtlk_retval = retval;
- mock_vbtlk_expected_flag = disk_flags;
-}
-
-static void displayed_eq(const char *text,
- enum vb2_screen screen,
- uint32_t locale_id,
- uint32_t selected_item,
- uint32_t hidden_item_mask,
- int line)
-{
- char text_info[32], text_buf[128];
-
- sprintf(text_info, "(line #%d, displayed #%d)", line, mock_displayed_i);
-
- if (mock_displayed_i >= mock_displayed_count) {
- sprintf(text_buf, " %s missing screen %s",
- text_info, text);
- TEST_TRUE(0, text_buf);
- return;
- }
-
- if (screen != MOCK_IGNORE) {
- sprintf(text_buf, " %s screen of %s", text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].screen->id, screen,
- text_buf);
- }
- if (locale_id != MOCK_IGNORE) {
- sprintf(text_buf, " %s locale_id of %s", text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].locale_id, locale_id,
- text_buf);
- }
- if (selected_item != MOCK_IGNORE) {
- sprintf(text_buf, " %s selected_item of %s",
- text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].selected_item,
- selected_item, text_buf);
- }
- if (hidden_item_mask != MOCK_IGNORE) {
- sprintf(text_buf, " %s hidden_item_mask of %s",
- text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].hidden_item_mask,
- hidden_item_mask, text_buf);
- }
- mock_displayed_i++;
-}
-
-static void displayed_no_extra(int line)
-{
- char text_info[32], text_buf[128];
-
- sprintf(text_info, "(line #%d)", line);
-
- if (mock_displayed_i == 0)
- sprintf(text_buf, " %s no screen", text_info);
- else
- sprintf(text_buf, " %s no extra screens", text_info);
- TEST_EQ(mock_displayed_count, mock_displayed_i, text_buf);
-}
-
-#define DISPLAYED_EQ(...) displayed_eq(__VA_ARGS__, __LINE__)
-
-#define DISPLAYED_PASS() \
- displayed_eq("", MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, \
- __LINE__)
-
-#define DISPLAYED_NO_EXTRA() displayed_no_extra(__LINE__)
-
-/* Reset mock data (for use before each test) */
-static void reset_common_data(void)
-{
- TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
- "vb2api_init failed");
-
- memset(&gbb, 0, sizeof(gbb));
-
- vb2_nv_init(ctx);
-
- sd = vb2_get_sd(ctx);
-
- /* For check_shutdown_request */
- mock_calls_until_shutdown = 10;
-
- /* Reset mock_screen_temp for test by test temporary screen_info */
- mock_screen_temp = (struct vb2_screen_info){
- .id = MOCK_NO_SCREEN,
- .name = "mock_screen_temp",
- };
-
- /* Mock ui_context based on mock screens */
- memset(&mock_ui_context, 0, sizeof(mock_ui_context));
- mock_ui_context.ctx = ctx;
-
- if (!mock_ui_context.state)
- mock_ui_context.state = malloc(sizeof(*mock_ui_context.state));
- memset(mock_ui_context.state, 0, sizeof(*mock_ui_context.state));
- mock_ui_context.state->screen = &mock_screen_temp;
-
- /* For vb2ex_display_ui */
- memset(mock_displayed, 0, sizeof(mock_displayed));
- mock_displayed_count = 0;
- mock_displayed_i = 0;
-
- /* For VbExKeyboardRead */
- memset(mock_key, 0, sizeof(mock_key));
- memset(mock_key_trusted, 0, sizeof(mock_key_trusted));
- mock_key_count = 0;
- mock_key_total = 0;
-
- /* For mock actions */
- mock_action_called = 0;
- mock_action_countdown_limit = 1;
- mock_action_flags = 0;
- mock_action_delay_ms = 0;
-
- /* For chagen_screen and vb2_get_screen_info */
- mock_get_screen_info_called = 0;
-
- /* For VbTryLoadKernel */
- mock_vbtlk_retval = VB2_ERROR_MOCK;
- mock_vbtlk_expected_flag = MOCK_IGNORE;
-
- /* For dev_boot* in 2misc.h */
- mock_dev_boot_allowed = 1;
- mock_dev_boot_altfw_allowed = 0;
-
- /* 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;
-}
-
-/* Mock functions */
-struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
-{
- return &gbb;
-}
-
-uint32_t VbExIsShutdownRequested(void)
-{
- if (mock_calls_until_shutdown < 0) /* Never request shutdown */
- return 0;
- if (mock_calls_until_shutdown == 0)
- return 1;
- mock_calls_until_shutdown--;
-
- return 0;
-}
-
-const struct vb2_screen_info *vb2_get_screen_info(enum vb2_screen screen)
-{
- mock_get_screen_info_called++;
-
- switch ((int)screen) {
- case MOCK_SCREEN_BLANK:
- return &mock_screen_blank;
- case MOCK_SCREEN_BASE:
- return &mock_screen_base;
- case MOCK_SCREEN_MENU:
- return &mock_screen_menu;
- case MOCK_SCREEN_TARGET0:
- return &mock_screen_target0;
- case MOCK_SCREEN_TARGET1:
- return &mock_screen_target1;
- case MOCK_SCREEN_TARGET2:
- return &mock_screen_target2;
- case MOCK_SCREEN_ACTION:
- return &mock_screen_action;
- case MOCK_SCREEN_ALL_ACTION:
- return &mock_screen_all_action;
- case MOCK_NO_SCREEN:
- return NULL;
- default:
- mock_screen_temp.id = screen;
- return &mock_screen_temp;
- }
-}
-
-vb2_error_t vb2ex_display_ui(enum vb2_screen screen,
- uint32_t locale_id,
- uint32_t selected_item,
- uint32_t disabled_item_mask,
- uint32_t hidden_item_mask,
- int timer_disabled,
- uint32_t current_page,
- enum vb2_ui_error error_code)
-{
- struct display_call displayed = (struct display_call){
- .screen = vb2_get_screen_info(screen),
- .locale_id = locale_id,
- .selected_item = selected_item,
- .disabled_item_mask = disabled_item_mask,
- .hidden_item_mask = hidden_item_mask,
- .timer_disabled = timer_disabled,
- .current_page = current_page,
- .error_code = error_code,
- };
-
- /* Ignore repeated calls with same arguments */
- if (mock_displayed_count > 0 &&
- !memcmp(&mock_displayed[mock_displayed_count - 1], &displayed,
- sizeof(struct display_call)))
- return VB2_SUCCESS;
-
- VB2_DEBUG("displayed %d: screen=%#x, locale_id=%u, selected_item=%u, "
- "disabled_item_mask=%#x, hidden_item_mask=%#x, "
- "timer_disabled=%d, current_page=%u, error=%#x\n",
- mock_displayed_count, screen, locale_id, selected_item,
- disabled_item_mask, hidden_item_mask,
- timer_disabled, current_page, error_code);
-
- if (mock_displayed_count >= ARRAY_SIZE(mock_displayed)) {
- TEST_TRUE(0, " mock vb2ex_display_ui ran out of entries!");
- return VB2_ERROR_MOCK;
- }
-
- mock_displayed[mock_displayed_count++] = displayed;
-
- return VB2_SUCCESS;
-}
-
-uint32_t VbExKeyboardRead(void)
-{
- return VbExKeyboardReadWithFlags(NULL);
-}
-
-uint32_t VbExKeyboardReadWithFlags(uint32_t *key_flags)
-{
- if (mock_key_count < mock_key_total) {
- if (key_flags != NULL) {
- if (mock_key_trusted[mock_key_count])
- *key_flags = VB_KEY_FLAG_TRUSTED_KEYBOARD;
- else
- *key_flags = 0;
- }
- return mock_key[mock_key_count++];
- }
-
- return 0;
-}
-
-vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags)
-{
- TEST_EQ(mock_vbtlk_expected_flag, disk_flags,
- " unexpected disk_flags");
- return mock_vbtlk_retval;
-}
-
-int vb2_dev_boot_allowed(struct vb2_context *c)
-{
- return mock_dev_boot_allowed;
-}
-
-int vb2_dev_boot_altfw_allowed(struct vb2_context *c)
-{
- return mock_dev_boot_altfw_allowed;
-}
-
-vb2_error_t vb2ex_run_altfw(uint32_t altfw_id)
-{
- mock_run_altfw_called++;
- mock_altfw_last = altfw_id;
-
- if (altfw_id <= mock_altfw_count)
- return VB2_SUCCESS;
- else
- return VB2_ERROR_UNKNOWN;
-}
-
-uint32_t vb2ex_get_altfw_count(void)
-{
- return mock_altfw_count;
-}
-
-uint32_t vb2ex_mtime(void)
-{
- return mock_time_ms;
-}
-
-void vb2ex_msleep(uint32_t msec)
-{
- mock_time_ms += msec;
-}
-
-/* Tests */
-static void menu_prev_tests(void)
-{
- VB2_DEBUG("Testing menu_prev...\n");
-
- /* Valid action */
- reset_common_data();
- 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_SUCCESS,
- "valid action");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 1,
- MOCK_IGNORE);
-
- /* Valid action with hidden mask */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "valid action with hidden mask");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 0,
- MOCK_IGNORE);
-
- /* Disabled mask does not affect menu_prev */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "valid action with disabled mask");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 1,
- MOCK_IGNORE);
-
- /* Invalid action (blocked) */
- reset_common_data();
- 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_SUCCESS,
- "invalid action (blocked)");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 0,
- MOCK_IGNORE);
-
- /* Invalid action (blocked by mask) */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "invalid action (blocked by mask)");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
- MOCK_IGNORE);
-
- /* Ignore volume-up when not DETACHABLE */
- if (!DETACHABLE) {
- reset_common_data();
- 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_SUCCESS,
- "ignore volume-up when not DETACHABLE");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
- MOCK_IGNORE);
- }
-
- VB2_DEBUG("...done.\n");
-}
-
-static void menu_next_tests(void)
-{
- VB2_DEBUG("Testing menu_next...\n");
-
- /* Valid action */
- reset_common_data();
- 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_SUCCESS,
- "valid action");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 3,
- MOCK_IGNORE);
-
- /* Valid action with hidden mask */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "valid action with hidden mask");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 4,
- MOCK_IGNORE);
-
- /* Disabled mask does not affect menu_next */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "valid action with disabled mask");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 3,
- MOCK_IGNORE);
-
- /* Invalid action (blocked) */
- reset_common_data();
- 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_SUCCESS,
- "invalid action (blocked)");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 4,
- MOCK_IGNORE);
-
- /* Invalid action (blocked by mask) */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "invalid action (blocked by mask)");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
- MOCK_IGNORE);
-
- /* Ignore volume-down when not DETACHABLE */
- if (!DETACHABLE) {
- reset_common_data();
- 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_SUCCESS,
- "ignore volume-down when not DETACHABLE");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 2,
- MOCK_IGNORE);
- }
-
- 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");
-
- /* select action with no item screen */
- 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_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");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_TARGET2, 0,
- MOCK_IGNORE);
-
- /* Try to select an item with an action (item 3) */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- mock_ui_context.state->selected_item = 3;
- mock_ui_context.key = VB_KEY_ENTER;
- TEST_EQ(vb2_ui_menu_select(&mock_ui_context),
- VB2_SUCCESS, "select an item with an action");
- TEST_EQ(mock_action_called, 1, " action called once");
-
- /* Try to select an item with neither targets nor actions (item 4) */
- reset_common_data();
- 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_SUCCESS,
- "select an item with neither targets nor actions");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 4,
- MOCK_IGNORE);
-
- /* Cannot select a disabled item (item 3) */
- reset_common_data();
- mock_ui_context.state->screen = &mock_screen_menu;
- 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_SUCCESS,
- "cannot select a disabled item");
- TEST_EQ(mock_action_called, 0, " no action called");
-
- /* Ignore power button short press when not DETACHABLE */
- if (!DETACHABLE) {
- reset_common_data();
- 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_SUCCESS,
- "ignore power button short press when not DETACHABLE");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU, 1,
- MOCK_IGNORE);
- }
-
- VB2_DEBUG("...done.\n");
-}
-
-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_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_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_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_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 altfw not allowed */
- reset_common_data();
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
- 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_altfw_allowed = 1;
- mock_ui_context.state->selected_item = 2;
- TEST_EQ(vb2_ui_developer_mode_boot_altfw_action(&mock_ui_context),
- VB2_REQUEST_UI_CONTINUE, "allowed");
- 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_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_altfw_action(&mock_ui_context),
- VB2_REQUEST_UI_CONTINUE, "allowed: ctrl+l");
- 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");
-}
-
-static void manual_recovery_action_tests(void)
-{
- VB2_DEBUG("Testing manual recovery action...\n");
-
- /* SUCCESS */
- reset_common_data();
- set_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- 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 */
- reset_common_data();
- set_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(manual_recovery_action(&mock_ui_context),
- VB2_REQUEST_UI_CONTINUE, "NO_DISK_FOUND");
- screen_state_eq(mock_ui_context.state, VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE);
-
- /* NO_DISK_FOUND -> INVALID_KERNEL -> SUCCESS */
- reset_common_data();
- set_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(manual_recovery_action(&mock_ui_context),
- VB2_REQUEST_UI_CONTINUE, "NO_DISK_FOUND");
- set_mock_vbtlk(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
- VB_DISK_FLAG_REMOVABLE);
- 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_REQUEST_UI_EXIT,
- "EXIT");
- screen_state_eq(mock_ui_context.state, VB2_SCREEN_RECOVERY_INVALID,
- MOCK_IGNORE, MOCK_IGNORE);
-
- /* INVALID_KERNEL */
- reset_common_data();
- set_mock_vbtlk(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
- VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(manual_recovery_action(&mock_ui_context),
- VB2_REQUEST_UI_CONTINUE, "INVALID_KERNEL");
- screen_state_eq(mock_ui_context.state, VB2_SCREEN_RECOVERY_INVALID,
- MOCK_IGNORE, MOCK_IGNORE);
-
- /* INVALID_KERNEL -> NO_DISK_FOUND -> SUCCESS */
- reset_common_data();
- set_mock_vbtlk(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
- VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(manual_recovery_action(&mock_ui_context),
- VB2_REQUEST_UI_CONTINUE, "INVALID_KERNEL");
- set_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- 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_REQUEST_UI_EXIT,
- "EXIT");
- screen_state_eq(mock_ui_context.state, VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE);
-
- VB2_DEBUG("...done.\n");
-}
-
-static void ui_loop_tests(void)
-{
- int i;
- const char *action_interfere_test_names[] = {
- "hook all actions: screen action return SUCCESS",
- "hook all actions: target action hooked return SUCCESS",
- "hook all actions: global action return SUCCESS",
- };
-
- VB2_DEBUG("Testing ui_loop...\n");
-
- /* Die if no root screen */
- reset_common_data();
- TEST_ABORT(ui_loop(ctx, MOCK_NO_SCREEN, NULL),
- "die if no root screen");
- DISPLAYED_NO_EXTRA();
-
- /* Shutdown if requested */
- reset_common_data();
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, NULL),
- VB2_REQUEST_SHUTDOWN, "shutdown if requested");
- TEST_EQ(mock_calls_until_shutdown, 0, " used up shutdown request");
- DISPLAYED_EQ("mock_screen_base", MOCK_SCREEN_BASE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Screen action */
- reset_common_data();
- mock_calls_until_shutdown = -1;
- mock_action_countdown_limit = 10;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_ACTION, NULL),
- VB2_SUCCESS, "screen action");
- TEST_EQ(mock_action_called, 10, " action called");
-
- /* Global action */
- reset_common_data();
- mock_calls_until_shutdown = -1;
- mock_action_countdown_limit = 10;
- 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, 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,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /*
- * Hook all actions, and receive SUCCESS from actions one by one
- * Action #0: screen action
- * Action #1: item target action
- * Action #2: global action
- */
- for (i = 0; i <= 2; i++) {
- reset_common_data();
- add_mock_keypress(VB_KEY_ENTER);
- mock_calls_until_shutdown = -1;
- mock_action_flags |= (1 << i);
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_ALL_ACTION, mock_action_flag2),
- VB2_SUCCESS, action_interfere_test_names[i]);
- }
-
- /* KEY_UP, KEY_DOWN, and KEY_ENTER navigation */
- reset_common_data();
- add_mock_keypress(VB_KEY_UP); /* (blocked) */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN); /* (blocked) */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_MENU, NULL),
- VB2_REQUEST_SHUTDOWN, "KEY_UP, KEY_DOWN, and KEY_ENTER");
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 0,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 1,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 2,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 3,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 4,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 3,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE, 2,
- MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_target_2", MOCK_SCREEN_TARGET2, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* For DETACHABLE */
- if (DETACHABLE) {
- reset_common_data();
- add_mock_keypress(VB_BUTTON_VOL_UP_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_DOWN_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_DOWN_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_DOWN_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_DOWN_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_DOWN_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_UP_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_VOL_UP_SHORT_PRESS);
- add_mock_keypress(VB_BUTTON_POWER_SHORT_PRESS);
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_MENU, NULL),
- VB2_REQUEST_SHUTDOWN, "DETACHABLE");
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 0, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 1, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 2, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 3, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 4, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 3, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_menu", MOCK_SCREEN_MENU, MOCK_IGNORE,
- 2, MOCK_IGNORE);
- DISPLAYED_EQ("mock_screen_target_2", MOCK_SCREEN_TARGET2,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
- }
-
- VB2_DEBUG("...done.\n");
-}
-
-static void ui_loop_delay_tests(void)
-{
- VB2_DEBUG("Testing ui_loop delay...\n");
-
- /* Sleep for 20 ms each iteration */
- reset_common_data();
- mock_calls_until_shutdown = 1;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, mock_action_msleep),
- VB2_REQUEST_SHUTDOWN, " sleep for 20 ms in each iteration");
- TEST_EQ(mock_time_ms - mock_time_start_ms, KEY_DELAY_MS,
- " delay 20 ms in total");
-
- /* Complement to 20 ms */
- reset_common_data();
- mock_calls_until_shutdown = 1;
- mock_action_delay_ms = KEY_DELAY_MS / 2;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, mock_action_msleep),
- VB2_REQUEST_SHUTDOWN, " complement to 20 ms");
- TEST_EQ(mock_time_ms - mock_time_start_ms, KEY_DELAY_MS,
- " delay 10 ms in total");
-
- /* No extra sleep if an iteration takes longer than KEY_DELAY_MS */
- reset_common_data();
- mock_calls_until_shutdown = 1;
- mock_action_delay_ms = 1234;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, mock_action_msleep),
- VB2_REQUEST_SHUTDOWN, " no extra sleep time");
- TEST_EQ(mock_time_ms - mock_time_start_ms, mock_action_delay_ms,
- " no extra delay");
-
- /* Integer overflow */
- reset_common_data();
- mock_calls_until_shutdown = 1;
- mock_time_ms = UINT32_MAX;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, mock_action_msleep),
- VB2_REQUEST_SHUTDOWN, " integer overflow #1");
- TEST_EQ(mock_time_ms - UINT32_MAX, KEY_DELAY_MS,
- " delay 20 ms in total");
-
- reset_common_data();
- mock_calls_until_shutdown = 1;
- mock_time_ms = UINT32_MAX;
- mock_action_delay_ms = KEY_DELAY_MS / 2;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, mock_action_msleep),
- VB2_REQUEST_SHUTDOWN, " integer overflow #2");
- TEST_EQ(mock_time_ms - UINT32_MAX, KEY_DELAY_MS,
- " delay 10 ms in total");
-
- reset_common_data();
- mock_calls_until_shutdown = 1;
- mock_time_ms = UINT32_MAX;
- mock_action_delay_ms = 1234;
- TEST_EQ(ui_loop(ctx, MOCK_SCREEN_BASE, mock_action_msleep),
- VB2_REQUEST_SHUTDOWN, " integer overflow #3");
- TEST_EQ(mock_time_ms - UINT32_MAX, mock_action_delay_ms,
- " no extra delay");
-
- VB2_DEBUG("...done.\n");
-}
-
-int main(void)
-{
- /* Input actions */
- menu_prev_tests();
- menu_next_tests();
- menu_select_tests();
-
- /* Screen actions */
- vb2_ui_developer_mode_boot_altfw_action_tests();
-
- /* Global actions */
- manual_recovery_action_tests();
-
- /* Core UI loop */
- ui_loop_tests();
- ui_loop_delay_tests();
-
- return gTestSuccess ? 0 : 255;
-}
diff --git a/tests/vb2_ui_tests.c b/tests/vb2_ui_tests.c
deleted file mode 100644
index 9a84a93..0000000
--- a/tests/vb2_ui_tests.c
+++ /dev/null
@@ -1,1922 +0,0 @@
-/* Copyright 2020 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.
- *
- * Tests for developer and recovery mode UIs.
- */
-
-#include "2api.h"
-#include "2common.h"
-#include "2misc.h"
-#include "2nvstorage.h"
-#include "2struct.h"
-#include "2ui.h"
-#include "2ui_private.h"
-#include "test_common.h"
-#include "vboot_kernel.h"
-
-/* Fixed value for ignoring some checks */
-#define MOCK_IGNORE 0xffffu
-
-/* Fuzzy matches for check_time() */
-#define FUZZ_MS 200
-
-/* Mock data */
-/* TODO(b/156448738): Add tests for timer_disabled and error_code */
-struct display_call {
- const struct vb2_screen_info *screen;
- uint32_t locale_id;
- uint32_t selected_item;
- uint32_t disabled_item_mask;
- uint32_t hidden_item_mask;
- int timer_disabled;
- uint32_t current_page;
- enum vb2_ui_error error_code;
-} __attribute__((packed));
-
-struct beep_call {
- uint32_t msec;
- uint32_t frequency;
- uint32_t time_expected;
-};
-
-static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
- __attribute__((aligned(VB2_WORKBUF_ALIGN)));
-static struct vb2_context *ctx;
-static struct vb2_shared_data *sd;
-static struct vb2_gbb_header gbb;
-
-static struct vb2_ui_context mock_ui_context;
-static struct vb2_screen_state mock_state;
-
-static struct display_call mock_displayed[64];
-static int mock_displayed_count;
-static int mock_displayed_i;
-
-static uint32_t mock_locale_count;
-
-static int mock_calls_until_shutdown;
-
-/* Iteration counter starts from 0
- Mock inputs should response according to this */
-static int mock_iters;
-
-static uint32_t mock_key[64];
-static int mock_key_trusted[64];
-static int mock_key_total;
-
-static uint32_t mock_time_ms;
-static const uint32_t mock_time_start_ms = 31ULL * VB2_MSEC_PER_SEC;
-
-static struct beep_call mock_beep[8];
-static int mock_beep_count;
-static int mock_beep_total;
-
-static enum vb2_dev_default_boot_target mock_default_boot;
-static int mock_dev_boot_allowed;
-static int mock_dev_boot_altfw_allowed;
-static int mock_dev_boot_external_allowed;
-
-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];
-static int mock_vbtlk_total;
-
-static int mock_allow_recovery;
-
-/* mock_pp_* = mock data for physical presence button */
-static int mock_pp_pressed[64];
-static int mock_pp_pressed_total;
-
-static int mock_enable_dev_mode;
-
-#define MOCK_PREPARE_LOG_SIZE 32
-
-static int mock_snapshot_count;
-static char mock_prepare_log[64][MOCK_PREPARE_LOG_SIZE];
-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) ||
- mock_key_total >= ARRAY_SIZE(mock_key_trusted)) {
- TEST_TRUE(0, " mock_key ran out of entries!");
- return;
- }
-
- mock_key[mock_key_total] = press;
- mock_key_trusted[mock_key_total] = trusted;
- mock_key_total++;
-}
-
-static void add_mock_keypress(uint32_t press)
-{
- add_mock_key(press, 0);
-}
-
-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)) {
- TEST_TRUE(0, " mock_vbtlk ran out of entries!");
- return;
- }
-
- mock_vbtlk_retval[mock_vbtlk_total] = retval;
- mock_vbtlk_expected_flag[mock_vbtlk_total] = disk_flags;
- mock_vbtlk_total++;
-}
-
-static void add_mock_pp_pressed(int pressed)
-{
- if (mock_pp_pressed_total >= ARRAY_SIZE(mock_pp_pressed)) {
- TEST_TRUE(0, " mock_pp ran out of entries!");
- return;
- }
-
- mock_pp_pressed[mock_pp_pressed_total++] = pressed;
-}
-
-static void extend_calls_until_shutdown(void)
-{
- if (mock_calls_until_shutdown < mock_key_total)
- mock_calls_until_shutdown = mock_key_total;
- if (mock_calls_until_shutdown < mock_vbtlk_total)
- mock_calls_until_shutdown = mock_vbtlk_total;
- if (mock_calls_until_shutdown < mock_pp_pressed_total)
- mock_calls_until_shutdown = mock_pp_pressed_total;
- mock_calls_until_shutdown++;
-}
-
-static void displayed_eq(const char *text,
- enum vb2_screen screen,
- uint32_t locale_id,
- uint32_t selected_item,
- uint32_t disabled_item_mask,
- uint32_t hidden_item_mask,
- uint32_t current_page,
- int line)
-{
- char text_info[32], text_buf[128];
-
- sprintf(text_info, "(line #%d, displayed #%d)", line, mock_displayed_i);
-
- if (mock_displayed_i >= mock_displayed_count) {
- sprintf(text_buf, " %s missing screen %s",
- text_info, text);
- TEST_TRUE(0, text_buf);
- return;
- }
-
- if (screen != MOCK_IGNORE) {
- sprintf(text_buf, " %s screen of %s", text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].screen->id, screen,
- text_buf);
- }
- if (locale_id != MOCK_IGNORE) {
- sprintf(text_buf, " %s locale_id of %s", text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].locale_id, locale_id,
- text_buf);
- }
- if (selected_item != MOCK_IGNORE) {
- sprintf(text_buf, " %s selected_item of %s",
- text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].selected_item,
- selected_item, text_buf);
- }
- if (disabled_item_mask != MOCK_IGNORE) {
- sprintf(text_buf, " %s disabled_item_mask of %s",
- text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].disabled_item_mask,
- disabled_item_mask, text_buf);
- }
- if (hidden_item_mask != MOCK_IGNORE) {
- sprintf(text_buf, " %s hidden_item_mask of %s",
- text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].hidden_item_mask,
- hidden_item_mask, text_buf);
- }
- if (current_page != MOCK_IGNORE) {
- sprintf(text_buf, " %s current_page of %s",
- text_info, text);
- TEST_EQ(mock_displayed[mock_displayed_i].current_page,
- current_page, text_buf);
- }
- mock_displayed_i++;
-}
-
-static void displayed_no_extra(int line)
-{
- char text_info[32], text_buf[128];
-
- sprintf(text_info, "(line #%d)", line);
-
- if (mock_displayed_i == 0)
- sprintf(text_buf, " %s no screen", text_info);
- else
- sprintf(text_buf, " %s no extra screens", text_info);
- TEST_EQ(mock_displayed_count, mock_displayed_i, text_buf);
-}
-
-#define DISPLAYED_EQ(...) displayed_eq(__VA_ARGS__, __LINE__)
-
-#define DISPLAYED_PASS() \
- displayed_eq("", MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, \
- MOCK_IGNORE, MOCK_IGNORE, __LINE__)
-
-#define DISPLAYED_NO_EXTRA() displayed_no_extra(__LINE__)
-
-static void expect_beep(uint32_t msec,
- uint32_t frequency,
- uint32_t time_expected)
-{
- if (mock_beep_total >= ARRAY_SIZE(mock_beep)) {
- TEST_TRUE(0, " mock_beep ran out of entries!");
- return;
- }
-
- mock_beep[mock_beep_total++] = (struct beep_call){
- .msec = msec,
- .frequency = frequency,
- .time_expected = time_expected,
- };
-}
-
-/* Check if the result time falls in range [expected, expected + FUZZ_MS) */
-static void check_time(uint32_t result, uint32_t expected, const char *desc)
-{
- TEST_TRUE(result >= expected, desc);
- TEST_TRUE(result - expected < FUZZ_MS, " within FUZZ_MS");
-}
-
-/* Type of test to reset for */
-enum reset_type {
- FOR_DEVELOPER,
- FOR_BROKEN_RECOVERY,
- FOR_MANUAL_RECOVERY,
- FOR_DIAGNOSTICS,
-};
-
-/* Reset mock data (for use before each test) */
-static void reset_common_data(enum reset_type t)
-{
- TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
- "vb2api_init failed");
-
- memset(&gbb, 0, sizeof(gbb));
-
- vb2_nv_init(ctx);
-
- sd = vb2_get_sd(ctx);
- sd->status |= VB2_SD_STATUS_SECDATA_KERNEL_INIT;
-
- if (t == FOR_DEVELOPER) {
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
- sd->flags |= VB2_SD_FLAG_DEV_MODE_ENABLED;
- }
-
- /* Mock ui_context based on real screens */
- memset(&mock_ui_context, 0, sizeof(mock_ui_context));
- mock_ui_context.ctx = ctx;
- mock_ui_context.state = &mock_state;
-
- /* For vb2ex_display_ui */
- memset(mock_displayed, 0, sizeof(mock_displayed));
- mock_displayed_count = 0;
- mock_displayed_i = 0;
-
- /* For vb2ex_get_locale_count */
- mock_locale_count = 1;
-
- /* For check_shutdown_request */
- if (t == FOR_DEVELOPER)
- mock_calls_until_shutdown = 2000; /* Larger than 30s */
- else
- mock_calls_until_shutdown = 10;
-
- /* For iteration counter */
- mock_iters = -1; /* Accumulates at the beginning of iterations */
-
- /* For VbExKeyboardRead */
- memset(mock_key, 0, sizeof(mock_key));
- memset(mock_key_trusted, 0, sizeof(mock_key_trusted));
- mock_key_total = 0;
-
- /* For vb2ex_mtime and vb2ex_msleep */
- mock_time_ms = mock_time_start_ms;
-
- /* For vb2ex_beep */
- memset(mock_beep, 0, sizeof(mock_beep));
- mock_beep_count = 0;
- mock_beep_total = 0;
-
- /* For dev_boot* in 2misc.h */
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_INTERNAL;
- mock_dev_boot_allowed = 1;
- mock_dev_boot_altfw_allowed = 0;
- mock_dev_boot_external_allowed = 1;
-
- /* 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));
- memset(mock_vbtlk_expected_flag, 0, sizeof(mock_vbtlk_expected_flag));
- mock_vbtlk_total = 0;
-
- /* For vb2_allow_recovery */
- mock_allow_recovery = t == FOR_MANUAL_RECOVERY;
-
- /* For vb2ex_physical_presence_pressed */
- memset(mock_pp_pressed, 0, sizeof(mock_pp_pressed));
- mock_pp_pressed_total = 0;
-
- /* For vb2_enable_developer_mode */
- mock_enable_dev_mode = 0;
-
- /* For vb2ex_prepare_log_screen */
- mock_snapshot_count = 0;
- mock_prepare_log_count = 0;
- mock_log_page_count = 1;
-
- /* Avoid Iteration #0 */
- add_mock_keypress(0);
- if (t == FOR_MANUAL_RECOVERY)
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND,
- VB_DISK_FLAG_REMOVABLE);
- else
- add_mock_vbtlk(VB2_ERROR_MOCK, 0);
- add_mock_pp_pressed(0);
-
- mock_diag_storage_test_rv = VB2_SUCCESS;
-}
-
-/* Mock functions */
-struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
-{
- return &gbb;
-}
-
-vb2_error_t vb2ex_display_ui(enum vb2_screen screen,
- uint32_t locale_id,
- uint32_t selected_item,
- uint32_t disabled_item_mask,
- uint32_t hidden_item_mask,
- int timer_disabled,
- uint32_t current_page,
- enum vb2_ui_error error_code)
-{
- struct display_call displayed = (struct display_call){
- .screen = vb2_get_screen_info(screen),
- .locale_id = locale_id,
- .selected_item = selected_item,
- .disabled_item_mask = disabled_item_mask,
- .hidden_item_mask = hidden_item_mask,
- .timer_disabled = timer_disabled,
- .current_page = current_page,
- .error_code = error_code,
- };
-
- /* Ignore repeated calls with same arguments */
- if (mock_displayed_count > 0 &&
- !memcmp(&mock_displayed[mock_displayed_count - 1], &displayed,
- sizeof(struct display_call)))
- return VB2_SUCCESS;
-
- VB2_DEBUG("displayed %d: screen=%#x, locale_id=%u, selected_item=%u, "
- "disabled_item_mask=%#x, hidden_item_mask=%#x, "
- "timer_disabled=%d, current_page=%u, error=%#x\n",
- mock_displayed_count, screen, locale_id, selected_item,
- disabled_item_mask, hidden_item_mask,
- timer_disabled, current_page, error_code);
-
- if (mock_displayed_count >= ARRAY_SIZE(mock_displayed)) {
- TEST_TRUE(0, " mock vb2ex_display_ui ran out of entries!");
- return VB2_ERROR_MOCK;
- }
-
- mock_displayed[mock_displayed_count++] = displayed;
-
- return VB2_SUCCESS;
-}
-
-uint32_t vb2ex_get_locale_count(void)
-{
- return mock_locale_count;
-}
-
-uint32_t VbExIsShutdownRequested(void)
-{
- if (mock_calls_until_shutdown < 0) /* Never request shutdown */
- return 0;
- if (mock_calls_until_shutdown == 0)
- return 1;
- mock_calls_until_shutdown--;
-
- return 0;
-}
-
-uint32_t VbExKeyboardRead(void)
-{
- return VbExKeyboardReadWithFlags(NULL);
-}
-
-uint32_t VbExKeyboardReadWithFlags(uint32_t *key_flags)
-{
- mock_iters++;
- if (mock_iters < mock_key_total) {
- if (key_flags != NULL) {
- if (mock_key_trusted[mock_iters])
- *key_flags = VB_KEY_FLAG_TRUSTED_KEYBOARD;
- else
- *key_flags = 0;
- }
- return mock_key[mock_iters];
- }
-
- return 0;
-}
-
-uint32_t vb2ex_mtime(void)
-{
- return mock_time_ms;
-}
-
-void vb2ex_msleep(uint32_t msec)
-{
- mock_time_ms += msec;
-}
-
-void vb2ex_beep(uint32_t msec, uint32_t frequency)
-{
- struct beep_call *beep;
- uint32_t cur_time = mock_time_ms - mock_time_start_ms;
-
- VB2_DEBUG("beep %d: msec = %d, frequency = %d at %d msec\n",
- mock_beep_count, msec, frequency, cur_time);
-
- if (mock_beep_total > 0) {
- TEST_TRUE(mock_beep_count < mock_beep_total,
- " too many beep calls!");
-
- beep = &mock_beep[mock_beep_count];
-
- VB2_DEBUG("beep expected: msec = %d, frequency = %d, "
- "at %d msec\n",
- beep->msec, beep->frequency, beep->time_expected);
-
- TEST_EQ(msec, beep->msec, " beep duration");
- TEST_EQ(frequency, beep->frequency, " beep frequency");
- check_time(cur_time, beep->time_expected,
- " beep started after expected time");
- }
-
- mock_time_ms += msec;
- mock_beep_count++;
-}
-
-enum vb2_dev_default_boot_target vb2api_get_dev_default_boot_target(
- struct vb2_context *c)
-{
- return mock_default_boot;
-}
-
-int vb2_dev_boot_allowed(struct vb2_context *c)
-{
- return mock_dev_boot_allowed;
-}
-
-int vb2_dev_boot_altfw_allowed(struct vb2_context *c)
-{
- return mock_dev_boot_altfw_allowed;
-}
-
-int vb2_dev_boot_external_allowed(struct vb2_context *c)
-{
- return mock_dev_boot_external_allowed;
-}
-
-vb2_error_t vb2ex_run_altfw(uint32_t altfw_id)
-{
- mock_run_altfw_called++;
- mock_altfw_last = altfw_id;
-
- return VB2_SUCCESS;
-}
-
-uint32_t vb2ex_get_altfw_count(void)
-{
- return mock_altfw_count;
-}
-
-vb2_error_t VbTryLoadKernel(struct vb2_context *c, uint32_t disk_flags)
-{
- int i = mock_iters;
-
- /* Return last entry if called too many times */
- if (i >= mock_vbtlk_total)
- i = mock_vbtlk_total - 1;
-
- TEST_EQ(mock_vbtlk_expected_flag[i], disk_flags,
- " unexpected disk_flags");
-
- return mock_vbtlk_retval[i];
-}
-
-int vb2_allow_recovery(struct vb2_context *c)
-{
- return mock_allow_recovery;
-}
-
-int vb2ex_physical_presence_pressed(void)
-{
- if (mock_iters >= mock_pp_pressed_total)
- return 0;
-
- return mock_pp_pressed[mock_iters];
-}
-
-void vb2_enable_developer_mode(struct vb2_context *c)
-{
- mock_enable_dev_mode = 1;
-}
-
-const char *vb2ex_get_debug_info(struct vb2_context *c)
-{
- return "mocked debug info";
-}
-
-const char *vb2ex_get_firmware_log(int reset)
-{
- static char mock_firmware_log_buf[MOCK_PREPARE_LOG_SIZE];
- if (reset)
- mock_snapshot_count++;
- snprintf(mock_firmware_log_buf, MOCK_PREPARE_LOG_SIZE,
- "%d", mock_snapshot_count);
- return mock_firmware_log_buf;
-}
-
-uint32_t vb2ex_prepare_log_screen(enum vb2_screen screen, uint32_t locale_id,
- const char *str)
-{
- if (mock_prepare_log_count < ARRAY_SIZE(mock_prepare_log))
- strncpy(mock_prepare_log[mock_prepare_log_count],
- str, MOCK_PREPARE_LOG_SIZE);
- mock_prepare_log_count++;
-
- 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)
-{
- VB2_DEBUG("Testing developer mode...\n");
-
- /* Power button short pressed = shutdown request */
- if (!DETACHABLE) {
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_BUTTON_POWER_SHORT_PRESS);
- mock_calls_until_shutdown = -1;
- TEST_EQ(vb2_developer_menu(ctx),
- VB2_REQUEST_SHUTDOWN,
- "power button short pressed = shutdown");
- }
-
- /* Proceed to internal disk after timeout */
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- expect_beep(250, 400, DEV_DELAY_BEEP1_MS);
- expect_beep(250, 400, DEV_DELAY_BEEP2_MS);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "proceed to internal disk after timeout");
- check_time(mock_time_ms - mock_time_start_ms, DEV_DELAY_NORMAL_MS,
- " finished delay");
- 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;
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "use short delay");
- check_time(mock_time_ms - mock_time_start_ms, DEV_DELAY_SHORT_MS,
- " finished delay");
- TEST_EQ(mock_beep_count, 0, " never beeped");
-
- /* Stop timer on any user input: normal delay */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress('A');
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "stop timer on any user input: normal delay");
- TEST_TRUE(mock_time_ms - mock_time_start_ms > DEV_DELAY_NORMAL_MS,
- " delay aborted");
- TEST_EQ(mock_calls_until_shutdown, 0, " loop forever");
- TEST_EQ(mock_beep_count, 0, " never beeped");
-
- /* Stop timer on any user input: short delay */
- reset_common_data(FOR_DEVELOPER);
- gbb.flags |= VB2_GBB_FLAG_DEV_SCREEN_SHORT_DELAY;
- add_mock_keypress('A');
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "stop timer on any user input: short delay");
- TEST_TRUE(mock_time_ms - mock_time_start_ms > DEV_DELAY_SHORT_MS,
- " delay aborted");
- TEST_EQ(mock_calls_until_shutdown, 0, " loop forever");
- TEST_EQ(mock_beep_count, 0, " never beeped");
-
- /* If fail to load internal disk, don't boot */
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_ERROR_LK_NO_DISK_FOUND,
- "if fail to load internal disk, don't boot");
-
- /* Select boot internal in dev menu */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "select boot internal in dev menu");
-
- /* Ctrl+U = boot external */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_CTRL('U'));
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "ctrl+u = boot external");
-
- /* Ctrl+D = boot internal */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_CTRL('D'));
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "ctrl+d = boot internal");
-
- /* VB_BUTTON_VOL_DOWN_LONG_PRESS = boot internal */
- if (DETACHABLE) {
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_BUTTON_VOL_DOWN_LONG_PRESS);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "VB_BUTTON_VOL_DOWN_LONG_PRESS = boot internal");
- }
-
- /* Proceed to external disk after timeout */
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
- expect_beep(250, 400, DEV_DELAY_BEEP1_MS);
- expect_beep(250, 400, DEV_DELAY_BEEP2_MS);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "proceed to external disk after timeout");
- check_time(mock_time_ms - mock_time_start_ms, DEV_DELAY_NORMAL_MS,
- " finished delay");
- TEST_EQ(mock_beep_count, 2, " beeped twice");
- TEST_TRUE(mock_iters >= mock_vbtlk_total, " used up mock_vbtlk");
-
- /* Default boot from external not allowed, don't boot */
- reset_common_data(FOR_DEVELOPER);
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
- mock_dev_boot_external_allowed = 0;
- 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);
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "if no external disk, don't boot");
-
- /* Select boot external in dev menu */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "select boot external in dev menu");
-
- /* Ctrl+L = boot altfw (allowed) */
- reset_common_data(FOR_DEVELOPER);
- 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 altfw");
- TEST_EQ(mock_run_altfw_called, 1, " vb2ex_run_altfw called");
-
- /* 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 altfw");
- TEST_EQ(mock_run_altfw_called, 0,
- " vb2ex_run_altfw not called");
-
- /* VB_BUTTON_VOL_UP_LONG_PRESS = boot external */
- if (DETACHABLE) {
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_BUTTON_VOL_UP_LONG_PRESS);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "VB_BUTTON_VOL_UP_LONG_PRESS = boot external");
- }
-
- /* Select to_norm in dev menu and confirm */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_REBOOT,
- "select to_norm in dev menu and confirm");
- 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);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "select to_norm in dev menu and cancel");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), 0,
- " disable dev request");
-
- /* Ctrl+S = to_norm */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_CTRL('S'));
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_REBOOT,
- "ctrl+s = to_norm");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), 1,
- " disable dev request");
-
- /* Dev mode forced by GBB flag */
- reset_common_data(FOR_DEVELOPER);
- gbb.flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON;
- add_mock_keypress(VB_KEY_CTRL('S'));
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "dev mode forced by GBB flag");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST), 0,
- " disable dev request");
-
- /* Power off */
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- /* Navigate to the bottom most menu item */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "select power off");
-
- VB2_DEBUG("...done.\n");
-}
-
-static void broken_recovery_tests(void)
-{
- VB2_DEBUG("Testing broken recovery mode...\n");
-
- /* Power button short pressed = shutdown request */
- if (!DETACHABLE) {
- reset_common_data(FOR_BROKEN_RECOVERY);
- add_mock_keypress(VB_BUTTON_POWER_SHORT_PRESS);
- mock_calls_until_shutdown = -1;
- TEST_EQ(vb2_broken_recovery_menu(ctx),
- VB2_REQUEST_SHUTDOWN,
- "power button short pressed = shutdown");
- }
-
- /* Shortcuts that are always ignored in BROKEN */
- reset_common_data(FOR_BROKEN_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_key(VB_KEY_CTRL('U'), 1);
- add_mock_key(VB_KEY_CTRL('L'), 1);
- add_mock_key(VB_BUTTON_VOL_UP_DOWN_COMBO_PRESS, 1);
- add_mock_key(VB_BUTTON_VOL_UP_LONG_PRESS, 1);
- add_mock_key(VB_BUTTON_VOL_DOWN_LONG_PRESS, 1);
- TEST_EQ(vb2_broken_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "Shortcuts ignored in BROKEN");
- TEST_EQ(mock_calls_until_shutdown, 0, " loop forever");
- TEST_EQ(mock_displayed_count, 1, " root screen only");
-
- VB2_DEBUG("...done.\n");
-}
-
-static void manual_recovery_tests(void)
-{
- VB2_DEBUG("Testing manual recovery mode...\n");
-
- /* Timeout, shutdown */
- reset_common_data(FOR_MANUAL_RECOVERY);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "timeout, shutdown");
- TEST_EQ(mock_displayed_count, 1, " root screen only");
-
- /* Power button short pressed = shutdown request */
- if (!DETACHABLE) {
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress(VB_BUTTON_POWER_SHORT_PRESS);
- TEST_EQ(vb2_manual_recovery_menu(ctx),
- VB2_REQUEST_SHUTDOWN,
- "power button short pressed = shutdown");
- }
-
- /* Boots if we have a valid image on first try */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_ERROR_MOCK, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_SUCCESS,
- "boots if valid on first try");
-
- /* Boots eventually if we get a valid image later */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_ERROR_MOCK, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_SUCCESS,
- "boots after valid image appears");
-
- /* Invalid image, then remove, then valid image */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_vbtlk(VB2_ERROR_MOCK, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- add_mock_vbtlk(VB2_ERROR_MOCK, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_SUCCESS,
- "boots after valid image appears");
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_EQ("recovery invalid", VB2_SCREEN_RECOVERY_INVALID,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Ctrl+D = to_dev; space = cancel */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_keypress(' ');
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "ctrl+d = to_dev; space = cancel");
- TEST_EQ(mock_enable_dev_mode, 0, " dev mode not enabled");
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_EQ("to_dev", VB2_SCREEN_RECOVERY_TO_DEV,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Cancel to_dev transition */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- if (PHYSICAL_PRESENCE_KEYBOARD)
- add_mock_key(VB_KEY_DOWN, 1);
- add_mock_key(VB_KEY_ENTER, 1);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "cancel to_dev transition");
- TEST_EQ(mock_enable_dev_mode, 0, " dev mode not enabled");
-
- /* Confirm to_dev transition */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- if (PHYSICAL_PRESENCE_KEYBOARD) {
- add_mock_key(VB_KEY_ENTER, 1);
- } else {
- add_mock_pp_pressed(0);
- add_mock_pp_pressed(1);
- add_mock_pp_pressed(1);
- add_mock_pp_pressed(0);
- }
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_REBOOT_EC_TO_RO,
- "confirm to_dev transition");
- if (!PHYSICAL_PRESENCE_KEYBOARD)
- TEST_TRUE(mock_iters >= mock_pp_pressed_total - 1,
- " used up mock_pp_pressed");
- TEST_EQ(mock_enable_dev_mode, 1, " dev mode enabled");
-
- /* Cannot confirm physical presence by untrusted keyboard */
- if (PHYSICAL_PRESENCE_KEYBOARD) {
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_key(VB_KEY_ENTER, 0);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "cannot confirm physical presence"
- " by untrusted keyboard");
- TEST_EQ(mock_enable_dev_mode, 0, " dev mode not enabled");
- }
-
- /* Cannot enable dev mode if already enabled */
- reset_common_data(FOR_MANUAL_RECOVERY);
- sd->flags |= VB2_SD_FLAG_DEV_MODE_ENABLED;
- add_mock_key(VB_KEY_CTRL('D'), 1);
- if (PHYSICAL_PRESENCE_KEYBOARD) {
- add_mock_key(VB_KEY_ENTER, 1);
- } else {
- add_mock_pp_pressed(0);
- add_mock_pp_pressed(1);
- add_mock_pp_pressed(0);
- }
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "cannot enable dev mode if already enabled");
- TEST_EQ(mock_enable_dev_mode, 0, " dev mode already on");
-
- /* Physical presence button tests */
- if (!PHYSICAL_PRESENCE_KEYBOARD) {
- /* Physical presence button stuck? */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_pp_pressed(1); /* Hold since boot */
- add_mock_pp_pressed(0);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "physical presence button stuck?");
- TEST_EQ(mock_enable_dev_mode, 0, " dev mode not enabled");
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Button stuck, enter to_dev again */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_pp_pressed(1); /* Hold since boot */
- add_mock_pp_pressed(0);
- add_mock_pp_pressed(1); /* Press again */
- add_mock_pp_pressed(0);
- TEST_EQ(vb2_manual_recovery_menu(ctx),
- VB2_REQUEST_REBOOT_EC_TO_RO,
- "button stuck, enter to_dev again");
- TEST_TRUE(mock_iters >= mock_pp_pressed_total - 1,
- " used up mock_pp_pressed");
- TEST_EQ(mock_enable_dev_mode, 1, " dev mode enabled");
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("to_dev", VB2_SCREEN_RECOVERY_TO_DEV,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Cancel with holding pp button, enter again */
- reset_common_data(FOR_MANUAL_RECOVERY);
- /* Enter to_dev */
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_pp_pressed(0);
- /* Press pp button */
- add_mock_keypress(0);
- add_mock_pp_pressed(1);
- /* Space = back */
- add_mock_keypress(' ');
- add_mock_pp_pressed(1);
- /* Wait */
- add_mock_keypress(0);
- add_mock_pp_pressed(0);
- /* Enter to_dev again */
- add_mock_key(VB_KEY_CTRL('D'), 1);
- add_mock_pp_pressed(0);
- /* Press pp button again */
- add_mock_pp_pressed(1);
- /* Release */
- add_mock_pp_pressed(0);
- TEST_EQ(vb2_manual_recovery_menu(ctx),
- VB2_REQUEST_REBOOT_EC_TO_RO,
- "cancel with holding pp button, enter again");
- TEST_TRUE(mock_iters >= mock_pp_pressed_total - 1,
- " used up mock_pp_pressed");
- TEST_EQ(mock_enable_dev_mode, 1, " dev mode enabled");
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("to_dev", VB2_SCREEN_RECOVERY_TO_DEV,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("to_dev", VB2_SCREEN_RECOVERY_TO_DEV,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
- }
-
- /* Enter diagnostics */
- if (DIAGNOSTIC_UI) {
- /* Launch diagnostics is inside manual recovery */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_manual_recovery_menu(ctx),
- VB2_REQUEST_REBOOT,
- "Reboot immediately after request diagnostics");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 1,
- "VB2_NV_DIAG_REQUEST is set");
- }
-
- VB2_DEBUG("...done.\n");
-}
-
-static void language_selection_tests(void)
-{
- VB2_DEBUG("Testing language selection...\n");
-
- /* Enter language menu and change language */
- reset_common_data(FOR_MANUAL_RECOVERY);
- mock_locale_count = 100;
- vb2_nv_set(ctx, VB2_NV_LOCALIZATION_INDEX, 23);
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER); /* select language */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER); /* select locale 24 */
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "change language");
- DISPLAYED_EQ("RECOVERY_SELECT default", VB2_SCREEN_RECOVERY_SELECT,
- 23, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("RECOVERY_SELECT lang", VB2_SCREEN_RECOVERY_SELECT,
- 23, 0, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("LANGUAGE_SELECT 23", VB2_SCREEN_LANGUAGE_SELECT,
- 23, 23, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("LANGUAGE_SELECT 24", VB2_SCREEN_LANGUAGE_SELECT,
- 23, 24, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("RECOVERY_SELECT new locale", VB2_SCREEN_RECOVERY_SELECT,
- 24, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_LOCALIZATION_INDEX), 24,
- " locale 24 saved to nvdata");
-
- /* Locale count = 0 */
- reset_common_data(FOR_MANUAL_RECOVERY);
- mock_locale_count = 0;
- vb2_nv_set(ctx, VB2_NV_LOCALIZATION_INDEX, 23);
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER); /* select language */
- add_mock_keypress(VB_KEY_ENTER); /* select locale 0 */
- add_mock_vbtlk(VB2_ERROR_LK_NO_DISK_FOUND, VB_DISK_FLAG_REMOVABLE);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "enter language menu");
- DISPLAYED_EQ("RECOVERY_SELECT default", VB2_SCREEN_RECOVERY_SELECT,
- 23, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("RECOVERY_SELECT lang", VB2_SCREEN_RECOVERY_SELECT,
- 23, 0, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("LANGUAGE_SELECT index 0", VB2_SCREEN_LANGUAGE_SELECT,
- 23, 0, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("RECOVERY_SELECT locale 0", VB2_SCREEN_RECOVERY_SELECT,
- 0, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- VB2_DEBUG("...done.\n");
-}
-
-static void debug_info_tests(void)
-{
- VB2_DEBUG("Testing debug info screen...\n");
-
- /* Tab = debug info for all menus */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress('\t');
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "tab = debug info in dev mode");
- DISPLAYED_PASS();
- DISPLAYED_EQ("debug info", VB2_SCREEN_DEBUG_INFO, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- reset_common_data(FOR_BROKEN_RECOVERY);
- add_mock_keypress('\t');
- TEST_EQ(vb2_broken_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "tab = debug info in broken recovery mode");
- DISPLAYED_PASS();
- DISPLAYED_EQ("debug info", VB2_SCREEN_DEBUG_INFO, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress('\t');
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "tab = debug info in manual recovery mode");
- DISPLAYED_PASS();
- DISPLAYED_EQ("debug info", VB2_SCREEN_DEBUG_INFO, MOCK_IGNORE,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Failed to enter debug info */
- reset_common_data(FOR_MANUAL_RECOVERY);
- mock_log_page_count = 0;
- add_mock_keypress('\t');
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "failed to enter debug info");
- DISPLAYED_PASS();
- DISPLAYED_PASS(); /* error code */
- DISPLAYED_NO_EXTRA();
-
- /* Get a one-page debug info */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress('\t');
- add_mock_keypress(VB_KEY_ENTER); /* back */
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "get a one-page debug info");
- DISPLAYED_PASS();
- DISPLAYED_EQ("debug info", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 3, 0x6, 0x0, 0);
- DISPLAYED_EQ("back to root screen", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Get a three-page debug info and navigate */
- reset_common_data(FOR_MANUAL_RECOVERY);
- mock_log_page_count = 3;
- add_mock_keypress('\t');
- add_mock_keypress(VB_KEY_ENTER); /* page 0, select on page down */
- add_mock_keypress(VB_KEY_ENTER); /* page 1, select on page down */
- add_mock_keypress(VB_KEY_UP); /* page 2, select on page down */
- add_mock_keypress(VB_KEY_ENTER); /* page 2, select on page up */
- add_mock_keypress(VB_KEY_ENTER); /* page 1, select on page up */
- add_mock_keypress(VB_KEY_DOWN); /* page 0, select on page up */
- add_mock_keypress(VB_KEY_ENTER); /* page 0, select on page down */
- add_mock_keypress(VB_KEY_DOWN); /* page 1, select on page down */
- add_mock_keypress(VB_KEY_ENTER); /* page 1, select on back */
- extend_calls_until_shutdown();
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "get a three-page debug info and navigate");
- DISPLAYED_PASS();
- DISPLAYED_EQ("debug info page #0", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 2, 0x2, 0x0, 0);
- DISPLAYED_EQ("debug info page #1", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 2, 0x0, 0x0, 1);
- DISPLAYED_EQ("debug info page #2", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 2, 0x4, 0x0, 2);
- DISPLAYED_EQ("debug info page #2", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 1, 0x4, 0x0, 2);
- DISPLAYED_EQ("debug info page #1", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 1, 0x0, 0x0, 1);
- DISPLAYED_EQ("debug info page #0", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 1, 0x2, 0x0, 0);
- DISPLAYED_EQ("debug info page #0", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 2, 0x2, 0x0, 0);
- DISPLAYED_EQ("debug info page #1", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 2, 0x0, 0x0, 1);
- DISPLAYED_EQ("debug info page #1", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, 3, 0x0, 0x0, 1);
- DISPLAYED_EQ("back to root screen", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- VB2_DEBUG("...done.\n");
-}
-
-static void firmware_log_tests(void)
-{
- VB2_DEBUG("Testing firmware log screens...\n");
-
- /* Get firmware log */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- if (DIAGNOSTIC_UI)
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "get firmware log");
- TEST_EQ(mock_prepare_log_count, 1,
- " prepared firmware log once");
- TEST_EQ(strcmp(mock_prepare_log[0], "1"), 0,
- " got correct firmware log");
-
- /* Enter firmware log screen again will reacquire a newer one */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- if (DIAGNOSTIC_UI)
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "enter the screen again and reacquire a new log");
- TEST_EQ(mock_prepare_log_count, 2,
- " prepared firmware log twice");
- TEST_EQ(strcmp(mock_prepare_log[0], "1"), 0,
- " got correct firmware log");
- TEST_EQ(strcmp(mock_prepare_log[1], "2"), 0,
- " got a new firmware log");
-
- /* Back to firmware log screen again will not reacquire a newer one */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- if (DIAGNOSTIC_UI)
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress('\t'); /* enter debug info screen */
- add_mock_keypress(VB_KEY_ESC);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "back to the screen and do not reacquire a new log");
- TEST_EQ(mock_prepare_log_count, 3,
- " prepared firmware log three times");
- TEST_EQ(strcmp(mock_prepare_log[0], "1"), 0,
- " got correct firmware log");
- /* Skip entry #1 which is for preparing debug info */
- TEST_EQ(strcmp(mock_prepare_log[2], "1"), 0,
- " got the same firmware log");
-
- VB2_DEBUG("...done.\n");
-}
-
-static void developer_screen_tests(void)
-{
- VB2_DEBUG("Testing developer mode screens...\n");
-
- /* Dev mode: default selected item */
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "dev mode screen: set default selection to boot internal");
- DISPLAYED_EQ("dev mode screen", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "dev mode screen: set default selection to boot external");
- DISPLAYED_EQ("dev mode screen", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-
- /* Dev mode: disabled and hidden item mask */
- reset_common_data(FOR_DEVELOPER);
- 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");
- DISPLAYED_EQ("dev mode screen", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE);
-
- reset_common_data(FOR_DEVELOPER);
- 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,
- "dev mode screen: hide to_norm item");
- DISPLAYED_EQ("dev mode screen", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x2, MOCK_IGNORE);
-
- reset_common_data(FOR_DEVELOPER);
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- mock_dev_boot_external_allowed = 0;
- 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,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x8, MOCK_IGNORE);
-
- /* Dev mode screen */
- reset_common_data(FOR_DEVELOPER); /* Select #2 by default */
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_FIXED);
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- /* #1: Return to secure mode */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #2: Boot internal */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "dev mode screen");
- /* #0: Language menu */
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_EQ("dev mode", VB2_SCREEN_DEVELOPER_MODE,
- 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: Return to secure mode */
- DISPLAYED_PASS();
- DISPLAYED_EQ("dev mode", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#1: return to secure mode", VB2_SCREEN_DEVELOPER_TO_NORM,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #2: Boot internal */
- DISPLAYED_PASS();
- DISPLAYED_EQ("dev mode", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- VB2_DEBUG("#2: boot internal (no extra screen)\n");
- DISPLAYED_NO_EXTRA();
-
- reset_common_data(FOR_DEVELOPER); /* Select #3 by default */
- add_mock_vbtlk(VB2_SUCCESS, VB_DISK_FLAG_REMOVABLE);
- mock_default_boot = VB2_DEV_DEFAULT_BOOT_TARGET_EXTERNAL;
- /* #3: Boot external */
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_SUCCESS,
- "dev mode screen");
- /* #3: Boot external */
- DISPLAYED_EQ("dev mode", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- VB2_DEBUG("#3: boot external (no extra screen)\n");
- DISPLAYED_NO_EXTRA();
-
- reset_common_data(FOR_DEVELOPER); /* Select #2 by default */
- mock_dev_boot_altfw_allowed = 1;
- /* #4: Alternate boot */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "dev mode screen");
- 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);
- /* #5: Advanced options */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* End of menu */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN); /* Blocked */
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "dev mode screen");
- /* #5: Advanced options */
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_EQ("dev mode", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 5, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#4: advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* End of menu */
- DISPLAYED_PASS();
- DISPLAYED_EQ("end of menu", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, 6, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Advanced options screen: disabled and hidden item mask */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "advanced options screen: hide to_dev");
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x2, MOCK_IGNORE);
-
- /* Advanced options screen */
- reset_common_data(FOR_DEVELOPER);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- /* #1: (Hidden) */
- /* #2: Debug info */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #3: Firmware log */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #4: Back */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* End of menu */
- add_mock_keypress(VB_KEY_ENTER);
- extend_calls_until_shutdown();
- TEST_EQ(vb2_developer_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "advanced options screen");
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- /* #0: Language menu */
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- 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: (Hidden) */
- /* #2: Debug info */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#2: debug info", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #3: Firmware log */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#3: firmware log", VB2_SCREEN_FIRMWARE_LOG,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #4: Back */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 4, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#4: back", VB2_SCREEN_DEVELOPER_MODE,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* End of menu */
- DISPLAYED_EQ("end of menu", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- VB2_DEBUG("...done.\n");
-}
-
-static void broken_recovery_screen_tests(void)
-{
- /* Broken screen: disabled and hidden item mask */
- reset_common_data(FOR_BROKEN_RECOVERY);
- TEST_EQ(vb2_broken_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "broken screen: no disabled and hidden item mask");
- DISPLAYED_EQ("broken screen", VB2_SCREEN_RECOVERY_BROKEN,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE);
-
- /* Broken screen */
- reset_common_data(FOR_BROKEN_RECOVERY);
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- /* #1: Advanced options */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* End of menu */
- add_mock_keypress(VB_KEY_ESC);
- extend_calls_until_shutdown();
- TEST_EQ(vb2_broken_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "broken screen");
- /* #0: Language menu */
- DISPLAYED_PASS();
- DISPLAYED_EQ("broken screen", VB2_SCREEN_RECOVERY_BROKEN,
- 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: Advanced options */
- DISPLAYED_PASS();
- DISPLAYED_EQ("broken screen", VB2_SCREEN_RECOVERY_BROKEN,
- MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#1: advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* End of menu */
- DISPLAYED_EQ("end of menu", VB2_SCREEN_RECOVERY_BROKEN,
- MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Advanced options screen: disabled and hidden item mask */
- reset_common_data(FOR_BROKEN_RECOVERY);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_broken_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "advanced options screen: hide to_dev item");
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x2, MOCK_IGNORE);
-
- /* Advanced options screen */
- reset_common_data(FOR_BROKEN_RECOVERY);
- add_mock_keypress(VB_KEY_ENTER);
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- /* #1: (Hidden) */
- /* #2: Debug info */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #3: Firmware log */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #4: Back */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* End of menu */
- add_mock_keypress(VB_KEY_ENTER);
- extend_calls_until_shutdown();
- TEST_EQ(vb2_broken_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "advanced options screen");
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- /* #0: Language menu */
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- 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: (Hidden) */
- /* #2: Debug info */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#2: debug info", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #3: Firmware log */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#3: firmware log", VB2_SCREEN_FIRMWARE_LOG,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #4: Back */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 4, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#4: back", VB2_SCREEN_RECOVERY_BROKEN,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* End of menu */
- DISPLAYED_EQ("end of menu", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- VB2_DEBUG("...done.\n");
-}
-
-static void manual_recovery_screen_tests(void)
-{
- /* Recovery select screen: disabled and hidden item mask */
- reset_common_data(FOR_MANUAL_RECOVERY);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- DIAGNOSTIC_UI ?
- "recovery select screen: no disabled or hidden item" :
- "recovery select screen: hide `launch diag`");
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, DIAGNOSTIC_UI ? 0x0 : 0x8,
- MOCK_IGNORE);
-
- /* Recovery select screen */
- reset_common_data(FOR_MANUAL_RECOVERY);
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- /* #1: Phone recovery */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #2: External disk recovery */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ESC);
- /* #3: Launch diagnostics */
- if (DIAGNOSTIC_UI)
- add_mock_keypress(VB_KEY_DOWN);
- /* #4: Advanced options */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* End of menu */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN); /* Blocked */
- extend_calls_until_shutdown();
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "recovery select screen");
- /* #0: Language menu */
- DISPLAYED_PASS();
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- 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: Phone recovery */
- DISPLAYED_PASS();
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#1: phone recovery", VB2_SCREEN_RECOVERY_PHONE_STEP1,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #2: External disk recovery */
- DISPLAYED_PASS();
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#2: disk recovery", VB2_SCREEN_RECOVERY_DISK_STEP1,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- /* #3: Launch diagnostics */
- if (DIAGNOSTIC_UI)
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- /* #4: Advanced options */
- DISPLAYED_EQ("recovery select", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, 4, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
-
- DISPLAYED_EQ("#3: advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* End of menu */
- DISPLAYED_PASS();
- DISPLAYED_EQ("end of menu", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, 5, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- /* Advanced options screen: disabled and hidden item mask */
- reset_common_data(FOR_MANUAL_RECOVERY);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- if (DIAGNOSTIC_UI)
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "advanced options screen: no disabled or hidden item");
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- if (DIAGNOSTIC_UI)
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, MOCK_IGNORE, 0x0, 0x0, MOCK_IGNORE);
-
- /* Advanced options screen */
- reset_common_data(FOR_MANUAL_RECOVERY);
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_DOWN);
- if (DIAGNOSTIC_UI)
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- /* #1: Enable dev mode */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #2: Debug info */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #3: Firmware log */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* #4: Back */
- add_mock_keypress(VB_KEY_ESC);
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- /* End of menu */
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_DOWN);
- extend_calls_until_shutdown();
- TEST_EQ(vb2_manual_recovery_menu(ctx), VB2_REQUEST_SHUTDOWN,
- "advanced options screen");
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- if (DIAGNOSTIC_UI)
- DISPLAYED_PASS();
- DISPLAYED_PASS();
- /* #0: Language menu */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- 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: Enable dev mode */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 1, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#1: enable dev mode", VB2_SCREEN_RECOVERY_TO_DEV,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #2: Debug info */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#2: debug info", VB2_SCREEN_DEBUG_INFO,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #3: Firmware log */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 3, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#3: firmware log", VB2_SCREEN_FIRMWARE_LOG,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* #4: Back */
- DISPLAYED_PASS();
- DISPLAYED_EQ("advanced options", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 4, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_EQ("#4: back", VB2_SCREEN_RECOVERY_SELECT,
- MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE,
- MOCK_IGNORE);
- /* End of menu */
- DISPLAYED_PASS();
- DISPLAYED_EQ("end of menu", VB2_SCREEN_ADVANCED_OPTIONS,
- MOCK_IGNORE, 2, MOCK_IGNORE, MOCK_IGNORE, MOCK_IGNORE);
- DISPLAYED_NO_EXTRA();
-
- VB2_DEBUG("...done.\n");
-}
-
-static void diagnostics_screen_tests(void)
-{
- VB2_DEBUG("Testing diagnostic screens...\n");
-
- /* Diagnostics screen: disabled and hidden item mask */
- 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);
-
- /* Diagnostics screen */
- reset_common_data(FOR_DIAGNOSTICS);
-
- /* #0: Language menu */
- add_mock_keypress(VB_KEY_UP);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ESC);
- /* #1: Storage health screen */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ESC);
- /* #2: Short storage self-test screen */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- add_mock_keypress(VB_KEY_ESC);
- /* #3: Extended storage self-test screen */
- add_mock_keypress(VB_KEY_DOWN);
- add_mock_keypress(VB_KEY_ENTER);
- 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);
- /* #0: Language menu */
- 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);
- DISPLAYED_PASS();
- /* #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);
- DISPLAYED_PASS();
- /* #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: 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);
- DISPLAYED_PASS();
- /* #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");
-}
-
-int main(void)
-{
- developer_tests();
- broken_recovery_tests();
- manual_recovery_tests();
- language_selection_tests();
- debug_info_tests();
- firmware_log_tests();
-
- /* Screen displayed */
- developer_screen_tests();
- broken_recovery_screen_tests();
- manual_recovery_screen_tests();
- diagnostics_screen_tests();
-
- return gTestSuccess ? 0 : 255;
-}
diff --git a/tests/vb2_ui_utility_tests.c b/tests/vb2_ui_utility_tests.c
deleted file mode 100644
index 1a7b19e..0000000
--- a/tests/vb2_ui_utility_tests.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/* Copyright 2020 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.
- *
- * Tests for UI utility functions.
- */
-
-#include "2api.h"
-#include "2common.h"
-#include "2misc.h"
-#include "2nvstorage.h"
-#include "2ui.h"
-#include "2ui_private.h"
-#include "test_common.h"
-#include "vboot_api.h"
-
-/* Fixed value for ignoring some checks. */
-#define MOCK_IGNORE 0xffffu
-
-/* 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_ROOT 0xefff
-
-/* Mock data */
-static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
- __attribute__((aligned(VB2_WORKBUF_ALIGN)));
-static struct vb2_context *ctx;
-static struct vb2_gbb_header gbb;
-
-static uint32_t mock_locale_count;
-static int mock_shutdown_request;
-
-static struct vb2_ui_context mock_ui_context;
-
-/* Mock actions */
-static uint32_t mock_action_called;
-static vb2_error_t mock_action_base(struct vb2_ui_context *ui)
-{
- mock_action_called++;
- return VB2_SUCCESS;
-}
-
-/* Mock screens */
-struct vb2_screen_info mock_screen_base = {
- .id = MOCK_SCREEN_BASE,
- .name = "mock_screen_base: menuless screen",
-};
-struct vb2_menu_item mock_screen_menu_items[] = {
- {
- .text = "option 0: language selection",
- .is_language_select = 1,
- },
- {
- .text = "option 1",
- },
- {
- .text = "option 2",
- },
- {
- .text = "option 3",
- },
- {
- .text = "option 4",
- },
-};
-struct vb2_screen_info mock_screen_menu = {
- .id = MOCK_SCREEN_MENU,
- .name = "mock_screen_menu: screen with 5 options",
- .menu = {
- .num_items = ARRAY_SIZE(mock_screen_menu_items),
- .items = mock_screen_menu_items,
- },
-};
-struct vb2_screen_info mock_screen_root = {
- .id = MOCK_SCREEN_ROOT,
- .name = "mock_screen_root",
-};
-
-static void screen_state_eq(const struct vb2_screen_state *state,
- enum vb2_screen screen,
- uint32_t selected_item,
- uint32_t hidden_item_mask)
-{
- if (screen != MOCK_IGNORE) {
- if (state->screen == NULL)
- TEST_TRUE(0, " state.screen does not exist");
- else
- TEST_EQ(state->screen->id, screen, " state.screen");
- }
- if (selected_item != MOCK_IGNORE)
- TEST_EQ(state->selected_item,
- selected_item, " state.selected_item");
- if (hidden_item_mask != MOCK_IGNORE)
- TEST_EQ(state->hidden_item_mask,
- hidden_item_mask, " state.hidden_item_mask");
-}
-
-/* Reset mock data (for use before each test) */
-static void reset_common_data(void)
-{
- TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
- "vb2api_init failed");
-
- memset(&gbb, 0, sizeof(gbb));
-
- vb2_nv_init(ctx);
-
- /* For vb2ex_get_locale_count */
- mock_locale_count = 1;
-
- /* For check_shutdown_request */
- mock_shutdown_request = MOCK_IGNORE;
-
- /* Mock ui_context based on mock screens */
- memset(&mock_ui_context, 0, sizeof(mock_ui_context));
- mock_ui_context.power_button = VB2_POWER_BUTTON_HELD_SINCE_BOOT;
-
- /* For mock actions */
- mock_action_called = 0;
-
- /* Reset init and action functions */
- mock_screen_base.init = NULL;
- mock_screen_base.action = NULL;
- mock_screen_menu.init = NULL;
- mock_screen_menu.action = NULL;
- mock_screen_root.init = NULL;
- mock_screen_root.action = NULL;
-}
-
-/* Mock functions */
-struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
-{
- return &gbb;
-}
-
-uint32_t vb2ex_get_locale_count(void)
-{
- return mock_locale_count;
-}
-
-uint32_t VbExIsShutdownRequested(void)
-{
- if (mock_shutdown_request != MOCK_IGNORE)
- return mock_shutdown_request;
-
- return 0;
-}
-
-const struct vb2_screen_info *vb2_get_screen_info(enum vb2_screen screen)
-{
- switch ((int)screen) {
- case MOCK_SCREEN_BASE:
- return &mock_screen_base;
- case MOCK_SCREEN_MENU:
- return &mock_screen_menu;
- case MOCK_SCREEN_ROOT:
- return &mock_screen_root;
- default:
- return NULL;
- }
-}
-
-/* Tests */
-static void check_shutdown_request_tests(void)
-{
- VB2_DEBUG("Testing check_shutdown_request...\n");
-
- /* Release, press, hold, and release */
- if (!DETACHABLE) {
- reset_common_data();
- mock_shutdown_request = 0;
- 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_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");
- }
-
- /* Press is ignored because we may held since boot */
- if (!DETACHABLE) {
- reset_common_data();
- mock_shutdown_request = VB_SHUTDOWN_REQUEST_POWER_BUTTON;
- TEST_EQ(check_shutdown_request(&mock_ui_context), VB2_SUCCESS,
- "press is ignored");
- }
-
- /* Power button short press from key */
- if (!DETACHABLE) {
- 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_SHUTDOWN, "power button short press");
- }
-
- /* Lid closure = shutdown request anyway */
- reset_common_data();
- mock_shutdown_request = VB_SHUTDOWN_REQUEST_LID_CLOSED;
- TEST_EQ(check_shutdown_request(&mock_ui_context),
- VB2_REQUEST_SHUTDOWN, "lid closure");
- mock_ui_context.key = 'A';
- TEST_EQ(check_shutdown_request(&mock_ui_context),
- VB2_REQUEST_SHUTDOWN, " lidsw + random key");
-
- /* Lid ignored by GBB flags */
- 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_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_SUCCESS,
- " lidsw + pwdsw");
- mock_shutdown_request = 0;
- TEST_EQ(check_shutdown_request(&mock_ui_context),
- VB2_REQUEST_SHUTDOWN, " pwdsw release");
- }
-
- /* Lid ignored; power button short pressed */
- if (!DETACHABLE) {
- reset_common_data();
- gbb.flags |= VB2_GBB_FLAG_DISABLE_LID_SHUTDOWN;
- mock_shutdown_request = VB_SHUTDOWN_REQUEST_LID_CLOSED;
- mock_ui_context.key = VB_BUTTON_POWER_SHORT_PRESS;
- TEST_EQ(check_shutdown_request(&mock_ui_context),
- VB2_REQUEST_SHUTDOWN,
- "lid ignored; power button short pressed");
- }
-
- /* DETACHABLE ignore power button */
- if (DETACHABLE) {
- /* Flag pwdsw */
- reset_common_data();
- mock_shutdown_request = VB_SHUTDOWN_REQUEST_POWER_BUTTON;
- 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_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_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");
-
- /* Change to screen which does not exist */
- reset_common_data();
- TEST_EQ(vb2_ui_screen_change(&mock_ui_context, MOCK_NO_SCREEN),
- VB2_REQUEST_UI_CONTINUE,
- "change to screen which does not exist");
- TEST_PTR_EQ(mock_ui_context.state, NULL, " stack is empty");
-
- /* Screen back with empty stack */
- reset_common_data();
- 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");
-
- /* Back to previous screen, restoring the state */
- reset_common_data();
- mock_screen_base.init = mock_action_base;
- vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_ROOT);
- vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_BASE);
- mock_ui_context.state->selected_item = 2;
- mock_ui_context.state->hidden_item_mask = 0x10;
- vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_MENU);
- TEST_EQ(vb2_ui_screen_back(&mock_ui_context), VB2_REQUEST_UI_CONTINUE,
- "back to previous screen");
- 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;
- vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_ROOT);
- vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_BASE);
- mock_ui_context.state->selected_item = 2;
- mock_ui_context.state->hidden_item_mask = 0x10;
- vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_MENU);
- TEST_EQ(vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_BASE),
- VB2_REQUEST_UI_CONTINUE, "change to target in stack");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_BASE, 2, 0x10);
- TEST_EQ(mock_action_called, 1, " action called once");
-
- /* Change to screen without init; using default init() */
- reset_common_data();
- TEST_EQ(vb2_ui_screen_change(&mock_ui_context, MOCK_SCREEN_MENU),
- VB2_REQUEST_UI_CONTINUE,
- "change to screen with language selection");
- screen_state_eq(mock_ui_context.state, MOCK_SCREEN_MENU,
- 1, /* Since index 0 is the language selection */
- 0);
-
- VB2_DEBUG("...done.\n");
-}
-
-static void get_language_menu_tests(void)
-{
- const struct vb2_menu *menu;
- const struct vb2_menu_item *items;
- VB2_DEBUG("Testing get_language_menu...\n");
-
- /* Only allocate menu items once */
- reset_common_data();
- mock_locale_count = 7;
- menu = get_language_menu(&mock_ui_context);
- TEST_PTR_NEQ(menu, NULL, "get language menu");
- TEST_EQ(menu->num_items, 7, " correct locale count");
- TEST_PTR_NEQ(menu->items, NULL, " items not null");
- items = menu->items;
-
- menu = get_language_menu(&mock_ui_context);
- TEST_PTR_NEQ(menu, NULL, "get language menu again");
- TEST_EQ(menu->num_items, 7, " correct locale count again");
- TEST_PTR_EQ(menu->items, items, " same pointer of items");
-
- /* Locale count = 0 */
- reset_common_data();
- mock_locale_count = 0;
- menu = get_language_menu(&mock_ui_context);
- TEST_PTR_NEQ(menu, NULL, "menu not null");
- TEST_EQ(menu->num_items, 1, " locale count 1");
-
- VB2_DEBUG("...done.\n");
-}
-
-int main(void)
-{
- check_shutdown_request_tests();
- screen_stack_tests();
- get_language_menu_tests();
-
- return gTestSuccess ? 0 : 255;
-}
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
index 32eaf02..f122eb3 100644
--- a/tests/vboot_api_kernel4_tests.c
+++ b/tests/vboot_api_kernel4_tests.c
@@ -11,13 +11,11 @@
#include "2nvstorage.h"
#include "2secdata.h"
#include "2sysincludes.h"
-#include "2ui.h"
#include "host_common.h"
#include "load_kernel_fw.h"
#include "test_common.h"
#include "tlcl.h"
#include "tss_constants.h"
-#include "vboot_kernel.h"
#include "vboot_struct.h"
#include "vboot_test.h"
@@ -138,7 +136,7 @@
return vbboot_retval;
}
-vb2_error_t vb2_developer_menu(struct vb2_context *c)
+vb2_error_t vb2ex_developer_ui(struct vb2_context *c)
{
return boot_dev(c);
}
@@ -150,7 +148,7 @@
TEST_TRUE(commit_data_called, " commit data");
}
-vb2_error_t vb2_manual_recovery_menu(struct vb2_context *c)
+vb2_error_t vb2ex_manual_recovery_ui(struct vb2_context *c)
{
rec_check(c);
if (vbboot_retval == -3)
@@ -158,7 +156,7 @@
return vbboot_retval;
}
-vb2_error_t vb2_broken_recovery_menu(struct vb2_context *c)
+vb2_error_t vb2ex_broken_screen_ui(struct vb2_context *c)
{
rec_check(c);
if (vbboot_retval == -4)
@@ -166,7 +164,7 @@
return vbboot_retval;
}
-vb2_error_t vb2_diagnostic_menu(struct vb2_context *c)
+vb2_error_t vb2ex_diagnostic_ui(struct vb2_context *c)
{
if (vbboot_retval == -5)
return VB2_ERROR_MOCK;
@@ -239,22 +237,19 @@
test_slk(VB2_ERROR_MOCK, 0, "Normal boot bad");
/* Check that NV_DIAG_REQUEST triggers diagnostic UI */
- if (DIAGNOSTIC_UI) {
- reset_common_data();
- mock_diagnostic_ui_enabled = 1;
- vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
- vbboot_retval = -5;
- test_slk(VB2_ERROR_MOCK, 0,
- "Normal boot with diag enabled");
- TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0,
- " diag not requested");
+ reset_common_data();
+ mock_diagnostic_ui_enabled = 1;
+ vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
+ vbboot_retval = -5;
+ test_slk(VB2_ERROR_MOCK, 0,
+ "Normal boot with diag enabled");
+ TEST_EQ(vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST), 0,
+ " diag not requested");
- reset_common_data();
- vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
- test_slk(VB2_REQUEST_REBOOT, 0,
- "Normal boot with diag disabled (reboot to "
- "unset)");
- }
+ reset_common_data();
+ vb2_nv_set(ctx, VB2_NV_DIAG_REQUEST, 1);
+ test_slk(VB2_REQUEST_REBOOT, 0,
+ "Normal boot with diag disabled (reboot to unset)");
/* Boot normal - phase1 failure */
reset_common_data();
diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c
index 9294fd7..51f0ddb 100644
--- a/tests/vboot_api_kernel_tests.c
+++ b/tests/vboot_api_kernel_tests.c
@@ -12,7 +12,6 @@
#include "load_kernel_fw.h"
#include "test_common.h"
#include "vboot_api.h"
-#include "vboot_kernel.h"
#include "vboot_test.h"
#define MAX_TEST_DISKS 10
@@ -51,7 +50,7 @@
static const char pickme[] = "correct choice";
#define DONT_CARE ((const char *)42)
-test_case_t test[] = {
+test_case_t normal_tests[] = {
{
.name = "first drive (removable)",
.ctx_flags = 0,
@@ -389,12 +388,52 @@
},
};
+test_case_t minios_tests[] = {
+ {
+ .name = "pick first fixed drive",
+ .ctx_flags = 0,
+ .disks_to_provide = {
+ {4096, 100, VB_DISK_FLAG_REMOVABLE, 0},
+ {4096, 100, VB_DISK_FLAG_FIXED, 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 = "skip failed fixed drive",
+ .ctx_flags = 0,
+ .disks_to_provide = {
+ {4096, 100, VB_DISK_FLAG_FIXED, "holygrail"},
+ {4096, 100, VB_DISK_FLAG_FIXED, pickme},
+ },
+ .disk_count_to_return = DEFAULT_COUNT,
+ .diskgetinfo_return_val = VB2_SUCCESS,
+ .loadkernel_return_val = {VB2_ERROR_LK_INVALID_KERNEL_FOUND, 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
+ },
+};
+
/****************************************************************************/
/* Mock data */
static VbDiskInfo mock_disks[MAX_TEST_DISKS];
static test_case_t *t;
static int load_kernel_calls;
+static int lk_normal_calls;
+static int lk_minios_calls;
static uint32_t got_recovery_request_val;
static const char *got_find_disk;
static const char *got_load_disk;
@@ -403,26 +442,31 @@
static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
static struct vb2_context *ctx;
+static struct VbSelectAndLoadKernelParams kparams;
/**
* Reset mock data (for use before each test)
*/
-static void ResetMocks(int i)
+static void ResetMocks(test_case_t *test_case)
{
TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
"vb2api_init failed");
- memset(VbApiKernelGetParams(), 0, sizeof(VbSelectAndLoadKernelParams));
+ memset(&kparams, 0, sizeof(VbSelectAndLoadKernelParams));
+ *VbApiKernelGetParamsPtr() = &kparams;
+
memset(&mock_disks, 0, sizeof(mock_disks));
load_kernel_calls = 0;
+ lk_normal_calls = 0;
+ lk_minios_calls = 0;
got_recovery_request_val = VB2_RECOVERY_NOT_REQUESTED;
got_find_disk = 0;
got_load_disk = 0;
got_return_val = 0xdeadbeef;
- t = test + i;
+ t = test_case;
}
static int is_nonzero(const void *vptr, size_t count)
@@ -495,9 +539,9 @@
return VB2_SUCCESS;
}
-vb2_error_t LoadKernel(struct vb2_context *c,
- VbSelectAndLoadKernelParams *params,
- VbDiskInfo *disk_info)
+static vb2_error_t LoadKernelImpl(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__,
@@ -509,6 +553,22 @@
return t->loadkernel_return_val[load_kernel_calls++];
}
+vb2_error_t LoadKernel(struct vb2_context *c,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info)
+{
+ lk_normal_calls++;
+ return LoadKernelImpl(c, params, disk_info);
+}
+
+vb2_error_t LoadMiniOsKernel(struct vb2_context *c,
+ VbSelectAndLoadKernelParams *params,
+ VbDiskInfo *disk_info)
+{
+ lk_minios_calls++;
+ return LoadKernelImpl(c, params, disk_info);
+}
+
void vb2_nv_set(struct vb2_context *c,
enum vb2_nv_param param,
uint32_t value)
@@ -525,11 +585,11 @@
static void VbTryLoadKernelTest(void)
{
int i;
- int num_tests = sizeof(test) / sizeof(test[0]);
+ int num_tests = ARRAY_SIZE(normal_tests);
for (i = 0; i < num_tests; i++) {
- printf("Test case: %s ...\n", test[i].name);
- ResetMocks(i);
+ printf("Test case: %s ...\n", normal_tests[i].name);
+ ResetMocks(&normal_tests[i]);
ctx->flags = t->ctx_flags;
TEST_EQ(VbTryLoadKernel(ctx, t->want_flags),
t->expected_return_val, " return value");
@@ -543,11 +603,40 @@
}
TEST_EQ(got_external_mismatch, 0, " external GPT errors");
}
+ TEST_EQ(lk_normal_calls, load_kernel_calls, " LoadKernel called");
+ TEST_EQ(lk_minios_calls, 0, " LoadMiniOsKernel not called");
+}
+
+static void VbTryLoadMiniOsKernelTest(void)
+{
+ int i;
+ int num_tests = ARRAY_SIZE(minios_tests);
+
+ for (i = 0; i < num_tests; i++) {
+ printf("Test case: %s ...\n", minios_tests[i].name);
+ ResetMocks(&minios_tests[i]);
+ ctx->flags = t->ctx_flags;
+ TEST_EQ(VbTryLoadMiniOsKernel(ctx),
+ t->expected_return_val, " return value");
+ TEST_EQ(got_recovery_request_val,
+ t->expected_recovery_request_val, " recovery_request");
+ if (t->expected_to_find_disk != DONT_CARE) {
+ TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk,
+ " find disk");
+ TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk,
+ " load disk");
+ }
+ TEST_EQ(got_external_mismatch, 0, " external GPT errors");
+ }
+ TEST_EQ(lk_normal_calls, 0, " LoadKernel not called");
+ TEST_EQ(lk_minios_calls, load_kernel_calls,
+ " LoadMiniOsKernel called");
}
int main(void)
{
VbTryLoadKernelTest();
+ VbTryLoadMiniOsKernelTest();
return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_kernel2_tests.c b/tests/vboot_kernel2_tests.c
new file mode 100644
index 0000000..5424e86
--- /dev/null
+++ b/tests/vboot_kernel2_tests.c
@@ -0,0 +1,434 @@
+/* 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.
+ *
+ * Tests for miniOS kernel selection, loading, verification, and booting.
+ */
+
+#include "2api.h"
+#include "2common.h"
+#include "2misc.h"
+#include "2nvstorage.h"
+#include "2secdata.h"
+#include "load_kernel_fw.h"
+#include "test_common.h"
+#include "vboot_api.h"
+
+#define MAX_MOCK_KERNELS 10
+#define KBUF_SIZE 65536
+
+/* Internal struct to simulate a stream for sector-based disks */
+struct disk_stream {
+ /* Disk handle */
+ VbExDiskHandle_t handle;
+
+ /* Next sector to read */
+ uint64_t sector;
+
+ /* Number of sectors left */
+ uint64_t sectors_left;
+};
+
+/* Represent a "kernel" located on the disk */
+struct mock_kernel {
+ /* Sector where the kernel begins */
+ uint64_t sector;
+
+ /* Return value from vb2_load_partition */
+ vb2_error_t rv;
+
+ /* Number of times the sector was read */
+ int read_count;
+};
+
+/* Mock data */
+static struct vb2_context *ctx;
+static struct vb2_shared_data *sd;
+static struct vb2_workbuf wb;
+static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
+ __attribute__((aligned(VB2_WORKBUF_ALIGN)));
+
+static VbSelectAndLoadKernelParams lkp;
+static VbDiskInfo disk_info;
+static struct vb2_keyblock kbh;
+static struct vb2_kernel_preamble kph;
+static uint8_t kernel_buffer[80000];
+
+static struct mock_kernel kernels[MAX_MOCK_KERNELS];
+static int kernel_count;
+static struct mock_kernel *cur_kernel;
+
+static int mock_tpm_set_mode_calls;
+
+static void add_mock_kernel(uint64_t sector, vb2_error_t rv)
+{
+ if (kernel_count >= ARRAY_SIZE(kernels)) {
+ TEST_TRUE(0, " kernel_count ran out of entries!");
+ return;
+ }
+
+ kernels[kernel_count].sector = sector;
+ kernels[kernel_count].rv = rv;
+ kernel_count++;
+}
+
+static void reset_common_data(void)
+{
+ TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx),
+ "vb2api_init failed");
+ vb2_workbuf_from_ctx(ctx, &wb);
+ vb2_nv_init(ctx);
+ vb2api_secdata_kernel_create(ctx);
+ vb2_secdata_kernel_init(ctx);
+ ctx->flags = VB2_CONTEXT_RECOVERY_MODE;
+
+ sd = vb2_get_sd(ctx);
+ sd->kernel_version_secdata = 0xabcdef | (1 << 24);
+
+ memset(&lkp, 0, sizeof(lkp));
+ 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.lba_count = 1024;
+ disk_info.handle = lkp.disk_handle;
+
+ memset(&kbh, 0, sizeof(kbh));
+ kbh.data_key.key_version = 2;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_1
+ | VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_1;
+ kbh.keyblock_size = sizeof(kbh);
+
+ memset(&kph, 0, sizeof(kph));
+ kph.kernel_version = 1;
+ kph.preamble_size = 4096 - kbh.keyblock_size;
+ kph.body_signature.data_size = 0;
+ kph.bootloader_address = 0xbeadd008;
+ kph.bootloader_size = 0x1234;
+
+
+ memset(&kernels, 0, sizeof(kernels));
+ kernel_count = 0;
+ cur_kernel = NULL;
+
+ mock_tpm_set_mode_calls = 0;
+}
+
+/* Mocks */
+
+vb2_error_t VbExStreamOpen(VbExDiskHandle_t handle, uint64_t lba_start,
+ uint64_t lba_count, VbExStream_t *stream)
+{
+ struct disk_stream *s;
+ uint64_t i;
+
+ if (!handle) {
+ *stream = NULL;
+ return VB2_ERROR_UNKNOWN;
+ }
+
+ if (lba_start + lba_count > disk_info.lba_count)
+ return VB2_ERROR_UNKNOWN;
+
+ s = malloc(sizeof(*s));
+ s->handle = handle;
+ s->sector = lba_start;
+ s->sectors_left = lba_count;
+
+ *stream = (void *)s;
+
+ for (i = 0; i < kernel_count; i++) {
+ if (kernels[i].sector == lba_start)
+ cur_kernel = &kernels[i];
+ }
+
+ return VB2_SUCCESS;
+}
+
+vb2_error_t VbExStreamRead(VbExStream_t stream, uint32_t bytes, void *buffer)
+{
+ struct disk_stream *s = (struct disk_stream *)stream;
+ uint64_t sectors;
+ uint64_t i;
+
+ if (!s)
+ return VB2_ERROR_UNKNOWN;
+
+ /* For now, require reads to be a multiple of the LBA size */
+ if (bytes % disk_info.bytes_per_lba)
+ return VB2_ERROR_UNKNOWN;
+
+ /* Fail on overflow */
+ sectors = bytes / disk_info.bytes_per_lba;
+ if (sectors > s->sectors_left)
+ return VB2_ERROR_UNKNOWN;
+
+ memset(buffer, 0, bytes);
+ for (i = 0; i < kernel_count; i++) {
+ if (kernels[i].sector >= s->sector &&
+ kernels[i].sector < s->sector + sectors) {
+ VB2_DEBUG("Simulating kernel %" PRIu64 " match\n", i);
+ uint64_t buf_offset = (kernels[i].sector - s->sector)
+ * disk_info.bytes_per_lba;
+ memcpy(buffer + buf_offset, VB2_KEYBLOCK_MAGIC,
+ VB2_KEYBLOCK_MAGIC_SIZE);
+ kernels[i].read_count++;
+ TEST_TRUE(kernels[i].read_count <= 2,
+ " Max read count exceeded");
+ }
+ }
+
+ s->sector += sectors;
+ s->sectors_left -= sectors;
+
+ return VB2_SUCCESS;
+}
+
+void VbExStreamClose(VbExStream_t stream)
+{
+ free(stream);
+}
+
+vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key,
+ const uint8_t *buf, uint32_t size)
+{
+ return cur_kernel->rv;
+}
+
+vb2_error_t vb2_verify_keyblock(struct vb2_keyblock *block, uint32_t size,
+ const struct vb2_public_key *key,
+ const struct vb2_workbuf *w)
+{
+ /* Use this as an opportunity to override the keyblock */
+ memcpy((void *)block, &kbh, sizeof(kbh));
+
+ return cur_kernel->rv;
+}
+
+vb2_error_t vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
+ uint32_t size,
+ const struct vb2_workbuf *w)
+{
+ /* Use this as an opportunity to override the keyblock */
+ memcpy((void *)block, &kbh, sizeof(kbh));
+
+ return cur_kernel->rv;
+}
+
+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 *w)
+{
+ /* Use this as an opportunity to override the preamble */
+ memcpy((void *)preamble, &kph, sizeof(kph));
+
+ return cur_kernel->rv;
+}
+
+vb2_error_t vb2_verify_data(const uint8_t *data, uint32_t size,
+ struct vb2_signature *sig,
+ const struct vb2_public_key *key,
+ const struct vb2_workbuf *w)
+{
+ return cur_kernel->rv;
+}
+
+vb2_error_t vb2_digest_buffer(const uint8_t *buf, uint32_t size,
+ enum vb2_hash_algorithm hash_alg, uint8_t *digest,
+ uint32_t digest_size)
+{
+ return cur_kernel->rv;
+}
+
+vb2_error_t vb2ex_tpm_set_mode(enum vb2_tpm_mode mode_val)
+{
+ mock_tpm_set_mode_calls++;
+ return VB2_SUCCESS;
+}
+
+/* Make sure nothing tested here ever calls this directly. */
+void vb2api_fail(struct vb2_context *c, uint8_t reason, uint8_t subcode)
+{
+ TEST_TRUE(0, " called vb2api_fail()");
+}
+
+/* Tests */
+
+static void load_minios_kernel_tests(void)
+{
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 1;
+ add_mock_kernel(0, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "{valid kernel}");
+ TEST_EQ(mock_tpm_set_mode_calls, 1,
+ " TPM disabled");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 1;
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND, "{no kernel}");
+ TEST_EQ(mock_tpm_set_mode_calls, 0,
+ " TPM not disabled");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(1, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "{no kernel, valid kernel}");
+ TEST_EQ(cur_kernel->sector, 1, " select kernel");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_ERROR_MOCK);
+ add_mock_kernel(1, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "{invalid kernel, valid kernel}");
+ TEST_EQ(cur_kernel->sector, 1, " select second kernel");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_ERROR_MOCK);
+ add_mock_kernel(1, VB2_ERROR_MOCK);
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "{invalid kernel, invalid kernel}");
+ TEST_EQ(mock_tpm_set_mode_calls, 0,
+ " TPM not disabled");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ add_mock_kernel(1, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "{valid kernel, valid kernel} minios_priority=0");
+ TEST_EQ(cur_kernel->sector, 0, " select first kernel");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ add_mock_kernel(1, VB2_SUCCESS);
+ vb2_nv_set(ctx, VB2_NV_MINIOS_PRIORITY, 1);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "{valid kernel, valid kernel} minios_priority=1");
+ TEST_EQ(cur_kernel->sector, 1, " select second kernel");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = VB2_KEYBLOCK_MAGIC_SIZE;
+ disk_info.lba_count = 4;
+ add_mock_kernel(1, VB2_SUCCESS);
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "valid kernel header near start of disk (disk too small)");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = VB2_KEYBLOCK_MAGIC_SIZE;
+ disk_info.lba_count = 1000;
+ add_mock_kernel(999, VB2_SUCCESS);
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "valid kernel header near end of disk");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = 1024;
+ disk_info.lba_count = 128;
+ add_mock_kernel(63, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "start/end overlap assuming >128 MB search range (start)");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = 1024;
+ disk_info.lba_count = 128;
+ add_mock_kernel(64, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "start/end overlap assuming >128 MB search range (end)");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = 128;
+ disk_info.lba_count = 1024;
+ add_mock_kernel(3, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "kernel at last sector in batch assuming 512 KB batches");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = 256;
+ disk_info.lba_count = 1024;
+ add_mock_kernel(3, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "kernel at last sector in batch assuming 1 MB batches");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = 512;
+ disk_info.lba_count = 1024;
+ add_mock_kernel(3, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "kernel at last sector in batch assuming 2 MB batches");
+
+ reset_common_data();
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_1;
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "kernel with minios keyblock flag");
+
+ reset_common_data();
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "kernel with !minios keyblock flag");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ sd->kernel_version_secdata = 5 << 24;
+ kph.kernel_version = 4;
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "kernel version too old");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ sd->kernel_version_secdata = 5 << 24;
+ kph.kernel_version = 0x100;
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "kernel version greater than 0xff");
+
+ reset_common_data();
+ disk_info.bytes_per_lba = KBUF_SIZE;
+ disk_info.lba_count = 2;
+ add_mock_kernel(0, VB2_SUCCESS);
+ sd->kernel_version_secdata = 5 << 24;
+ kph.kernel_version = 6;
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ "newer kernel version");
+}
+
+int main(void)
+{
+ load_minios_kernel_tests();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c
index 486602c..14e7e1f 100644
--- a/tests/vboot_kernel_tests.c
+++ b/tests/vboot_kernel_tests.c
@@ -11,23 +11,12 @@
#include "2nvstorage.h"
#include "2secdata.h"
#include "2secdata_struct.h"
-#include "2sha.h"
-#include "2sysincludes.h"
#include "cgptlib.h"
#include "cgptlib_internal.h"
-#include "crc32.h"
#include "gpt.h"
-#include "host_common.h"
#include "load_kernel_fw.h"
#include "test_common.h"
#include "vboot_api.h"
-#include "vboot_kernel.h"
-
-#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
-#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
-
-#define MOCK_SECTOR_SIZE 512
-#define MOCK_SECTOR_COUNT 1024
/* Mock kernel partition */
struct mock_part {
@@ -41,10 +30,8 @@
static int mock_part_next;
/* Mock data */
-static char call_log[4096];
static uint8_t kernel_buffer[80000];
static int disk_read_to_fail;
-static int disk_write_to_fail;
static int gpt_init_fail;
static int keyblock_verify_fail; /* 0=ok, 1=sig, 2=hash */
static int preamble_verify_fail;
@@ -53,17 +40,11 @@
static int gpt_flag_external;
static struct vb2_gbb_header gbb;
-static VbExDiskHandle_t handle;
static VbSelectAndLoadKernelParams lkp;
static VbDiskInfo disk_info;
static struct vb2_keyblock kbh;
static struct vb2_kernel_preamble kph;
static struct vb2_secdata_fwmp *fwmp;
-static uint8_t mock_disk[MOCK_SECTOR_SIZE * MOCK_SECTOR_COUNT];
-static GptHeader *mock_gpt_primary =
- (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * 1];
-static GptHeader *mock_gpt_secondary =
- (GptHeader*)&mock_disk[MOCK_SECTOR_SIZE * (MOCK_SECTOR_COUNT - 1)];
static uint8_t mock_digest[VB2_SHA256_DIGEST_SIZE] = {12, 34, 56, 78};
static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
@@ -72,56 +53,11 @@
static struct vb2_packed_key mock_key;
/**
- * Prepare a valid GPT header that will pass CheckHeader() tests
- */
-static void SetupGptHeader(GptHeader *h, int is_secondary)
-{
- memset(h, '\0', MOCK_SECTOR_SIZE);
-
- /* "EFI PART" */
- memcpy(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE);
- h->revision = GPT_HEADER_REVISION;
- h->size = MIN_SIZE_OF_HEADER;
-
- /* 16KB: 128 entries of 128 bytes */
- h->size_of_entry = sizeof(GptEntry);
- h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
-
- /* Set LBA pointers for primary or secondary header */
- if (is_secondary) {
- h->my_lba = MOCK_SECTOR_COUNT - GPT_HEADER_SECTORS;
- h->entries_lba = h->my_lba - CalculateEntriesSectors(h,
- MOCK_SECTOR_SIZE);
- } else {
- h->my_lba = GPT_PMBR_SECTORS;
- h->entries_lba = h->my_lba + 1;
- }
-
- h->first_usable_lba = 2 + CalculateEntriesSectors(h, MOCK_SECTOR_SIZE);
- h->last_usable_lba = MOCK_SECTOR_COUNT - 2 - CalculateEntriesSectors(h,
- MOCK_SECTOR_SIZE);
-
- h->header_crc32 = HeaderCrc(h);
-}
-
-static void ResetCallLog(void)
-{
- *call_log = 0;
-}
-
-/**
* Reset mock data (for use before each test)
*/
static void ResetMocks(void)
{
- ResetCallLog();
-
- memset(&mock_disk, 0, sizeof(mock_disk));
- SetupGptHeader(mock_gpt_primary, 0);
- SetupGptHeader(mock_gpt_secondary, 1);
-
disk_read_to_fail = -1;
- disk_write_to_fail = -1;
gpt_init_fail = 0;
keyblock_verify_fail = 0;
@@ -219,29 +155,15 @@
vb2_error_t VbExDiskRead(VbExDiskHandle_t h, uint64_t lba_start,
uint64_t lba_count, void *buffer)
{
- LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
-
if ((int)lba_start == disk_read_to_fail)
return VB2_ERROR_MOCK;
- memcpy(buffer, &mock_disk[lba_start * MOCK_SECTOR_SIZE],
- lba_count * MOCK_SECTOR_SIZE);
-
return VB2_SUCCESS;
}
-vb2_error_t VbExDiskWrite(VbExDiskHandle_t h, uint64_t lba_start,
- uint64_t lba_count, const void *buffer)
+int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
{
- LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
-
- if ((int)lba_start == disk_write_to_fail)
- return VB2_ERROR_MOCK;
-
- memcpy(&mock_disk[lba_start * MOCK_SECTOR_SIZE], buffer,
- lba_count * MOCK_SECTOR_SIZE);
-
- return VB2_SUCCESS;
+ return GPT_SUCCESS;
}
int GptInit(GptData *gpt)
@@ -266,6 +188,16 @@
return GPT_SUCCESS;
}
+int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type)
+{
+ return GPT_SUCCESS;
+}
+
+int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
+{
+ return GPT_SUCCESS;
+}
+
void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
{
static char fake_guid[] = "FakeGuid";
@@ -343,257 +275,6 @@
TEST_TRUE(0, " called vb2api_fail()");
}
-/**
- * Test reading/writing GPT
- */
-static void ReadWriteGptTest(void)
-{
- GptData g;
- GptHeader *h;
-
- g.sector_bytes = MOCK_SECTOR_SIZE;
- g.streaming_drive_sectors = g.gpt_drive_sectors = MOCK_SECTOR_COUNT;
- g.valid_headers = g.valid_entries = MASK_BOTH;
-
- ResetMocks();
- TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
- TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
- "VbExDiskRead(h, 2, 32)\n"
- "VbExDiskRead(h, 1023, 1)\n"
- "VbExDiskRead(h, 991, 32)\n");
- ResetCallLog();
- /*
- * Valgrind complains about access to uninitialized memory here, so
- * zero the primary header before each test.
- */
- memset(g.primary_header, '\0', g.sector_bytes);
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
- TEST_CALLS("");
-
- /*
- * Invalidate primary GPT header,
- * check that AllocAndReadGptData still succeeds
- */
- ResetMocks();
- memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
- TEST_EQ(AllocAndReadGptData(handle, &g), 0,
- "AllocAndRead primary invalid");
- TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 1, "Primary header is invalid");
- TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 0, "Secondary header is valid");
- TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
- "VbExDiskRead(h, 1023, 1)\n"
- "VbExDiskRead(h, 991, 32)\n");
- WriteAndFreeGptData(handle, &g);
-
- /*
- * Invalidate secondary GPT header,
- * check that AllocAndReadGptData still succeeds
- */
- ResetMocks();
- memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
- TEST_EQ(AllocAndReadGptData(handle, &g), 0,
- "AllocAndRead secondary invalid");
- TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 0, "Primary header is valid");
- TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 1, "Secondary header is invalid");
- TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
- "VbExDiskRead(h, 2, 32)\n"
- "VbExDiskRead(h, 1023, 1)\n");
- WriteAndFreeGptData(handle, &g);
-
- /*
- * Invalidate primary AND secondary GPT header,
- * check that AllocAndReadGptData fails.
- */
- ResetMocks();
- memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
- memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
- TEST_EQ(AllocAndReadGptData(handle, &g), 1,
- "AllocAndRead primary and secondary invalid");
- TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 1, "Primary header is invalid");
- TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 1, "Secondary header is invalid");
- TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
- "VbExDiskRead(h, 1023, 1)\n");
- WriteAndFreeGptData(handle, &g);
-
- /*
- * Invalidate primary GPT header and check that it is
- * repaired by GptRepair().
- *
- * This would normally be called by LoadKernel()->GptInit()
- * but this callback is mocked in these tests.
- */
- ResetMocks();
- memset(mock_gpt_primary, '\0', sizeof(*mock_gpt_primary));
- TEST_EQ(AllocAndReadGptData(handle, &g), 0,
- "Fix Primary GPT: AllocAndRead");
- /* Call GptRepair() with input indicating secondary GPT is valid */
- g.valid_headers = g.valid_entries = MASK_SECONDARY;
- GptRepair(&g);
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
- "Fix Primary GPT: WriteAndFreeGptData");
- TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
- "VbExDiskRead(h, 1023, 1)\n"
- "VbExDiskRead(h, 991, 32)\n"
- "VbExDiskWrite(h, 1, 1)\n"
- "VbExDiskWrite(h, 2, 32)\n");
- TEST_EQ(CheckHeader(mock_gpt_primary, 0, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 0, "Fix Primary GPT: Primary header is valid");
-
- /*
- * Invalidate secondary GPT header and check that it can be
- * repaired by GptRepair().
- *
- * This would normally be called by LoadKernel()->GptInit()
- * but this callback is mocked in these tests.
- */
- ResetMocks();
- memset(mock_gpt_secondary, '\0', sizeof(*mock_gpt_secondary));
- TEST_EQ(AllocAndReadGptData(handle, &g), 0,
- "Fix Secondary GPT: AllocAndRead");
- /* Call GptRepair() with input indicating primary GPT is valid */
- g.valid_headers = g.valid_entries = MASK_PRIMARY;
- GptRepair(&g);
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0,
- "Fix Secondary GPT: WriteAndFreeGptData");
- TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
- "VbExDiskRead(h, 2, 32)\n"
- "VbExDiskRead(h, 1023, 1)\n"
- "VbExDiskWrite(h, 1023, 1)\n"
- "VbExDiskWrite(h, 991, 32)\n");
- TEST_EQ(CheckHeader(mock_gpt_secondary, 1, g.streaming_drive_sectors,
- g.gpt_drive_sectors, 0, g.sector_bytes),
- 0, "Fix Secondary GPT: Secondary header is valid");
-
- /* Data which is changed is written */
- ResetMocks();
- AllocAndReadGptData(handle, &g);
- g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
- ResetCallLog();
- memset(g.primary_header, '\0', g.sector_bytes);
- h = (GptHeader*)g.primary_header;
- h->entries_lba = 2;
- h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
- h->size_of_entry = sizeof(GptEntry);
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
- TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
- "VbExDiskWrite(h, 2, 32)\n");
-
- /* Data which is changed is written */
- ResetMocks();
- AllocAndReadGptData(handle, &g);
- g.modified = -1;
- ResetCallLog();
- memset(g.primary_header, '\0', g.sector_bytes);
- h = (GptHeader*)g.primary_header;
- h->entries_lba = 2;
- h->number_of_entries = MAX_NUMBER_OF_ENTRIES;
- h->size_of_entry = sizeof(GptEntry);
- h = (GptHeader*)g.secondary_header;
- h->entries_lba = 991;
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
- TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
- "VbExDiskWrite(h, 2, 32)\n"
- "VbExDiskWrite(h, 1023, 1)\n"
- "VbExDiskWrite(h, 991, 32)\n");
-
- /* If legacy signature, don't modify GPT header/entries 1 */
- ResetMocks();
- AllocAndReadGptData(handle, &g);
- h = (GptHeader *)g.primary_header;
- memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
- g.modified = -1;
- ResetCallLog();
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
- TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
- "VbExDiskWrite(h, 991, 32)\n");
-
- /* Error reading */
- ResetMocks();
- disk_read_to_fail = 1;
- TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
- g.valid_headers = g.valid_entries = MASK_SECONDARY;
- GptRepair(&g);
- ResetCallLog();
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
- TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
- "VbExDiskWrite(h, 2, 32)\n");
-
- ResetMocks();
- disk_read_to_fail = 2;
- TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
- g.valid_headers = MASK_BOTH;
- g.valid_entries = MASK_SECONDARY;
- GptRepair(&g);
- ResetCallLog();
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
- TEST_CALLS("VbExDiskWrite(h, 2, 32)\n");
-
- ResetMocks();
- disk_read_to_fail = 991;
- TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
- g.valid_headers = MASK_BOTH;
- g.valid_entries = MASK_PRIMARY;
- GptRepair(&g);
- ResetCallLog();
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
- TEST_CALLS("VbExDiskWrite(h, 991, 32)\n");
-
- ResetMocks();
- disk_read_to_fail = 1023;
- TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
- g.valid_headers = g.valid_entries = MASK_PRIMARY;
- GptRepair(&g);
- ResetCallLog();
- TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 2");
- TEST_CALLS("VbExDiskWrite(h, 1023, 1)\n"
- "VbExDiskWrite(h, 991, 32)\n");
-
- /* Error writing */
- ResetMocks();
- disk_write_to_fail = 1;
- AllocAndReadGptData(handle, &g);
- g.modified = -1;
- memset(g.primary_header, '\0', g.sector_bytes);
- TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
-
- ResetMocks();
- disk_write_to_fail = 2;
- AllocAndReadGptData(handle, &g);
- g.modified = -1;
- memset(g.primary_header, '\0', g.sector_bytes);
- h = (GptHeader*)g.primary_header;
- h->entries_lba = 2;
- TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
-
- ResetMocks();
- disk_write_to_fail = 991;
- AllocAndReadGptData(handle, &g);
- g.modified = -1;
- memset(g.primary_header, '\0', g.sector_bytes);
- TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
-
- ResetMocks();
- disk_write_to_fail = 1023;
- AllocAndReadGptData(handle, &g);
- g.modified = -1;
- memset(g.primary_header, '\0', g.sector_bytes);
- TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
-
-}
-
static void TestLoadKernel(int expect_retval, const char *test_name)
{
TEST_EQ(LoadKernel(ctx, &lkp, &disk_info), expect_retval, test_name);
@@ -682,50 +363,94 @@
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Fail key block dev sig fwmp");
- /* Check keyblock flag mismatches */
+ /* Check keyblock flags */
ResetMocks();
- kbh.keyblock_flags =
- VB2_KEYBLOCK_FLAG_RECOVERY_0 | VB2_KEYBLOCK_FLAG_DEVELOPER_1;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Keyblock dev flag mismatch");
ResetMocks();
- kbh.keyblock_flags =
- VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Keyblock rec flag mismatch");
ResetMocks();
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_1;
+ TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+ "Keyblock minios flag mismatch");
+
+ ResetMocks();
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- kbh.keyblock_flags =
- VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_1;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Keyblock recdev flag mismatch");
ResetMocks();
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
+ TestLoadKernel(0, "Keyblock rec flag okay");
+
+ ResetMocks();
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE | VB2_CONTEXT_DEVELOPER_MODE;
- kbh.keyblock_flags =
- VB2_KEYBLOCK_FLAG_RECOVERY_1 | VB2_KEYBLOCK_FLAG_DEVELOPER_0;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
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_RECOVERY_MODE | VB2_CONTEXT_DEVELOPER_MODE;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
+ TestLoadKernel(0, "Keyblock recdev flag okay");
+
+ /* Check keyblock flags (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;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_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;
+ kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_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_0
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_0
+ | VB2_KEYBLOCK_FLAG_MINIOS_1;
+ TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
+ "Keyblock dev flag mismatch (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_0
+ | VB2_KEYBLOCK_FLAG_DEVELOPER_1
+ | VB2_KEYBLOCK_FLAG_MINIOS_0;
+ TestLoadKernel(0, "Keyblock dev flag okay (signed kernel required)");
+
/* Check kernel key version */
ResetMocks();
kbh.data_key.key_version = 1;
@@ -878,7 +603,6 @@
int main(void)
{
- ReadWriteGptTest();
InvalidParamsTest();
LoadKernelTest();
diff --git a/tests/verify_kernel.c b/tests/verify_kernel.c
index 8fe969e..a79f33a 100644
--- a/tests/verify_kernel.c
+++ b/tests/verify_kernel.c
@@ -14,7 +14,7 @@
#include "host_common.h"
#include "util_misc.h"
#include "vboot_api.h"
-#include "vboot_kernel.h"
+#include "load_kernel_fw.h"
static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
diff --git a/utility/crossystem.c b/utility/crossystem.c
index 079bf32..7781e94 100644
--- a/utility/crossystem.c
+++ b/utility/crossystem.c
@@ -52,12 +52,12 @@
{"ecfw_act", IS_STRING, "Active EC firmware"},
{"post_ec_sync_delay", CAN_WRITE,
"Short delay after EC software sync (persistent, writable, eve only)"},
- {"fw_prev_result", IS_STRING, "Firmware result of previous boot (vboot2)"},
- {"fw_prev_tried", IS_STRING, "Firmware tried on previous boot (vboot2)"},
- {"fw_result", IS_STRING|CAN_WRITE, "Firmware result this boot (vboot2)"},
- {"fw_tried", IS_STRING, "Firmware tried this boot (vboot2)"},
+ {"fw_prev_result", IS_STRING, "Firmware result of previous boot"},
+ {"fw_prev_tried", IS_STRING, "Firmware tried on previous boot (A or B)"},
+ {"fw_result", IS_STRING|CAN_WRITE, "Firmware result this boot"},
+ {"fw_tried", IS_STRING, "Firmware tried this boot (A or B)"},
{"fw_try_count", CAN_WRITE, "Number of times to try fw_try_next"},
- {"fw_try_next", IS_STRING|CAN_WRITE, "Firmware to try next (vboot2)"},
+ {"fw_try_next", IS_STRING|CAN_WRITE, "Firmware to try next (A or B)"},
{"fw_vboot2", 0, "1 if firmware was selected by vboot2 or 0 otherwise"},
{"fwb_tries", CAN_WRITE, "Try firmware B count"},
{"fwid", IS_STRING, "Active firmware ID"},
@@ -72,6 +72,8 @@
{"loc_idx", CAN_WRITE, "Localization index for firmware screens"},
{"mainfw_act", IS_STRING, "Active main firmware"},
{"mainfw_type", IS_STRING, "Active main firmware type"},
+ {"minios_priority", IS_STRING|CAN_WRITE,
+ "miniOS image to try first (A or B)"},
{"nvram_cleared", CAN_WRITE, "Have NV settings been lost? Write 0 to clear"},
{"display_request", CAN_WRITE, "Should we initialize the display at boot?"},
{"phase_enforcement", 0,
@@ -86,7 +88,7 @@
{"tpm_attack", CAN_WRITE, "TPM was interrupted since this flag was cleared"},
{"tpm_fwver", 0, "Firmware version stored in TPM", "0x%08x"},
{"tpm_kernver", 0, "Kernel version stored in TPM", "0x%08x"},
- {"tpm_rebooted", 0, "TPM requesting repeated reboot (vboot2)"},
+ {"tpm_rebooted", 0, "TPM requesting repeated reboot"},
{"tried_fwb", 0, "Tried firmware B before A this boot"},
{"try_ro_sync", 0, "try read only software sync"},
{"vdat_flags", 0, "Flags from VbSharedData", "0x%08x"},
diff --git a/utility/load_kernel_test.c b/utility/load_kernel_test.c
index cad82fd..405fced 100644
--- a/utility/load_kernel_test.c
+++ b/utility/load_kernel_test.c
@@ -16,7 +16,6 @@
#include "2sysincludes.h"
#include "host_common.h"
#include "load_kernel_fw.h"
-#include "vboot_kernel.h"
#define LBA_BYTES 512
#define KERNEL_BUFFER_SIZE 0xA00000