Merge commit 'c31013768eb4ed052c54df50c398f70f2d7ef36d' into 14542.0.0
BUG=b/222349736
TEST=local BE run
RELEASE_NOTE=None
Signed-off-by: Rayan Dasoriya <dasoriya@google.com>
Change-Id: Ie0b27e4c165dec7db1bcca809d14e859894babe1
diff --git a/.gitignore b/.gitignore
index 6ac51f7..9edc243 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
/build
/build-au
/build-main
+Cargo.lock
ID
scripts/newbitmaps/default_source/*.bmp
scripts/newbitmaps/images/out_*
@@ -8,3 +9,5 @@
scripts/newbitmaps/strings/font
scripts/newbitmaps/strings/*.png
scripts/newbitmaps/strings/localized_text/*/*.png
+target
+.idea
diff --git a/Makefile b/Makefile
index 82d6a44..6340fb2 100644
--- a/Makefile
+++ b/Makefile
@@ -56,6 +56,7 @@
# US_DIR = shared data directory (for static content like devkeys)
# DF_DIR = utility defaults directory
# VB_DIR = vboot binary directory for dev-mode-only scripts
+# DUT_TEST_DIR = vboot dut tests binary directory
UB_DIR=${DESTDIR}/usr/bin
UL_DIR=${DESTDIR}/usr/${LIBDIR}
ULP_DIR=${UL_DIR}/pkgconfig
@@ -63,6 +64,7 @@
US_DIR=${DESTDIR}/usr/share/vboot
DF_DIR=${DESTDIR}/etc/default
VB_DIR=${US_DIR}/bin
+DUT_TEST_DIR=${US_DIR}/tests
# Where to install the (exportable) executables for testing?
TEST_INSTALL_DIR = ${BUILD}/install_for_test
@@ -71,12 +73,12 @@
SDK_BUILD ?=
# Verbose? Use V=1
-ifeq (${V},)
+ifeq ($(filter-out 0,${V}),)
Q := @
endif
# Quiet? Use QUIET=1
-ifeq (${QUIET},)
+ifeq ($(filter-out 0,${QUIET}),)
PRINTF := printf
else
PRINTF := :
@@ -123,7 +125,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 -Og,-g -Os)
+DEBUG_FLAGS := $(if $(filter-out 0,${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,35 +173,28 @@
# Needs -Wl because LD is actually set to CC by default.
LDFLAGS += -Wl,--gc-sections
-ifneq (${DEBUG}$(filter-out 0,${TEST_PRINT}),)
+ifneq ($(filter-out 0,${DEBUG})$(filter-out 0,${TEST_PRINT}),)
CFLAGS += -DVBOOT_DEBUG
endif
-ifeq (${DISABLE_NDEBUG},)
+ifeq ($(filter-out 0,${DISABLE_NDEBUG}),)
CFLAGS += -DNDEBUG
endif
-ifneq (${FORCE_LOGGING_ON},)
+ifneq ($(filter-out 0,${FORCE_LOGGING_ON}),)
CFLAGS += -DFORCE_LOGGING_ON=${FORCE_LOGGING_ON}
endif
-ifneq (${TPM2_MODE},)
+ifneq ($(filter-out 0,${TPM2_MODE}),)
CFLAGS += -DTPM2_MODE
endif
# Support devices with GPT in SPI-NOR (for nand device)
# TODO(b:184812319): Consider removing this code if nobody uses it.
-ifneq (${GPT_SPI_NOR},)
+ifneq ($(filter-out 0,${GPT_SPI_NOR}),)
CFLAGS += -DGPT_SPI_NOR
endif
-# Enable boot from external disk when switching to dev mode
-ifneq ($(filter-out 0,${BOOT_EXTERNAL_ON_DEV}),)
-CFLAGS += -DBOOT_EXTERNAL_ON_DEV=1
-else
-CFLAGS += -DBOOT_EXTERNAL_ON_DEV=0
-endif
-
# Enable EC early firmware selection.
ifneq ($(filter-out 0,${EC_EFS}),)
CFLAGS += -DEC_EFS=1
@@ -208,7 +203,7 @@
endif
# Some tests need to be disabled when using mocked_secdata_tpm.
-ifneq (${MOCK_TPM},)
+ifneq ($(filter-out 0,${MOCK_TPM}),)
CFLAGS += -DMOCK_TPM
endif
@@ -219,29 +214,6 @@
CFLAGS += -DTPM2_SIMULATOR=0
endif
-# VTPM_PROXY indicates whether the TPM driver simulator feature
-# is enable or not.
-# This flag only takes effect when TPM2_SIMULATOR is enabled.
-ifneq ($(filter-out 0,${VTPM_PROXY}),)
-CFLAGS += -DVTPM_PROXY=1
-else
-CFLAGS += -DVTPM_PROXY=0
-endif
-
-# DETACHABLE indicates whether the device is a detachable or not.
-ifneq ($(filter-out 0,${DETACHABLE}),)
-CFLAGS += -DDETACHABLE=1
-else
-CFLAGS += -DDETACHABLE=0
-endif
-
-# Confirm physical presence using keyboard
-ifneq ($(filter-out 0,${PHYSICAL_PRESENCE_KEYBOARD}),)
-CFLAGS += -DPHYSICAL_PRESENCE_KEYBOARD=1
-else
-CFLAGS += -DPHYSICAL_PRESENCE_KEYBOARD=0
-endif
-
# NOTE: We don't use these files but they are useful for other packages to
# query about required compiling/linking flags.
PC_IN_FILES = vboot_host.pc.in
@@ -264,7 +236,7 @@
CFLAGS += $(cflags_use_64bits)
# Code coverage
-ifneq (${COV},)
+ifneq ($(filter-out 0,${COV}),)
COV_FLAGS = -O0 --coverage -DCOVERAGE
CFLAGS += ${COV_FLAGS}
LDFLAGS += ${COV_FLAGS}
@@ -286,7 +258,7 @@
PKG_CONFIG ?= pkg-config
# Static?
-ifneq (${STATIC},)
+ifneq ($(filter-out 0,${STATIC}),)
LDFLAGS += -static
PKG_CONFIG += --static
endif
@@ -298,11 +270,17 @@
# Optional Libraries
LIBZIP_VERSION := $(shell ${PKG_CONFIG} --modversion libzip 2>/dev/null)
HAVE_LIBZIP := $(if ${LIBZIP_VERSION},1)
-ifneq (${HAVE_LIBZIP},)
+ifneq ($(filter-out 0,${HAVE_LIBZIP}),)
CFLAGS += -DHAVE_LIBZIP $(shell ${PKG_CONFIG} --cflags libzip)
LIBZIP_LIBS := $(shell ${PKG_CONFIG} --libs libzip)
endif
+HAVE_CROSID := $(shell ${PKG_CONFIG} --exists crosid && echo 1)
+ifeq ($(HAVE_CROSID),1)
+ CFLAGS += -DHAVE_CROSID $(shell ${PKG_CONFIG} --cflags crosid)
+ CROSID_LIBS := $(shell ${PKG_CONFIG} --libs crosid)
+endif
+
# Determine QEMU architecture needed, if any
ifeq (${ARCH},${HOST_ARCH})
# Same architecture; no need for QEMU
@@ -344,9 +322,9 @@
# Default target.
.PHONY: all
all: fwlib futil utillib hostlib cgpt tlcl \
- $(if ${SDK_BUILD},utils_sdk,utils_board) \
+ $(if ${SDK_BUILD},${UTIL_FILES_SDK},${UTIL_FILES_BOARD}) \
$(if $(filter x86_64,${ARCH}),$(if $(filter clang,${CC}),fuzzers)) \
- $(if ${COV},coverage)
+ $(if $(filter-out 0,${COV}),coverage)
##############################################################################
# Now we need to describe everything we might want or need to build
@@ -416,7 +394,7 @@
firmware/lib20/kernel.c
# TPM lightweight command library
-ifeq (${TPM2_MODE},)
+ifeq ($(filter-out 0,${TPM2_MODE}),)
TLCL_SRCS = \
firmware/lib/tpm_lite/tlcl.c
else
@@ -427,7 +405,7 @@
endif
# Support real TPM unless MOCK_TPM is set
-ifneq (${MOCK_TPM},)
+ifneq ($(filter-out 0,${MOCK_TPM}),)
FWLIB_SRCS += \
firmware/lib/tpm_lite/mocked_tlcl.c
endif
@@ -455,6 +433,19 @@
TLCL_OBJS = ${TLCL_SRCS:%.c=${BUILD}/%.o}
ALL_OBJS += ${FWLIB_OBJS} ${TLCL_OBJS}
+# Maintain behaviour of default on.
+USE_FLASHROM ?= 1
+
+ifneq ($(filter-out 0,${USE_FLASHROM}),)
+$(info building with libflashrom support)
+FLASHROM_LIBS := $(shell ${PKG_CONFIG} --libs flashrom)
+COMMONLIB_SRCS = \
+ host/lib/flashrom.c \
+ host/lib/flashrom_drv.c \
+ host/lib/subprocess.c
+CFLAGS += -DUSE_FLASHROM
+endif
+
# Intermediate library for the vboot_reference utilities to link against.
UTILLIB = ${BUILD}/libvboot_util.a
@@ -473,7 +464,7 @@
host/lib/crossystem.c \
host/lib/crypto.c \
host/lib/file_keys.c \
- host/lib/flashrom.c \
+ $(COMMONLIB_SRCS) \
host/lib/fmap.c \
host/lib/host_common.c \
host/lib/host_key2.c \
@@ -482,7 +473,6 @@
host/lib/host_signature.c \
host/lib/host_signature2.c \
host/lib/signature_digest.c \
- host/lib/subprocess.c \
host/lib/util_misc.c \
host/lib21/host_common.c \
host/lib21/host_key.c \
@@ -533,14 +523,13 @@
host/lib/crossystem.c \
host/lib/crypto.c \
host/lib/extract_vmlinuz.c \
- host/lib/flashrom.c \
+ $(COMMONLIB_SRCS) \
host/lib/fmap.c \
host/lib/host_misc.c \
- host/lib/subprocess.c \
host/lib21/host_misc.c \
${TLCL_SRCS}
-ifneq (${GPT_SPI_NOR},)
+ifneq ($(filter-out 0,${GPT_SPI_NOR}),)
HOSTLIB_SRCS += cgpt/cgpt_nor.c
endif
@@ -574,7 +563,7 @@
cgpt/cmd_repair.c \
cgpt/cmd_show.c
-ifneq (${GPT_SPI_NOR},)
+ifneq ($(filter-out 0,${GPT_SPI_NOR}),)
CGPT_SRCS += cgpt/cgpt_nor.c
endif
@@ -596,27 +585,32 @@
UTIL_DEFAULTS = ${BUILD}/default/vboot_reference
# Scripts to install directly (not compiled)
-UTIL_SCRIPTS_SDK = \
+UTIL_SCRIPT_NAMES_SDK = \
utility/dev_make_keypair \
utility/vbutil_what_keys
-UTIL_SCRIPTS_BOARD = \
+UTIL_SCRIPT_NAMES_BOARD = \
utility/chromeos-tpm-recovery \
utility/dev_debug_vboot \
utility/enable_dev_usb_boot \
utility/tpm-nvsize
-UTIL_NAMES_SDK = \
+UTIL_BIN_NAMES_SDK = \
+ utility/dumpRSAPublicKey \
utility/load_kernel_test \
utility/pad_digest_utility \
utility/signature_digest_utility \
utility/verify_data
-UTIL_NAMES_BOARD = \
+UTIL_BIN_NAMES_BOARD = \
utility/crossystem \
utility/dumpRSAPublicKey \
utility/tpmc
-UTIL_BINS_SDK = $(addprefix ${BUILD}/,${UTIL_NAMES_SDK})
-UTIL_BINS_BOARD = $(addprefix ${BUILD}/,${UTIL_NAMES_BOARD})
+UTIL_SCRIPTS_SDK = $(addprefix ${BUILD}/,${UTIL_SCRIPT_NAMES_SDK})
+UTIL_SCRIPTS_BOARD = $(addprefix ${BUILD}/,${UTIL_SCRIPT_NAMES_BOARD})
+UTIL_BINS_SDK = $(addprefix ${BUILD}/,${UTIL_BIN_NAMES_SDK})
+UTIL_BINS_BOARD = $(addprefix ${BUILD}/,${UTIL_BIN_NAMES_BOARD})
+UTIL_FILES_SDK = ${UTIL_BINS_SDK} ${UTIL_SCRIPTS_SDK}
+UTIL_FILES_BOARD = ${UTIL_BINS_BOARD} ${UTIL_SCRIPTS_BOARD}
ALL_OBJS += $(addsuffix .o,${UTIL_BINS_SDK})
ALL_OBJS += $(addsuffix .o,${UTIL_BINS_BOARD})
@@ -654,6 +648,7 @@
futility/cmd_dump_fmap.c \
futility/cmd_dump_kernel_config.c \
futility/cmd_gbb_utility.c \
+ futility/cmd_gscvd.c \
futility/cmd_load_fmap.c \
futility/cmd_pcr.c \
futility/cmd_show.c \
@@ -663,20 +658,24 @@
futility/cmd_vbutil_firmware.c \
futility/cmd_vbutil_firmware.c \
futility/cmd_vbutil_kernel.c \
+ futility/cmd_vbutil_key.c \
futility/cmd_vbutil_keyblock.c \
- futility/cmd_vbutil_key.c \
- futility/cmd_vbutil_key.c \
futility/file_type_bios.c \
futility/file_type.c \
futility/file_type_rwsig.c \
futility/file_type_usbpd1.c \
futility/misc.c \
- futility/updater.c \
+ futility/vb1_helper.c \
+ futility/vb2_helper.c
+
+ifneq ($(filter-out 0,${USE_FLASHROM}),)
+FUTIL_SRCS += host/lib/flashrom_drv.c \
+ futility/flashrom_wp_drv.c \
futility/updater_archive.c \
futility/updater_quirks.c \
futility/updater_utils.c \
- futility/vb1_helper.c \
- futility/vb2_helper.c
+ futility/updater.c
+endif
# List of commands built in futility.
FUTIL_CMD_LIST = ${BUILD}/gen/futility_cmds.c
@@ -713,7 +712,7 @@
tests/vboot_kernel2_tests \
tests/verify_kernel
-ifeq (${MOCK_TPM}${TPM2_MODE},)
+ifeq ($(filter-out 0,${MOCK_TPM})$(filter-out 0,${TPM2_MODE}),)
# tlcl_tests only works when MOCK_TPM is disabled
# TODO(apronin): tests for TPM2 case?
TEST_NAMES += \
@@ -768,13 +767,15 @@
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
+# Tests which should be run on dut
+ifeq (${ARCH}, x86_64)
+DUT_TEST_NAMES += tests/vb2_sha256_x86_tests
+endif
+
+TEST_NAMES += ${DUT_TEST_NAMES}
# And a few more...
-ifeq (${TPM2_MODE},)
+ifeq ($(filter-out 0,${TPM2_MODE}),)
TLCL_TEST_NAMES = \
tests/tpm_lite/tpmtest_earlyextend \
tests/tpm_lite/tpmtest_earlynvram \
@@ -832,7 +833,9 @@
.PHONY: install
install: cgpt_install signing_install futil_install pc_files_install \
- lib_install $(if ${SDK_BUILD},utils_install_sdk,utils_install_board)
+ lib_install $(if ${SDK_BUILD},,util_install_defaults) \
+ $(foreach f,$(if ${SDK_BUILD},${UTIL_FILES_SDK},${UTIL_FILES_BOARD}), \
+ util_install-$(patsubst ${BUILD}/%,%,${f}))
.PHONY: install_dev
install_dev: devkeys_install headers_install
@@ -842,8 +845,9 @@
.PHONY: install_for_test
install_for_test: override DESTDIR = ${TEST_INSTALL_DIR}
-install_for_test: test_setup
-install_for_test: install utils_install_sdk utils_install_board
+install_for_test: test_setup install \
+ $(foreach f,${UTIL_FILES_SDK} ${UTIL_FILES_BOARD}, \
+ util_install-$(patsubst ${BUILD}/%,%,${f}))
# Don't delete intermediate object files
.SECONDARY:
@@ -963,7 +967,7 @@
${Q}${LD} -o ${CGPT_WRAPPER} ${LDFLAGS} $^ ${LDLIBS}
.PHONY: cgpt
-cgpt: ${CGPT} $(if ${GPT_SPI_NOR},cgpt_wrapper)
+cgpt: ${CGPT} $(if $(filter-out 0,${GPT_SPI_NOR}),cgpt_wrapper)
# on FreeBSD: install misc/e2fsprogs-libuuid from ports,
# or e2fsprogs-libuuid from its binary package system.
@@ -1001,27 +1005,23 @@
${UTIL_BINS_BOARD}: ${UTILLIB}
${UTIL_BINS_BOARD}: LIBS = ${UTILLIB}
-.PHONY: utils_sdk
-utils_sdk: ${UTIL_BINS_SDK} ${UTIL_SCRIPTS_SDK}
- ${Q}cp -f ${UTIL_SCRIPTS_SDK} ${BUILD}/utility
- ${Q}chmod a+rx $(patsubst %,${BUILD}/%,${UTIL_SCRIPTS_SDK})
+${UTIL_SCRIPTS_SDK} ${UTIL_SCRIPTS_BOARD}: ${BUILD}/%: %
+ ${Q}cp -f $< $@
+ ${Q}chmod a+rx $@
-.PHONY: utils_board
-utils_board: ${UTIL_BINS_BOARD} ${UTIL_SCRIPTS_BOARD}
- ${Q}cp -f ${UTIL_SCRIPTS_BOARD} ${BUILD}/utility
- ${Q}chmod a+rx $(patsubst %,${BUILD}/%,${UTIL_SCRIPTS_BOARD})
+define UTIL_INSTALL_template
+.PHONY: util_install-$(1)
+util_install-$(1): $$(addprefix $${BUILD}/,$(1))
+ @${PRINTF} " INSTALL $(1)\n"
+ ${Q}mkdir -p $${UB_DIR}
+ ${Q}${INSTALL} -t $${UB_DIR} $$<
+endef
-.PHONY: utils_install_sdk
-utils_install_sdk: utils_sdk
- @${PRINTF} " INSTALL UTILS\n"
- ${Q}mkdir -p ${UB_DIR}
- ${Q}${INSTALL} -t ${UB_DIR} ${UTIL_BINS_SDK} ${UTIL_SCRIPTS_SDK}
+$(foreach f, $(sort ${UTIL_FILES_SDK} ${UTIL_FILES_BOARD}), \
+ $(eval $(call UTIL_INSTALL_template,$(patsubst ${BUILD}/%,%,${f}))))
-.PHONY: utils_install_board
-utils_install_board: utils_board ${UTIL_DEFAULTS}
- @${PRINTF} " INSTALL UTILS\n"
- ${Q}mkdir -p ${UB_DIR}
- ${Q}${INSTALL} -t ${UB_DIR} ${UTIL_BINS_BOARD} ${UTIL_SCRIPTS_BOARD}
+.PHONY: util_install_defaults
+util_install_defaults: ${UTIL_DEFAULTS}
${Q}mkdir -p ${DF_DIR}
${Q}${INSTALL} -t ${DF_DIR} -m 'u=rw,go=r,a-s' ${UTIL_DEFAULTS}
@@ -1040,7 +1040,7 @@
futil: ${FUTIL_BIN}
# FUTIL_LIBS is shared by FUTIL_BIN and TEST_FUTIL_BINS.
-FUTIL_LIBS = ${CRYPTO_LIBS} ${LIBZIP_LIBS}
+FUTIL_LIBS = ${CROSID_LIBS} ${CRYPTO_LIBS} ${LIBZIP_LIBS} ${FLASHROM_LIBS}
${FUTIL_BIN}: LDLIBS += ${FUTIL_LIBS}
${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} ${FWLIB}
@@ -1094,17 +1094,28 @@
${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 $@
@${PRINTF} " AR $(subst ${BUILD}/,,$@)\n"
${Q}ar qc $@ $^
+DUT_TEST_BINS = $(addprefix ${BUILD}/,${DUT_TEST_NAMES})
+
+# Special build for sha256_x86 test
+${BUILD}/tests/vb2_sha256_x86_tests: \
+ ${BUILD}/firmware/2lib/2sha256_x86.o
+${BUILD}/tests/vb2_sha256_x86_tests: \
+ LIBS += ${BUILD}/firmware/2lib/2sha256_x86.o
+
+.PHONY: install_dut_test
+install_dut_test: ${DUT_TEST_BINS}
+ifneq ($(strip ${DUT_TEST_BINS}),)
+ @${PRINTF} " INSTALL DUT TESTS\n"
+ ${Q}mkdir -p ${DUT_TEST_DIR}
+ ${Q}${INSTALL} -t ${DUT_TEST_DIR} $^
+endif
+
# ----------------------------------------------------------------------------
# Fuzzers
@@ -1171,7 +1182,7 @@
${BUILD}/tests/%: LDLIBS += -lrt -luuid
${BUILD}/tests/%: LIBS += ${TESTLIB}
-ifeq (${TPM2_MODE},)
+ifeq ($(filter-out 0,${TPM2_MODE}),)
# TODO(apronin): tests for TPM2 case?
TLCL_TEST_BINS = $(addprefix ${BUILD}/,${TLCL_TEST_NAMES})
${TLCL_TEST_BINS}: OBJS += ${BUILD}/tests/tpm_lite/tlcl_tests.o
@@ -1208,7 +1219,7 @@
# Targets that exist just to run tests
.PHONY: test_setup
-test_setup:: cgpt utils_sdk utils_board futil tests
+test_setup:: cgpt ${UTIL_FILES_SDK} ${UTIL_FILES_BOARD} futil tests
# Qemu setup for cross-compiled tests. Need to copy qemu binary into the
# sysroot.
@@ -1261,7 +1272,7 @@
runmisctests: install_for_test
${RUNTEST} ${BUILD_RUN}/tests/gpt_misc_tests
${RUNTEST} ${BUILD_RUN}/tests/subprocess_tests
-ifeq (${MOCK_TPM}${TPM2_MODE},)
+ifeq ($(filter-out 0,${MOCK_TPM})$(filter-out 0,${TPM2_MODE}),)
# tlcl_tests only works when MOCK_TPM is disabled
${RUNTEST} ${BUILD_RUN}/tests/tlcl_tests
endif
@@ -1345,7 +1356,7 @@
-o ${COV_INFO}.firmware
.PHONY: coverage
-ifeq (${COV},)
+ifeq ($(filter-out 0,${COV}),)
coverage:
$(error Build coverage like this: make clean && COV=1 make coverage)
else
diff --git a/OWNERS b/OWNERS
index 74ba71a..21ecb22 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,5 @@
jwerner@chromium.org
yupingso@chromium.org
-furquan@chromium.org
+twawrzynczak@chromium.org
hungte@chromium.org
*
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg
index 54d538d..9f66545 100644
--- a/PRESUBMIT.cfg
+++ b/PRESUBMIT.cfg
@@ -1,5 +1,6 @@
[Hook Overrides]
branch_check: true
+cargo_clippy_check: true
checkpatch_check: true
long_line_check: false
signoff_check: true
@@ -10,3 +11,6 @@
[Hook Overrides Options]
cros_license_check: --exclude_regex=^\.checkpatch\.conf$
+
+cargo_clippy_check:
+ --project=rust/vboot_reference-sys
diff --git a/README b/README
index 04ab0c9..1787d4d 100644
--- a/README
+++ b/README
@@ -48,6 +48,9 @@
Tools and scripts used to generate and use new signing keypairs. These are
typically used only on a secure machine.
+rust/
+
+ Rust bindings for vboot_reference. See rust/README.md for more details.
--------------------
Building and testing
diff --git a/cgpt/cgpt_nor.c b/cgpt/cgpt_nor.c
index 2e43918..1530271 100644
--- a/cgpt/cgpt_nor.c
+++ b/cgpt/cgpt_nor.c
@@ -70,7 +70,7 @@
return status;
}
-int ForkExecL(const char *cwd, const char *cmd, ...) {
+static int ForkExecL(const char *cwd, const char *cmd, ...) {
int argc;
va_list ap;
va_start(ap, cmd);
@@ -199,6 +199,10 @@
return nftw(dir, remove_file_or_dir, 20, FTW_DEPTH | FTW_PHYS);
}
+#define FLASHROM_RW_GPT_PRI "RW_GPT_PRIMARY:rw_gpt_1",
+#define FLASHROM_RW_GPT_SEC "RW_GPT_SECONDARY:rw_gpt_2"
+#define FLASHROM_RW_GPT "RW_GPT:rw_gpt"
+
// Read RW_GPT from NOR flash to "rw_gpt" in a temp dir |temp_dir_template|.
// |temp_dir_template| is passed to mkdtemp() so it must satisfy all
// requirements by mkdtemp.
@@ -225,7 +229,7 @@
Error("Cannot change directory.\n");
goto out_free;
}
- const char *const argv[] = {FLASHROM_PATH, "-i", "RW_GPT:rw_gpt", "-r"};
+ const char *const argv[] = {FLASHROM_PATH, "-i", FLASHROM_RW_GPT, "-r"};
// Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
// output.
if (subprocess_run(argv, &subprocess_null, &subprocess_null, NULL) != 0) {
@@ -266,7 +270,7 @@
Error("Cannot change directory.\n");
goto out_free;
}
- const char *const argv1[] = {FLASHROM_PATH, "-i", "RW_GPT_PRIMARY:rw_gpt_1",
+ const char *const argv1[] = {FLASHROM_PATH, "-i", FLASHROM_RW_GPT_PRI,
"-w", "--noverify-all"};
// Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
// output.
@@ -274,7 +278,7 @@
Warning("Cannot write the 1st half of rw_gpt back with flashrom.\n");
nr_fails++;
}
- const char *const argv2[] = {FLASHROM_PATH, "-i", "RW_GPT_SECONDARY:rw_gpt_2",
+ const char *const argv2[] = {FLASHROM_PATH, "-i", FLASHROM_RW_GPT_SEC,
"-w", "--noverify-all"};
// Redirect stdout to /dev/null so that flashrom does not muck up cgpt's
// output.
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c
index 593a12c..c041d8a 100644
--- a/firmware/2lib/2api.c
+++ b/firmware/2lib/2api.c
@@ -67,8 +67,8 @@
/*
* Check for recovery. Note that this function returns void, since any
* errors result in requesting recovery. That's also why we don't
- * return error from failures in the preceding two steps; those
- * failures simply cause us to detect recovery mode here.
+ * return error from failures in the preceding steps; those failures
+ * simply cause us to detect recovery mode here.
*/
vb2_check_recovery(ctx);
@@ -89,6 +89,9 @@
if (ctx->flags & VB2_CONTEXT_DISPLAY_INIT)
sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE;
+ /* Decide the boot mode */
+ vb2_set_boot_mode(ctx);
+
/* Return error if recovery is needed */
if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
/* Always clear RAM when entering recovery mode */
diff --git a/firmware/2lib/2auxfw_sync.c b/firmware/2lib/2auxfw_sync.c
index da7bc97..eaea1d4 100644
--- a/firmware/2lib/2auxfw_sync.c
+++ b/firmware/2lib/2auxfw_sync.c
@@ -28,40 +28,6 @@
}
/**
- * Update the specified auxfw and verify the update succeeded.
- *
- * @param ctx Vboot2 context
- * @return VB2_SUCCESS, or non-zero error code.
- */
-static vb2_error_t update_auxfw(struct vb2_context *ctx)
-{
- vb2_error_t rv;
-
- VB2_DEBUG("Updating auxfw\n");
-
- /*
- * The underlying platform is expected to know how and where to find the
- * firmware image for all auxfw devices.
- */
- rv = vb2ex_auxfw_update();
- if (rv != VB2_SUCCESS) {
- VB2_DEBUG("vb2ex_auxfw_update() returned %d\n", rv);
-
- /*
- * The device may need a reboot. It may need to unprotect the
- * region before updating, or may need to reboot after updating.
- * Either way, it's not an error requiring recovery mode.
- *
- * If we fail for any other reason, trigger recovery mode.
- */
- if (rv != VB2_REQUEST_REBOOT_EC_TO_RO)
- vb2api_fail(ctx, VB2_RECOVERY_AUXFW_UPDATE, rv);
- }
-
- return rv;
-}
-
-/**
* Decides if auxfw sync is allowed to be performed.
*
* If sync is allowed, invokes the external callback,
@@ -90,7 +56,8 @@
VB2_TRY(auxfw_sync_check_update(ctx, &fw_update));
if (fw_update > VB2_AUXFW_NO_UPDATE) {
- VB2_TRY(update_auxfw(ctx));
+ VB2_DEBUG("Updating auxfw\n");
+ VB2_TRY(vb2ex_auxfw_update(), ctx, VB2_RECOVERY_AUXFW_UPDATE);
/*
* auxfw update is applied successfully. Request EC reboot to
* RO, so that the chips that had FW update get reset to a
diff --git a/firmware/2lib/2ec_sync.c b/firmware/2lib/2ec_sync.c
index 20490e0..e75313b 100644
--- a/firmware/2lib/2ec_sync.c
+++ b/firmware/2lib/2ec_sync.c
@@ -160,10 +160,10 @@
struct vb2_shared_data *sd = vb2_get_sd(ctx);
int in_rw = 0;
/*
- * We don't use vb2ex_ec_trusted, which checks EC_IN_RW. It is
- * controlled by cr50 but on some platforms, cr50 can't know when a EC
- * resets. So, we trust what EC-RW says. If it lies it's in RO, we'll
- * flash RW while it's in RW.
+ * We don't use VB2_CONTEXT_EC_TRUSTED, which checks if not EC_IN_RW.
+ * It is controlled by cr50 but on some platforms, cr50 can't know when
+ * a EC resets. So, we trust what EC-RW says. If it lies it's in RO,
+ * we'll flash RW while it's in RW.
*/
/* If we couldn't determine where the EC was, reboot to recovery. */
VB2_TRY(vb2ex_ec_running_rw(&in_rw),
diff --git a/firmware/2lib/2kernel.c b/firmware/2lib/2kernel.c
index 86fb286..5b18cad 100644
--- a/firmware/2lib/2kernel.c
+++ b/firmware/2lib/2kernel.c
@@ -164,7 +164,7 @@
/* Load recovery key from GBB. */
rv = vb2_gbb_read_recovery_key(ctx, &packed_key, NULL, &wb);
if (rv) {
- if (vb2api_allow_recovery(ctx))
+ if (ctx->boot_mode != VB2_BOOT_MODE_BROKEN_SCREEN)
VB2_DIE("GBB read recovery key failed.\n");
else
/*
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index efa33a8..6e92690 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -154,7 +154,6 @@
else
/* Recovery was forced. Override recovery reason */
sd->recovery_reason = VB2_RECOVERY_RO_MANUAL;
- sd->flags |= VB2_SD_FLAG_MANUAL_RECOVERY;
}
/* If recovery reason is non-zero, tell caller we need recovery mode */
@@ -164,6 +163,8 @@
sd->recovery_reason,
vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE));
}
+
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
}
vb2_error_t vb2_fw_init_gbb(struct vb2_context *ctx)
@@ -377,7 +378,7 @@
vb2_error_t vb2api_enable_developer_mode(struct vb2_context *ctx)
{
- if (!vb2api_allow_recovery(ctx)) {
+ if (ctx->boot_mode != VB2_BOOT_MODE_MANUAL_RECOVERY) {
VB2_DEBUG("ERROR: Can only enable developer mode from manual "
"recovery mode\n");
return VB2_ERROR_API_ENABLE_DEV_NOT_ALLOWED;
@@ -391,9 +392,6 @@
flags |= VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE;
vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS, flags);
- if (BOOT_EXTERNAL_ON_DEV)
- vb2_nv_set(ctx, VB2_NV_DEV_BOOT_EXTERNAL, 1);
-
VB2_DEBUG("Mode change will take effect on next reboot\n");
return VB2_SUCCESS;
@@ -416,30 +414,6 @@
VB2_DEBUG("Diagnostics requested\n");
}
-test_mockable
-int vb2api_allow_recovery(struct vb2_context *ctx)
-{
- if (ctx->flags & VB2_CONTEXT_NO_BOOT)
- return 0;
-
- /* VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY forces this to always return
- true. */
- if (vb2_get_gbb(ctx)->flags & VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY)
- return 1;
-
- /*
- * If EC is in RW, it implies recovery wasn't manually requested.
- * On some platforms, EC_IN_RW can't be reset by the EC, thus, this may
- * return false (=RW). That's ok because if recovery is manual, we will
- * get the right signal and that's the case we care about.
- */
- if (!(ctx->flags & VB2_CONTEXT_EC_TRUSTED) && !vb2ex_ec_trusted())
- return 0;
-
- /* Now we confidently check the recovery switch state at boot */
- return !!(vb2_get_sd(ctx)->flags & VB2_SD_FLAG_MANUAL_RECOVERY);
-}
-
void vb2_clear_recovery(struct vb2_context *ctx)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
@@ -451,13 +425,13 @@
reason, subcode,
vb2_get_recovery_reason_string(reason));
- /* Clear recovery request for both manual and non-manual. */
+ /* Clear recovery request for both the manual recovery and the broken
+ screen. */
vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, VB2_RECOVERY_NOT_REQUESTED);
vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 0);
- /* But stow recovery reason as subcode for non-manual recovery. */
- if ((ctx->flags & VB2_CONTEXT_RECOVERY_MODE) &&
- !vb2api_allow_recovery(ctx)) {
+ /* But stow recovery reason as subcode for the broken screen. */
+ if (ctx->boot_mode == VB2_BOOT_MODE_BROKEN_SCREEN) {
VB2_DEBUG("Stow recovery reason as subcode (%#x)\n",
sd->recovery_reason);
vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, sd->recovery_reason);
@@ -734,3 +708,35 @@
buf[DEBUG_INFO_MAX_LENGTH] = '\0';
return buf;
}
+
+void vb2_set_boot_mode(struct vb2_context *ctx)
+{
+ struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ struct vb2_gbb_header *gbb = vb2_get_gbb(ctx);
+
+ /* Cast boot mode to non-constant and assign */
+ enum vb2_boot_mode *boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode;
+ *boot_mode = VB2_BOOT_MODE_NORMAL;
+
+ /*
+ * 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.
+ */
+ if ((ctx->flags & VB2_CONTEXT_FORCE_RECOVERY_MODE) &&
+ !(ctx->flags & VB2_CONTEXT_NO_BOOT) &&
+ (ctx->flags & VB2_CONTEXT_EC_TRUSTED)) {
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
+ } else if (sd->recovery_reason) {
+ if (gbb->flags & VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY)
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
+ else
+ *boot_mode = VB2_BOOT_MODE_BROKEN_SCREEN;
+ } else if (vb2api_diagnostic_ui_enabled(ctx) &&
+ vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) {
+ *boot_mode = VB2_BOOT_MODE_DIAGNOSTICS;
+ } else if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) {
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
+ }
+}
diff --git a/firmware/2lib/2stub.c b/firmware/2lib/2stub.c
index 956b4bb..da754ad 100644
--- a/firmware/2lib/2stub.c
+++ b/firmware/2lib/2stub.c
@@ -75,12 +75,6 @@
/* auxfw and EC-related stubs */
__attribute__((weak))
-int vb2ex_ec_trusted(void)
-{
- return 1;
-}
-
-__attribute__((weak))
vb2_error_t vb2ex_ec_running_rw(int *in_rw)
{
*in_rw = 0;
@@ -180,13 +174,6 @@
}
__attribute__((weak))
-uint32_t vb2ex_prepare_log_screen(enum vb2_screen screen, uint32_t locale_id,
- const char *str)
-{
- return 1;
-}
-
-__attribute__((weak))
vb2_error_t vb2ex_diag_get_storage_health(const char **out)
{
*out = "mock";
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 1f9d70f..1430111 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -259,6 +259,58 @@
VB2_CONTEXT_DEV_BOOT_ALTFW_ALLOWED = (1 << 27),
};
+/* Boot mode decided in vb2api_fw_phase1.
+ *
+ * Boot mode is a constant set by verified boot and may be read (but should not
+ * be set or cleared) by the caller.
+ * The boot modes are mutually exclusive. If a boot fulfill more than one
+ * constraints of the listing boot modes, it will be set to the most important
+ * one. The priority is the same as the listing order.
+ */
+enum vb2_boot_mode {
+ /* Undefined, The boot mode is not set. */
+ VB2_BOOT_MODE_UNDEFINED = 0,
+
+ /*
+ * Manual recovery boot, regardless of dev mode state.
+ *
+ * VB2_CONTEXT_RECOVERY_MODE is set and the recovery is physically
+ * requested (a.k.a. Manual recovery). All other recovery requests
+ * including manual recovery requested by a (compromised) host will end
+ * up with a broken screen.
+ */
+ VB2_BOOT_MODE_MANUAL_RECOVERY = 1,
+
+ /*
+ * Broken screen.
+ *
+ * If a recovery boot is not a manual recovery (a.k.a. not requested
+ * physically), the recovery is not allowed and will end up with
+ * broken screen.
+ */
+ VB2_BOOT_MODE_BROKEN_SCREEN = 2,
+
+ /*
+ * Diagnostic boot.
+ *
+ * If diagnostic boot is enabled (a.k.a. vb2api_diagnostic_ui_enabled)
+ * and the nvdata contains VB2_NV_DIAG_REQUEST from previous boot, it
+ * will boot to diagnostic mode.
+ */
+ VB2_BOOT_MODE_DIAGNOSTICS = 3,
+
+ /*
+ * Developer boot: self-signed kernel okay.
+ *
+ * The developer mode switch is set (a.k.a. VB2_CONTEXT_DEVELOPER_MODE)
+ * and we are in the developer boot mode.
+ */
+ VB2_BOOT_MODE_DEVELOPER = 4,
+
+ /* Normal boot: kernel must be verified. */
+ VB2_BOOT_MODE_NORMAL = 5,
+};
+
/* Helper for aligning fields in vb2_context. */
#define VB2_PAD_STRUCT3(size, align, count) \
uint8_t _pad##count[align - (((size - 1) % align) + 1)]
@@ -333,6 +385,16 @@
*/
uint8_t secdata_fwmp[VB2_SECDATA_FWMP_MAX_SIZE];
VB2_PAD_STRUCT(VB2_SECDATA_FWMP_MAX_SIZE, 8);
+
+ /**********************************************************************
+ * Fields below added in struct version 3.1.
+ */
+
+ /*
+ * Mutually exclusive boot mode.
+ * This constant is initialized after calling vb2api_fw_phase1().
+ */
+ const enum vb2_boot_mode boot_mode;
};
/* Resource index for vb2ex_read_resource() */
@@ -950,19 +1012,6 @@
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
@@ -1303,14 +1352,6 @@
vb2_error_t vb2api_ec_sync(struct vb2_context *ctx);
/**
- * This is called only if the system implements a keyboard-based (virtual)
- * developer switch. It must return true only if the system has an embedded
- * controller which is provably running in its RO firmware at the time the
- * function is called.
- */
-int vb2ex_ec_trusted(void);
-
-/**
* Check if the EC is currently running rewritable code.
*
* If the EC is in RO code, sets *in_rw=0.
@@ -1446,113 +1487,6 @@
#define VB2_CLR_BIT(mask, index) ((mask) &= ~((uint32_t)1 << (index)))
#define VB2_GET_BIT(mask, index) ((mask) & ((uint32_t)1 << (index)))
-/* Screens. */
-enum vb2_screen {
- /* Wait screen for EC sync and AUXFW sync */
- VB2_SCREEN_FIRMWARE_SYNC = 0x100,
- /* Broken screen */
- VB2_SCREEN_RECOVERY_BROKEN = 0x110,
- /* Advanced options */
- VB2_SCREEN_ADVANCED_OPTIONS = 0x120,
- /* Language selection screen */
- VB2_SCREEN_LANGUAGE_SELECT = 0x130,
- /* Debug info */
- VB2_SCREEN_DEBUG_INFO = 0x140,
- /* Firmware log */
- VB2_SCREEN_FIRMWARE_LOG = 0x150,
- /* First recovery screen to select recovering from disk or phone */
- VB2_SCREEN_RECOVERY_SELECT = 0x200,
- /* Invalid recovery media inserted */
- VB2_SCREEN_RECOVERY_INVALID = 0x201,
- /* Confirm transition to developer mode */
- VB2_SCREEN_RECOVERY_TO_DEV = 0x202,
- /* Recovery using phone */
- VB2_SCREEN_RECOVERY_PHONE_STEP1 = 0x210,
- VB2_SCREEN_RECOVERY_PHONE_STEP2 = 0x211,
- /* Recovery using disk */
- VB2_SCREEN_RECOVERY_DISK_STEP1 = 0x220,
- VB2_SCREEN_RECOVERY_DISK_STEP2 = 0x221,
- VB2_SCREEN_RECOVERY_DISK_STEP3 = 0x222,
- /* Developer mode screen */
- VB2_SCREEN_DEVELOPER_MODE = 0x300,
- /* Confirm transition to normal mode */
- VB2_SCREEN_DEVELOPER_TO_NORM = 0x310,
- /* Developer boot from external disk */
- VB2_SCREEN_DEVELOPER_BOOT_EXTERNAL = 0x320,
- /* Invalid external disk inserted */
- VB2_SCREEN_DEVELOPER_INVALID_DISK = 0x330,
- /* Select alternate bootloader ("altfw") */
- VB2_SCREEN_DEVELOPER_SELECT_ALTFW = 0x340,
- /* Diagnostic tools */
- VB2_SCREEN_DIAGNOSTICS = 0x400,
- /* Storage diagnostic screen */
- VB2_SCREEN_DIAGNOSTICS_STORAGE_HEALTH = 0x410,
- VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_SHORT = 0x411,
- VB2_SCREEN_DIAGNOSTICS_STORAGE_TEST_EXTENDED = 0x412,
- /* Memory diagnostic screens */
- VB2_SCREEN_DIAGNOSTICS_MEMORY_QUICK = 0x420,
- VB2_SCREEN_DIAGNOSTICS_MEMORY_FULL = 0x421,
-};
-
-enum vb2_ui_error {
- /* No error */
- VB2_UI_ERROR_NONE = 0,
- /* Dev mode already enabled */
- VB2_UI_ERROR_DEV_MODE_ALREADY_ENABLED,
- /* Untrusted confirmation */
- 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 */
- VB2_UI_ERROR_ALTFW_DISABLED,
- /* No alternate bootloader was found */
- VB2_UI_ERROR_ALTFW_EMPTY,
- /* Alternate bootloader failed */
- VB2_UI_ERROR_ALTFW_FAILED,
- /* Debug info screen initialization failed */
- VB2_UI_ERROR_DEBUG_LOG,
- /* Firmware log screen initialization failed */
- VB2_UI_ERROR_FIRMWARE_LOG,
- /* Diagnostics internal failure */
- VB2_UI_ERROR_DIAGNOSTICS,
-};
-
-/**
- * Display UI screen.
- *
- * @param screen Screen to display.
- * @param locale_id Id of current locale.
- * @param selected_item Index of the selected menu item. If the screen
- * doesn't have a menu, this value will be ignored.
- * @param disabled_item_mask Mask for disabled menu items. Bit (1 << idx)
- * indicates whether item 'idx' is disabled.
- * A disabled menu item is visible and selectable,
- * with a different button style.
- * @param hidden_item_mask Mask for hidden menu items. Bit (1 << idx)
- * indicates whether item 'idx' is hidden.
- * A hidden menu item is neither visible nor
- * selectable.
- * @param timer_disabled Whether timer is disabled or not. Some screen
- * descriptions will depend on this value.
- * @param current_page Current page number for a log screen. If the
- * screen doesn't show logs, this value will be
- * ignored.
- * @param error_code Error code if an error occurred.
- * @return VB2_SUCCESS, or error code on error.
- */
-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);
-
/**
* Check that physical presence button is currently pressed by the user.
*
@@ -1645,22 +1579,6 @@
const char *vb2ex_get_firmware_log(int reset);
/**
- * Specify the string to be used for an upcoming log screen display.
- *
- * Before a vb2ex_display_ui() call is made for a screen which displays logs,
- * the log string should be provided via this function. The total number of
- * pages in the log string is returned. If the log string ever changes, this
- * function should be called again before the next vb2ex_display_ui() call.
- *
- * @param screen Screen to display the log.
- * @param locale_id Id of current locale.
- * @param str The log string to display.
- * @return The number of pages after pagination. 0 if none or error.
- */
-uint32_t vb2ex_prepare_log_screen(enum vb2_screen screen, uint32_t locale_id,
- const char *str);
-
-/**
* Get the health info of the storage.
*
* @param out For returning a read-only pointer of full log string which is
diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h
index 695f50d..d43f18a 100644
--- a/firmware/2lib/include/2common.h
+++ b/firmware/2lib/include/2common.h
@@ -10,6 +10,7 @@
#include "2api.h"
#include "2gbb.h"
+#include "2misc.h"
#include "2packed_key.h"
#include "2return_codes.h"
#include "2sha.h"
@@ -66,7 +67,8 @@
#define VB2_REC_OR_DIE(ctx, format, args...) do { \
VB2_DEBUG(format, ## args); \
- if (!(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { \
+ if ((vb2_get_sd(ctx)->status & VB2_SD_STATUS_RECOVERY_DECIDED) && \
+ !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) { \
vb2ex_abort(); \
for (;;); \
} \
diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h
index b36e127..3d29287 100644
--- a/firmware/2lib/include/2misc.h
+++ b/firmware/2lib/include/2misc.h
@@ -191,4 +191,19 @@
*/
void vb2_fill_dev_boot_flags(struct vb2_context *ctx);
+/**
+ * Determine and set a mutually exclusive boot mode in the vboot context.
+ *
+ * Determine the most relevant boot mode for current boot, store into
+ * ctx->boot_mode, which is a ctx field introduced in struct version 3.1.
+ *
+ * This function should be only called by vb2api_fw_phase1.
+ * The vb2api_fw_phase1 should call this function at its end phase once and all
+ * the following steps should directly access ctx->boot_mode to retrieve the
+ * most relevant boot mode.
+ *
+ * @param ctx Vboot context.
+ */
+void vb2_set_boot_mode(struct vb2_context *ctx);
+
#endif /* VBOOT_REFERENCE_2MISC_H_ */
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 0dc7c44..176c2c6 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -29,7 +29,7 @@
*/
VB2_REQUEST = 0x1000,
- /* Calling firmware requested shutdown via VbExIsShutdownRequested() */
+ /* Calling firmware requested shutdown */
VB2_REQUEST_SHUTDOWN = 0x1001,
/* Calling firmware needs to perform a reboot */
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index ea193d7..3e2c422 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -23,8 +23,14 @@
/* Flags for vb2_shared_data.flags */
enum vb2_shared_data_flags {
- /* User has explicitly and physically requested recovery */
- VB2_SD_FLAG_MANUAL_RECOVERY = (1 << 0),
+ /*
+ * VB2_SD_FLAG_MANUAL_RECOVERY (1 << 0) is deprecated. This flag is not
+ * necessary since the introduction of persistent context (CL:1716351).
+ * With introducing vb2_boot_mode and differentiating between manual
+ * recovery and broken screen (CL:3274699), it is suggested to leverage
+ * the vb2_boot_mode instead to determine if the user has physically
+ * requested recovery.
+ */
/* Developer mode is enabled */
VB2_SD_FLAG_DEV_MODE_ENABLED = (1 << 1),
@@ -85,6 +91,8 @@
/* EC Sync completed successfully */
VB2_SD_STATUS_EC_SYNC_COMPLETE = (1 << 6),
+ /* Have checked whether we are booting into recovery mode or not. */
+ VB2_SD_STATUS_RECOVERY_DECIDED = (1 << 7),
};
/* "V2SD" = vb2_shared_data.magic */
@@ -92,7 +100,7 @@
/* Current version of vb2_shared_data struct */
#define VB2_SHARED_DATA_VERSION_MAJOR 3
-#define VB2_SHARED_DATA_VERSION_MINOR 0
+#define VB2_SHARED_DATA_VERSION_MINOR 1
/* MAX_SIZE should not be changed without bumping up DATA_VERSION_MAJOR. */
#define VB2_CONTEXT_MAX_SIZE 384
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index f19ee74..ce3ac2d 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -89,6 +89,11 @@
*/
vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags);
+/* miniOS flags */
+
+/* Boot from non-active miniOS partition only */
+#define VB_MINIOS_FLAG_NON_ACTIVE (1 << 0)
+
/**
* Attempt loading a miniOS kernel from internal disk.
*
@@ -100,9 +105,11 @@
* VB2_SUCCESS.
*
* @param ctx Vboot context
+ * @param minios_flags Flags for miniOS
* @return VB2_SUCCESS or the most specific VB2_ERROR_LK error.
*/
-vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx);
+vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx,
+ uint32_t minios_flags);
/*****************************************************************************/
/* Disk access (previously in boot_device.h) */
@@ -281,33 +288,6 @@
*/
void VbExStreamClose(VbExStream_t stream);
-/*****************************************************************************/
-/* Misc */
-
-/**
- * Check if the firmware needs to shut down the system.
- *
- * Returns a non-zero VB_SHUTDOWN_REQUEST mask indicating the reason(s) for
- * shutdown if a shutdown is being requested (see VB_SHUTDOWN_REQUEST_*), or 0
- * if a shutdown is not being requested.
- *
- * NOTE: When we're displaying a screen, pressing the power button should shut
- * down the computer. We need a way to break out of our control loop so this
- * can occur cleanly.
- */
-uint32_t VbExIsShutdownRequested(void);
-
-/*
- * Shutdown requested for a reason which is not defined among other
- * VB_SHUTDOWN_REQUEST_* values. This must be defined as 1 for backward
- * compatibility with old versions of the API.
- */
-#define VB_SHUTDOWN_REQUEST_OTHER 0x00000001
-/* Shutdown requested due to a lid switch being closed. */
-#define VB_SHUTDOWN_REQUEST_LID_CLOSED 0x00000002
-/* Shutdown requested due to a power button being pressed. */
-#define VB_SHUTDOWN_REQUEST_POWER_BUTTON 0x00000004
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/firmware/lib/include/load_kernel_fw.h b/firmware/lib/include/load_kernel_fw.h
index af45470..76d2556 100644
--- a/firmware/lib/include/load_kernel_fw.h
+++ b/firmware/lib/include/load_kernel_fw.h
@@ -30,11 +30,12 @@
* @param ctx Vboot context
* @param params Params specific to loading the kernel
* @param disk_info Disk from which to read kernel
+ * @param minios_flags Flags for miniOS
*
* Returns VB2_SUCCESS if successful. If unsuccessful, returns an error code.
*/
vb2_error_t LoadMiniOsKernel(struct vb2_context *ctx,
VbSelectAndLoadKernelParams *params,
- VbDiskInfo *disk_info);
+ VbDiskInfo *disk_info, uint32_t minios_flags);
#endif /* VBOOT_REFERENCE_LOAD_KERNEL_FW_H_ */
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 2abd57e..9e89620 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -62,7 +62,8 @@
}
static vb2_error_t VbTryLoadKernelImpl(struct vb2_context *ctx,
- uint32_t disk_flags, int minios)
+ uint32_t disk_flags, int minios,
+ uint32_t minios_flags)
{
vb2_error_t rv = VB2_ERROR_LK_NO_DISK_FOUND;
VbDiskInfo* disk_info = NULL;
@@ -96,7 +97,7 @@
if (minios) {
new_rv = LoadMiniOsKernel(ctx, kparams_ptr,
- &disk_info[i]);
+ &disk_info[i], minios_flags);
VB2_DEBUG("LoadMiniOsKernel() = %#x\n", new_rv);
} else {
new_rv = LoadKernel(ctx, kparams_ptr, &disk_info[i]);
@@ -142,13 +143,14 @@
test_mockable
vb2_error_t VbTryLoadKernel(struct vb2_context *ctx, uint32_t disk_flags)
{
- return VbTryLoadKernelImpl(ctx, disk_flags, 0);
+ return VbTryLoadKernelImpl(ctx, disk_flags, 0, 0);
}
test_mockable
-vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx)
+vb2_error_t VbTryLoadMiniOsKernel(struct vb2_context *ctx,
+ uint32_t minios_flags)
{
- return VbTryLoadKernelImpl(ctx, VB_DISK_FLAG_FIXED, 1);
+ return VbTryLoadKernelImpl(ctx, VB_DISK_FLAG_FIXED, 1, minios_flags);
}
vb2_error_t VbSelectAndLoadKernel(struct vb2_context *ctx,
@@ -180,13 +182,15 @@
}
/*
- * If in non-manual recovery mode, save the recovery reason as subcode.
+ * If in the broken screen, save the recovery reason as subcode.
* Otherwise, clear any leftover recovery requests or subcodes.
*/
vb2_clear_recovery(ctx);
/* Select boot path */
- if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
+ switch (ctx->boot_mode) {
+ case VB2_BOOT_MODE_MANUAL_RECOVERY:
+ case VB2_BOOT_MODE_BROKEN_SCREEN:
/* If we're in recovery mode just to do memory retraining, all
we need to do is reboot. */
if (sd->recovery_reason == VB2_RECOVERY_TRAIN_AND_REBOOT) {
@@ -211,12 +215,12 @@
VB2_DEBUG("NO_BOOT in RECOVERY mode\n");
/* Recovery boot. This has UI. */
- if (vb2api_allow_recovery(ctx))
+ if (ctx->boot_mode == VB2_BOOT_MODE_MANUAL_RECOVERY)
VB2_TRY(vb2ex_manual_recovery_ui(ctx));
else
VB2_TRY(vb2ex_broken_screen_ui(ctx));
- } else if (vb2api_diagnostic_ui_enabled(ctx) &&
- vb2_nv_get(ctx, VB2_NV_DIAG_REQUEST)) {
+ break;
+ case VB2_BOOT_MODE_DIAGNOSTICS:
/*
* Need to clear the request flag and commit nvdata changes
* immediately to avoid booting back into diagnostic tool when a
@@ -232,12 +236,16 @@
* return either of reboot or shutdown.
*/
return VB2_REQUEST_REBOOT;
- } else if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) {
+ case VB2_BOOT_MODE_DEVELOPER:
/* Developer boot. This has UI. */
VB2_TRY(vb2ex_developer_ui(ctx));
- } else {
+ break;
+ case VB2_BOOT_MODE_NORMAL:
/* Normal boot */
VB2_TRY(vb2_normal_boot(ctx));
+ break;
+ default:
+ return VB2_ERROR_ESCAPE_NO_BOOT;
}
/*
@@ -245,6 +253,7 @@
* GBB flag disables software sync.
*/
if (!(gbb_flags & VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC)
+ && (ctx->flags & VB2_CONTEXT_EC_SYNC_SUPPORTED)
&& (ctx->flags & VB2_CONTEXT_NO_BOOT)) {
VB2_DEBUG("Blocking escape from NO_BOOT mode.\n");
vb2api_fail(ctx, VB2_RECOVERY_ESCAPE_NO_BOOT, 0);
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index 34a8a42..1edf4a5 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -6,6 +6,7 @@
* (Firmware portion)
*/
+#include "2api.h"
#include "2common.h"
#include "2misc.h"
#include "2nvstorage.h"
@@ -31,34 +32,6 @@
#define LOWEST_TPM_VERSION 0xffffffff
-enum vb2_boot_mode {
- /* Normal boot: kernel must be verified. */
- VB2_BOOT_MODE_NORMAL = 0,
-
- /* Recovery boot, regardless of dev mode state. */
- VB2_BOOT_MODE_RECOVERY = 1,
-
- /* Developer boot: self-signed kernel okay. */
- VB2_BOOT_MODE_DEVELOPER = 2,
-};
-
-/**
- * Return the current boot mode (normal, recovery, or dev).
- *
- * @param ctx Vboot context
- * @return Current boot mode (see vb2_boot_mode enum).
- */
-static enum vb2_boot_mode get_boot_mode(struct vb2_context *ctx)
-{
- if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
- return VB2_BOOT_MODE_RECOVERY;
-
- if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE)
- return VB2_BOOT_MODE_DEVELOPER;
-
- return VB2_BOOT_MODE_NORMAL;
-}
-
/**
* Check if a valid keyblock is required.
*
@@ -69,7 +42,7 @@
static int need_valid_keyblock(struct vb2_context *ctx)
{
/* Normal and recovery modes always require official OS */
- if (get_boot_mode(ctx) != VB2_BOOT_MODE_DEVELOPER)
+ if (ctx->boot_mode != VB2_BOOT_MODE_DEVELOPER)
return 1;
/* FWMP can require developer mode to use signed kernels */
@@ -264,9 +237,8 @@
}
/* Check for rollback of key version except in recovery mode. */
- enum vb2_boot_mode boot_mode = get_boot_mode(ctx);
uint32_t key_version = keyblock->data_key.key_version;
- if (boot_mode != VB2_BOOT_MODE_RECOVERY) {
+ if (ctx->boot_mode != VB2_BOOT_MODE_MANUAL_RECOVERY) {
if (key_version < (sd->kernel_version_secdata >> 16)) {
keyblock_valid = 0;
if (need_keyblock_valid) {
@@ -288,7 +260,7 @@
}
/* If in developer mode and using key hash, check it. */
- if (boot_mode == VB2_BOOT_MODE_DEVELOPER &&
+ if (ctx->boot_mode == VB2_BOOT_MODE_DEVELOPER &&
vb2_secdata_fwmp_get_flag(ctx, VB2_SECDATA_FWMP_DEV_USE_KEY_HASH)) {
VB2_TRY(vb2_verify_kernel_dev_key_hash(ctx, keyblock));
}
@@ -356,7 +328,7 @@
/* If not in recovery mode, check for rollback of the kernel version. */
if (need_keyblock_valid &&
- boot_mode != VB2_BOOT_MODE_RECOVERY &&
+ ctx->boot_mode != VB2_BOOT_MODE_MANUAL_RECOVERY &&
sd->kernel_version < sd->kernel_version_secdata) {
VB2_DEBUG("Kernel version too low.\n");
return VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK;
@@ -607,12 +579,17 @@
*/
vb2_error_t LoadMiniOsKernel(struct vb2_context *ctx,
VbSelectAndLoadKernelParams *params,
- VbDiskInfo *disk_info)
+ VbDiskInfo *disk_info, uint32_t minios_flags)
{
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 (minios_flags & VB_MINIOS_FLAG_NON_ACTIVE)
+ rv = VB2_ERROR_UNKNOWN; /* Ignore active partition */
+ else
+ 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);
@@ -739,7 +716,7 @@
* non-officially-signed kernel, there's no rollback
* protection, so we can stop at the first valid kernel.
*/
- if (get_boot_mode(ctx) == VB2_BOOT_MODE_RECOVERY ||
+ if (ctx->boot_mode == VB2_BOOT_MODE_MANUAL_RECOVERY ||
!keyblock_valid) {
VB2_DEBUG("In recovery mode or dev-signed kernel\n");
break;
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c
index 5e08556..9335c8b 100644
--- a/firmware/stub/vboot_api_stub.c
+++ b/firmware/stub/vboot_api_stub.c
@@ -19,12 +19,6 @@
#include "vboot_test.h"
__attribute__((weak))
-uint32_t VbExIsShutdownRequested(void)
-{
- return 0;
-}
-
-__attribute__((weak))
vb2_error_t vb2ex_run_altfw(uint32_t altfw_id)
{
return VB2_SUCCESS;
diff --git a/futility/cmd_gscvd.c b/futility/cmd_gscvd.c
new file mode 100644
index 0000000..7fff293
--- /dev/null
+++ b/futility/cmd_gscvd.c
@@ -0,0 +1,1050 @@
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "fmap.h"
+#include "futility.h"
+#include "gsc_ro.h"
+#include "host_key21.h"
+#include "host_keyblock.h"
+#include "host_signature.h"
+
+/*
+ * for testing purposes let's use
+ * - tests/devkeys/arv_root.vbprivk as the root private key
+ * - tests/devkeys/arv_root.vbpubk as the root public key
+ * used for signing of the platform public key
+ * - tests/devkeys/arv_platform.vbprivk signing platform key
+ * - tests/devkeys/arv_platform.vbpubk - public key used for signature
+ * verification
+ *------------
+ * Command to create the signed public key block in ~/tmp/packed:
+ *
+ ./build/futility/futility vbutil_keyblock --pack ~/tmp/packed \
+ --datapubkey tests/devkeys/arv_platform.vbpubk \
+ --signprivate tests/devkeys/arv_root.vbprivk
+ *------------
+ * Command to fill RO_GSCVD FMAP area in an AP firmware file. The input AP
+ * firmware file is ~/tmp/image-guybrush.serial.bin, the output signed
+ * AP firmware file is ~/tmp/guybrush-signed:
+ *
+ ./build/futility/futility gscvd --outfile ~/tmp/guybrush-signed \
+ -R 818100:10000,f00000:100,f80000:2000,f8c000:1000,0x00804000:0x00000800 \
+ -k ~/tmp/packed -p tests/devkeys/arv_platform.vbprivk -b 5a5a4352 \
+ -r tests/devkeys/arv_root.vbpubk ~/tmp/image-guybrush.serial.bin
+ *------------
+ * Command to validate a previously signed AP firmware file. The hash is the
+ * sha256sum of tests/devkeys/kernel_subkey.vbpubk:
+ *
+ build/futility/futility gscvd ~/tmp/guybrush-signed \
+ 3d74429f35be8d34bcb425d4397e2218e6961afed456a78ce30047f5b54ed158
+ */
+
+/* Command line options processing support. */
+enum no_short_opts {
+ OPT_OUTFILE = 1000,
+};
+
+static const struct option long_opts[] = {
+ /* name hasarg *flag val */
+ {"outfile", 1, NULL, OPT_OUTFILE},
+ {"ranges", 1, NULL, 'R'},
+ {"board_id", 1, NULL, 'b'},
+ {"root_pub_key", 1, NULL, 'r'},
+ {"keyblock", 1, NULL, 'k'},
+ {"platform_priv", 1, NULL, 'p'},
+ {"help", 0, NULL, 'h'},
+ {}
+};
+
+static const char *short_opts = "R:b:hk:p:r:";
+
+static const char usage[] =
+ "\n"
+ "This utility creates an RO verification space in the Chrome OS AP\n"
+ "firmware image or allows to validate a previously prepared image\n"
+ "containing the RO verification space.\n\n"
+ "Usage: " MYNAME " gscvd PARAMS <AP FIRMWARE FILE> [<root key hash>]\n"
+ "\n\nCreation of RO Verification space:\n\n"
+ "Required PARAMS:\n"
+ " -R|--ranges STRING Comma separated colon delimited\n"
+ " hex tuples <offset>:<size>, the\n"
+ " areas of the RO covered by the\n"
+ " signature\n"
+ " -b|--board_id <hex value> The Board ID of the board for which\n"
+ " the image is being signed\n"
+ " -r|--root_pub_key <file> The main public key, in .vbpubk\n"
+ " format, used to verify platform\n"
+ " key\n"
+ " -k|--keyblock <file> Signed platform public key in\n"
+ " .keyblock format, used for run\n"
+ " time RO verifcation\n"
+ " -p|--platform_priv <file> Private platform key in .vbprivk\n"
+ " format, used for signing RO\n"
+ " verification data\n"
+ "Optional PARAMS:\n"
+ " [--outfile] OUTFILE Output firmware image containing\n"
+ " RO verification information\n"
+ "\n\n"
+ "Validation of RO Verification space:\n\n"
+ " The only required parameter is <AP FIRMWARE FILE>, if optional\n"
+ " <root key hash> is given, it is compared to the hash\n"
+ " of the root key found in <AP_FIRMWARE_FILE>.\n"
+ "\n\n"
+ " -h|--help Print this message\n\n";
+
+/* Structure helping to keep track of the file mapped into memory. */
+struct file_buf {
+ uint32_t len;
+ uint8_t *data;
+ int fd;
+ FmapAreaHeader *ro_gscvd;
+};
+
+/*
+ * Max number of RO ranges to cover. 32 is more than enough, this must be kept
+ * in sync with APRO_MAX_NUM_RANGES declaration in
+ * common/ap_ro_integrity_check.c in the Cr50 tree.
+ */
+#define MAX_RANGES 32
+
+/*
+ * Container keeping track of the set of ranges to include in hash
+ * calculation.
+ */
+struct gscvd_ro_ranges {
+ size_t range_count;
+ struct gscvd_ro_range ranges[MAX_RANGES];
+};
+
+/**
+ * Load the AP firmware file into memory.
+ *
+ * Map the requested file into memory, find RO_GSCVD area in the file, and
+ * cache the information in the passed in file_buf structure.
+ *
+ * @param file_name name of the AP firmware file
+ * @param file_buf pointer to the helper structure keeping information about
+ * the file
+ *
+ * @return 0 on success 1 on failure.
+ */
+static int load_ap_firmware(const char *file_name, struct file_buf *file)
+{
+ int fd;
+ int rv;
+
+ fd = open(file_name, O_RDWR);
+ if (fd < 0) {
+ ERROR("Can't open %s: %s\n", file_name,
+ strerror(errno));
+ return 1;
+ }
+
+ file->fd = fd;
+ do {
+ rv = 1;
+
+ if (futil_map_file(fd, MAP_RW, &file->data, &file->len)) {
+ file->data = NULL;
+ break;
+ }
+
+ if (!fmap_find_by_name(file->data, file->len, NULL, "RO_GSCVD",
+ &file->ro_gscvd)) {
+ ERROR("Could not find RO_GSCVD in the FMAP\n");
+ break;
+ }
+ rv = 0;
+ } while (false);
+
+ return rv;
+}
+
+/**
+ * Check if the passed in offset falls into the passed in FMAP area.
+ */
+static bool in_range(uint32_t offset, const FmapAreaHeader *ah)
+{
+ return (offset >= ah->area_offset) &&
+ (offset <= (ah->area_offset + ah->area_size));
+}
+
+/**
+ * Check if the passed in range fits into the passed in FMAP area.
+ */
+static bool range_fits(const struct gscvd_ro_range *range,
+ const FmapAreaHeader *ah)
+{
+ if (in_range(range->offset, ah) &&
+ in_range(range->offset + range->size, ah))
+ return true;
+
+ ERROR("Range %#x..+%#x does not fit in %s\n", range->offset,
+ range->size, ah->area_name);
+
+ return false;
+}
+
+/**
+ * Check if the passed in range overlaps with the area.
+ *
+ * @param range pointer to the range to check
+ * @param offset offset of the area to check against
+ * @param size size of the area to check against
+ *
+ * @return true if range overlaps with the area, false otherwise.
+ */
+static bool range_overlaps(const struct gscvd_ro_range *range, uint32_t offset,
+ size_t size)
+{
+ if (((range->offset + range->size) <= offset) ||
+ (offset + size) <= range->offset)
+ return false;
+
+ ERROR("Range %x..+%x overlaps with %x..+%zx\n", range->offset,
+ range->size, offset, size);
+
+ return true;
+}
+
+/*
+ * Check validity of the passed in ranges.
+ *
+ * All ranges must
+ * - fit into the WP_RO FMAP area
+ * - not overlap with the RO_GSCVD FMAP area
+ * - not overlap with each other
+ *
+ * @param ranges - pointer to the container of ranges to check
+ * @param file - pointer to the file layout descriptor
+ *
+ * @return zero on success, -1 on failures
+ */
+static int verify_ranges(const struct gscvd_ro_ranges *ranges,
+ const struct file_buf *file)
+{
+ size_t i;
+ FmapAreaHeader *wp_ro;
+ int errorcount;
+
+ if (!fmap_find_by_name(file->data, file->len, NULL, "WP_RO", &wp_ro)) {
+ ERROR("Could not find WP_RO in the FMAP\n");
+ return 1;
+ }
+
+ errorcount = 0;
+ for (i = 0; i < ranges->range_count; i++) {
+ size_t j;
+
+ /* Must fit into WP_RO. */
+ if (!range_fits(ranges->ranges + i, wp_ro))
+ errorcount++;
+
+ /* Must not overlap with RO_GSCVD. */
+ if (range_overlaps(ranges->ranges + i,
+ file->ro_gscvd->area_offset,
+ file->ro_gscvd->area_size))
+ errorcount++;
+
+ /* The last range is nothing to compare against. */
+ if (i == ranges->range_count - 1)
+ break;
+
+ /* Must not overlap with all following ranges. */
+ for (j = i + 1; j < ranges->range_count; j++)
+ if (range_overlaps(ranges->ranges + i,
+ ranges->ranges[j].offset,
+ ranges->ranges[j].size))
+ errorcount++;
+ }
+
+ return errorcount ? -1 : 0;
+}
+
+/**
+ * Parse range specification supplied by the user.
+ *
+ * The input is a string of the following format:
+ * <hex base>:<hex size>[,<hex base>:<hex size>[,...]]
+ *
+ * @param input user input, part of the command line
+ * @param output pointer to the ranges container
+ *
+ * @return zero on success, -1 on failure
+ */
+static int parse_ranges(const char *input, struct gscvd_ro_ranges *output)
+{
+ char *cursor;
+ char *delim;
+ char *str = strdup(input);
+ int rv = 0;
+
+ if (!str) {
+ ERROR("Failed to allocate memory for ranges string copy!\n");
+ return -1;
+ }
+
+ output->range_count = 0;
+ cursor = str;
+ do {
+ char *colon;
+ char *e;
+
+ if (output->range_count >= ARRAY_SIZE(output->ranges)) {
+ ERROR("Too many ranges!\n");
+ rv = -1;
+ break;
+ }
+
+ delim = strchr(cursor, ',');
+ if (delim)
+ *delim = '\0';
+ colon = strchr(cursor, ':');
+ if (!colon) {
+ rv = -1;
+ break;
+ }
+ *colon = '\0';
+
+ errno = 0;
+ output->ranges[output->range_count].offset =
+ strtol(cursor, &e, 16);
+ if (errno || *e) {
+ rv = -1;
+ break;
+ }
+
+ output->ranges[output->range_count].size =
+ strtol(colon + 1, &e, 16);
+ if (errno || *e) {
+ rv = -1;
+ break;
+ }
+
+ output->range_count++;
+ cursor = delim + 1;
+ /* Iterate until there is no more commas. */
+ } while (delim);
+
+ free(str);
+ if (rv)
+ ERROR("Misformatted ranges string\n");
+
+ return rv;
+}
+
+/**
+ * Calculate hash of the RO ranges.
+ *
+ * @param ap_firmware_file pointer to the AP firmware file layout descriptor
+ * @param ranges pointer to the container of ranges to include in hash
+ * calculation
+ * @param hash_alg algorithm to use for hashing
+ * @param digest memory to copy the calculated hash to
+ * @param digest_ size requested size of the digest, padded with zeros if the
+ * SHA digest size is smaller than digest_size
+ *
+ * @return zero on success, -1 on failure.
+ */
+static int calculate_ranges_digest(const struct file_buf *ap_firmware_file,
+ const struct gscvd_ro_ranges *ranges,
+ enum vb2_hash_algorithm hash_alg,
+ void *digest, size_t digest_size)
+{
+ struct vb2_digest_context dc;
+ size_t i;
+
+ /* Calculate the ranges digest. */
+ if (vb2_digest_init(&dc, hash_alg) != VB2_SUCCESS) {
+ ERROR("Failed to init digest!\n");
+ return 1;
+ }
+
+ for (i = 0; i < ranges->range_count; i++) {
+ if (vb2_digest_extend(&dc,
+ ap_firmware_file->data +
+ ranges->ranges[i].offset,
+ ranges->ranges[i].size) != VB2_SUCCESS) {
+ ERROR("Failed to extend digest!\n");
+ return -1;
+ }
+ }
+
+ memset(digest, 0, digest_size);
+ if (vb2_digest_finalize(&dc, digest, digest_size) != VB2_SUCCESS) {
+ ERROR("Failed to finalize digest!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Build GSC verification data.
+ *
+ * Calculate size of the structure including the signature and the root key,
+ * allocate memory, fill up the structure, calculate AP RO ranges digest and
+ * then the GVD signature.
+ *
+ * @param ap_firmware_file pointer to the AP firmware file layout descriptor
+ * @param ranges pointer to the container of ranges to include in verification
+ * @param root_pubk pointer to the root pubk container
+ * @param privk pointer to the private key to use for signing
+ * @param board_id Board ID value to use.
+ *
+ * @return pointer to the created GVD (to be freed by the caller) on success,
+ * NULL on failure.
+ */
+static
+struct gsc_verification_data *create_gvd(struct file_buf *ap_firmware_file,
+ struct gscvd_ro_ranges *ranges,
+ const struct vb2_packed_key *root_pubk,
+ const struct vb2_private_key *privk,
+ uint32_t board_id)
+{
+ struct gsc_verification_data *gvd;
+ size_t total_size;
+ size_t sig_size;
+ size_t ranges_size;
+ struct vb2_signature *sig;
+ const FmapHeader *fmh;
+
+ sig_size = vb2_rsa_sig_size(privk->sig_alg);
+ ranges_size = ranges->range_count * sizeof(struct gscvd_ro_range);
+ total_size = sizeof(struct gsc_verification_data) +
+ root_pubk->key_size + sig_size + ranges_size;
+
+ gvd = calloc(total_size, 1);
+
+ if (!gvd) {
+ ERROR("Failed to allocate %zd bytes for gvd\n", total_size);
+ return NULL;
+ }
+
+ gvd->gv_magic = GSC_VD_MAGIC;
+ gvd->size = total_size;
+ gvd->gsc_board_id = board_id;
+ gvd->rollback_counter = GSC_VD_ROLLBACK_COUNTER;
+
+ /* Guaranteed to succeed. */
+ fmh = fmap_find(ap_firmware_file->data, ap_firmware_file->len);
+
+ gvd->fmap_location = (uintptr_t)fmh - (uintptr_t)ap_firmware_file->data;
+
+ gvd->hash_alg = VB2_HASH_SHA256;
+
+ if (calculate_ranges_digest(ap_firmware_file, ranges, gvd->hash_alg,
+ gvd->ranges_digest,
+ sizeof(gvd->ranges_digest))) {
+ free(gvd);
+ return NULL;
+ }
+
+ /* Prepare signature header. */
+ vb2_init_signature(&gvd->sig_header,
+ (uint8_t *)(gvd + 1) + ranges_size,
+ sig_size,
+ sizeof(struct gsc_verification_data) + ranges_size);
+
+ /* Copy root key into the structure. */
+ vb2_init_packed_key(&gvd->root_key_header,
+ (uint8_t *)(gvd + 1) + ranges_size + sig_size,
+ root_pubk->key_size);
+ vb2_copy_packed_key(&gvd->root_key_header, root_pubk);
+
+ /* Copy ranges into the ranges section. */
+ gvd->range_count = ranges->range_count;
+ memcpy(gvd->ranges, ranges->ranges, ranges_size);
+
+ sig = vb2_calculate_signature((uint8_t *)gvd,
+ sizeof(struct gsc_verification_data) +
+ ranges_size, privk);
+ if (!sig) {
+ ERROR("Failed to calculate signature\n");
+ free(gvd);
+ return NULL;
+ }
+
+ /* Copy signature body into GVD after some basic checks. */
+ if ((sig_size == sig->sig_size) &&
+ (gvd->sig_header.data_size == sig->data_size)) {
+ vb2_copy_signature(&gvd->sig_header, sig);
+ } else {
+ ERROR("Inconsistent signature headers\n");
+ free(sig);
+ free(gvd);
+ return NULL;
+ }
+
+ free(sig);
+
+ return gvd;
+}
+
+/**
+ * Fill RO_GSCVD FMAP area.
+ *
+ * All trust chain components have been verified, AP RO sections digest
+ * calculated, and GVD signature created; put it all together in the dedicated
+ * FMAP area.
+ *
+ * @param ap_firmware_file pointer to the AP firmware file layout descriptor
+ * @param gvd pointer to the GVD header
+ * @param keyblock pointer to the keyblock container
+ *
+ * @return zero on success, -1 on failure
+ */
+static int fill_gvd_area(struct file_buf *ap_firmware_file,
+ struct gsc_verification_data *gvd,
+ struct vb2_keyblock *keyblock)
+{
+ size_t total;
+ uint8_t *cursor;
+
+ /* How much room is needed for the whole thing? */
+ total = gvd->size + keyblock->keyblock_size;
+
+ if (total > ap_firmware_file->ro_gscvd->area_size) {
+ ERROR("GVD section does not fit, %zd > %d\n",
+ total, ap_firmware_file->ro_gscvd->area_size);
+ return -1;
+ }
+
+ cursor = ap_firmware_file->data +
+ ap_firmware_file->ro_gscvd->area_offset;
+
+ /* Copy GSC verification data */
+ memcpy(cursor, gvd, gvd->size);
+ cursor += gvd->size;
+
+ /* Keyblock, size includes everything. */
+ memcpy(cursor, keyblock, keyblock->keyblock_size);
+
+ return 0;
+}
+
+/**
+ * Initialize a work buffer structure.
+ *
+ * Embedded vboot reference code does not use malloc/free, it uses the so
+ * called work buffer structure to provide a poor man's memory management
+ * tool. This program uses some of the embedded library functions, let's
+ * implement work buffer support to keep the embedded code happy.
+ *
+ * @param wb pointer to the workubffer structure to initialize
+ * @param size size of the buffer to allocate
+ *
+ * @return pointer to the allocated buffer on success, NULL on failure.
+ */
+static void *init_wb(struct vb2_workbuf *wb, size_t size)
+{
+ void *buf = malloc(size);
+
+ if (!buf)
+ ERROR("Failed to allocate workblock of %zd\n", size);
+ else
+ vb2_workbuf_init(wb, buf, size);
+
+ return buf;
+}
+
+/**
+ * Validate that platform key keyblock was signed by the root key.
+ *
+ * This function performs the same step the GSC is supposed to perform:
+ * validate the platform key keyblock signature using the root public key.
+ *
+ * @param root_pubk pointer to the root public key container
+ * @param kblock pointer to the platform public key keyblock
+ *
+ * @return 0 on success, -1 on failure
+ */
+static int validate_pubk_signature(const struct vb2_packed_key *root_pubk,
+ struct vb2_keyblock *kblock)
+{
+ struct vb2_public_key pubk;
+ struct vb2_workbuf wb;
+ uint32_t kbsize;
+ int rv;
+ void *buf;
+
+ if (vb2_unpack_key(&pubk, root_pubk) != VB2_SUCCESS) {
+ ERROR("Failed to unpack public key\n");
+ return -1;
+ }
+
+ /* Let's create an ample sized work buffer. */
+ buf = init_wb(&wb, 8192);
+ if (!buf)
+ return -1;
+
+ rv = -1;
+ do {
+ void *work;
+
+ kbsize = kblock->keyblock_size;
+ work = vb2_workbuf_alloc(&wb, kbsize);
+ if (!work) {
+ ERROR("Failed to allocate workblock space %d\n",
+ kbsize);
+ break;
+ }
+
+ memcpy(work, kblock, kbsize);
+
+ if (vb2_verify_keyblock(work, kbsize, &pubk, &wb) !=
+ VB2_SUCCESS) {
+ ERROR("Root and keyblock mismatch\n");
+ break;
+ }
+
+ rv = 0;
+ } while (false);
+
+ free(buf);
+
+ return rv;
+}
+
+/**
+ * Validate that private and public parts of the platform key match.
+ *
+ * This is a fairly routine validation, the N components of the private and
+ * public RSA keys are compared.
+ *
+ * @param keyblock pointer to the keyblock containing the public key
+ * @param plat_privk pointer to the matching private key
+ *
+ * @return 0 on success, nonzero on failure
+ */
+static int validate_privk(struct vb2_keyblock *kblock,
+ struct vb2_private_key *plat_privk)
+{
+ const BIGNUM *privn;
+ BIGNUM *pubn;
+ struct vb2_public_key pubk;
+ int rv;
+
+ privn = pubn = NULL;
+
+ RSA_get0_key(plat_privk->rsa_private_key, &privn, NULL, NULL);
+
+ if (vb2_unpack_key(&pubk, &kblock->data_key) != VB2_SUCCESS) {
+ ERROR("Failed to unpack public key\n");
+ return -1;
+ }
+
+ pubn = BN_new();
+ pubn = BN_lebin2bn((uint8_t *)pubk.n, vb2_rsa_sig_size(pubk.sig_alg),
+ pubn);
+ rv = BN_cmp(pubn, privn);
+ if (rv)
+ ERROR("Public/private key N mismatch!\n");
+
+ BN_free(pubn);
+ return rv;
+}
+
+/**
+ * Copy ranges from AP firmware file into gscvd_ro_ranges container
+ *
+ * While copying the ranges verify that they do not overlap.
+ *
+ * @param ap_firmware_file pointer to the AP firmware file layout descriptor
+ * @param gvd pointer to the GVD header followed by the ranges
+ * @param ranges pointer to the ranges container to copy ranges to
+ *
+ * @return 0 on successful copy nonzero on errors.
+ */
+static int copy_ranges(const struct file_buf *ap_firmware_file,
+ const struct gsc_verification_data *gvd,
+ struct gscvd_ro_ranges *ranges)
+{
+ ranges->range_count = gvd->range_count;
+ memcpy(ranges->ranges, gvd->ranges,
+ sizeof(ranges->ranges[0]) * ranges->range_count);
+
+ return verify_ranges(ranges, ap_firmware_file);
+}
+
+/**
+ * Basic validation of GVD included in a AP firmware file.
+ *
+ * This is not a cryptographic verification, just a check that the structure
+ * makes sense and the expected values are found in certain fields.
+ *
+ * @param gvd pointer to the GVD header followed by the ranges
+ * @param ap_firmware_file pointer to the AP firmware file layout descriptor
+ *
+ * @return zero on success, -1 on failure.
+ */
+static int validate_gvd(const struct gsc_verification_data *gvd,
+ const struct file_buf *ap_firmware_file)
+{
+ const FmapHeader *fmh;
+
+ if (gvd->gv_magic != GSC_VD_MAGIC) {
+ ERROR("Incorrect gscvd magic %x\n", gvd->gv_magic);
+ return -1;
+ }
+
+ if (!gvd->range_count || (gvd->range_count > MAX_RANGES)) {
+ ERROR("Incorrect gscvd range count %d\n", gvd->range_count);
+ return -1;
+ }
+
+ /* Guaranteed to succeed. */
+ fmh = fmap_find(ap_firmware_file->data, ap_firmware_file->len);
+
+ if (gvd->fmap_location !=
+ ((uintptr_t)fmh - (uintptr_t)ap_firmware_file->data)) {
+ ERROR("Incorrect gscvd fmap offset %x\n", gvd->fmap_location);
+ return -1;
+ }
+
+ /* Make sure signature and root key fit. */
+ if (vb2_verify_signature_inside(gvd, gvd->size, &gvd->sig_header) !=
+ VB2_SUCCESS) {
+ ERROR("Corrupted signature header in GVD\n");
+ return -1;
+ }
+
+ if (vb2_verify_packed_key_inside(gvd, gvd->size,
+ &gvd->root_key_header) !=
+ VB2_SUCCESS) {
+ ERROR("Corrupted root key header in GVD\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Validate GVD signature.
+ *
+ * Given the entire GVD space (header plus ranges array), the signature and
+ * the public key, verify that the signature matches.
+ *
+ * @param gvd pointer to gsc_verification_data followed by the ranges array
+ * @param gvd_signature pointer to the vb2 signature container
+ * @param packedk pointer to the keyblock containing the public key
+ *
+ * @return zero on success, non-zero on failure
+ */
+static int validate_gvd_signature(struct gsc_verification_data *gvd,
+ const struct vb2_packed_key *packedk)
+{
+ struct vb2_workbuf wb;
+ void *buf;
+ int rv;
+ struct vb2_public_key pubk;
+ size_t signed_size;
+
+ /* Extract public key from the public key keyblock. */
+ if (vb2_unpack_key(&pubk, packedk) != VB2_SUCCESS) {
+ ERROR("Failed to unpack public key\n");
+ return -1;
+ }
+
+ /* Let's create an ample sized work buffer. */
+ buf = init_wb(&wb, 8192);
+ if (!buf)
+ return -1;
+
+ signed_size = sizeof(struct gsc_verification_data) +
+ gvd->range_count * sizeof(gvd->ranges[0]);
+
+ rv = vb2_verify_data((const uint8_t *)gvd, signed_size,
+ &gvd->sig_header,
+ &pubk, &wb);
+
+ free(buf);
+ return rv;
+}
+
+/*
+ * Validate GVD of the passed in AP firmware file and possibly the root key hash
+ *
+ * The input parameters are the subset of the command line, the first argv
+ * string is the AP firmware file name, the second string, if present, is the
+ * hash of the root public key included in the RO_GSCVD area of the AP
+ * firmware file.
+ *
+ * @return zero on success, -1 on failure.
+ */
+static int validate_gscvd(int argc, char *argv[])
+{
+ struct file_buf ap_firmware_file;
+ int rv;
+ struct gscvd_ro_ranges ranges;
+ struct gsc_verification_data *gvd;
+ const char *file_name;
+ uint8_t digest[sizeof(gvd->ranges_digest)];
+ struct vb2_hash root_key_digest = { .algo = VB2_HASH_SHA256 };
+
+ /* Guaranteed to be available. */
+ file_name = argv[0];
+
+ if (argc > 1)
+ parse_digest_or_die(root_key_digest.sha256,
+ sizeof(root_key_digest.sha256),
+ argv[1]);
+
+ do {
+ struct vb2_keyblock *kblock;
+
+ rv = -1; /* Speculative, will be cleared on success. */
+
+ if (load_ap_firmware(file_name, &ap_firmware_file))
+ break;
+
+ /* Copy ranges from gscvd to local structure. */
+ gvd = (struct gsc_verification_data
+ *)(ap_firmware_file.data +
+ ap_firmware_file.ro_gscvd->area_offset);
+
+ if (validate_gvd(gvd, &ap_firmware_file))
+ break;
+
+ if (copy_ranges(&ap_firmware_file, gvd, &ranges))
+ break;
+
+ if (calculate_ranges_digest(&ap_firmware_file, &ranges,
+ gvd->hash_alg, digest,
+ sizeof(digest)))
+ break;
+
+ if (memcmp(digest, gvd->ranges_digest, sizeof(digest))) {
+ ERROR("Ranges digest mismatch\n");
+ break;
+ }
+
+ /* Find the keyblock. */
+ kblock = (struct vb2_keyblock *)((uintptr_t)gvd + gvd->size);
+
+ if ((argc > 1) && (vb2_hash_verify
+ (vb2_packed_key_data(&gvd->root_key_header),
+ gvd->root_key_header.key_size,
+ &root_key_digest) != VB2_SUCCESS)) {
+ ERROR("Sha256 mismatch\n");
+ break;
+ }
+
+ if (validate_pubk_signature(&gvd->root_key_header,
+ kblock))
+ break;
+
+ if (validate_gvd_signature(gvd, &kblock->data_key))
+ break;
+
+ rv = 0;
+ } while (false);
+
+ return rv;
+}
+
+/**
+ * Calculate and report sha256 hash of the public key body.
+ *
+ * The hash will be incorporated into GVC firmware to allow it to validate the
+ * root key.
+ *
+ * @param pubk pointer to the public key to process.
+ */
+static void dump_pubk_hash(const struct vb2_packed_key *pubk)
+{
+ struct vb2_hash hash;
+ size_t i;
+
+ vb2_hash_calculate(vb2_packed_key_data(pubk), pubk->key_size,
+ VB2_HASH_SHA256, &hash);
+
+ printf("Root key body sha256 hash:\n");
+
+ for (i = 0; i < sizeof(hash.sha256); i++)
+ printf("%02x", hash.sha256[i]);
+
+ printf("\n");
+}
+
+/**
+ * The main function of this futilty option.
+ *
+ * See the usage string for input details.
+ *
+ * @return zero on success, nonzero on failure.
+ */
+static int do_gscvd(int argc, char *argv[])
+{
+ int i;
+ int longindex;
+ char *infile = NULL;
+ char *outfile = NULL;
+ char *work_file = NULL;
+ struct gscvd_ro_ranges ranges;
+ int errorcount = 0;
+ struct vb2_packed_key *root_pubk = NULL;
+ struct vb2_keyblock *kblock = NULL;
+ struct vb2_private_key *plat_privk = NULL;
+ struct gsc_verification_data *gvd = NULL;
+ struct file_buf ap_firmware_file = { .fd = -1 };
+ uint32_t board_id = UINT32_MAX;
+ int rv = 0;
+
+ ranges.range_count = 0;
+
+ while ((i = getopt_long(argc, argv, short_opts, long_opts,
+ &longindex)) != -1) {
+ switch (i) {
+ case OPT_OUTFILE:
+ outfile = optarg;
+ break;
+ case 'R':
+ if (parse_ranges(optarg, &ranges)) {
+ ERROR("Could not parse ranges\n");
+ /* Error message has been already printed. */
+ errorcount++;
+ }
+ break;
+ case 'b': {
+ char *e;
+ long long bid;
+
+ bid = strtoull(optarg, &e, 16);
+ if (*e || (bid >= UINT32_MAX)) {
+ ERROR("Board ID value '%s' is invalid\n",
+ optarg);
+ errorcount++;
+ } else {
+ board_id = (uint32_t)bid;
+ }
+ break;
+ }
+ case 'r':
+ root_pubk = vb2_read_packed_key(optarg);
+ if (!root_pubk) {
+ ERROR("Could not read %s\n", optarg);
+ errorcount++;
+ }
+ break;
+ case 'k':
+ kblock = vb2_read_keyblock(optarg);
+ if (!kblock) {
+ ERROR("Could not read %s\n", optarg);
+ errorcount++;
+ }
+ break;
+ case 'p':
+ plat_privk = vb2_read_private_key(optarg);
+ if (!plat_privk) {
+ ERROR("Could not read %s\n", optarg);
+ errorcount++;
+ }
+ break;
+ case 'h':
+ printf("%s", usage);
+ return 0;
+ case '?':
+ if (optopt)
+ ERROR("Unrecognized option: -%c\n", optopt);
+ else
+ ERROR("Unrecognized option: %s\n",
+ argv[optind - 1]);
+ errorcount++;
+ break;
+ case ':':
+ ERROR("Missing argument to -%c\n", optopt);
+ errorcount++;
+ break;
+ case 0: /* handled option */
+ break;
+ default:
+ FATAL("Unrecognized getopt output: %d\n", i);
+ }
+ }
+
+ if ((optind == 1) && (argc > 1))
+ /* This must be a validation request. */
+ return validate_gscvd(argc - 1, argv + 1);
+
+ if (optind != (argc - 1)) {
+ ERROR("Misformatted command line\n%s\n", usage);
+ return 1;
+ }
+
+ if (errorcount || !ranges.range_count || !root_pubk || !kblock ||
+ !plat_privk || (board_id == UINT32_MAX)) {
+ /* Error message(s) should have been printed by now. */
+ ERROR("%s\n", usage);
+ return 1;
+ }
+
+ infile = argv[optind];
+
+ if (outfile) {
+ futil_copy_file_or_die(infile, outfile);
+ work_file = outfile;
+ } else {
+ work_file = infile;
+ }
+
+ do {
+ rv = 1; /* Speculative, will be cleared on success. */
+
+ if (validate_pubk_signature(root_pubk, kblock))
+ break;
+
+ if (validate_privk(kblock, plat_privk))
+ break;
+
+ if (load_ap_firmware(work_file, &ap_firmware_file))
+ break;
+
+ if (verify_ranges(&ranges, &ap_firmware_file))
+ break;
+
+ gvd = create_gvd(&ap_firmware_file, &ranges,
+ root_pubk, plat_privk, board_id);
+ if (!gvd)
+ break;
+
+ if (fill_gvd_area(&ap_firmware_file, gvd, kblock))
+ break;
+
+ dump_pubk_hash(root_pubk);
+
+ rv = 0;
+ } while (false);
+
+ free(gvd);
+ free(root_pubk);
+ free(kblock);
+ vb2_private_key_free(plat_privk);
+
+ /* Now flush the file. */
+ if (ap_firmware_file.data) {
+ rv |= futil_unmap_file(ap_firmware_file.fd, true,
+ ap_firmware_file.data,
+ ap_firmware_file.len);
+ }
+
+ if (ap_firmware_file.fd != -1)
+ close(ap_firmware_file.fd);
+
+ return rv;
+}
+
+DECLARE_FUTIL_COMMAND(gscvd, do_gscvd, VBOOT_VERSION_2_1,
+ "Create RO verification structure");
diff --git a/futility/cmd_pcr.c b/futility/cmd_pcr.c
index dc4c3ff..e267b24 100644
--- a/futility/cmd_pcr.c
+++ b/futility/cmd_pcr.c
@@ -40,57 +40,6 @@
printf(usage, argv[0], argv[0], argv[0]);
}
-static int parse_hex(uint8_t *val, const char *str)
-{
- uint8_t v = 0;
- char c;
- int digit;
-
- for (digit = 0; digit < 2; digit++) {
- c = *str;
- if (!c)
- return 0;
- if (!isxdigit(c))
- return 0;
- c = tolower(c);
- if (c >= '0' && c <= '9')
- v += c - '0';
- else
- v += 10 + c - 'a';
- if (!digit)
- v <<= 4;
- str++;
- }
-
- *val = v;
- return 1;
-}
-
-static void parse_digest_or_die(uint8_t *buf, int len, const char *str)
-{
- const char *s = str;
- int i;
-
- for (i = 0; i < len; i++) {
- /* skip whitespace */
- while (*s && isspace(*s))
- s++;
- if (!*s)
- break;
- if (!parse_hex(buf, s))
- break;
-
- /* on to the next byte */
- s += 2;
- buf++;
- }
-
- if (i != len) {
- fprintf(stderr, "Invalid DIGEST \"%s\"\n", str);
- exit(1);
- }
-}
-
static void print_digest(const uint8_t *buf, int len)
{
int i;
diff --git a/futility/cmd_update.c b/futility/cmd_update.c
index 57fa083..e4b3765 100644
--- a/futility/cmd_update.c
+++ b/futility/cmd_update.c
@@ -13,6 +13,8 @@
#include "futility.h"
#include "updater.h"
+#ifdef USE_FLASHROM
+
enum {
OPT_DUMMY = 0x100,
@@ -358,6 +360,17 @@
updater_delete_config(cfg);
return !!errorcnt;
}
+#define CMD_HELP_STR "Update system firmware"
-DECLARE_FUTIL_COMMAND(update, do_update, VBOOT_VERSION_ALL,
- "Update system firmware");
+#else /* USE_FLASHROM */
+
+static int do_update(int argc, char *argv[])
+{
+ FATAL(MYNAME " was built without flashrom support, `update` command unavailable!\n");
+ return -1;
+}
+#define CMD_HELP_STR "Update system firmware (unavailable in this build)"
+
+#endif /* !USE_FLASHROM */
+
+DECLARE_FUTIL_COMMAND(update, do_update, VBOOT_VERSION_ALL, CMD_HELP_STR);
diff --git a/futility/flashrom_wp_drv.c b/futility/flashrom_wp_drv.c
new file mode 100644
index 0000000..ff7a821
--- /dev/null
+++ b/futility/flashrom_wp_drv.c
@@ -0,0 +1,50 @@
+/* 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.
+ *
+ * The utility functions for firmware updater.
+ */
+
+#include <libflashrom.h>
+
+#include "updater.h"
+
+#define FLASHROM_OUTPUT_WP_PATTERN "write protect is "
+
+/* System environment values. */
+static const char * const FLASHROM_OUTPUT_WP_ENABLED =
+ FLASHROM_OUTPUT_WP_PATTERN "enabled",
+ * const FLASHROM_OUTPUT_WP_DISABLED =
+ FLASHROM_OUTPUT_WP_PATTERN "disabled";
+
+
+/* Helper function to return write protection status via given programmer. */
+enum wp_state flashrom_get_wp(const char *programmer)
+{
+ char *command, *result;
+ const char *postfix;
+ int r;
+
+ /* grep is needed because host_shell only returns 1 line. */
+ postfix = " 2>/dev/null | grep \"" FLASHROM_OUTPUT_WP_PATTERN "\"";
+
+
+ /* TODO(b/203715651): link with flashrom directly. */
+ ASPRINTF(&command, "flashrom --wp-status -p %s %s", programmer, postfix);
+
+ /* invokes flashrom(8) with non-zero result if error. */
+ result = host_shell(command);
+ strip_string(result, NULL);
+ free(command);
+ VB2_DEBUG("wp-status: %s\n", result);
+
+ if (strstr(result, FLASHROM_OUTPUT_WP_ENABLED))
+ r = WP_ENABLED;
+ else if (strstr(result, FLASHROM_OUTPUT_WP_DISABLED))
+ r = WP_DISABLED;
+ else
+ r = WP_ERROR;
+ free(result);
+
+ return r;
+}
diff --git a/futility/futility.h b/futility/futility.h
index 1f34713..9d40ba7 100644
--- a/futility/futility.h
+++ b/futility/futility.h
@@ -140,6 +140,12 @@
enum futil_file_err futil_unmap_file(int fd, int writeable,
uint8_t *buf, uint32_t len);
+/*
+ * Parse input string as a hex representation of size len, exit with error if
+ * the string is not a valid hex string or is of a wrongs size.
+ */
+void parse_digest_or_die(uint8_t *buf, int len, const char *str);
+
/* The CPU architecture is occasionally important */
enum arch_t {
ARCH_UNSPECIFIED,
diff --git a/futility/misc.c b/futility/misc.c
index f3e7748..76b8ad1 100644
--- a/futility/misc.c
+++ b/futility/misc.c
@@ -352,3 +352,54 @@
return FILE_TYPE_CHROMIUMOS_DISK;
}
+
+static int parse_hex(uint8_t *val, const char *str)
+{
+ uint8_t v = 0;
+ char c;
+ int digit;
+
+ for (digit = 0; digit < 2; digit++) {
+ c = *str;
+ if (!c)
+ return 0;
+ if (!isxdigit(c))
+ return 0;
+ c = tolower(c);
+ if (c >= '0' && c <= '9')
+ v += c - '0';
+ else
+ v += 10 + c - 'a';
+ if (!digit)
+ v <<= 4;
+ str++;
+ }
+
+ *val = v;
+ return 1;
+}
+
+void parse_digest_or_die(uint8_t *buf, int len, const char *str)
+{
+ const char *s = str;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ /* skip whitespace */
+ while (*s && isspace(*s))
+ s++;
+ if (!*s)
+ break;
+ if (!parse_hex(buf, s))
+ break;
+
+ /* on to the next byte */
+ s += 2;
+ buf++;
+ }
+
+ if ((i != len) || *s) {
+ fprintf(stderr, "Invalid DIGEST \"%s\"\n", str);
+ exit(1);
+ }
+}
diff --git a/futility/updater.c b/futility/updater.c
index 87ac6fd..06a696c 100644
--- a/futility/updater.c
+++ b/futility/updater.c
@@ -275,7 +275,7 @@
static int set_try_cookies(struct updater_config *cfg, const char *target,
int has_update, int is_vboot2)
{
- int tries = 6;
+ int tries = 8;
const char *slot;
/* EC Software Sync needs few more reboots. */
@@ -334,6 +334,10 @@
struct firmware_section from, to;
int errorcnt = 0;
+ INFO("(emulation) Writing %s from %s to %s (emu=%s).\n",
+ section_name ? section_name : "the whole image",
+ image->file_name, image->programmer, filename);
+
from.data = image->data;
from.size = image->size;
@@ -384,30 +388,80 @@
}
/*
- * Writes a section from given firmware image to system firmware.
- * If section_name is NULL, write whole image.
+ * Returns the number of retries when reading or writing to flash.
+ */
+static int get_io_retries(struct updater_config *cfg)
+{
+ return 1 + get_config_quirk(QUIRK_EXTRA_RETRIES, cfg);
+}
+
+/*
+ * Returns 1 if the programmers in image1 and image2 are the same.
+ */
+static int is_the_same_programmer(const struct firmware_image *image1,
+ const struct firmware_image *image2)
+{
+ assert(image1 && image2);
+
+ /* Including if both are NULL. */
+ if (image1->programmer == image2->programmer)
+ return 1;
+
+ /* Not the same if either one is NULL. */
+ if (!image1->programmer || !image2->programmer)
+ return 0;
+
+ return strcmp(image1->programmer, image2->programmer) == 0;
+}
+
+/*
+ * Writes multiple sections from the given firmware image to the system.
+ * The 'sections' should be NULL (write the whole image) or a list of section
+ * names to write, and ended with NULL.
+ * Returns 0 if success, non-zero if error.
+ */
+static int write_firmware_sections(struct updater_config *cfg,
+ const struct firmware_image *image,
+ const char * const sections[])
+{
+ int r = 0;
+ struct firmware_image *diff_image = NULL;
+
+ if (cfg->emulation) {
+ int i;
+ if (!sections)
+ return emulate_write_firmware(
+ cfg->emulation, image, NULL);
+ for (i = 0; sections[i] && !r; i++) {
+ r |= emulate_write_firmware(
+ cfg->emulation, image, sections[i]);
+ }
+ return r;
+ }
+
+ if (cfg->use_diff_image && cfg->image_current.data &&
+ is_the_same_programmer(&cfg->image_current, image))
+ diff_image = &cfg->image_current;
+
+ return write_system_firmware(image, diff_image, sections,
+ &cfg->tempfiles, cfg->do_verify,
+ get_io_retries(cfg), cfg->verbosity + 1);
+}
+
+/*
+ * Writes a single section from the given firmware image to the system.
+ * Writes the whole firmware image if the section_name is NULL.
* Returns 0 if success, non-zero if error.
*/
static int write_firmware(struct updater_config *cfg,
const struct firmware_image *image,
const char *section_name)
{
- struct firmware_image *diff_image = NULL;
+ const char *sections[2] = {0};
- if (cfg->emulation) {
- INFO("(emulation) Writing %s from %s to %s (emu=%s).\n",
- section_name ? section_name : "whole image",
- image->file_name, image->programmer, cfg->emulation);
-
- return emulate_write_firmware(
- cfg->emulation, image, section_name);
- }
-
- if (cfg->fast_update && image == &cfg->image && cfg->image_current.data)
- diff_image = &cfg->image_current;
-
- return write_system_firmware(image, diff_image, section_name,
- &cfg->tempfiles, cfg->verbosity + 1);
+ sections[0] = section_name;
+ return write_firmware_sections(cfg, image,
+ section_name ? sections : NULL);
}
/*
@@ -458,7 +512,7 @@
*/
if (check_programmer_wp &&
get_system_property(SYS_PROP_WP_HW, cfg) == WP_ENABLED &&
- host_get_wp(image->programmer) == WP_ENABLED) {
+ flashrom_get_wp(image->programmer) == WP_ENABLED) {
ERROR("Target %s is write protected, skip updating.\n",
image->programmer);
return 0;
@@ -481,19 +535,27 @@
const struct vb2_gbb_header *gbb_from;
struct vb2_gbb_header *gbb_to;
- gbb_from = find_gbb(image_from);
- /* We do want to change GBB contents later. */
+ /* Cast to non-const because we do want to change GBB contents later. */
gbb_to = (struct vb2_gbb_header *)find_gbb(image_to);
- if (!gbb_from || !gbb_to)
+ /*
+ * For all cases, we need a valid gbb_to. Note for 'override GBB flags
+ * on a erased device', we only need gbb_to, not gbb_from.
+ */
+ if (!gbb_to)
return -1;
+ gbb_from = find_gbb(image_from);
+
/* Preserve (for non-factory mode) or override flags. */
if (override_flags)
gbb_to->flags = override_value;
- else if (preserve_flags)
+ else if (preserve_flags && gbb_from)
gbb_to->flags = gbb_from->flags;
+ if (!gbb_from)
+ return -1;
+
/* Preserve HWID. */
return futil_set_gbb_hwid(
gbb_to, (const char *)gbb_from + gbb_from->hwid_offset);
@@ -520,11 +582,16 @@
image_from, image_to, FMAP_SI_DESC);
}
- if (try_apply_quirk(QUIRK_PRESERVE_ME, cfg) > 0) {
- VB2_DEBUG("ME needs to be preserved - preserving %s.\n",
- FMAP_SI_ME);
- return preserve_firmware_section(
- image_from, image_to, FMAP_SI_ME);
+ if (!strcmp(image_from->programmer, PROG_HOST)) {
+ if (try_apply_quirk(QUIRK_PRESERVE_ME, cfg) > 0) {
+ VB2_DEBUG("ME needs to be preserved - preserving %s.\n",
+ FMAP_SI_ME);
+ return preserve_firmware_section(image_from, image_to,
+ FMAP_SI_ME);
+ }
+ } else {
+ VB2_DEBUG("Flashing via non-host programmer %s - no need to "
+ "preserve ME.\n", image_from->programmer);
}
return try_apply_quirk(QUIRK_UNLOCK_ME_FOR_UPDATE, cfg);
@@ -866,16 +933,18 @@
int has_from, has_to;
const char * const tag = "cros_allow_auto_update";
const char *section = FMAP_RW_LEGACY;
- const char *tmp_path;
+ const char *tmp_to, *tmp_from;
VB2_DEBUG("Checking %s contents...\n", FMAP_RW_LEGACY);
- tmp_path = get_firmware_image_temp_file(&cfg->image, &cfg->tempfiles);
- if (!tmp_path)
+ tmp_to = get_firmware_image_temp_file(&cfg->image, &cfg->tempfiles);
+ tmp_from = get_firmware_image_temp_file(&cfg->image_current,
+ &cfg->tempfiles);
+ if (!tmp_from || !tmp_to)
return 0;
- has_to = cbfs_file_exists(tmp_path, section, tag);
- has_from = cbfs_file_exists(tmp_path, section, tag);
+ has_to = cbfs_file_exists(tmp_to, section, tag);
+ has_from = cbfs_file_exists(tmp_from, section, tag);
if (!has_from || !has_to) {
VB2_DEBUG("Current legacy firmware has%s updater tag (%s) and "
@@ -1075,6 +1144,15 @@
struct firmware_image *image_from,
struct firmware_image *image_to)
{
+ int sections_start = 0;
+ static const char * const sections[] = {
+ FMAP_RW_LEGACY,
+ FMAP_RW_SECTION_A,
+ FMAP_RW_SECTION_B,
+ FMAP_RW_SHARED,
+ NULL,
+ };
+
STATUS("RW UPDATE: Updating RW sections (%s, %s, %s, and %s).\n",
FMAP_RW_SECTION_A, FMAP_RW_SECTION_B, FMAP_RW_SHARED,
FMAP_RW_LEGACY);
@@ -1084,14 +1162,18 @@
return UPDATE_ERR_ROOT_KEY;
if (check_compatible_tpm_keys(cfg, image_to))
return UPDATE_ERR_TPM_ROLLBACK;
+
/*
- * TODO(hungte) Speed up by flashing multiple sections in one
- * command, or provide diff file.
+ * We may also consider only updating legacy if legacy_needs_update()
+ * returns true. However, given this is for 'recovery', it is probably
+ * better to restore everything to the default states. We may revisit
+ * this if a new scenario is found.
*/
- if (write_firmware(cfg, image_to, FMAP_RW_SECTION_A) ||
- write_firmware(cfg, image_to, FMAP_RW_SECTION_B) ||
- write_firmware(cfg, image_to, FMAP_RW_SHARED) ||
- write_optional_firmware(cfg, image_to, FMAP_RW_LEGACY, 0, 1))
+ if (!firmware_section_exists(image_from, sections[sections_start]) ||
+ !firmware_section_exists(image_to, sections[sections_start]))
+ sections_start++;
+
+ if (write_firmware_sections(cfg, image_to, §ions[sections_start]))
return UPDATE_ERR_WRITE_FIRMWARE;
return UPDATE_ERR_DONE;
@@ -1187,6 +1269,7 @@
image_to->file_name, image_to->ro_version,
image_to->rw_version_a, image_to->rw_version_b);
+ try_apply_quirk(QUIRK_NO_VERIFY, cfg);
if (try_apply_quirk(QUIRK_MIN_PLATFORM_VERSION, cfg)) {
if (!cfg->force_update) {
ERROR("Add --force to waive checking the version.\n");
@@ -1195,9 +1278,10 @@
}
if (!image_from->data) {
int ret;
+
INFO("Loading current system firmware...\n");
ret = load_system_firmware(image_from, &cfg->tempfiles,
- cfg->verbosity);
+ get_io_retries(cfg), cfg->verbosity);
if (ret == IMAGE_PARSE_FAILURE && cfg->force_update) {
WARN("No compatible firmware in system.\n");
cfg->check_platform = 0;
@@ -1272,6 +1356,7 @@
cfg->pd_image.programmer = PROG_PD;
cfg->check_platform = 1;
+ cfg->do_verify = 1;
init_system_properties(&cfg->system_properties[0],
ARRAY_SIZE(cfg->system_properties));
@@ -1376,17 +1461,15 @@
assert(model->is_white_label);
if (!signature_id) {
- if (cfg->image_current.data) {
- tmp_image = get_firmware_image_temp_file(
- &cfg->image_current, &cfg->tempfiles);
- if (!tmp_image)
- return 1;
- } else {
+ if (!cfg->image_current.data) {
INFO("Loading system firmware for white label...\n");
load_system_firmware(&cfg->image_current,
- &cfg->tempfiles, cfg->verbosity);
- tmp_image = cfg->image_current.file_name;
+ &cfg->tempfiles,
+ get_io_retries(cfg),
+ cfg->verbosity);
}
+ tmp_image = get_firmware_image_temp_file(
+ &cfg->image_current, &cfg->tempfiles);
if (!tmp_image) {
ERROR("Failed to get system current firmware\n");
return 1;
@@ -1475,7 +1558,8 @@
/* Setup values that may change output or decision of other argument. */
cfg->verbosity = arg->verbosity;
- cfg->fast_update = arg->fast_update;
+ cfg->use_diff_image = arg->fast_update;
+ cfg->do_verify = !arg->fast_update;
cfg->factory_update = arg->is_factory;
if (arg->force_update)
cfg->force_update = 1;
@@ -1626,7 +1710,7 @@
errorcnt += !!setup_config_quirks(arg->quirks, cfg);
/* Additional checks. */
- if (check_single_image && (cfg->ec_image.data || cfg->pd_image.data)) {
+ if (check_single_image && !do_output && (cfg->ec_image.data || cfg->pd_image.data)) {
errorcnt++;
ERROR("EC/PD images are not supported in current mode.\n");
}
diff --git a/futility/updater.h b/futility/updater.h
index 69ba5e2..6dda928 100644
--- a/futility/updater.h
+++ b/futility/updater.h
@@ -14,6 +14,7 @@
/* FMAP section names. */
static const char * const FMAP_RO_FRID = "RO_FRID",
* const FMAP_RO_SECTION = "RO_SECTION",
+ * const FMAP_RO_CBFS = "COREBOOT",
* const FMAP_RO_GBB = "GBB",
* const FMAP_RW_VBLOCK_A = "VBLOCK_A",
* const FMAP_RW_VBLOCK_B = "VBLOCK_B",
@@ -46,6 +47,8 @@
QUIRK_OVERRIDE_SIGNATURE_ID,
QUIRK_PRESERVE_ME,
QUIRK_NO_CHECK_PLATFORM,
+ QUIRK_NO_VERIFY,
+ QUIRK_EXTRA_RETRIES,
QUIRK_MAX,
};
@@ -68,7 +71,8 @@
int legacy_update;
int factory_update;
int check_platform;
- int fast_update;
+ int use_diff_image;
+ int do_verify;
int verbosity;
const char *emulation;
int override_gbb_flags;
diff --git a/futility/updater_archive.c b/futility/updater_archive.c
index 4ad5287..9c3a608 100644
--- a/futility/updater_archive.c
+++ b/futility/updater_archive.c
@@ -30,6 +30,10 @@
#include <zip.h>
#endif
+#ifdef HAVE_CROSID
+#include <crosid.h>
+#endif
+
#include "host_misc.h"
#include "updater.h"
#include "util_misc.h"
@@ -815,6 +819,30 @@
return !manifest_add_model(manifest, &model);
}
+/**
+ * get_manifest_key() - Wrapper to get the firmware manifest key from crosid
+ *
+ * @manifest_key_out - Output parameter of the firmware manifest key.
+ *
+ * Returns:
+ * - <0 if libcrosid is unavailable or there was an error reading
+ * device data
+ * - >=0 (the matched device index) success
+ */
+static int get_manifest_key(char **manifest_key_out)
+{
+#ifdef HAVE_CROSID
+ return crosid_get_firmware_manifest_key(manifest_key_out);
+#else
+ ERROR("This version of futility was compiled without libcrosid "
+ "(perhaps compiled outside of the Chrome OS build system?) and "
+ "the update command is not fully supported. Either compile "
+ "from the Chrome OS build, or pass --model to manually specify "
+ "the machine model.\n");
+ return -1;
+#endif
+}
+
/*
* Finds the existing model_config from manifest that best matches current
* system (as defined by model_name).
@@ -823,9 +851,10 @@
const struct model_config *manifest_find_model(const struct manifest *manifest,
const char *model_name)
{
- char *sys_model_name = NULL;
+ char *manifest_key = NULL;
const struct model_config *model = NULL;
int i;
+ int matched_index;
/*
* For manifest with single model defined, we should just return because
@@ -836,9 +865,18 @@
return &manifest->models[0];
if (!model_name) {
- sys_model_name = host_shell("mosys platform model");
- VB2_DEBUG("System model name: '%s'\n", sys_model_name);
- model_name = sys_model_name;
+ matched_index = get_manifest_key(&manifest_key);
+ if (matched_index < 0) {
+ ERROR("Failed to get device identity. "
+ "Run \"crosid -v\" for explanation.\n");
+ return NULL;
+ }
+
+ INFO("Identified the device using libcrosid, "
+ "matched chromeos-config index: %d, "
+ "manifest key (model): %s\n",
+ matched_index, manifest_key);
+ model_name = manifest_key;
}
for (i = 0; !model && i < manifest->num; i++) {
@@ -846,27 +884,27 @@
model = &manifest->models[i];
}
if (!model) {
- if (!*model_name)
- ERROR("Cannot get model name.\n");
- else
- ERROR("Unsupported model: '%s'.\n", model_name);
+ ERROR("Unsupported model: '%s'.\n", model_name);
fprintf(stderr,
- "You are probably running an image for wrong board, or "
- "a device in early stage that 'mosys' command is not "
- "ready, or image from old (or factory) branches that "
- "Unified Build config is not updated yet for 'mosys'.\n"
- "Please check command 'mosys platform model', "
- "which should output one of the supported models below:"
- "\n");
+ "The firmware manifest key '%s' is not present in this "
+ "updater archive. The known keys to this updater "
+ "archive are:\n", model_name);
for (i = 0; i < manifest->num; i++)
fprintf(stderr, " %s", manifest->models[i].name);
- fprintf(stderr, "\n");
+ fprintf(stderr, "\n\n");
+ fprintf(stderr,
+ "Perhaps you are trying to use an updater archive for "
+ "the wrong board, or designed for an older OS version "
+ "before this model was supported.\n");
+ fprintf(stderr,
+ "Hint: Read the FIRMWARE_MANIFEST_KEY from the output "
+ "of the crosid command.\n");
}
- free(sys_model_name);
+ free(manifest_key);
return model;
}
diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c
index 1d1ba62..c8140c1 100644
--- a/futility/updater_quirks.c
+++ b/futility/updater_quirks.c
@@ -21,6 +21,14 @@
const char * const quirks;
};
+/*
+ * The 'match by firmware name' is now deprecated. Please do not add any
+ * new records below. We now support reading quirks from CBFS, which is
+ * easier and more reliable. To do that, create a text file 'updater_quirks'
+ * and install to the CBFS.
+ *
+ * Examples: CL:*3365287, CL:*3351831, CL:*4441527
+ */
static const struct quirks_record quirks_records[] = {
{ .match = "Google_Whirlwind.", .quirks = "enlarge_image" },
{ .match = "Google_Arkham.", .quirks = "enlarge_image" },
@@ -116,10 +124,10 @@
ERROR("EC image has invalid section '%s'.\n", "EC_RO");
return 1;
}
- ec_ro_path = cbfs_extract_file(tmp_path, FMAP_RO_SECTION, "ecro",
+ ec_ro_path = cbfs_extract_file(tmp_path, FMAP_RO_CBFS, "ecro",
&cfg->tempfiles);
if (!ec_ro_path ||
- !cbfs_file_exists(tmp_path, FMAP_RO_SECTION, "ecro.hash")) {
+ !cbfs_file_exists(tmp_path, FMAP_RO_CBFS, "ecro.hash")) {
INFO("No valid EC RO for software sync in AP firmware.\n");
return 1;
}
@@ -331,6 +339,11 @@
* only RO and expect EC software sync to update RW later, or perform EC RO
* software sync.
*
+ * Note: EC RO software sync was not fully tested and may cause problems
+ * (b/218612817, b/187789991).
+ * RO-update (without extra sysjump) needs support from flashrom and is
+ * currently disabled.
+ *
* Returns:
* EC_RECOVERY_FULL to indicate a full recovery is needed.
* EC_RECOVERY_RO to indicate partial update (WP_RO) is needed.
@@ -345,23 +358,10 @@
*/
const char *ec_ro = "WP_RO";
struct firmware_image *ec_image = &cfg->ec_image;
-
int do_partial = get_config_quirk(QUIRK_EC_PARTIAL_RECOVERY, cfg);
- if (do_partial == -1) {
- char arch[VB_MAX_STRING_PROPERTY];
- /*
- * Don't do partial update if can't decide arch (usually implies
- * running outside DUT).
- */
- do_partial = 0;
- if (VbGetSystemPropertyString("arch", arch, sizeof(arch)) > 0) {
- /* By default disabled for x86, otherwise enabled. */
- do_partial = !!strcmp(arch, "x86");
- }
- }
if (!do_partial) {
- return EC_RECOVERY_FULL;
+ /* Need full update. */
} else if (!firmware_section_exists(ec_image, ec_ro)) {
INFO("EC image does not have section '%s'.\n", ec_ro);
/* Need full update. */
@@ -411,6 +411,15 @@
return 0;
}
+ /*
+ * b/213706510: subratabanik@ confirmed CSE may modify itself while we
+ * are doing system update, and currently the 'preserve' is done by
+ * flashing the same (e.g., "previously read") contents to skip erasing
+ * and writing; so we have to use the diff image to prevent contents
+ * being changed when writing.
+ */
+ cfg->use_diff_image = 1;
+
return 1;
}
@@ -425,6 +434,16 @@
}
/*
+ * Disable verifying contents after flashing.
+ */
+static int quirk_no_verify(struct updater_config *cfg)
+{
+ WARN("Disabled verifying flashed contents. You are on your own.\n");
+ cfg->do_verify = 0;
+ return 0;
+}
+
+/*
* Registers known quirks to a updater_config object.
*/
void updater_register_quirks(struct updater_config *cfg)
@@ -470,7 +489,6 @@
quirks->name = "ec_partial_recovery";
quirks->help = "chromium/1024401; recover EC by partial RO update.";
quirks->apply = quirk_ec_partial_recovery;
- quirks->value = -1; /* Decide at runtime. */
quirks = &cfg->quirks[QUIRK_OVERRIDE_SIGNATURE_ID];
quirks->name = "override_signature_id";
@@ -488,6 +506,16 @@
quirks->name = "no_check_platform";
quirks->help = "Do not check platform name.";
quirks->apply = quirk_no_check_platform;
+
+ quirks = &cfg->quirks[QUIRK_NO_VERIFY];
+ quirks->name = "no_verify";
+ quirks->help = "Do not verify when flashing.";
+ quirks->apply = quirk_no_verify;
+
+ quirks = &cfg->quirks[QUIRK_EXTRA_RETRIES];
+ quirks->name = "extra_retries";
+ quirks->help = "Extra retries when writing to system firmware.";
+ quirks->apply = NULL; /* Simple config. */
}
/*
diff --git a/futility/updater_utils.c b/futility/updater_utils.c
index 70ed396..18e4000 100644
--- a/futility/updater_utils.c
+++ b/futility/updater_utils.c
@@ -9,6 +9,7 @@
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <string.h>
#include <unistd.h>
#if defined (__FreeBSD__) || defined(__OpenBSD__)
#include <sys/wait.h>
@@ -21,20 +22,9 @@
#include "updater.h"
#define COMMAND_BUFFER_SIZE 256
-#define FLASHROM_OUTPUT_WP_PATTERN "write protect is "
-
-enum flashrom_ops {
- FLASHROM_READ,
- FLASHROM_WRITE,
- FLASHROM_WP_STATUS,
-};
/* System environment values. */
-static const char * const STR_REV = "rev",
- * const FLASHROM_OUTPUT_WP_ENABLED =
- FLASHROM_OUTPUT_WP_PATTERN "enabled",
- * const FLASHROM_OUTPUT_WP_DISABLED =
- FLASHROM_OUTPUT_WP_PATTERN "disabled";
+static const char * const STR_REV = "rev";
/*
* Strips a string (usually from shell execution output) by removing all the
@@ -172,6 +162,45 @@
return 0;
}
+static int parse_firmware_image(struct firmware_image *image)
+{
+ int ret = IMAGE_LOAD_SUCCESS;
+ const char *section_a = NULL, *section_b = NULL;
+
+ VB2_DEBUG("Image size: %d\n", image->size);
+ assert(image->data);
+
+ image->fmap_header = fmap_find(image->data, image->size);
+
+ if (!image->fmap_header) {
+ ERROR("Invalid image file (missing FMAP): %s\n", image->file_name);
+ ret = IMAGE_PARSE_FAILURE;
+ }
+
+ if (load_firmware_version(image, FMAP_RO_FRID, &image->ro_version))
+ ret = IMAGE_PARSE_FAILURE;
+
+ if (firmware_section_exists(image, FMAP_RW_FWID_A)) {
+ section_a = FMAP_RW_FWID_A;
+ section_b = FMAP_RW_FWID_B;
+ } else if (firmware_section_exists(image, FMAP_RW_FWID)) {
+ section_a = FMAP_RW_FWID;
+ section_b = FMAP_RW_FWID;
+ } else if (!ret) {
+ ERROR("Unsupported VBoot firmware (no RW ID): %s\n", image->file_name);
+ ret = IMAGE_PARSE_FAILURE;
+ }
+
+ /*
+ * Load and initialize both RW A and B sections.
+ * Note some unit tests will create only RW A.
+ */
+ load_firmware_version(image, section_a, &image->rw_version_a);
+ load_firmware_version(image, section_b, &image->rw_version_b);
+
+ return ret;
+}
+
/*
* Loads a firmware image from file.
* If archive is provided and file_name is a relative path, read the file from
@@ -182,9 +211,6 @@
int load_firmware_image(struct firmware_image *image, const char *file_name,
struct archive *archive)
{
- int ret = IMAGE_LOAD_SUCCESS;
- const char *section_a = NULL, *section_b = NULL;
-
if (!file_name) {
ERROR("No file name given\n");
return IMAGE_READ_FAILURE;
@@ -202,38 +228,9 @@
return IMAGE_READ_FAILURE;
}
- VB2_DEBUG("Image size: %d\n", image->size);
- assert(image->data);
image->file_name = strdup(file_name);
- image->fmap_header = fmap_find(image->data, image->size);
- if (!image->fmap_header) {
- ERROR("Invalid image file (missing FMAP): %s\n", file_name);
- ret = IMAGE_PARSE_FAILURE;
- }
-
- if (load_firmware_version(image, FMAP_RO_FRID, &image->ro_version))
- ret = IMAGE_PARSE_FAILURE;
-
- if (firmware_section_exists(image, FMAP_RW_FWID_A)) {
- section_a = FMAP_RW_FWID_A;
- section_b = FMAP_RW_FWID_B;
- } else if (firmware_section_exists(image, FMAP_RW_FWID)) {
- section_a = FMAP_RW_FWID;
- section_b = FMAP_RW_FWID;
- } else if (!ret) {
- ERROR("Unsupported VBoot firmware (no RW ID): %s\n", file_name);
- ret = IMAGE_PARSE_FAILURE;
- }
-
- /*
- * Load and initialize both RW A and B sections.
- * Note some unit tests will create only RW A.
- */
- load_firmware_version(image, section_a, &image->rw_version_a);
- load_firmware_version(image, section_b, &image->rw_version_b);
-
- return ret;
+ return parse_firmware_image(image);
}
/*
@@ -462,6 +459,7 @@
char *host_detect_servo(int *need_prepare_ptr)
{
const char *servo_port = getenv(ENV_SERVOD_PORT);
+ const char *servo_name = getenv(ENV_SERVOD_NAME);
char *servo_type = host_shell("dut-control -o servo_type 2>/dev/null");
const char *programmer = NULL;
char *ret = NULL;
@@ -469,10 +467,11 @@
char *servo_serial = NULL;
/* Get serial name if servo port is provided. */
- if (servo_port && *servo_port) {
+ if ((servo_port && *servo_port) || (servo_name && *servo_name)) {
const char *cmd = "dut-control -o serialname 2>/dev/null";
- VB2_DEBUG("Select servod using port: %s\n", servo_port);
+ VB2_DEBUG("Select servod using port: %s or name: %s\n",
+ servo_port, servo_name);
if (strstr(servo_type, "with_servo_micro"))
cmd = ("dut-control -o servo_micro_serialname"
" 2>/dev/null");
@@ -491,8 +490,9 @@
VB2_DEBUG("Selected Servo Micro.\n");
programmer = "raiden_debug_spi";
need_prepare = 1;
- } else if (strstr(servo_type, "ccd_cr50")) {
- VB2_DEBUG("Selected CCD CR50.\n");
+ } else if (strstr(servo_type, "ccd_cr50") ||
+ strstr(servo_type, "ccd_gsc")) {
+ VB2_DEBUG("Selected CCD.\n");
programmer = "raiden_debug_spi:target=AP";
} else {
VB2_DEBUG("Selected Servo V2.\n");
@@ -519,175 +519,86 @@
}
/*
- * A helper function to invoke flashrom(8) command.
+ * Loads the active system firmware image (usually from SPI flash chip).
* Returns 0 if success, non-zero if error.
*/
-static int host_flashrom(enum flashrom_ops op, const char *image_path,
- const char *programmer, int verbose,
- const char *section_name, const char *extra)
+int load_system_firmware(struct firmware_image *image,
+ struct tempfile *tempfiles,
+ int retries, int verbosity)
{
- char *command, *result;
- const char *op_cmd, *dash_i = "-i", *postfix = "";
- int r;
+ int r, i;
- switch (verbose) {
- case 0:
- postfix = " >/dev/null 2>&1";
- break;
- case 1:
- break;
- case 2:
- postfix = "-V";
- break;
- case 3:
- postfix = "-V -V";
- break;
- default:
- postfix = "-V -V -V";
- break;
+ INFO("flasrhom -r <IMAGE> -p %s%s\n",
+ image->programmer,
+ verbosity ? " -V" : "");
+
+ for (i = 1, r = -1; i <= retries && r != 0; i++) {
+ if (i > 1)
+ WARN("Retry reading firmware (%d/%d)...\n", i, retries);
+ r = flashrom_read_image(image, NULL, verbosity + 1);
}
-
- if (!section_name || !*section_name) {
- dash_i = "";
- section_name = "";
- }
-
- switch (op) {
- case FLASHROM_READ:
- op_cmd = "-r";
- assert(image_path);
- break;
-
- case FLASHROM_WRITE:
- op_cmd = "-w";
- assert(image_path);
- break;
-
- case FLASHROM_WP_STATUS:
- op_cmd = "--wp-status";
- assert(image_path == NULL);
- image_path = "";
- /* grep is needed because host_shell only returns 1 line. */
- postfix = " 2>/dev/null | grep \"" \
- FLASHROM_OUTPUT_WP_PATTERN "\"";
- break;
-
- default:
- assert(0);
- return -1;
- }
-
- if (!extra)
- extra = "";
-
- /* TODO(hungte) In future we should link with flashrom directly. */
- ASPRINTF(&command, "flashrom %s %s -p %s %s %s %s %s", op_cmd,
- image_path, programmer, dash_i, section_name, extra,
- postfix);
-
- if (verbose)
- INFO("Executing: %s\n", command);
-
- if (op != FLASHROM_WP_STATUS) {
- r = system(command);
- free(command);
- if (r)
- ERROR("Error code: %d\n", r);
- return r;
- }
-
- result = host_shell(command);
- strip_string(result, NULL);
- free(command);
- VB2_DEBUG("wp-status: %s\n", result);
-
- if (strstr(result, FLASHROM_OUTPUT_WP_ENABLED))
- r = WP_ENABLED;
- else if (strstr(result, FLASHROM_OUTPUT_WP_DISABLED))
- r = WP_DISABLED;
- else
- r = WP_ERROR;
- free(result);
+ if (!r)
+ r = parse_firmware_image(image);
return r;
}
-/* Helper function to return write protection status via given programmer. */
-enum wp_state host_get_wp(const char *programmer)
+/*
+ * Writes sections from a given firmware image to the system firmware.
+ * Regions should be NULL for writing the whole image, or a list of
+ * FMAP section names (and ended with a NULL).
+ * Returns 0 if success, non-zero if error.
+ */
+int write_system_firmware(const struct firmware_image *image,
+ const struct firmware_image *diff_image,
+ const char * const sections[],
+ struct tempfile *tempfiles,
+ int do_verify, int retries, int verbosity)
{
- return host_flashrom(FLASHROM_WP_STATUS, NULL, programmer, 0, NULL,
- NULL);
+ int r, i, len = 0;
+ char *partial = NULL;
+
+ for (i = 0; sections && sections[i]; i++)
+ len += strlen(sections[i]) + strlen(" -i ");
+ if (len) {
+ partial = (char *)malloc(len + 1);
+ if (!partial) {
+ ERROR("Failed to allocate a string buffer.\n");
+ return -1;
+ }
+ partial[0] = '\0';
+ for (i = 0; sections[i]; i++) {
+ strcat(partial, " -i ");
+ strcat(partial, sections[i]);
+ }
+ assert(strlen(partial) == len);
+ }
+
+ INFO("flashrom -w <IMAGE> -p %s%s%s%s%s\n",
+ image->programmer,
+ diff_image ? " --flash-contents <DIFF_IMAGE>" : "",
+ do_verify ? "" : " --noverify",
+ verbosity > 1 ? " -V" : "",
+ partial ? partial : "");
+ free(partial);
+
+ for (i = 1, r = -1; i <= retries && r != 0; i++) {
+ if (i > 1)
+ WARN("Retry writing firmware (%d/%d)...\n", i, retries);
+ r = flashrom_write_image(image, sections, diff_image, do_verify,
+ verbosity + 1);
+ /*
+ * Force a newline to flush stdout in case if
+ * flashrom_write_image left some messages in the buffer.
+ */
+ fprintf(stdout, "\n");
+ }
+ return r;
}
/* Helper function to return host software write protection status. */
static int host_get_wp_sw(void)
{
- return host_get_wp(PROG_HOST);
-}
-
-/*
- * Loads the active system firmware image (usually from SPI flash chip).
- * Returns 0 if success, non-zero if error.
- */
-int load_system_firmware(struct firmware_image *image,
- struct tempfile *tempfiles, int verbosity)
-{
- int r;
- const char *tmp_path = create_temp_file(tempfiles);
-
- if (!tmp_path)
- return -1;
-
- r = host_flashrom(FLASHROM_READ, tmp_path, image->programmer,
- verbosity, NULL, NULL);
- /*
- * The verbosity for host_flashrom will be translated to
- * (verbosity-1)*'-V', and usually 3*'-V' is enough for debugging.
- */
- const int debug_verbosity = 4;
- if (r && verbosity < debug_verbosity) {
- /* Read again, with verbose messages for debugging. */
- WARN("Failed reading system firmware (%d), try again...\n", r);
- r = host_flashrom(FLASHROM_READ, tmp_path, image->programmer,
- debug_verbosity, NULL, NULL);
- }
- if (!r)
- r = load_firmware_image(image, tmp_path, NULL);
- return r;
-}
-
-/*
- * Writes a section from given firmware image to system firmware.
- * If section_name is NULL, write whole image.
- * Returns 0 if success, non-zero if error.
- */
-int write_system_firmware(const struct firmware_image *image,
- const struct firmware_image *diff_image,
- const char *section_name,
- struct tempfile *tempfiles,
- int verbosity)
-{
- const char *tmp_path = get_firmware_image_temp_file(image, tempfiles);
- const char *tmp_diff = NULL;
-
- const char *programmer = image->programmer;
- char *extra = NULL;
- int r;
-
- if (!tmp_path)
- return -1;
-
- if (diff_image) {
- tmp_diff = get_firmware_image_temp_file(
- diff_image, tempfiles);
- if (!tmp_diff)
- return -1;
- ASPRINTF(&extra, "--noverify --flash-contents=%s", tmp_diff);
- }
-
- r = host_flashrom(FLASHROM_WRITE, tmp_path, programmer, verbosity,
- section_name, extra);
- free(extra);
- return r;
+ return flashrom_get_wp(PROG_HOST);
}
/* Helper function to configure all properties. */
diff --git a/futility/updater_utils.h b/futility/updater_utils.h
index 2531675..3eb1d33 100644
--- a/futility/updater_utils.h
+++ b/futility/updater_utils.h
@@ -54,15 +54,8 @@
*/
void remove_all_temp_files(struct tempfile *head);
-/* Utilities for firmware images and (FMAP) sections */
-struct firmware_image {
- const char *programmer;
- uint32_t size;
- uint8_t *data;
- char *file_name;
- char *ro_version, *rw_version_a, *rw_version_b;
- FmapHeader *fmap_header;
-};
+/* Include definition of 'struct firmware_image;' */
+#include "flashrom.h"
enum {
IMAGE_LOAD_SUCCESS = 0,
@@ -85,7 +78,8 @@
* Returns 0 if success, non-zero if error.
*/
int load_system_firmware(struct firmware_image *image,
- struct tempfile *tempfiles, int verbosity);
+ struct tempfile *tempfiles,
+ int retries, int verbosity);
/* Frees the allocated resource from a firmware image object. */
void free_firmware_image(struct firmware_image *image);
@@ -99,15 +93,16 @@
struct tempfile *tempfiles);
/*
- * Writes a section from given firmware image to system firmware.
- * If section_name is NULL, write whole image.
+ * Writes sections from a given firmware image to the system firmware.
+ * Regions should be NULL for writing the whole image, or a list of
+ * FMAP section names (and ended with a NULL).
* Returns 0 if success, non-zero if error.
*/
int write_system_firmware(const struct firmware_image *image,
const struct firmware_image *diff_image,
- const char *section_name,
+ const char * const sections[],
struct tempfile *tempfiles,
- int verbosity);
+ int do_verify, int retries, int verbosity);
struct firmware_section {
uint8_t *data;
@@ -175,11 +170,14 @@
};
/* Helper function to return write protection status via given programmer. */
-enum wp_state host_get_wp(const char *programmer);
+enum wp_state flashrom_get_wp(const char *programmer);
/* The environment variable name for setting servod port. */
#define ENV_SERVOD_PORT "SERVOD_PORT"
+/* The environment variable name for setting servod name. */
+#define ENV_SERVOD_NAME "SERVOD_NAME"
+
/*
* Helper function to detect type of Servo board attached to host.
* Returns a string as programmer parameter on success, otherwise NULL.
diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c
index e805e2a..d48cf87 100644
--- a/host/arch/x86/lib/crossystem_arch.c
+++ b/host/arch/x86/lib/crossystem_arch.c
@@ -733,6 +733,7 @@
/* INTC105x are for Alderlake */
{ "INTC1055:00", FindGpioChipOffsetByLabel },
{ "INTC1056:00", FindGpioChipOffsetByLabel },
+ { "INTC1057:00", FindGpioChipOffsetByLabel },
/* INT3453 are for GLK */
{ "INT3453:00", FindGpioChipOffsetByLabel },
{ "INT3453:01", FindGpioChipOffsetByLabel },
diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c
index 02443b1..a5427c2 100644
--- a/host/lib/crossystem.c
+++ b/host/lib/crossystem.c
@@ -4,9 +4,11 @@
*/
#include <ctype.h>
+#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
+#include <sys/file.h>
#include <unistd.h>
#include "2api.h"
@@ -22,14 +24,12 @@
#include "subprocess.h"
#include "vboot_struct.h"
+/* Filename for crossystem lock */
+#define CROSSYSTEM_LOCK_PATH "/run/lock/crossystem.lock"
+
/* Filename for kernel command line */
#define KERNEL_CMDLINE_PATH "/proc/cmdline"
-/* Filename for the mount-encrypted key */
-/* TODO(b/174807059): Remove this after we land driver-level TPM simulator on
- * all VM boards */
-#define MOUNT_ENCRYPTED_KEY_PATH "/mnt/stateful_partition/encrypted.key"
-
/* Filename for the TPM simulator NV data */
#define TPM_SIMULATOR_NVCHIP_PATH \
"/mnt/stateful_partition/unencrypted/tpm2-simulator/NVChip"
@@ -92,6 +92,32 @@
return 0 == strncmp(fwid, start, strlen(start));
}
+/* Acquire the lock for crossystem SetSystemProperty call. */
+static int AcquireCrossystemLock(void)
+{
+ int lock_fd;
+
+ lock_fd = open(CROSSYSTEM_LOCK_PATH, O_RDWR | O_CREAT, 0600);
+ if (lock_fd < 0)
+ return -1;
+
+ if (flock(lock_fd, LOCK_EX) < 0)
+ return -1;
+
+ return lock_fd;
+}
+
+/* Release the lock for crossystem SetSystemProperty call. */
+static int ReleaseCrossystemLock(int lock_fd)
+{
+ if (flock(lock_fd, F_UNLCK) < 0)
+ return -1;
+
+ close(lock_fd);
+
+ return 0;
+}
+
static struct vb2_context *get_fake_context(void)
{
static uint8_t fake_workbuf[sizeof(struct vb2_shared_data) + 16]
@@ -381,12 +407,9 @@
} else if (!strcasecmp(name,"disable_dev_request")) {
value = vb2_get_nv_storage(VB2_NV_DISABLE_DEV_REQUEST);
} else if (!strcasecmp(name,"clear_tpm_owner_request")) {
- if (TPM2_SIMULATOR && VTPM_PROXY)
+ if (TPM2_SIMULATOR)
/* Check TPM simulator NVChip status */
value = access(TPM_SIMULATOR_NVCHIP_PATH, F_OK) != 0;
- else if (TPM2_SIMULATOR)
- /* Check mount-encrypted key status */
- value = access(MOUNT_ENCRYPTED_KEY_PATH, F_OK) != 0;
else
value = vb2_get_nv_storage(
VB2_NV_CLEAR_TPM_OWNER_REQUEST);
@@ -488,8 +511,7 @@
return value;
}
-const char *VbGetSystemPropertyString(const char *name, char *dest,
- size_t size)
+const char *VbGetSystemPropertyString(const char *name, char *dest, size_t size)
{
/* Check for HWID override via cros_config */
if (!strcasecmp(name, "hwid")) {
@@ -552,8 +574,7 @@
return NULL;
}
-
-int VbSetSystemPropertyInt(const char *name, int value)
+static int VbSetSystemPropertyIntInternal(const char *name, int value)
{
/* Check architecture-dependent properties first */
@@ -581,13 +602,10 @@
* on simulator */
if (value == 0)
return -1;
- const char *tpm_path =
- VTPM_PROXY ? TPM_SIMULATOR_NVCHIP_PATH
- : MOUNT_ENCRYPTED_KEY_PATH;
/* Check TPM simulator data status */
- if (!access(tpm_path, F_OK)) {
+ if (!access(TPM_SIMULATOR_NVCHIP_PATH, F_OK)) {
/* Remove the TPM2.0 simulator data */
- return remove(tpm_path);
+ return remove(TPM_SIMULATOR_NVCHIP_PATH);
} else {
/* Return success when the file is already
* removed */
@@ -673,7 +691,25 @@
return -1;
}
-int VbSetSystemPropertyString(const char* name, const char* value)
+int VbSetSystemPropertyInt(const char *name, int value)
+{
+ int result = -1;
+ int lock_fd;
+
+ lock_fd = AcquireCrossystemLock();
+ if (lock_fd < 0)
+ return -1;
+
+ result = VbSetSystemPropertyIntInternal(name, value);
+
+ if (ReleaseCrossystemLock(lock_fd) < 0)
+ return -1;
+
+ return result;
+}
+
+static int VbSetSystemPropertyStringInternal(const char *name,
+ const char *value)
{
/* Chain to architecture-dependent properties */
if (0 == VbSetArchPropertyString(name, value))
@@ -725,6 +761,23 @@
return -1;
}
+int VbSetSystemPropertyString(const char *name, const char *value)
+{
+ int result = -1;
+ int lock_fd;
+
+ lock_fd = AcquireCrossystemLock();
+ if (lock_fd < 0)
+ return -1;
+
+ result = VbSetSystemPropertyStringInternal(name, value);
+
+ if (ReleaseCrossystemLock(lock_fd) < 0)
+ return -1;
+
+ return result;
+}
+
/**
* Get index of the last valid VBNV entry in an EEPROM.
*
@@ -768,21 +821,21 @@
{
int index;
int vbnv_size = vb2_nv_get_size(ctx);
- uint8_t *flash_buf;
- uint32_t flash_size;
- if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, VBNV_FMAP_REGION,
- &flash_buf, &flash_size))
+ struct firmware_image image = {
+ .programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
+ };
+ if (flashrom_read(&image, VBNV_FMAP_REGION))
return -1;
- index = vb2_nv_index(flash_buf, flash_size, vbnv_size);
+ index = vb2_nv_index(image.data, image.size, vbnv_size);
if (index < 0) {
- free(flash_buf);
+ free(image.data);
return -1;
}
- memcpy(ctx->nvdata, &flash_buf[index * vbnv_size], vbnv_size);
- free(flash_buf);
+ memcpy(ctx->nvdata, &image.data[index * vbnv_size], vbnv_size);
+ free(image.data);
return 0;
}
@@ -792,34 +845,33 @@
int current_index;
int next_index;
int vbnv_size = vb2_nv_get_size(ctx);
- uint8_t *flash_buf;
- uint32_t flash_size;
- if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, VBNV_FMAP_REGION,
- &flash_buf, &flash_size))
+ struct firmware_image image = {
+ .programmer = FLASHROM_PROGRAMMER_INTERNAL_AP,
+ };
+ if (flashrom_read(&image, VBNV_FMAP_REGION))
return -1;
- current_index = vb2_nv_index(flash_buf, flash_size, vbnv_size);
+ current_index = vb2_nv_index(image.data, image.size, vbnv_size);
if (current_index < 0) {
rv = -1;
goto exit;
}
next_index = current_index + 1;
- if (next_index * vbnv_size == flash_size) {
+ if (next_index * vbnv_size == image.size) {
/* VBNV is full. Erase and write at beginning. */
- memset(flash_buf, 0xff, flash_size);
+ memset(image.data, 0xff, image.size);
next_index = 0;
}
- memcpy(&flash_buf[next_index * vbnv_size], ctx->nvdata, vbnv_size);
- if (flashrom_write(FLASHROM_PROGRAMMER_INTERNAL_AP, VBNV_FMAP_REGION,
- flash_buf, flash_size)) {
+ memcpy(&image.data[next_index * vbnv_size], ctx->nvdata, vbnv_size);
+ if (flashrom_write(&image, VBNV_FMAP_REGION)) {
rv = -1;
goto exit;
}
exit:
- free(flash_buf);
+ free(image.data);
return rv;
}
diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c
index e83dfb2..6ee5971 100644
--- a/host/lib/flashrom.c
+++ b/host/lib/flashrom.c
@@ -103,15 +103,14 @@
return VB2_SUCCESS;
}
-vb2_error_t flashrom_read(const char *programmer, const char *region,
- uint8_t **data_out, uint32_t *size_out)
+vb2_error_t flashrom_read(struct firmware_image *image, const char *region)
{
char *tmpfile;
char region_param[PATH_MAX];
vb2_error_t rv;
- *data_out = NULL;
- *size_out = 0;
+ image->data = NULL;
+ image->size = 0;
VB2_TRY(write_temp_file(NULL, 0, &tmpfile));
@@ -122,7 +121,7 @@
const char *const argv[] = {
FLASHROM_EXEC_NAME,
"-p",
- programmer,
+ image->programmer,
"-r",
region ? "-i" : tmpfile,
region ? region_param : NULL,
@@ -131,21 +130,20 @@
rv = run_flashrom(argv);
if (rv == VB2_SUCCESS)
- rv = vb2_read_file(tmpfile, data_out, size_out);
+ rv = vb2_read_file(tmpfile, &image->data, &image->size);
unlink(tmpfile);
free(tmpfile);
return rv;
}
-vb2_error_t flashrom_write(const char *programmer, const char *region,
- uint8_t *data, uint32_t size)
+vb2_error_t flashrom_write(struct firmware_image *image, const char *region)
{
char *tmpfile;
char region_param[PATH_MAX];
vb2_error_t rv;
- VB2_TRY(write_temp_file(data, size, &tmpfile));
+ VB2_TRY(write_temp_file(image->data, image->size, &tmpfile));
if (region)
snprintf(region_param, sizeof(region_param), "%s:%s", region,
@@ -154,7 +152,7 @@
const char *const argv[] = {
FLASHROM_EXEC_NAME,
"-p",
- programmer,
+ image->programmer,
"--noverify-all",
"-w",
region ? "-i" : tmpfile,
diff --git a/host/lib/flashrom_drv.c b/host/lib/flashrom_drv.c
new file mode 100644
index 0000000..1d9e3fd
--- /dev/null
+++ b/host/lib/flashrom_drv.c
@@ -0,0 +1,212 @@
+/* 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.
+ *
+ * The utility functions for firmware updater.
+ */
+
+#include <libflashrom.h>
+
+#include "2common.h"
+#include "crossystem.h"
+#include "host_misc.h"
+#include "util_misc.h"
+//#include "updater.h"
+#include "../../futility/futility.h"
+#include "flashrom.h"
+
+// global to allow verbosity level to be injected into callback.
+static enum flashrom_log_level g_verbose_screen = FLASHROM_MSG_INFO;
+
+static int flashrom_print_cb(enum flashrom_log_level level, const char *fmt,
+ va_list ap)
+{
+ int ret = 0;
+ FILE *output_type = (level < FLASHROM_MSG_INFO) ? stderr : stdout;
+
+ if (level > g_verbose_screen)
+ return ret;
+
+ ret = vfprintf(output_type, fmt, ap);
+ /* msg_*spew often happens inside chip accessors
+ * in possibly time-critical operations.
+ * Don't slow them down by flushing.
+ */
+ if (level != FLASHROM_MSG_SPEW)
+ fflush(output_type);
+
+ return ret;
+}
+
+static char *flashrom_extract_params(const char *str, char **prog, char **params)
+{
+ char *tmp = strdup(str);
+ *prog = strtok(tmp, ":");
+ *params = strtok(NULL, "");
+ return tmp;
+}
+
+int flashrom_read_image(struct firmware_image *image, const char *region,
+ int verbosity)
+{
+ int r = 0;
+ size_t len = 0;
+
+ g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
+
+ char *programmer, *params;
+ char *tmp = flashrom_extract_params(image->programmer, &programmer, ¶ms);
+
+ struct flashrom_programmer *prog = NULL;
+ struct flashrom_flashctx *flashctx = NULL;
+ struct flashrom_layout *layout = NULL;
+
+ flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
+
+ if (flashrom_init(1)
+ || flashrom_programmer_init(&prog, programmer, params)) {
+ r = -1;
+ goto err_init;
+ }
+ if (flashrom_flash_probe(&flashctx, prog, NULL)) {
+ r = -1;
+ goto err_probe;
+ }
+
+ len = flashrom_flash_getsize(flashctx);
+
+ if (region) {
+ r = flashrom_layout_read_fmap_from_buffer(
+ &layout, flashctx, (const uint8_t *)image->data,
+ image->size);
+ if (r > 0) {
+ WARN("could not read fmap from image, r=%d, "
+ "falling back to read from rom\n", r);
+ r = flashrom_layout_read_fmap_from_rom(
+ &layout, flashctx, 0, len);
+ if (r > 0) {
+ ERROR("could not read fmap from rom, r=%d\n", r);
+ r = -1;
+ goto err_cleanup;
+ }
+ }
+ // empty region causes seg fault in API.
+ r |= flashrom_layout_include_region(layout, region);
+ if (r > 0) {
+ ERROR("could not include region = '%s'\n", region);
+ r = -1;
+ goto err_cleanup;
+ }
+ flashrom_layout_set(flashctx, layout);
+ }
+
+ image->data = calloc(1, len);
+ image->size = len;
+ image->file_name = strdup("<sys-flash>");
+
+ r |= flashrom_image_read(flashctx, image->data, len);
+
+err_cleanup:
+ flashrom_layout_release(layout);
+ flashrom_flash_release(flashctx);
+
+err_probe:
+ r |= flashrom_programmer_shutdown(prog);
+
+err_init:
+ free(tmp);
+ return r;
+}
+
+int flashrom_write_image(const struct firmware_image *image,
+ const char * const regions[],
+ const struct firmware_image *diff_image,
+ int do_verify, int verbosity)
+{
+ int r = 0;
+ size_t len = 0;
+
+ g_verbose_screen = (verbosity == -1) ? FLASHROM_MSG_INFO : verbosity;
+
+ char *programmer, *params;
+ char *tmp = flashrom_extract_params(image->programmer, &programmer, ¶ms);
+
+ struct flashrom_programmer *prog = NULL;
+ struct flashrom_flashctx *flashctx = NULL;
+ struct flashrom_layout *layout = NULL;
+
+ flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
+
+ if (flashrom_init(1)
+ || flashrom_programmer_init(&prog, programmer, params)) {
+ r = -1;
+ goto err_init;
+ }
+ if (flashrom_flash_probe(&flashctx, prog, NULL)) {
+ r = -1;
+ goto err_probe;
+ }
+
+ len = flashrom_flash_getsize(flashctx);
+ if (len == 0) {
+ ERROR("zero sized flash detected\n");
+ r = -1;
+ goto err_cleanup;
+ }
+
+ if (diff_image) {
+ if (diff_image->size != image->size) {
+ ERROR("diff_image->size != image->size");
+ r = -1;
+ goto err_cleanup;
+ }
+ }
+
+ if (regions) {
+ int i;
+ r = flashrom_layout_read_fmap_from_buffer(
+ &layout, flashctx, (const uint8_t *)image->data,
+ image->size);
+ if (r > 0) {
+ WARN("could not read fmap from image, r=%d, "
+ "falling back to read from rom\n", r);
+ r = flashrom_layout_read_fmap_from_rom(
+ &layout, flashctx, 0, len);
+ if (r > 0) {
+ ERROR("could not read fmap from rom, r=%d\n", r);
+ r = -1;
+ goto err_cleanup;
+ }
+ }
+ for (i = 0; regions[i]; i++) {
+ // empty region causes seg fault in API.
+ r |= flashrom_layout_include_region(layout, regions[i]);
+ if (r > 0) {
+ ERROR("could not include region = '%s'\n",
+ regions[i]);
+ r = -1;
+ goto err_cleanup;
+ }
+ }
+ flashrom_layout_set(flashctx, layout);
+ }
+
+ flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, true);
+ flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true);
+ if (!do_verify)
+ flashrom_flag_set(flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, false);
+
+ r |= flashrom_image_write(flashctx, image->data, image->size,
+ diff_image ? diff_image->data : NULL);
+
+err_cleanup:
+ flashrom_layout_release(layout);
+ flashrom_flash_release(flashctx);
+
+err_probe:
+ r |= flashrom_programmer_shutdown(prog);
+
+err_init:
+ free(tmp);
+ return r;
+}
diff --git a/host/lib/include/flashrom.h b/host/lib/include/flashrom.h
index 560fbb0..6058d64 100644
--- a/host/lib/include/flashrom.h
+++ b/host/lib/include/flashrom.h
@@ -8,43 +8,54 @@
#include <stdint.h>
#include "2return_codes.h"
+#include "fmap.h"
#define FLASHROM_PROGRAMMER_INTERNAL_AP "host"
#define FLASHROM_PROGRAMMER_INTERNAL_EC "ec"
+/* Utilities for firmware images and (FMAP) sections */
+struct firmware_image {
+ /**
+ * programmer The name of the programmer to use. Use either
+ * FLASHROM_PROGRAMMER_INTERNAL_AP or,
+ * FLASHROM_PROGRAMMER_INTERNAL_EC
+ * for the AP and EC respectively.
+ */
+ const char *programmer;
+ uint32_t size; /* buffer size. */
+ uint8_t *data; /* data allocated buffer to read/write with. */
+ char *file_name;
+ char *ro_version, *rw_version_a, *rw_version_b;
+ FmapHeader *fmap_header;
+};
+
/**
* Read using flashrom into an allocated buffer.
*
- * @param programmer The name of the programmer to use. There are
- * named constants FLASHROM_PROGRAMMER_INTERNAL_AP
- * and FLASHROM_PROGRAMMER_INTERNAL_EC available
- * for the AP and EC respectively, or a custom
- * programmer string can be provided.
+ * @param image The parameter that contains the programmer, buffer and
+ * size to use in the read operation.
* @param region The name of the fmap region to read, or NULL to
* read the entire flash chip.
- * @param data_out Output parameter of allocated buffer to read into.
- * The caller should free the buffer.
- * @param size_out Output parameter of buffer size.
*
* @return VB2_SUCCESS on success, or a relevant error.
*/
-vb2_error_t flashrom_read(const char *programmer, const char *region,
- uint8_t **data_out, uint32_t *size_out);
+vb2_error_t flashrom_read(struct firmware_image *image, const char *region);
+int flashrom_read_image(struct firmware_image *image, const char *region,
+ int verbosity);
/**
* Write using flashrom from a buffer.
*
- * @param programmer The name of the programmer to use. There are
- * named constants FLASHROM_PROGRAMMER_INTERNAL_AP
- * and FLASHROM_PROGRAMMER_INTERNAL_EC available
- * for the AP and EC respectively, or a custom
- * programmer string can be provided.
- * @param region The name of the fmap region to write, or NULL to
- * write the entire flash chip.
- * @param data The buffer to write.
- * @param size The size of the buffer to write.
+ * @param image The parameter that contains the programmer, buffer and
+ * size to use in the write operation.
+ * @param regions A list of the names of the fmap regions to write, or
+ * NULL to write the entire flash chip. The list must be
+ * ended with a NULL pointer.
*
* @return VB2_SUCCESS on success, or a relevant error.
*/
-vb2_error_t flashrom_write(const char *programmer, const char *region,
- uint8_t *data, uint32_t size);
+vb2_error_t flashrom_write(struct firmware_image *image, const char *region);
+int flashrom_write_image(const struct firmware_image *image,
+ const char * const regions[],
+ const struct firmware_image *diff_image,
+ int do_verify, int verbosity);
diff --git a/host/lib/include/gsc_ro.h b/host/lib/include/gsc_ro.h
new file mode 100644
index 0000000..00a4011
--- /dev/null
+++ b/host/lib/include/gsc_ro.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef __VBOOT_REFERENCE_HOST_LIB_INCLUDE_GSC_RO_H
+#define __VBOOT_REFERENCE_HOST_LIB_INCLUDE_GSC_RO_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "2sha.h"
+
+struct gscvd_ro_range {
+ uint32_t offset;
+ uint32_t size; /* Use uint32_t as opposed to size_to be portable. */
+};
+
+#define GSC_VD_MAGIC 0x65666135 /* Little endian '5 a f e' */
+#define GSC_VD_ROLLBACK_COUNTER 1
+
+struct gsc_verification_data {
+ uint32_t gv_magic;
+ /*
+ * Size of this structure in bytes, including the ranges array,
+ * signature and root key bodies.
+ */
+ uint16_t size;
+ uint16_t major_version; /* Version of this struct layout. Starts at 0 */
+ uint16_t minor_version;
+ /*
+ * GSC will cache the counter value and will not accept verification
+ * data blobs with a lower value.
+ */
+ uint16_t rollback_counter;
+ uint32_t gsc_board_id; /* Locks blob to certain platform. */
+ uint32_t gsc_flags; /* A field for future enhancements. */
+ /*
+ * The location of fmap that points to this blob. This location must
+ * also be in one of the verified sections, expressed as offset in
+ * flash
+ */
+ uint32_t fmap_location;
+ uint32_t hash_alg; /* one of enum vb2_hash_algorithm alg. */
+ struct vb2_signature sig_header;
+ struct vb2_packed_key root_key_header;
+ /*
+ * SHAxxx(ranges[0].offset..ranges[0].size || ... ||
+ * ranges[n].offset..ranges[n].size)
+ *
+ * Let the digest space allow to accommodate the largest possible one.
+ */
+ uint8_t ranges_digest[VB2_SHA512_DIGEST_SIZE];
+ uint32_t range_count; /* Number of gscvd_ro_range entries. */
+ struct gscvd_ro_range ranges[0];
+};
+
+#endif /* ! __VBOOT_REFERENCE_HOST_LIB_INCLUDE_GSC_RO_H */
diff --git a/rust/OWNERS b/rust/OWNERS
new file mode 100644
index 0000000..fe3921f
--- /dev/null
+++ b/rust/OWNERS
@@ -0,0 +1 @@
+allenwebb@chromium.org
diff --git a/rust/README.md b/rust/README.md
new file mode 100644
index 0000000..3a899ce
--- /dev/null
+++ b/rust/README.md
@@ -0,0 +1,18 @@
+# Rust bindings for vboot_reference
+
+This path contains the vboot_reference-sys crate which uses bindgen to generate
+Rust bindings for the vboot_reference C library.
+
+Each header is included as its own submodule. To use these bindings:
+ * Add `vboot_reference-sys` to your `Cargo.toml` for example:
+```toml
+[dependencies]
+vboot_reference-sys = { path = "../../vboot_reference/rust/vboot_reference-sys" }
+```
+ * Include the symbols you need for example:
+```rust
+use vboot_reference_sys::crossystem::*;
+```
+
+The `build.rs` in `vboot_reference-sys` takes care of adding the necessary
+includes and linker flags for `vboot_host` through the `pkg-config` crate.
diff --git a/rust/vboot_reference-sys/Cargo.toml b/rust/vboot_reference-sys/Cargo.toml
new file mode 100644
index 0000000..59769ee
--- /dev/null
+++ b/rust/vboot_reference-sys/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "vboot_reference-sys"
+version = "1.0.0"
+description = "Provides raw (unsafe) bindings to the vboot_reference C library."
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+build = "build.rs"
+
+[lib]
+path = "lib.rs"
+
+[dependencies]
+libc = "0.2.44"
+
+[build-dependencies]
+pkg-config = "0.3"
+which = "4.0.0"
diff --git a/rust/vboot_reference-sys/build.rs b/rust/vboot_reference-sys/build.rs
new file mode 100644
index 0000000..523602f
--- /dev/null
+++ b/rust/vboot_reference-sys/build.rs
@@ -0,0 +1,54 @@
+// Copyright 2019 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.
+
+/// Minijail's build script invoked by cargo.
+///
+/// This script prefers linking against a pkg-config provided libminijail, but will fall back to
+/// building libminijail statically.
+use std::env;
+use std::fs::remove_file;
+use std::io;
+use std::path::Path;
+use std::process::Command;
+
+fn bindings_generation() -> io::Result<()> {
+ let bindgen = which::which("bindgen").unwrap();
+
+ let out_dir = env::var("OUT_DIR").unwrap();
+ let gen_file = Path::new(&out_dir).join("./crossystem.rs");
+ if gen_file.exists() {
+ remove_file(&gen_file).expect("Failed to remove generated file.");
+ }
+ let header_dir = Path::new(".");
+ let header_path = header_dir.join("crossystem.h");
+ println!("cargo:rerun-if-changed={}", header_path.display());
+ let status = Command::new(&bindgen)
+ .args(&["--default-enum-style", "rust"])
+ .args(&["--blacklist-type", "__rlim64_t"])
+ .args(&["--raw-line", "pub type __rlim64_t = u64;"])
+ .args(&["--blacklist-type", "__u\\d{1,2}"])
+ .args(&["--raw-line", "pub type __u8 = u8;"])
+ .args(&["--raw-line", "pub type __u16 = u16;"])
+ .args(&["--raw-line", "pub type __u32 = u32;"])
+ .args(&["--blacklist-type", "__uint64_t"])
+ .arg("--no-layout-tests")
+ .arg("--disable-header-comment")
+ .args(&["--output", gen_file.to_str().unwrap()])
+ .arg(header_path.to_str().unwrap())
+ .args(&[
+ "--",
+ "-DUSE_BINDGEN",
+ "-D_FILE_OFFSET_BITS=64",
+ "-D_LARGEFILE_SOURCE",
+ "-D_LARGEFILE64_SOURCE",
+ ])
+ .status()?;
+ assert!(status.success());
+ Ok(())
+}
+
+fn main() -> io::Result<()> {
+ pkg_config::Config::new().probe("vboot_host").unwrap();
+ bindings_generation()
+}
diff --git a/rust/vboot_reference-sys/crossystem.h b/rust/vboot_reference-sys/crossystem.h
new file mode 120000
index 0000000..9672639
--- /dev/null
+++ b/rust/vboot_reference-sys/crossystem.h
@@ -0,0 +1 @@
+../../host/include/crossystem.h
\ No newline at end of file
diff --git a/rust/vboot_reference-sys/lib.rs b/rust/vboot_reference-sys/lib.rs
new file mode 100644
index 0000000..85b6f2a
--- /dev/null
+++ b/rust/vboot_reference-sys/lib.rs
@@ -0,0 +1,15 @@
+// Copyright 2022 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.
+
+/// vboot_reference bindings for Rust.
+
+#[allow(
+ clippy::all,
+ non_camel_case_types,
+ non_snake_case,
+ non_upper_case_globals
+)]
+pub mod crossystem {
+ include!(concat!(env!("OUT_DIR"), "/crossystem.rs"));
+}
diff --git a/scripts/image_signing/gbb_flags_common.sh b/scripts/image_signing/gbb_flags_common.sh
index 63c3f12..ed51f15 100755
--- a/scripts/image_signing/gbb_flags_common.sh
+++ b/scripts/image_signing/gbb_flags_common.sh
@@ -51,9 +51,50 @@
${GBBFLAGS_DESCRIPTION}"
flashrom_read() {
- flashrom -p host -i GBB -r "$@"
+ local file="$1"
+ local programmer="$2"
+ flashrom -p "${programmer}" -i GBB -i FMAP -r "${file}"
}
flashrom_write() {
- flashrom -p host -i GBB --noverify-all -w "$@"
+ local file="$1"
+ local programmer="$2"
+ flashrom -p "${programmer}" -i GBB --noverify-all -w "${file}"
+}
+
+get_programmer_for_servo() {
+ local servo_type
+ local serial
+ local programmer
+ servo_type=$(dut-control -o servo_type 2>/dev/null) || \
+ die "Failed to get servo information. Is servod running?"
+ case "${servo_type}" in
+ *with_servo_micro*)
+ serial=$(dut-control -o servo_micro_serialname 2>/dev/null)
+ ;;
+ *with_c2d2*)
+ serial=$(dut-control -o c2d2_serialname 2>/dev/null)
+ ;;
+ *with_ccd*)
+ serial=$(dut-control -o ccd_serialname 2>/dev/null)
+ ;;
+ *)
+ serial=$(dut-control -o serialname 2>/dev/null)
+ ;;
+ esac
+ case "${servo_type}" in
+ *servo_micro*|*c2d2*)
+ # TODO(sammc): Support servo micro, servo v2 and C2D2. This requires
+ # toggling cpu_fw_spi via dut-control before and after running flashrom.
+ # C2D2 additionally requires a working cpu_fw_spi implementation.
+ die "Unsupported servo type ${servo_type}"
+ ;;
+ *ccd_cr50*|*ccd_gsc*)
+ programmer="raiden_debug_spi:target=AP,serial=${serial}"
+ ;;
+ *)
+ die "Unsupported servo type ${servo_type}"
+ ;;
+ esac
+ echo "${programmer}"
}
diff --git a/scripts/image_signing/get_gbb_flags.sh b/scripts/image_signing/get_gbb_flags.sh
index 2b78af6..1191e9f 100755
--- a/scripts/image_signing/get_gbb_flags.sh
+++ b/scripts/image_signing/get_gbb_flags.sh
@@ -13,6 +13,8 @@
# DEFINE_string name default_value description flag
DEFINE_string file "" "Path to firmware image. Default to system firmware." "f"
DEFINE_boolean explicit ${FLAGS_FALSE} "Print list of what flags are set." "e"
+DEFINE_string programmer "host" "Programmer to use when setting GBB flags" "p"
+DEFINE_boolean servo "${FLAGS_FALSE}" "Determine programmer using servo" ""
set -e
@@ -23,10 +25,14 @@
fi
local image_file="${FLAGS_file}"
+ local programmer="${FLAGS_programmer}"
if [ -z "${FLAGS_file}" ]; then
image_file="$(make_temp_file)"
- flashrom_read "${image_file}"
+ if [ "${FLAGS_servo}" = "${FLAGS_TRUE}" ]; then
+ programmer=$(get_programmer_for_servo)
+ fi
+ flashrom_read "${image_file}" "${programmer}"
fi
# Process file.
diff --git a/scripts/image_signing/make_dev_ssd.sh b/scripts/image_signing/make_dev_ssd.sh
index ed102a6..d9df52a 100755
--- a/scripts/image_signing/make_dev_ssd.sh
+++ b/scripts/image_signing/make_dev_ssd.sh
@@ -35,7 +35,15 @@
DEFINE_string image "$ROOTDEV_DISK" "Path to device or image file" "i"
DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k"
DEFINE_boolean remove_rootfs_verification \
- $FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" ""
+ "${FLAGS_FALSE}" "Modify kernel boot config to disable rootfs verification" ""
+DEFINE_boolean enable_earlycon "${FLAGS_FALSE}" \
+ "Enable earlycon from stdout-path (ARM/ARM64) or SPCR (x86)." ""
+DEFINE_boolean disable_earlycon "${FLAGS_FALSE}" \
+ "Disable earlycon." ""
+DEFINE_boolean enable_console "${FLAGS_FALSE}" \
+ "Enable serial console." ""
+DEFINE_boolean disable_console "${FLAGS_FALSE}" \
+ "Disable serial console." ""
DEFINE_string backup_dir \
"$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" ""
DEFINE_string save_config "" \
@@ -98,14 +106,37 @@
debug_msg "Removing rootfs verification for legacy boot configuration."
mount_image_partition "$image" 12 "$mount_point" || return $FLAGS_FALSE
config_file="$mount_point/efi/boot/grub.cfg"
- [ ! -f "$config_file" ] ||
- sudo sed -i 's/^ *set default=2 *$/set default=0/g' "$config_file"
+ [ ! -f "${config_file}" ] ||
+ sudo sed -i -e 's/^ *defaultA=2 *$/defaultA=0/g' \
+ -e 's/^ *defaultB=3 *$/defaultB=1/g' "${config_file}"
config_file="$mount_point/syslinux/default.cfg"
[ ! -f "$config_file" ] ||
sudo sed -i 's/-vusb/-usb/g; s/-vhd/-hd/g' "$config_file"
sudo umount "$mount_point"
}
+# Enable/Disable earlycon or serial console
+insert_parameter() {
+ local cmdline="$1"
+ local param="$2"
+
+ if [ -n "${cmdline##*${param}*}" ]; then
+ cmdline="${param} ${cmdline}"
+ fi
+
+ echo "${cmdline}"
+}
+
+remove_parameter() {
+ local cmdline="$1"
+ local param="$2"
+
+ cmdline=$(echo "${cmdline}" | sed '
+ s/'"${param} "'//g')
+
+ echo "${cmdline}"
+}
+
# Wrapped version of dd
mydd() {
# oflag=sync is safer, but since we need bs=512, syncing every block would be
@@ -244,6 +275,26 @@
remove_legacy_boot_rootfs_verification "$ssd_device"
fi
+ if [ "${FLAGS_enable_earlycon}" = "${FLAGS_TRUE}" ]; then
+ debug_msg "Enabling earlycon"
+ kernel_config="$(insert_parameter "${kernel_config}" "earlycon")"
+ debug_msg "New kernel config: ${kernel_config}"
+ elif [ "${FLAGS_disable_earlycon}" = "${FLAGS_TRUE}" ]; then
+ debug_msg "Disabling earlycon"
+ kernel_config="$(remove_parameter "${kernel_config}" "earlycon")"
+ debug_msg "New kernel config: ${kernel_config}"
+ fi
+
+ if [ "${FLAGS_enable_console}" = "${FLAGS_TRUE}" ]; then
+ debug_msg "Enabling serial console"
+ kernel_config="$(remove_parameter "${kernel_config}" "console=")"
+ debug_msg "New kernel config: ${kernel_config}"
+ elif [ "${FLAGS_disable_console}" = "${FLAGS_TRUE}" ]; then
+ debug_msg "Disabling serial console"
+ kernel_config="$(insert_parameter "${kernel_config}" "console=")"
+ debug_msg "New kernel config: ${kernel_config}"
+ fi
+
local new_kernel_config_file="$(make_temp_file)"
echo -n "$kernel_config" >"$new_kernel_config_file"
diff --git a/scripts/image_signing/set_gbb_flags.sh b/scripts/image_signing/set_gbb_flags.sh
index 7a22b85..3057da5 100755
--- a/scripts/image_signing/set_gbb_flags.sh
+++ b/scripts/image_signing/set_gbb_flags.sh
@@ -13,6 +13,8 @@
# DEFINE_string name default_value description flag
DEFINE_string file "" "Path to firmware image. Default to system firmware." "f"
DEFINE_boolean check_wp ${FLAGS_TRUE} "Check write protection states first." ""
+DEFINE_string programmer "host" "Programmer to use when setting GBB flags" "p"
+DEFINE_boolean servo "${FLAGS_FALSE}" "Determine programmer using servo" ""
set -e
@@ -20,12 +22,13 @@
# ----------------------------------------------------------------------------
check_write_protection() {
local hw_wp="" sw_wp=""
- if ! crossystem "wpsw_cur?0"; then
+ local programmer="$1"
+ if [ "${programmer}" = "host" ] && ! crossystem "wpsw_cur?0"; then
hw_wp="on"
fi
# Keep 'local' declaration split from assignment so return code is checked.
local wp_states
- wp_states="$(flashrom -p host --wp-status 2>/dev/null | grep WP)"
+ wp_states="$(flashrom -p "${programmer}" --wp-status 2>/dev/null | grep WP)"
local wp_disabled="$(echo "${wp_states}" | grep "WP:.*is disabled.")"
local wp_zero_len="$(echo "${wp_states}" | grep "WP:.*, len=0x00000000")"
if [ -z "${wp_disabled}" -a -z "${wp_zero_len}" ]; then
@@ -47,10 +50,15 @@
local value="$(($1))"
local image_file="${FLAGS_file}"
+ local programmer="${FLAGS_programmer}"
if [ -z "${FLAGS_file}" ]; then
image_file="$(make_temp_file)"
- flashrom_read "${image_file}"
+ if [ "${FLAGS_servo}" = "${FLAGS_TRUE}" ]; then
+ programmer=$(get_programmer_for_servo)
+ fi
+
+ flashrom_read "${image_file}" "${programmer}"
fi
# Process file
@@ -62,14 +70,14 @@
if [ -z "${FLAGS_file}" ]; then
if [ "${FLAGS_check_wp}" = "${FLAGS_TRUE}" ]; then
- if ! check_write_protection; then
+ if ! check_write_protection "${programmer}"; then
echo ""
echo "WARNING: System GBB Flags are NOT changed!!!"
echo "ERROR: You must disable write protection before setting flags."
exit 1
fi
fi
- flashrom_write "$image_file"
+ flashrom_write "${image_file}" "${programmer}"
fi
}
diff --git a/scripts/image_signing/sign_android_image.sh b/scripts/image_signing/sign_android_image.sh
index a7d0fc6..5af1aa6 100755
--- a/scripts/image_signing/sign_android_image.sh
+++ b/scripts/image_signing/sign_android_image.sh
@@ -315,7 +315,7 @@
elif [[ "${compression}" == "Compression lz4" ]]; then
compression_flags="-comp lz4 -Xhc -b 256K"
elif [[ "${compression}" == "Compression zstd" ]]; then
- compression_flags="-comp zstd"
+ compression_flags="-comp zstd -b 256K"
else
die "Unexpected compression type: ${compression}"
fi
diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh
index 53a9264..98c8610 100755
--- a/scripts/image_signing/sign_official_build.sh
+++ b/scripts/image_signing/sign_official_build.sh
@@ -110,28 +110,30 @@
get_hash_from_config() {
local kernel_config=$1
local dm_config=$(get_dmparams_from_config "${kernel_config}")
- local vroot_dev=$(get_dm_slave "${dm_config}" vroot)
+ local vroot_dev=$(get_dm_device "${dm_config}" vroot)
echo $(get_verity_arg "${vroot_dev}" root_hexdigest)
}
-# Get the slave device and its args
-# get_dm_ags $dm_config [vboot|vroot]
-# Assumes we have only one slave device per device
-get_dm_slave() {
+# Get the mapped device and its args.
+# Usage:
+# get_dm_device $dm_config [vboot|vroot]
+# Assumes we have only one mapped device per device.
+get_dm_device() {
local dm=$1
local device=$2
echo $(echo "${dm}" | sed -nre "s/.*${device}[^,]*,([^,]*).*/\1/p")
}
-# Set the slave device and its args for a device
-# get_dm_ags $dm_config [vboot|vroot] args
-# Assumes we have only one slave device per device
-set_dm_slave() {
+# Set the mapped device and its args for a device.
+# Usage:
+# set_dm_device $dm_config [vboot|vroot] args
+# Assumes we have only one mapped device per device.
+set_dm_device() {
local dm=$1
local device=$2
- local slave=$3
+ local args=$3
echo $(echo "${dm}" |
- sed -nre "s#(.*${device}[^,]*,)([^,]*)(.*)#\1${slave}\3#p")
+ sed -nre "s#(.*${device}[^,]*,)([^,]*)(.*)#\1${args}\3#p")
}
CALCULATED_KERNEL_CONFIG=
@@ -154,7 +156,7 @@
warn "Couldn't grab dm_config. Aborting rootfs hash calculation."
return 1
fi
- local vroot_dev=$(get_dm_slave "${dm_config}" vroot)
+ local vroot_dev=$(get_dm_device "${dm_config}" vroot)
# Extract the key-value parameters from the kernel command line.
local rootfs_sectors=$(get_verity_arg "${vroot_dev}" hashstart)
@@ -169,15 +171,15 @@
fi
# Run the verity tool on the rootfs partition.
- local slave=$(sudo verity mode=create \
+ local table=$(sudo verity mode=create \
alg=${verity_algorithm} \
payload="${rootfs_image}" \
payload_blocks=$((rootfs_sectors / 8)) \
hashtree="${hash_image}" ${salt_arg})
# Reconstruct new kernel config command line and replace placeholders.
- slave="$(echo "${slave}" |
+ table="$(echo "${table}" |
sed -s "s|ROOT_DEV|${root_dev}|g;s|HASH_DEV|${hash_dev}|")"
- CALCULATED_DM_ARGS="$(set_dm_slave "${dm_config}" vroot "${slave}")"
+ CALCULATED_DM_ARGS="$(set_dm_device "${dm_config}" vroot "${table}")"
CALCULATED_KERNEL_CONFIG="$(echo "${kernel_config}" |
sed -e 's#\(.*dm="\)\([^"]*\)\(".*\)'"#\1${CALCULATED_DM_ARGS}\3#g")"
}
@@ -709,6 +711,7 @@
# Args: LOOPDEV
sign_uefi_binaries() {
local loopdev="$1"
+ local efi_glob="*.efi"
if [[ ! -d "${KEY_DIR}/uefi" ]]; then
return 0
@@ -725,13 +728,18 @@
# 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"
+ else
+ # b/205145491: the reven board's boot*.efi files are already signed,
+ # change the glob so that they don't get resigned.
+ efi_glob="grub*.efi"
fi
- "${SCRIPT_DIR}/sign_uefi.sh" "${esp_dir}" "${KEY_DIR}/uefi"
+ "${SCRIPT_DIR}/sign_uefi.sh" "${esp_dir}" "${KEY_DIR}/uefi" "${efi_glob}"
sudo umount "${esp_dir}"
local rootfs_dir="$(make_temp_dir)"
mount_loop_image_partition "${loopdev}" 3 "${rootfs_dir}"
- "${SCRIPT_DIR}/sign_uefi.sh" "${rootfs_dir}/boot" "${KEY_DIR}/uefi"
+ "${SCRIPT_DIR}/sign_uefi.sh" "${rootfs_dir}/boot" "${KEY_DIR}/uefi" \
+ "${efi_glob}"
sudo umount "${rootfs_dir}"
info "Signed UEFI binaries"
@@ -1145,6 +1153,9 @@
--version "${FIRMWARE_VERSION}" "${OUTPUT_IMAGE}"
elif [[ "${TYPE}" == "gsc_firmware" ]]; then
sign_gsc_firmware "${INPUT_IMAGE}" "${KEY_DIR}" "${OUTPUT_IMAGE}"
+elif [[ "${TYPE}" == "hps_firmware" ]]; then
+ hps-sign-rom --input "${INPUT_IMAGE}" --output "${OUTPUT_IMAGE}" \
+ --private-key "${KEY_DIR}/key_hps.priv.pem"
else
die "Invalid type ${TYPE}"
fi
diff --git a/scripts/image_signing/sign_uefi.sh b/scripts/image_signing/sign_uefi.sh
index 14c328e..d0f9e51 100755
--- a/scripts/image_signing/sign_uefi.sh
+++ b/scripts/image_signing/sign_uefi.sh
@@ -130,7 +130,8 @@
local working_dir="$(make_temp_dir)"
local efi_file
- for efi_file in "${bootloader_dir}"/*.efi; do
+ # Leave ${efi_glob} unquoted so that globbing occurs.
+ for efi_file in "${bootloader_dir}"/${efi_glob}; do
if [[ ! -f "${efi_file}" ]]; then
continue
fi
diff --git a/scripts/keygeneration/accessory/common_leverage_hammer.sh b/scripts/keygeneration/accessory/common_leverage_hammer.sh
index 1e0f712..7c51af1 100644
--- a/scripts/keygeneration/accessory/common_leverage_hammer.sh
+++ b/scripts/keygeneration/accessory/common_leverage_hammer.sh
@@ -7,13 +7,27 @@
# Load common constants and functions.
. "$(dirname "$0")/../common.sh"
+: "${HAS_ARG_KEYNAME:=}"
+
usage() {
- cat <<EOF
+ if [[ -n "${HAS_ARG_KEYNAME}" ]]; then
+ cat <<EOF
+Usage: ${PROG} <keyname> [options]
+
+Arguments:
+ keyname: Name of the hammer device (e.g. Staff, Wand).
+
+Options:
+ -o, --output_dir <dir>: Where to write the keys (default is cwd)
+EOF
+ else
+ cat <<EOF
Usage: ${PROG} [options]
Options:
-o, --output_dir <dir>: Where to write the keys (default is cwd)
EOF
+ fi
if [[ $# -ne 0 ]]; then
die "$*"
@@ -40,8 +54,7 @@
# to specific accessory's name.
leverage_hammer_to_create_key() {
local output_dir="${PWD}"
- local key_name="$1"
- shift
+ local key_name=""
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -51,19 +64,26 @@
-o|--output_dir)
output_dir="$2"
if [[ ! -d "${output_dir}" ]]; then
- die "output dir ("${output_dir}") doesn't exist."
+ die "output dir (\"${output_dir}\") doesn't exist."
fi
shift
;;
-*)
- usage "Unknown option: "$1""
+ usage "Unknown option: \"$1\""
;;
*)
- usage "Unknown argument "$1""
+ if [[ -n "${key_name}" ]]; then
+ usage "Unknown argument \"$1\""
+ fi
+ key_name="$1"
;;
esac
shift
done
+ if [[ -z "${key_name}" ]]; then
+ usage "Missing key name"
+ fi
+
generate_rsa3072_exp3_key "${output_dir}" "${key_name}"
}
diff --git a/scripts/keygeneration/accessory/create_new_hammer_like_keys.sh b/scripts/keygeneration/accessory/create_new_hammer_like_keys.sh
index 3d5c96e..96d2da0 100755
--- a/scripts/keygeneration/accessory/create_new_hammer_like_keys.sh
+++ b/scripts/keygeneration/accessory/create_new_hammer_like_keys.sh
@@ -5,12 +5,13 @@
# found in the LICENSE file.
# Load common constants and functions.
+export HAS_ARG_KEYNAME=1
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
- leverage_hammer_to_create_key "hammerlike" "$@"
+ leverage_hammer_to_create_key "$@"
}
main "$@"
diff --git a/scripts/keygeneration/accessory/create_new_hps_key.sh b/scripts/keygeneration/accessory/create_new_hps_key.sh
new file mode 100755
index 0000000..6d175c8
--- /dev/null
+++ b/scripts/keygeneration/accessory/create_new_hps_key.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# Copyright 2022 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.
+
+# Load common constants and functions.
+. "$(dirname "$0")/../common.sh"
+
+usage() {
+ cat <<EOF
+Usage: ${PROG} [options]
+
+Options:
+ -o, --output_dir <dir>: Where to write the keys (default is cwd)
+EOF
+
+ if [[ $# -ne 0 ]]; then
+ die "$*"
+ else
+ exit 0
+ fi
+}
+
+generate_ed25519_key() {
+ local output_dir="$1"
+
+ # Generate ed25519 private and public key.
+ openssl genpkey -algorithm Ed25519 -out "${output_dir}/key_hps.priv.pem"
+ openssl pkey -in "${output_dir}/key_hps.priv.pem" -pubout -text_pub \
+ -out "${output_dir}/key_hps.pub.pem"
+}
+
+main() {
+ set -euo pipefail
+
+ local output_dir="${PWD}"
+
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -h|--help)
+ usage
+ ;;
+ -o|--output_dir)
+ output_dir="$2"
+ if [[ ! -d "${output_dir}" ]]; then
+ die "output dir (${output_dir}) doesn't exist."
+ fi
+ shift
+ ;;
+ -*)
+ usage "Unknown option: $1"
+ ;;
+ *)
+ usage "Unknown argument $1"
+ ;;
+ esac
+ shift
+ done
+
+ generate_ed25519_key "${output_dir}"
+}
+
+main "$@"
diff --git a/scripts/keygeneration/common.sh b/scripts/keygeneration/common.sh
index da06f3c..af6cd71 100644
--- a/scripts/keygeneration/common.sh
+++ b/scripts/keygeneration/common.sh
@@ -63,6 +63,10 @@
KERNEL_SUBKEY_ALGOID=${RSA4096_SHA256_ALGOID}
KERNEL_DATAKEY_ALGOID=${RSA2048_SHA256_ALGOID}
+# AP RO Verification.
+ARV_ROOT_ALGOID=${RSA4096_SHA256_ALGOID}
+ARV_PLATFORM_ALGOID=${RSA4096_SHA256_ALGOID}
+
# Keyblock modes determine which boot modes a signing key is valid for use
# in verification.
# !DEV 0x1 DEV 0x2
diff --git a/scripts/keygeneration/create_new_keys.sh b/scripts/keygeneration/create_new_keys.sh
index 11aedc1..2e1fd22 100755
--- a/scripts/keygeneration/create_new_keys.sh
+++ b/scripts/keygeneration/create_new_keys.sh
@@ -169,6 +169,8 @@
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}
+ make_pair arv_root ${ARV_ROOT_ALGOID}
+ make_pair arv_platform ${ARV_PLATFORM_ALGOID}
# Create the firmware keyblock for use only in Normal mode. This is redundant,
# since it's never even checked during Recovery mode.
diff --git a/tests/devkeys/arv_platform.vbprivk b/tests/devkeys/arv_platform.vbprivk
new file mode 100644
index 0000000..e0bc670
--- /dev/null
+++ b/tests/devkeys/arv_platform.vbprivk
Binary files differ
diff --git a/tests/devkeys/arv_platform.vbpubk b/tests/devkeys/arv_platform.vbpubk
new file mode 100644
index 0000000..2ac3bde
--- /dev/null
+++ b/tests/devkeys/arv_platform.vbpubk
Binary files differ
diff --git a/tests/devkeys/arv_root.vbprivk b/tests/devkeys/arv_root.vbprivk
new file mode 100644
index 0000000..7747717
--- /dev/null
+++ b/tests/devkeys/arv_root.vbprivk
Binary files differ
diff --git a/tests/devkeys/arv_root.vbpubk b/tests/devkeys/arv_root.vbpubk
new file mode 100644
index 0000000..aebe2a4
--- /dev/null
+++ b/tests/devkeys/arv_root.vbpubk
Binary files differ
diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh
index 31f3ecb..25c5543 100755
--- a/tests/futility/test_update.sh
+++ b/tests/futility/test_update.sh
@@ -141,6 +141,9 @@
cp -f "${TMP}.expected.full" "${TMP}.expected.me_unlocked"
patch_file "${TMP}.expected.me_unlocked" SI_DESC 128 \
"\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff"
+cp -f "${TMP}.expected.full" "${TMP}.expected.me_preserved"
+"${FUTILITY}" load_fmap "${TMP}.expected.me_preserved" \
+ "SI_ME:${TMP}.from/SI_ME"
# A special set of images that only RO_VPD is preserved (RW_VPD is wiped) using
# FMAP_AREA_PRESERVE (\010=0x08).
@@ -357,6 +360,17 @@
--quirks no_check_platform \
-i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,1
+test_update "Full update (--quirks preserve_me with non-host programmer)" \
+ "${FROM_IMAGE}" "${TMP}.expected.full" \
+ --quirks preserve_me \
+ -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,1 \
+ -p raiden_debug_spi:target=AP
+
+test_update "Full update (--quirks preserve_me)" \
+ "${FROM_IMAGE}" "${TMP}.expected.me_preserved" \
+ --quirks preserve_me \
+ -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,1
+
# Test archive and manifest.
A="${TMP}.archive"
mkdir -p "${A}/bin"
@@ -471,8 +485,8 @@
if type flashrom >/dev/null 2>&1; then
echo "TEST: Full update (dummy programmer)"
cp -f "${FROM_IMAGE}" "${TMP}.emu"
- sudo "${FUTILITY}" update --programmer \
- dummy:emulate=VARIABLE_SIZE,image=${TMP}.emu,size=8388608 \
+ "${FUTILITY}" update --programmer \
+ dummy:emulate=VARIABLE_SIZE,image="${TMP}".emu,size=8388608 \
-i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,1,3 >&2
cmp "${TMP}.emu" "${TMP}.expected.full"
fi
diff --git a/tests/vb20_api_kernel_tests.c b/tests/vb20_api_kernel_tests.c
index 893cd4e..b835251 100644
--- a/tests/vb20_api_kernel_tests.c
+++ b/tests/vb20_api_kernel_tests.c
@@ -59,6 +59,7 @@
"vb2api_init failed");
sd = vb2_get_sd(ctx);
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
vb2_nv_init(ctx);
vb2api_secdata_kernel_create(ctx);
diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c
index beab239..15c9bd1 100644
--- a/tests/vb2_api_tests.c
+++ b/tests/vb2_api_tests.c
@@ -374,6 +374,8 @@
0, " secdata firmware initialized");
TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT,
0, " secdata kernel initialized");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
retval_vb2_fw_init_gbb = VB2_ERROR_GBB_MAGIC;
@@ -383,6 +385,8 @@
" recovery reason");
TEST_NEQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE, 0, " recovery flag");
TEST_NEQ(ctx->flags & VB2_CONTEXT_CLEAR_RAM, 0, " clear ram flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
/* Dev switch error proceeds to a recovery boot */
reset_common_data(FOR_MISC);
@@ -398,6 +402,8 @@
0, " display init context flag");
TEST_NEQ(sd->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE,
0, " display available SD flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
ctx->secdata_firmware[0] ^= 0x42;
@@ -407,6 +413,8 @@
" recovery reason");
TEST_NEQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE, 0, " recovery flag");
TEST_NEQ(ctx->flags & VB2_CONTEXT_CLEAR_RAM, 0, " clear ram flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
/* Bad secdata_kernel causes recovery mode */
reset_common_data(FOR_MISC);
@@ -417,6 +425,8 @@
" recovery reason");
TEST_NEQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE, 0, " recovery flag");
TEST_NEQ(ctx->flags & VB2_CONTEXT_CLEAR_RAM, 0, " clear ram flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
/* Test secdata_firmware-requested reboot */
reset_common_data(FOR_MISC);
@@ -428,6 +438,8 @@
1, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
0, " recovery request");
+ TEST_EQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
vb2_nv_set(ctx, VB2_NV_TPM_REQUESTED_REBOOT, 1);
@@ -438,6 +450,8 @@
0, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
0, " recovery request");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
ctx->flags |= VB2_CONTEXT_SECDATA_WANTS_REBOOT;
@@ -450,6 +464,8 @@
1, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
0, " recovery request");
+ TEST_EQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
ctx->flags |= VB2_CONTEXT_SECDATA_WANTS_REBOOT;
@@ -462,6 +478,8 @@
1, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
VB2_RECOVERY_RO_TPM_REBOOT, " recovery request");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
ctx->flags |= VB2_CONTEXT_SECDATA_WANTS_REBOOT;
@@ -474,6 +492,8 @@
1, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
VB2_RECOVERY_RO_UNSPECIFIED, " recovery request");
+ TEST_EQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
vb2_nv_set(ctx, VB2_NV_TPM_REQUESTED_REBOOT, 1);
@@ -486,6 +506,8 @@
0, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
VB2_RECOVERY_RO_UNSPECIFIED, " recovery request");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
ctx->flags |= VB2_CONTEXT_SECDATA_WANTS_REBOOT;
@@ -499,6 +521,8 @@
1, " tpm reboot request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
VB2_RECOVERY_RO_UNSPECIFIED, " recovery request");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
/* Cases for checking DISPLAY_INIT and DISPLAY_AVAILABLE. */
reset_common_data(FOR_MISC);
@@ -508,6 +532,8 @@
0, " display init context flag");
TEST_NEQ(sd->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE,
0, " display available SD flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1);
@@ -516,6 +542,8 @@
0, " display init context flag");
TEST_NEQ(sd->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE,
0, " display available SD flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
reset_common_data(FOR_MISC);
force_dev_mode = 1;
@@ -524,6 +552,8 @@
0, " display init context flag");
TEST_NEQ(sd->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE,
0, " display available SD flag");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, " recovery decided");
}
static void phase2_tests(void)
diff --git a/tests/vb2_auxfw_sync_tests.c b/tests/vb2_auxfw_sync_tests.c
index 3987d64..bcdd67a 100644
--- a/tests/vb2_auxfw_sync_tests.c
+++ b/tests/vb2_auxfw_sync_tests.c
@@ -65,14 +65,15 @@
{
*severity = auxfw_mock_severity;
auxfw_update_severity = auxfw_mock_severity;
- if (*severity == VB2_AUXFW_SLOW_UPDATE)
- if (!auxfw_mock_display_available)
- return VB2_REQUEST_REBOOT;
return VB2_SUCCESS;
}
vb2_error_t vb2ex_auxfw_update(void)
{
+ if (auxfw_update_severity == VB2_AUXFW_SLOW_UPDATE)
+ if (!auxfw_mock_display_available)
+ return VB2_REQUEST_REBOOT;
+
if (auxfw_update_severity != VB2_AUXFW_NO_DEVICE &&
auxfw_update_severity != VB2_AUXFW_NO_UPDATE)
auxfw_update_req = 1;
diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c
index 16496e4..f4631b7 100644
--- a/tests/vb2_ec_sync_tests.c
+++ b/tests/vb2_ec_sync_tests.c
@@ -111,21 +111,6 @@
return &gbb;
}
-uint32_t VbExIsShutdownRequested(void)
-{
- if (shutdown_request_calls_left == 0)
- return 1;
- else if (shutdown_request_calls_left > 0)
- shutdown_request_calls_left--;
-
- return 0;
-}
-
-int vb2ex_ec_trusted(void)
-{
- return !ec_run_image;
-}
-
vb2_error_t vb2ex_ec_running_rw(int *in_rw)
{
*in_rw = ec_run_image;
diff --git a/tests/vb2_host_flashrom_tests.c b/tests/vb2_host_flashrom_tests.c
index 8552d0a..815657d 100644
--- a/tests/vb2_host_flashrom_tests.c
+++ b/tests/vb2_host_flashrom_tests.c
@@ -145,10 +145,11 @@
static void test_read_whole_chip(void)
{
- uint8_t *buf;
- uint32_t buf_sz;
+ struct firmware_image image = {
+ .programmer = "someprog",
+ };
- TEST_SUCC(flashrom_read("someprog", NULL, &buf, &buf_sz),
+ TEST_SUCC(flashrom_read(&image, NULL),
"Flashrom read succeeds");
TEST_STR_EQ(captured_programmer, "someprog",
"Using specified programmer");
@@ -158,19 +159,20 @@
TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME,
"Reading to correct file");
TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region");
- TEST_EQ(buf_sz, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
- TEST_SUCC(memcmp(buf, MOCK_ROM_CONTENTS, buf_sz),
+ TEST_EQ(image.size, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
+ TEST_SUCC(memcmp(image.data, MOCK_ROM_CONTENTS, image.size),
"Buffer has correct contents");
- free(buf);
+ free(image.data);
}
static void test_read_region(void)
{
- uint8_t *buf;
- uint32_t buf_sz;
+ struct firmware_image image = {
+ .programmer = "someprog",
+ };
- TEST_SUCC(flashrom_read("someprog", "SOME_REGION", &buf, &buf_sz),
+ TEST_SUCC(flashrom_read(&image, "SOME_REGION"),
"Flashrom read succeeds");
TEST_STR_EQ(captured_programmer, "someprog",
"Using specified programmer");
@@ -181,20 +183,21 @@
"Not doing a read of the whole ROM");
TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME,
"Reading to correct file and from correct region");
- TEST_EQ(buf_sz, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
- TEST_SUCC(memcmp(buf, MOCK_ROM_CONTENTS, buf_sz),
+ TEST_EQ(image.size, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
+ TEST_SUCC(memcmp(image.data, MOCK_ROM_CONTENTS, image.size),
"Buffer has correct contents");
- free(buf);
+ free(image.data);
}
static void test_read_failure(void)
{
- uint8_t *buf;
- uint32_t buf_sz;
+ struct firmware_image image = {
+ .programmer = "someprog",
+ };
flashrom_mock_success = false;
- TEST_NEQ(flashrom_read("someprog", "SOME_REGION", &buf, &buf_sz),
+ TEST_NEQ(flashrom_read(&image, "SOME_REGION"),
VB2_SUCCESS, "Flashrom read fails");
flashrom_mock_success = true;
}
@@ -202,10 +205,15 @@
static void test_write_whole_chip(void)
{
uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1];
+ struct firmware_image image = {
+ .programmer = "someprog",
+ .data = buf,
+ .size = sizeof(buf),
+ };
memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf));
- TEST_SUCC(flashrom_write("someprog", NULL, buf, sizeof(buf)),
+ TEST_SUCC(flashrom_write(&image, NULL),
"Flashrom write succeeds");
TEST_STR_EQ(captured_programmer, "someprog",
"Using specified programmer");
@@ -224,10 +232,15 @@
static void test_write_region(void)
{
uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1];
+ struct firmware_image image = {
+ .programmer = "someprog",
+ .data = buf,
+ .size = sizeof(buf),
+ };
memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf));
- TEST_SUCC(flashrom_write("someprog", "SOME_REGION", buf, sizeof(buf)),
+ TEST_SUCC(flashrom_write(&image, "SOME_REGION"),
"Flashrom write succeeds");
TEST_STR_EQ(captured_programmer, "someprog",
"Using specified programmer");
@@ -247,9 +260,14 @@
static void test_write_failure(void)
{
uint8_t buf[20] = { 0 };
+ struct firmware_image image = {
+ .programmer = "someprog",
+ .data = buf,
+ .size = sizeof(buf),
+ };
flashrom_mock_success = false;
- TEST_NEQ(flashrom_write("someprog", "SOME_REGION", buf, sizeof(buf)),
+ TEST_NEQ(flashrom_write(&image, "SOME_REGION"),
VB2_SUCCESS, "Flashrom write fails");
flashrom_mock_success = true;
}
diff --git a/tests/vb2_host_nvdata_flashrom_tests.c b/tests/vb2_host_nvdata_flashrom_tests.c
index 33b435d..068b23a 100644
--- a/tests/vb2_host_nvdata_flashrom_tests.c
+++ b/tests/vb2_host_nvdata_flashrom_tests.c
@@ -81,35 +81,33 @@
}
/* Mocked flashrom_read for tests. */
-vb2_error_t flashrom_read(const char *programmer, const char *region,
- uint8_t **data_out, uint32_t *size_out)
+vb2_error_t flashrom_read(struct firmware_image *image, const char *region)
{
if (mock_flashrom_fail) {
- *data_out = NULL;
- *size_out = 0;
+ image->data = NULL;
+ image->size = 0;
return VB2_ERROR_FLASHROM;
}
- assert_mock_params(programmer, region);
+ assert_mock_params(image->programmer, region);
- *data_out = malloc(sizeof(fake_flash_region));
- *size_out = sizeof(fake_flash_region);
- memcpy(*data_out, fake_flash_region, sizeof(fake_flash_region));
+ image->data = malloc(sizeof(fake_flash_region));
+ image->size = sizeof(fake_flash_region);
+ memcpy(image->data, fake_flash_region, sizeof(fake_flash_region));
return VB2_SUCCESS;
}
/* Mocked flashrom_write for tests. */
-vb2_error_t flashrom_write(const char *programmer, const char *region,
- uint8_t *data, uint32_t data_size)
+vb2_error_t flashrom_write(struct firmware_image *image, const char *region)
{
if (mock_flashrom_fail)
return VB2_ERROR_FLASHROM;
- assert_mock_params(programmer, region);
+ assert_mock_params(image->programmer, region);
- TEST_EQ(data_size, sizeof(fake_flash_region),
+ TEST_EQ(image->size, sizeof(fake_flash_region),
"The flash size is correct");
- memcpy(fake_flash_region, data, data_size);
+ memcpy(fake_flash_region, image->data, image->size);
return VB2_SUCCESS;
}
diff --git a/tests/vb2_kernel_tests.c b/tests/vb2_kernel_tests.c
index 0dc0e74..0b3e94c 100644
--- a/tests/vb2_kernel_tests.c
+++ b/tests/vb2_kernel_tests.c
@@ -24,6 +24,7 @@
static struct vb2_shared_data *sd;
static struct vb2_fw_preamble *fwpre;
static const char fw_kernel_key_data[36] = "Test kernel key data";
+static enum vb2_boot_mode *boot_mode;
/* Mocked function data */
@@ -82,6 +83,14 @@
mock_gbb.recovery_key.key_offset +
mock_gbb.recovery_key.key_size;
+ /* For boot_mode */
+ boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode;
+ if (t == FOR_PHASE1)
+ *boot_mode = VB2_BOOT_MODE_BROKEN_SCREEN;
+ else if (t == FOR_NORMAL_BOOT)
+ *boot_mode = VB2_BOOT_MODE_NORMAL;
+ else
+ *boot_mode = VB2_BOOT_MODE_UNDEFINED;
if (t == FOR_PHASE1) {
uint8_t *kdata;
@@ -274,6 +283,7 @@
TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset");
TEST_EQ(sd->kernel_key_size, 0, " workbuf key size");
mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery");
reset_common_data(FOR_PHASE1);
@@ -284,6 +294,7 @@
TEST_EQ(sd->kernel_key_offset, 0, " workbuf key offset");
TEST_EQ(sd->kernel_key_size, 0, " workbuf key size");
mock_gbb.h.flags |= VB2_GBB_FLAG_FORCE_MANUAL_RECOVERY;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
mock_read_res_fail_on_call = 1;
TEST_ABORT(vb2api_kernel_phase1(ctx), " fatal for manual recovery");
diff --git a/tests/vb2_misc_tests.c b/tests/vb2_misc_tests.c
index c4b3ce4..99f8bae 100644
--- a/tests/vb2_misc_tests.c
+++ b/tests/vb2_misc_tests.c
@@ -22,6 +22,7 @@
static struct vb2_shared_data *sd;
static struct vb2_gbb_header gbb;
static struct vb2_secdata_fwmp *fwmp;
+static enum vb2_boot_mode *boot_mode;
/* Mocked function data */
static enum vb2_resource_index mock_resource_index;
@@ -29,7 +30,6 @@
static uint32_t mock_resource_size;
static int mock_tpm_clear_called;
static int mock_tpm_clear_retval;
-static int allow_recovery_retval;
static void reset_common_data(void)
{
@@ -40,7 +40,7 @@
"vb2api_init failed");
sd = vb2_get_sd(ctx);
- sd->status = VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT;
memset(&gbb, 0, sizeof(gbb));
@@ -53,16 +53,13 @@
mock_tpm_clear_called = 0;
mock_tpm_clear_retval = VB2_SUCCESS;
- allow_recovery_retval = 0;
+
+ boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode;
+ *boot_mode = VB2_BOOT_MODE_NORMAL;
};
/* Mocked functions */
-int vb2api_allow_recovery(struct vb2_context *c)
-{
- return allow_recovery_retval;
-}
-
struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
{
return &gbb;
@@ -268,12 +265,17 @@
"vb_workbuf_from_ctx() size");
reset_common_data();
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
TEST_ABORT(VB2_REC_OR_DIE(ctx, "die\n"), "REC_OR_DIE in normal mode");
reset_common_data();
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
VB2_REC_OR_DIE(ctx, "VB2_REC_OR_DIE() test in recovery mode\n");
/* Would exit here if it didn't work as intended. */
+
+ reset_common_data();
+ VB2_REC_OR_DIE(ctx, "VB2_REC_OR_DIE() test in fw_phase1\n");
}
static void gbb_tests(void)
@@ -421,12 +423,14 @@
{
/* No recovery */
reset_common_data();
+ TEST_EQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "recovery not yet decided before testing check_recovery()");
vb2_check_recovery(ctx);
TEST_EQ(sd->recovery_reason, 0, "No recovery reason");
- TEST_EQ(sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY,
- 0, "Not manual recovery");
TEST_EQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE,
0, "Not recovery mode");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "Recovery decided");
/* From request */
reset_common_data();
@@ -434,10 +438,10 @@
vb2_check_recovery(ctx);
TEST_EQ(sd->recovery_reason, 3, "Recovery reason from request");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST), 3, "NV not cleared");
- TEST_EQ(sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY,
- 0, "Not manual recovery");
TEST_NEQ(ctx->flags & VB2_CONTEXT_RECOVERY_MODE,
0, "Recovery mode");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "Recovery decided");
/* From request, but already failed */
reset_common_data();
@@ -447,6 +451,8 @@
TEST_EQ(sd->recovery_reason, 5, "Recovery reason already failed");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
4, "NV not cleared");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "Recovery decided");
/* Override */
reset_common_data();
@@ -455,8 +461,8 @@
vb2_check_recovery(ctx);
TEST_EQ(sd->recovery_reason, VB2_RECOVERY_RO_MANUAL,
"Recovery reason forced");
- TEST_NEQ(sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY,
- 0, "SD flag set");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "Recovery decided");
/* Override subcode TRAIN_AND_REBOOT */
reset_common_data();
@@ -465,8 +471,8 @@
vb2_check_recovery(ctx);
TEST_EQ(sd->recovery_reason, VB2_RECOVERY_RO_MANUAL,
"Recovery reason forced");
- TEST_NEQ(sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY,
- 0, "SD flag set");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "Recovery decided");
/* Promote subcode from BROKEN screen*/
reset_common_data();
@@ -475,8 +481,8 @@
vb2_check_recovery(ctx);
TEST_EQ(sd->recovery_reason, VB2_RECOVERY_US_TEST,
"Recovery reason forced from BROKEN");
- TEST_NEQ(sd->flags & VB2_SD_FLAG_MANUAL_RECOVERY,
- 0, "SD flag set");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_RECOVERY_DECIDED,
+ 0, "Recovery decided");
}
static void dev_switch_tests(void)
@@ -589,13 +595,15 @@
/*
* secdata_firmware failure in normal mode fails and shows dev=0 even
- * if dev mode was on in the (inaccessible) secdata_firmware.
+ * if dev mode was on in the (inaccessible) secdata_firmware. Since this
+ * happens in fw_phase1, we do not abort -- we know that when secdata
+ * is uninitialized here, we must be headed for recovery mode.
*/
reset_common_data();
vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_FLAGS,
VB2_SECDATA_FIRMWARE_FLAG_DEV_MODE);
sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
- TEST_ABORT(vb2_check_dev_switch(ctx), "secdata_firmware fail normal");
+ TEST_SUCC(vb2_check_dev_switch(ctx), "secdata_firmware fail normal");
TEST_EQ(sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED, 0, " sd not in dev");
TEST_EQ(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE, 0, " ctx not in dev");
@@ -640,7 +648,6 @@
static void enable_dev_tests(void)
{
reset_common_data();
- 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) &
@@ -648,19 +655,18 @@
" dev mode flag not set");
reset_common_data();
- allow_recovery_retval = 1;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
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");
- 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");
/* secdata_firmware not initialized, aborts */
reset_common_data();
- allow_recovery_retval = 1;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
TEST_ABORT(vb2api_enable_developer_mode(ctx),
"secdata_firmware no init, enable dev mode aborted");
sd->status |= VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
@@ -810,7 +816,7 @@
/* Manual recovery */
reset_common_data();
- allow_recovery_retval = 1;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
sd->recovery_reason = 4;
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 5);
@@ -821,9 +827,9 @@
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_SUBCODE),
0, " subcode cleared");
- /* BROKEN recovery */
+ /* Broken screen */
reset_common_data();
- allow_recovery_retval = 0;
+ *boot_mode = VB2_BOOT_MODE_BROKEN_SCREEN;
sd->recovery_reason = 4;
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, 5);
diff --git a/tests/vb2_secdata_firmware_tests.c b/tests/vb2_secdata_firmware_tests.c
index 387cda3..c1b0a73 100644
--- a/tests/vb2_secdata_firmware_tests.c
+++ b/tests/vb2_secdata_firmware_tests.c
@@ -28,6 +28,9 @@
sd = vb2_get_sd(ctx);
+ /* Most tests assume we have passed fw_phase1() */
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
+
sec = (struct vb2_secdata_firmware *)ctx->secdata_firmware;
}
@@ -136,6 +139,25 @@
0x123456ff),
"Set uninitialized");
test_changed(ctx, 0, "Set uninitialized doesn't change data");
+
+ /* Read/write uninitialized in recovery mode */
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_VERSIONS), 0,
+ "Get uninitialized (recmode)");
+ test_changed(ctx, 0, "Get uninitialized (recmode) doesn't change data");
+ vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
+ 0x123456ff);
+ test_changed(ctx, 0, "Set uninitialized (recmode) doesn't change data");
+
+ /* Read/write early in fw_phase1 */
+ ctx->flags &= ~VB2_CONTEXT_RECOVERY_MODE;
+ sd->status &= ~VB2_SD_STATUS_RECOVERY_DECIDED;
+ TEST_EQ(vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_VERSIONS), 0,
+ "Get uninitialized (phase1)");
+ test_changed(ctx, 0, "Get uninitialized (phase1) doesn't change data");
+ vb2_secdata_firmware_set(ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
+ 0x123456ff);
+ test_changed(ctx, 0, "Set uninitialized (phase1) doesn't change data");
}
int main(int argc, char* argv[])
diff --git a/tests/vb2_secdata_fwmp_tests.c b/tests/vb2_secdata_fwmp_tests.c
index 699f3fa..79b0f55 100644
--- a/tests/vb2_secdata_fwmp_tests.c
+++ b/tests/vb2_secdata_fwmp_tests.c
@@ -25,7 +25,8 @@
"vb2api_init failed");
sd = vb2_get_sd(ctx);
- sd->status = VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
memset(&gbb, 0, sizeof(gbb));
@@ -199,6 +200,13 @@
sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
TEST_ABORT(vb2_secdata_fwmp_get_flag(ctx, 0),
"non-init in normal mode triggers abort");
+
+ /* FWMP hasn't been initialized (before recovery decision) */
+ reset_common_data();
+ sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ sd->status &= ~VB2_SD_STATUS_RECOVERY_DECIDED;
+ TEST_EQ(vb2_secdata_fwmp_get_flag(ctx, 0), 0,
+ "non-init in fw_phase1 forces default flag value");
}
static void get_dev_key_hash_test(void)
@@ -222,6 +230,13 @@
TEST_ABORT(vb2_secdata_fwmp_get_dev_key_hash(ctx),
"non-init in normal mode triggers abort");
+ /* FWMP hasn't been initialized (before recovery decision) */
+ reset_common_data();
+ sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ sd->status &= ~VB2_SD_STATUS_RECOVERY_DECIDED;
+ TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(ctx) == NULL,
+ "non-init in fw_phase1 forces NULL pointer");
+
/* Success case */
reset_common_data();
TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(ctx) ==
diff --git a/tests/vb2_secdata_kernel_tests.c b/tests/vb2_secdata_kernel_tests.c
index 327018d..dc41f1a 100644
--- a/tests/vb2_secdata_kernel_tests.c
+++ b/tests/vb2_secdata_kernel_tests.c
@@ -30,6 +30,9 @@
sd = vb2_get_sd(ctx);
+ /* Most tests assume we have passed fw_phase1() */
+ sd->status |= VB2_SD_STATUS_RECOVERY_DECIDED;
+
sec02 = (struct vb2_secdata_kernel_v0 *)ctx->secdata_kernel;
sec10 = (struct vb2_secdata_kernel_v1 *)ctx->secdata_kernel;
}
@@ -245,7 +248,27 @@
"Set uninitialized");
test_changed(ctx, 0, "Set uninitialized doesn't change data");
+ /* Read/write uninitialized in recovery mode */
+ ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ TEST_EQ(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS), 0,
+ "Get uninitialized (recmode)");
+ test_changed(ctx, 0, "Get uninitialized (recmode) doesn't change data");
+ vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS,
+ 0x123456ff);
+ test_changed(ctx, 0, "Set uninitialized (recmode) doesn't change data");
+
+ /* Read/write early in fw_phase1 */
+ ctx->flags &= ~VB2_CONTEXT_RECOVERY_MODE;
+ sd->status &= ~VB2_SD_STATUS_RECOVERY_DECIDED;
+ TEST_EQ(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS), 0,
+ "Get uninitialized (phase1)");
+ test_changed(ctx, 0, "Get uninitialized (phase1) doesn't change data");
+ vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS,
+ 0x123456ff);
+ test_changed(ctx, 0, "Set uninitialized (phase1) doesn't change data");
+
/* Test EC hash set */
+ reset_common_data();
vb2api_secdata_kernel_create(ctx);
vb2_secdata_kernel_init(ctx);
memset(ec_hash, 0xaa, sizeof(ec_hash));
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
index f122eb3..60d87c6 100644
--- a/tests/vboot_api_kernel4_tests.c
+++ b/tests/vboot_api_kernel4_tests.c
@@ -80,6 +80,9 @@
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
expected_recovery_reason = recovery_reason;
+ /* The VbSelectAndLoadKernel directly leverages the value at
+ ctx->boot_mode, so we have to call vb2_set_boot_mode first. */
+ vb2_set_boot_mode(ctx);
TEST_EQ(VbSelectAndLoadKernel(ctx, &kparams), retval, desc);
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
recovery_reason, " recovery reason");
@@ -259,12 +262,14 @@
/* Recovery - VB2_ERROR_ESCAPE_NO_BOOT */
reset_common_data();
ctx->flags |= VB2_CONTEXT_NO_BOOT;
+ ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
test_slk(VB2_ERROR_ESCAPE_NO_BOOT,
VB2_RECOVERY_ESCAPE_NO_BOOT, "Recovery for NO_BOOT escape");
/* Boot normal - VB2_ERROR_ESCAPE_NO_BOOT */
reset_common_data();
ctx->flags |= VB2_CONTEXT_NO_BOOT;
+ ctx->flags |= VB2_CONTEXT_EC_SYNC_SUPPORTED;
gbb.flags |= VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC;
test_slk(VB2_SUCCESS, 0, "DISABLE_EC_SOFTWARE_SYNC ignores NO_BOOT");
@@ -325,7 +330,7 @@
reset_common_data();
sd->recovery_reason = VB2_RECOVERY_RO_MANUAL;
vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, 13);
- sd->flags |= VB2_SD_FLAG_MANUAL_RECOVERY;
+ ctx->flags &= VB2_CONTEXT_FORCE_RECOVERY_MODE;
test_slk(0, 0, "Manual recovery");
TEST_TRUE(commit_data_called, " commit data");
}
diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c
index 51f0ddb..b66c432 100644
--- a/tests/vboot_api_kernel_tests.c
+++ b/tests/vboot_api_kernel_tests.c
@@ -563,7 +563,7 @@
vb2_error_t LoadMiniOsKernel(struct vb2_context *c,
VbSelectAndLoadKernelParams *params,
- VbDiskInfo *disk_info)
+ VbDiskInfo *disk_info, uint32_t minios_flags)
{
lk_minios_calls++;
return LoadKernelImpl(c, params, disk_info);
@@ -616,7 +616,7 @@
printf("Test case: %s ...\n", minios_tests[i].name);
ResetMocks(&minios_tests[i]);
ctx->flags = t->ctx_flags;
- TEST_EQ(VbTryLoadMiniOsKernel(ctx),
+ TEST_EQ(VbTryLoadMiniOsKernel(ctx, 0),
t->expected_return_val, " return value");
TEST_EQ(got_recovery_request_val,
t->expected_recovery_request_val, " recovery_request");
diff --git a/tests/vboot_kernel2_tests.c b/tests/vboot_kernel2_tests.c
index 5424e86..5fc66f1 100644
--- a/tests/vboot_kernel2_tests.c
+++ b/tests/vboot_kernel2_tests.c
@@ -47,6 +47,7 @@
static struct vb2_workbuf wb;
static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
+static enum vb2_boot_mode *boot_mode;
static VbSelectAndLoadKernelParams lkp;
static VbDiskInfo disk_info;
@@ -82,6 +83,9 @@
vb2_secdata_kernel_init(ctx);
ctx->flags = VB2_CONTEXT_RECOVERY_MODE;
+ boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
+
sd = vb2_get_sd(ctx);
sd->kernel_version_secdata = 0xabcdef | (1 << 24);
@@ -264,7 +268,7 @@
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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"{valid kernel}");
TEST_EQ(mock_tpm_set_mode_calls, 1,
" TPM disabled");
@@ -272,7 +276,7 @@
reset_common_data();
disk_info.bytes_per_lba = KBUF_SIZE;
disk_info.lba_count = 1;
- TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND, "{no kernel}");
TEST_EQ(mock_tpm_set_mode_calls, 0,
" TPM not disabled");
@@ -281,7 +285,7 @@
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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"{no kernel, valid kernel}");
TEST_EQ(cur_kernel->sector, 1, " select kernel");
@@ -290,7 +294,7 @@
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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"{invalid kernel, valid kernel}");
TEST_EQ(cur_kernel->sector, 1, " select second kernel");
@@ -299,7 +303,7 @@
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),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND,
"{invalid kernel, invalid kernel}");
TEST_EQ(mock_tpm_set_mode_calls, 0,
@@ -310,7 +314,7 @@
disk_info.lba_count = 2;
add_mock_kernel(0, VB2_SUCCESS);
add_mock_kernel(1, VB2_SUCCESS);
- TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"{valid kernel, valid kernel} minios_priority=0");
TEST_EQ(cur_kernel->sector, 0, " select first kernel");
@@ -320,15 +324,36 @@
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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"{valid kernel, valid kernel} minios_priority=1");
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_SUCCESS);
+ add_mock_kernel(1, VB2_SUCCESS);
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info,
+ VB_MINIOS_FLAG_NON_ACTIVE),
+ "{valid kernel, valid kernel} minios_priority=0 non-active");
+ 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_SUCCESS);
+ vb2_nv_set(ctx, VB2_NV_MINIOS_PRIORITY, 1);
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info,
+ VB_MINIOS_FLAG_NON_ACTIVE),
+ VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "{invalid kernel, valid kernel} minios_priority=1 non-active");
+
+ 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),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND,
"valid kernel header near start of disk (disk too small)");
@@ -336,7 +361,7 @@
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),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND,
"valid kernel header near end of disk");
@@ -344,35 +369,35 @@
disk_info.bytes_per_lba = 1024;
disk_info.lba_count = 128;
add_mock_kernel(63, VB2_SUCCESS);
- TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"kernel at last sector in batch assuming 2 MB batches");
reset_common_data();
@@ -382,7 +407,7 @@
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),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"kernel with minios keyblock flag");
reset_common_data();
@@ -392,7 +417,7 @@
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),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND,
"kernel with !minios keyblock flag");
@@ -402,7 +427,7 @@
add_mock_kernel(0, VB2_SUCCESS);
sd->kernel_version_secdata = 5 << 24;
kph.kernel_version = 4;
- TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND,
"kernel version too old");
@@ -412,7 +437,7 @@
add_mock_kernel(0, VB2_SUCCESS);
sd->kernel_version_secdata = 5 << 24;
kph.kernel_version = 0x100;
- TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ TEST_EQ(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
VB2_ERROR_LK_NO_KERNEL_FOUND,
"kernel version greater than 0xff");
@@ -422,7 +447,7 @@
add_mock_kernel(0, VB2_SUCCESS);
sd->kernel_version_secdata = 5 << 24;
kph.kernel_version = 6;
- TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info),
+ TEST_SUCC(LoadMiniOsKernel(ctx, &lkp, &disk_info, 0),
"newer kernel version");
}
diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c
index 14e7e1f..1f77cc5 100644
--- a/tests/vboot_kernel_tests.c
+++ b/tests/vboot_kernel_tests.c
@@ -51,6 +51,7 @@
static struct vb2_context *ctx;
static struct vb2_shared_data *sd;
static struct vb2_packed_key mock_key;
+static enum vb2_boot_mode *boot_mode;
/**
* Reset mock data (for use before each test)
@@ -114,6 +115,9 @@
fwmp = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp;
memcpy(&fwmp->dev_key_hash, mock_digest, sizeof(fwmp->dev_key_hash));
+ boot_mode = (enum vb2_boot_mode *)&ctx->boot_mode;
+ *boot_mode = VB2_BOOT_MODE_NORMAL;
+
// TODO: more workbuf fields - flags, secdata_firmware
vb2api_secdata_kernel_create(ctx);
@@ -337,6 +341,7 @@
/* In dev mode, fail if hash is bad too */
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
keyblock_verify_fail = 2;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Fail key block dev hash");
@@ -344,6 +349,7 @@
/* But just bad sig is ok */
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
keyblock_verify_fail = 1;
TestLoadKernel(0, "Succeed keyblock dev sig");
TEST_EQ(sd->flags & VB2_SD_FLAG_KERNEL_SIGNED, 0, " use hash");
@@ -351,6 +357,7 @@
/* In dev mode and requiring signed kernel, fail if sig is bad */
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
keyblock_verify_fail = 1;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
@@ -358,6 +365,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY;
keyblock_verify_fail = 1;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
@@ -387,6 +395,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
| VB2_KEYBLOCK_FLAG_DEVELOPER_1
| VB2_KEYBLOCK_FLAG_MINIOS_0;
@@ -395,6 +404,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
| VB2_KEYBLOCK_FLAG_DEVELOPER_0
| VB2_KEYBLOCK_FLAG_MINIOS_0;
@@ -402,6 +412,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE | VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
| VB2_KEYBLOCK_FLAG_DEVELOPER_0
| VB2_KEYBLOCK_FLAG_MINIOS_0;
@@ -410,6 +421,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_RECOVERY_MODE | VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
| VB2_KEYBLOCK_FLAG_DEVELOPER_1
| VB2_KEYBLOCK_FLAG_MINIOS_0;
@@ -418,6 +430,7 @@
/* Check keyblock flags (dev mode + signed kernel required) */
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
| VB2_KEYBLOCK_FLAG_DEVELOPER_0
@@ -427,6 +440,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY;
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_1
| VB2_KEYBLOCK_FLAG_DEVELOPER_0
@@ -436,6 +450,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY;
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0
| VB2_KEYBLOCK_FLAG_DEVELOPER_0
@@ -445,6 +460,7 @@
ResetMocks();
ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
kbh.keyblock_flags = VB2_KEYBLOCK_FLAG_RECOVERY_0
| VB2_KEYBLOCK_FLAG_DEVELOPER_1
@@ -477,12 +493,12 @@
ResetMocks();
kbh.data_key.key_version = 1;
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
TestLoadKernel(0, "Key version ignored in dev mode");
ResetMocks();
kbh.data_key.key_version = 1;
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
TestLoadKernel(0, "Key version ignored in rec mode");
ResetMocks();
@@ -500,18 +516,18 @@
ResetMocks();
kph.kernel_version = 0;
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
TestLoadKernel(0, "Kernel version ignored in dev mode");
ResetMocks();
kph.kernel_version = 0;
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
TestLoadKernel(0, "Kernel version ignored in rec mode");
/* Check kernel version (dev mode + signed kernel required) */
ResetMocks();
kbh.data_key.key_version = 0;
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1);
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Keyblock key version checked in dev mode "
@@ -519,7 +535,7 @@
ResetMocks();
kbh.data_key.key_version = 0;
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"Keyblock key version checked in dev mode "
@@ -527,7 +543,7 @@
/* Check developer key hash - bad */
ResetMocks();
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH;
fwmp->dev_key_hash[0]++;
TestLoadKernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND,
@@ -535,15 +551,14 @@
/* Check developer key hash - bad (recovery mode) */
ResetMocks();
- ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_MANUAL_RECOVERY;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH;
fwmp->dev_key_hash[0]++;
TestLoadKernel(0, "Bad keyblock dev fwmp hash ignored in rec mode");
/* Check developer key hash - good */
ResetMocks();
- ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
+ *boot_mode = VB2_BOOT_MODE_DEVELOPER;
fwmp->flags |= VB2_SECDATA_FWMP_DEV_USE_KEY_HASH;
TestLoadKernel(0, "Good keyblock dev fwmp hash");
diff --git a/unblocked_terms.txt b/unblocked_terms.txt
index c54d786..e9ad8c2 100644
--- a/unblocked_terms.txt
+++ b/unblocked_terms.txt
@@ -1,3 +1,2 @@
dummy
-master
-slave
\ No newline at end of file
+master
\ No newline at end of file
diff --git a/utility/chromeos-tpm-recovery b/utility/chromeos-tpm-recovery
index ac7dfcc..12616b4 100755
--- a/utility/chromeos-tpm-recovery
+++ b/utility/chromeos-tpm-recovery
@@ -30,9 +30,9 @@
}
use_v0_secdata_kernel() {
- local fwid=$(crossystem ro_fwid)
- local major=$(printf "$fwid" | cut -d. -f2)
- local minor=$(printf "$fwid" | cut -d. -f3)
+ local fwid="$(crossystem ro_fwid)"
+ local major="$(printf "$fwid" | cut -d. -f2)"
+ local minor="$(printf "$fwid" | cut -d. -f3)"
# TPM1 firmware never supports the v1 kernel space format.
if ! tpm2_target; then