summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-02-13 09:05:00 -0800
committerBill Richardson <wfrichar@chromium.org>2013-02-13 09:05:55 -0800
commit7f5e3d744af83584c307b9dc2b6ec36f8b308285 (patch)
tree010dc3fa99ea54ad731910327950a463b6fa52e7
parent4c3f6e0e16844db159ccaa7e1f8fe8fa5a1d6e01 (diff)
parent886a9047f07d6bf9f424fd83247136c79706e136 (diff)
downloadvboot-7f5e3d744af83584c307b9dc2b6ec36f8b308285.tar.gz
Support installing futility on target
There is a corresponding ebuild change needed to make this work. I'll merge that into ToT Real Soon Now, then this will work. BUG=chromium-os:37062 BRANCH=none TEST=none Everything should continue to work as before. Change-Id: Iad103183938f0dd42a18fd14fc96b35fb58b4413 Signed-off-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--Makefile95
-rw-r--r--PRESUBMIT.cfg6
-rw-r--r--firmware/include/tlcl.h2
-rw-r--r--firmware/include/vboot_api.h13
-rw-r--r--firmware/include/vboot_nvstorage.h4
-rw-r--r--firmware/lib/cgptlib/cgptlib.c303
-rw-r--r--firmware/lib/cgptlib/cgptlib_internal.c706
-rw-r--r--[-rwxr-xr-x]firmware/lib/cgptlib/crc32.c121
-rw-r--r--firmware/lib/cgptlib/include/cgptlib.h139
-rw-r--r--firmware/lib/cgptlib/include/cgptlib_internal.h125
-rw-r--r--firmware/lib/cgptlib/include/gpt.h126
-rw-r--r--firmware/lib/crc8.c38
-rw-r--r--firmware/lib/include/vboot_display.h30
-rw-r--r--firmware/lib/include/vboot_kernel.h45
-rw-r--r--firmware/lib/rollback_index.c21
-rw-r--r--firmware/lib/stateful_util.c106
-rw-r--r--firmware/lib/tpm_bootmode.c187
-rw-r--r--firmware/lib/tpm_lite/tlcl.c5
-rw-r--r--firmware/lib/utility.c26
-rw-r--r--firmware/lib/utility_string.c108
-rw-r--r--firmware/lib/vboot_api_firmware.c204
-rw-r--r--firmware/lib/vboot_api_init.c551
-rw-r--r--firmware/lib/vboot_api_kernel.c1681
-rw-r--r--firmware/lib/vboot_audio.c463
-rw-r--r--firmware/lib/vboot_display.c1272
-rw-r--r--firmware/lib/vboot_firmware.c643
-rw-r--r--firmware/lib/vboot_kernel.c1127
-rw-r--r--firmware/lib/vboot_nvstorage.c455
-rw-r--r--firmware/stub/vboot_api_stub.c240
-rw-r--r--futility/futility.c14
-rwxr-xr-xfutility/setup_futility_symlinks.sh19
-rw-r--r--[-rwxr-xr-x]scripts/image_signing/common.sh0
-rw-r--r--[-rwxr-xr-x]scripts/image_signing/common_minimal.sh0
-rw-r--r--[-rwxr-xr-x]scripts/image_signing/sample-test-configs/ensure_no_nonrelease_files.config0
-rw-r--r--[-rwxr-xr-x]scripts/image_signing/sample-test-configs/ensure_secure_kernelparams.config0
-rwxr-xr-xscripts/image_signing/set_lsb_release.sh34
-rwxr-xr-xscripts/image_signing/sign_official_build.sh2
-rw-r--r--[-rwxr-xr-x]scripts/keygeneration/common.sh0
-rw-r--r--[-rwxr-xr-x]tests/common.sh0
-rw-r--r--tests/tlcl_tests.c351
-rw-r--r--tests/vboot_api_kernel2_tests.c554
-rw-r--r--tests/vboot_api_kernel3_tests.c362
-rw-r--r--tests/vboot_api_kernel4_tests.c241
-rw-r--r--tests/vboot_api_kernel_tests.c491
-rw-r--r--tests/vboot_display_tests.c173
-rw-r--r--tests/vboot_kernel_tests.c538
46 files changed, 7296 insertions, 4325 deletions
diff --git a/Makefile b/Makefile
index fff514d7..15120295 100644
--- a/Makefile
+++ b/Makefile
@@ -35,14 +35,15 @@
# Our convention is that we only use := for variables that will never be
# changed or appended. They must be defined before being used anywhere.
-# we should only run pwd once, not every time we refer to ${BUILD}.
+# We should only run pwd once, not every time we refer to ${BUILD}.
SRCDIR := $(shell pwd)
BUILD ?= $(SRCDIR)/build
export BUILD
-# Target for 'make install'
-DESTDIR ?= /usr/bin
+# Stuff for 'make install'
INSTALL ?= install
+DESTDIR ?= /usr/bin
+O_DESTDIR = ${DESTDIR}/old_bins
# Where to install the (exportable) executables for testing?
TEST_INSTALL_DIR = ${BUILD}/install_for_test
@@ -322,16 +323,20 @@ CGPT_SRCS = \
CGPT_OBJS = ${CGPT_SRCS:%.c=${BUILD}/%.o}
ALL_OBJS += ${CGPT_OBJS}
-C_DESTDIR = ${DESTDIR}/old_bins
+C_DESTDIR = ${O_DESTDIR}
# Scripts to install directly (not compiled)
UTIL_SCRIPTS = \
utility/dev_debug_vboot \
- utility/dev_make_keypair \
utility/enable_dev_usb_boot \
utility/vbutil_what_keys
+ifeq (${MINIMAL},)
+UTIL_SCRIPTS += \
+ utility/dev_make_keypair
+endif
+
# These utilities should be linked statically.
UTIL_NAMES_STATIC = \
crossystem \
@@ -342,39 +347,61 @@ UTIL_NAMES = ${UTIL_NAMES_STATIC} \
dev_sign_file \
dump_kernel_config \
dumpRSAPublicKey \
- load_kernel_test \
- pad_digest_utility \
- signature_digest_utility \
tpm_init_temp_fix \
tpmc \
vbutil_firmware \
vbutil_kernel \
vbutil_key \
vbutil_keyblock \
- verify_data
-
-ifneq (${IN_CHROOT},)
-UTIL_NAMES += mount-encrypted
-endif
ifeq (${MINIMAL},)
UTIL_NAMES += \
bmpblk_font \
bmpblk_utility \
eficompress \
- efidecompress
+ efidecompress \
+ load_kernel_test \
+ pad_digest_utility \
+ signature_digest_utility \
+ verify_data
+endif
+
+ifneq (${IN_CHROOT},)
+UTIL_NAMES += mount-encrypted
endif
UTIL_BINS_STATIC := $(addprefix ${BUILD}/utility/,${UTIL_NAMES_STATIC})
UTIL_BINS = $(addprefix ${BUILD}/utility/,${UTIL_NAMES})
ALL_DEPS += $(addsuffix .d,${UTIL_BINS})
-U_DESTDIR = ${DESTDIR}/old_bins
+U_DESTDIR = ${O_DESTDIR}
+
+# Scripts for signing stuff.
+SIGNING_SCRIPTS = \
+ utility/tpm-nvsize \
+ utility/chromeos-tpm-recovery
+# We need these wrapped, but the symlinks go in different places.
+SIGNING_SCRIPTS_DEV = \
+ scripts/image_signing/resign_firmwarefd.sh \
+ scripts/image_signing/make_dev_firmware.sh \
+ scripts/image_signing/make_dev_ssd.sh \
+ scripts/image_signing/set_gbb_flags.sh
+
+# Installed, but not made executable.
+SIGNING_COMMON = scripts/image_signing/common_minimal.sh
# The unified firmware utility will eventually replace all the others
FUTIL_BIN = ${BUILD}/futility/futility
+# These are the others it will replace.
+FUTIL_OLD = $(notdir ${CGPT} ${UTIL_BINS} ${UTIL_SCRIPTS} ${SIGNING_SCRIPTS})
+
+# The ebuild will put these somewhere else on the target.
+ifeq (${MINIMAL},)
+FUTIL_OLD += $(notdir ${SIGNING_SCRIPTS_DEV})
+endif
+
FUTIL_SRCS = \
futility/futility.c \
futility/cmd_foo.c
@@ -412,6 +439,7 @@ TEST_NAMES = \
sha_benchmark \
sha_tests \
stateful_util_tests \
+ tlcl_tests \
tpm_bootmode_tests \
utility_string_tests \
utility_tests \
@@ -419,12 +447,16 @@ TEST_NAMES = \
vboot_api_devmode_tests \
vboot_api_firmware_tests \
vboot_api_kernel_tests \
+ vboot_api_kernel2_tests \
+ vboot_api_kernel3_tests \
+ vboot_api_kernel4_tests \
vboot_audio_tests \
vboot_common_tests \
vboot_common2_tests \
vboot_common3_tests \
vboot_display_tests \
vboot_firmware_tests \
+ vboot_kernel_tests \
vboot_nvstorage_test
# Grrr
@@ -646,6 +678,16 @@ utils_install: ${UTIL_BINS} ${UTIL_SCRIPTS}
${Q}mkdir -p ${U_DESTDIR}
${Q}${INSTALL} -t ${U_DESTDIR} $^
+# And some signing stuff...
+
+.PHONY: signing_install
+signing_install: ${SIGNING_SCRIPTS} ${SIGNING_SCRIPTS_DEV} ${SIGNING_COMMON}
+ @printf " INSTALL SIGNING\n"
+ ${Q}mkdir -p ${U_DESTDIR}
+ ${Q}${INSTALL} -t ${U_DESTDIR} ${SIGNING_SCRIPTS}
+ ${Q}${INSTALL} -t ${U_DESTDIR} ${SIGNING_SCRIPTS_DEV}
+ ${Q}${INSTALL} -t ${U_DESTDIR} -m 'u=rw,go=r,a-s' ${SIGNING_COMMON}
+
# ----------------------------------------------------------------------------
# new Firmware Utility
@@ -657,12 +699,13 @@ ${FUTIL_BIN}: ${FUTIL_LDS} ${FUTIL_OBJS}
${Q}${LD} -o $@ ${CFLAGS} $^ ${LDFLAGS} ${LDLIBS}
.PHONY: futil_install
-futil_install: ${FUTIL_BIN} cgpt_install utils_install
+futil_install: ${FUTIL_BIN} cgpt_install utils_install signing_install
@printf " INSTALL futility\n"
${Q}mkdir -p ${F_DESTDIR}
${Q}${INSTALL} -t ${F_DESTDIR} ${FUTIL_BIN}
- futility/setup_futility_symlinks.sh ${F_DESTDIR}
-
+ ${Q}mkdir -p ${O_DESTDIR}
+ ${Q}for prog in ${FUTIL_OLD}; do \
+ ln -sf futility "${F_DESTDIR}/$$prog"; done
# ----------------------------------------------------------------------------
# Mount-encrypted utility for cryptohome
@@ -844,6 +887,11 @@ ${BUILD}/tests/rollback_index2_tests: OBJS += \
${BUILD}/tests/rollback_index2_tests: \
${BUILD}/firmware/lib/rollback_index_for_test.o
+${BUILD}/tests/tlcl_tests: OBJS += \
+ ${BUILD}/firmware/lib/tpm_lite/tlcl_for_test.o
+${BUILD}/tests/tlcl_tests: \
+ ${BUILD}/firmware/lib/tpm_lite/tlcl_for_test.o
+
${BUILD}/tests/vboot_audio_tests: OBJS += \
${BUILD}/firmware/lib/vboot_audio_for_test.o
${BUILD}/tests/vboot_audio_tests: \
@@ -939,18 +987,24 @@ runmisctests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/rsa_utility_tests
${RUNTEST} ${BUILD_RUN}/tests/sha_tests
${RUNTEST} ${BUILD_RUN}/tests/stateful_util_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/tlcl_tests
${RUNTEST} ${BUILD_RUN}/tests/tpm_bootmode_tests
${RUNTEST} ${BUILD_RUN}/tests/utility_string_tests
${RUNTEST} ${BUILD_RUN}/tests/utility_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_devmode_tests
- ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_init_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_api_firmware_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_init_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel2_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel3_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_api_kernel4_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_audio_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_common_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_common2_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vboot_common3_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vboot_display_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_firmware_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vboot_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vboot_nvstorage_test
.PHONY: runfutiltests
@@ -992,7 +1046,8 @@ coverage_html:
# Generate addtional coverage stats just for firmware subdir, because the
# per-directory stats for the whole project don't include their own subdirs.
- lcov -e ${COV_INFO}.local '${SRCDIR}/firmware/*' \
+ lcov -r ${COV_INFO}.local '*/stub/*' -o ${COV_INFO}.nostub
+ lcov -e ${COV_INFO}.nostub '${SRCDIR}/firmware/*' \
-o ${COV_INFO}.firmware
.PHONY: coverage
diff --git a/PRESUBMIT.cfg b/PRESUBMIT.cfg
new file mode 100644
index 00000000..2e8cdb66
--- /dev/null
+++ b/PRESUBMIT.cfg
@@ -0,0 +1,6 @@
+[Hook Overrides]
+
+# We are using Linux style indentation with tabs
+# The indentation is checked by checkpatch not the python script
+tab_check: false
+
diff --git a/firmware/include/tlcl.h b/firmware/include/tlcl.h
index ca4e47f7..5ce05638 100644
--- a/firmware/include/tlcl.h
+++ b/firmware/include/tlcl.h
@@ -134,6 +134,8 @@ uint32_t TlclPhysicalPresenceCMDEnable(void);
*/
uint32_t TlclFinalizePhysicalPresence(void);
+uint32_t TlclAssertPhysicalPresenceResult(void);
+
/**
* Turn off physical presence and locks it off until next reboot. The TPM
* error code is returned.
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index d91db7d8..31e91a7b 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -105,7 +105,11 @@ enum VbErrorPredefined_t {
/* Need VGA and don't have it, or vice-versa */
VBERROR_VGA_OPROM_MISMATCH = 0x10021,
/* Need EC to reboot to read-only code */
- VBERROR_EC_REBOOT_TO_RO_REQUIRED = 0x10022
+ VBERROR_EC_REBOOT_TO_RO_REQUIRED = 0x10022,
+
+ /* VbExEcGetExpectedRWHash() may return the following codes */
+ /* Compute expected RW hash from the EC image; BIOS doesn't have it */
+ VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE = 0x20000,
};
@@ -755,6 +759,13 @@ VbError_t VbExEcGetExpectedRW(enum VbSelectFirmware_t select,
const uint8_t **image, int *image_size);
/**
+ * Read the SHA-256 hash of the expected contents of the EC image associated
+ * with the main firmware specified by the "select" argument.
+ */
+VbError_t VbExEcGetExpectedRWHash(enum VbSelectFirmware_t select,
+ const uint8_t **hash, int *hash_size);
+
+/**
* Update the EC rewritable image.
*/
VbError_t VbExEcUpdateRW(const uint8_t *image, int image_size);
diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h
index 890af4b6..943a5664 100644
--- a/firmware/include/vboot_nvstorage.h
+++ b/firmware/include/vboot_nvstorage.h
@@ -142,6 +142,10 @@ typedef enum VbNvParam {
#define VBNV_RECOVERY_EC_JUMP_RW 0x27
/* EC software sync - unable to protect / unprotect EC-RW */
#define VBNV_RECOVERY_EC_PROTECT 0x28
+/* EC software sync - error obtaining expected EC hash */
+#define VBNV_RECOVERY_EC_EXPECTED_HASH 0x29
+/* EC software sync - expected EC image doesn't match hash */
+#define VBNV_RECOVERY_EC_HASH_MISMATCH 0x2A
/* Unspecified/unknown error in read-only firmware */
#define VBNV_RECOVERY_RO_UNSPECIFIED 0x3F
/*
diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c
index c3f37442..370530f1 100644
--- a/firmware/lib/cgptlib/cgptlib.c
+++ b/firmware/lib/cgptlib/cgptlib.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -10,150 +10,173 @@
#include "utility.h"
#include "vboot_api.h"
-int GptInit(GptData *gpt) {
- int retval;
+int GptInit(GptData *gpt)
+{
+ int retval;
- gpt->modified = 0;
- gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
- gpt->current_priority = 999;
+ gpt->modified = 0;
+ gpt->current_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+ gpt->current_priority = 999;
- retval = GptSanityCheck(gpt);
- if (GPT_SUCCESS != retval) {
- VBDEBUG(("GptInit() failed sanity check\n"));
- return retval;
- }
+ retval = GptSanityCheck(gpt);
+ if (GPT_SUCCESS != retval) {
+ VBDEBUG(("GptInit() failed sanity check\n"));
+ return retval;
+ }
- GptRepair(gpt);
- return GPT_SUCCESS;
+ GptRepair(gpt);
+ return GPT_SUCCESS;
}
-
-int GptNextKernelEntry(GptData* gpt, uint64_t* start_sector, uint64_t* size) {
- GptHeader* header = (GptHeader*)gpt->primary_header;
- GptEntry* entries = (GptEntry*)gpt->primary_entries;
- GptEntry* e;
- int new_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
- int new_prio = 0;
- uint32_t i;
-
- /* If we already found a kernel, continue the scan at the current
- * kernel's prioity, in case there is another kernel with the same
- * priority. */
- if (gpt->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) {
- for (i = gpt->current_kernel + 1; i < header->number_of_entries; i++) {
- e = entries + i;
- if (!IsKernelEntry(e))
- continue;
- VBDEBUG(("GptNextKernelEntry looking at same prio partition %d\n", i+1));
- VBDEBUG(("GptNextKernelEntry s%d t%d p%d\n",
- GetEntrySuccessful(e), GetEntryTries(e), GetEntryPriority(e)));
- if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
- continue;
- if (GetEntryPriority(e) == gpt->current_priority) {
- gpt->current_kernel = i;
- *start_sector = e->starting_lba;
- *size = e->ending_lba - e->starting_lba + 1;
- VBDEBUG(("GptNextKernelEntry likes that one\n"));
- return GPT_SUCCESS;
- }
- }
- }
-
- /* We're still here, so scan for the remaining kernel with the
- * highest priority less than the previous attempt. */
- for (i = 0, e = entries; i < header->number_of_entries; i++, e++) {
- int current_prio = GetEntryPriority(e);
- if (!IsKernelEntry(e))
- continue;
- VBDEBUG(("GptNextKernelEntry looking at new prio partition %d\n", i+1));
- VBDEBUG(("GptNextKernelEntry s%d t%d p%d\n",
- GetEntrySuccessful(e), GetEntryTries(e), GetEntryPriority(e)));
- if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
- continue;
- if (current_prio >= gpt->current_priority)
- continue; /* Already returned this kernel in a previous call */
- if (current_prio > new_prio) {
- new_kernel = i;
- new_prio = current_prio;
- }
- }
-
- /* Save what we found. Note that if we didn't find a new kernel,
- * new_prio will still be -1, so future calls to this function will
- * also fail. */
- gpt->current_kernel = new_kernel;
- gpt->current_priority = new_prio;
-
- if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) {
- VBDEBUG(("GptNextKernelEntry no more kernels\n"));
- return GPT_ERROR_NO_VALID_KERNEL;
- }
-
- VBDEBUG(("GptNextKernelEntry likes partition %d\n", new_kernel+1));
- e = entries + new_kernel;
- *start_sector = e->starting_lba;
- *size = e->ending_lba - e->starting_lba + 1;
- return GPT_SUCCESS;
+int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
+{
+ GptHeader *header = (GptHeader *)gpt->primary_header;
+ GptEntry *entries = (GptEntry *)gpt->primary_entries;
+ GptEntry *e;
+ int new_kernel = CGPT_KERNEL_ENTRY_NOT_FOUND;
+ int new_prio = 0;
+ uint32_t i;
+
+ /*
+ * If we already found a kernel, continue the scan at the current
+ * kernel's priority, in case there is another kernel with the same
+ * priority.
+ */
+ if (gpt->current_kernel != CGPT_KERNEL_ENTRY_NOT_FOUND) {
+ for (i = gpt->current_kernel + 1;
+ i < header->number_of_entries; i++) {
+ e = entries + i;
+ if (!IsKernelEntry(e))
+ continue;
+ VBDEBUG(("GptNextKernelEntry looking at same prio "
+ "partition %d\n", i+1));
+ VBDEBUG(("GptNextKernelEntry s%d t%d p%d\n",
+ GetEntrySuccessful(e), GetEntryTries(e),
+ GetEntryPriority(e)));
+ if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
+ continue;
+ if (GetEntryPriority(e) == gpt->current_priority) {
+ gpt->current_kernel = i;
+ *start_sector = e->starting_lba;
+ *size = e->ending_lba - e->starting_lba + 1;
+ VBDEBUG(("GptNextKernelEntry likes it\n"));
+ return GPT_SUCCESS;
+ }
+ }
+ }
+
+ /*
+ * We're still here, so scan for the remaining kernel with the highest
+ * priority less than the previous attempt.
+ */
+ for (i = 0, e = entries; i < header->number_of_entries; i++, e++) {
+ int current_prio = GetEntryPriority(e);
+ if (!IsKernelEntry(e))
+ continue;
+ VBDEBUG(("GptNextKernelEntry looking at new prio "
+ "partition %d\n", i+1));
+ VBDEBUG(("GptNextKernelEntry s%d t%d p%d\n",
+ GetEntrySuccessful(e), GetEntryTries(e),
+ GetEntryPriority(e)));
+ if (!(GetEntrySuccessful(e) || GetEntryTries(e)))
+ continue;
+ if (current_prio >= gpt->current_priority) {
+ /* Already returned this kernel in a previous call */
+ continue;
+ }
+ if (current_prio > new_prio) {
+ new_kernel = i;
+ new_prio = current_prio;
+ }
+ }
+
+ /*
+ * Save what we found. Note that if we didn't find a new kernel,
+ * new_prio will still be -1, so future calls to this function will
+ * also fail.
+ */
+ gpt->current_kernel = new_kernel;
+ gpt->current_priority = new_prio;
+
+ if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) {
+ VBDEBUG(("GptNextKernelEntry no more kernels\n"));
+ return GPT_ERROR_NO_VALID_KERNEL;
+ }
+
+ VBDEBUG(("GptNextKernelEntry likes partition %d\n", new_kernel + 1));
+ e = entries + new_kernel;
+ *start_sector = e->starting_lba;
+ *size = e->ending_lba - e->starting_lba + 1;
+ return GPT_SUCCESS;
}
-
-int GptUpdateKernelEntry(GptData* gpt, uint32_t update_type) {
- GptHeader* header = (GptHeader*)gpt->primary_header;
- GptEntry* entries = (GptEntry*)gpt->primary_entries;
- GptEntry* e = entries + gpt->current_kernel;
- uint16_t previous_attr = e->attrs.fields.gpt_att;
-
- if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND)
- return GPT_ERROR_INVALID_UPDATE_TYPE;
- if (!IsKernelEntry(e))
- return GPT_ERROR_INVALID_UPDATE_TYPE;
-
- switch (update_type) {
- case GPT_UPDATE_ENTRY_TRY: {
- /* Used up a try */
- int tries;
- if (GetEntrySuccessful(e))
- return GPT_SUCCESS; /* Successfully booted this partition, so
- * tries field is ignored. */
- tries = GetEntryTries(e);
- if (tries > 1) {
- /* Still have tries left */
- SetEntryTries(e, tries - 1);
- break;
- }
- /* Out of tries, so drop through and mark partition bad. */
- }
- case GPT_UPDATE_ENTRY_BAD: {
- /* Giving up on this partition entirely. */
- if (!GetEntrySuccessful(e)) {
- /* Only clear tries and priority if the successful bit is not set. */
- e->attrs.fields.gpt_att = previous_attr & ~(
- CGPT_ATTRIBUTE_TRIES_MASK |
- CGPT_ATTRIBUTE_PRIORITY_MASK);
- }
- break;
- }
- default:
- return GPT_ERROR_INVALID_UPDATE_TYPE;
- }
-
- /* If no change to attributes, we're done */
- if (e->attrs.fields.gpt_att == previous_attr)
- return GPT_SUCCESS;
-
- /* Update the CRCs */
- header->entries_crc32 = Crc32((const uint8_t *)entries,
- header->size_of_entry *
- header->number_of_entries);
- header->header_crc32 = HeaderCrc(header);
- gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
-
- /* Use the repair function to update the other copy of the GPT.
- * This is a tad inefficient, but is much faster than the disk I/O
- * to update the GPT on disk so it doesn't matter. */
- gpt->valid_headers = MASK_PRIMARY;
- gpt->valid_entries = MASK_PRIMARY;
- GptRepair(gpt);
-
- return GPT_SUCCESS;
+int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type)
+{
+ GptHeader *header = (GptHeader *)gpt->primary_header;
+ GptEntry *entries = (GptEntry *)gpt->primary_entries;
+ GptEntry *e = entries + gpt->current_kernel;
+ uint16_t previous_attr = e->attrs.fields.gpt_att;
+
+ if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND)
+ return GPT_ERROR_INVALID_UPDATE_TYPE;
+ if (!IsKernelEntry(e))
+ return GPT_ERROR_INVALID_UPDATE_TYPE;
+
+ switch (update_type) {
+ case GPT_UPDATE_ENTRY_TRY: {
+ /* Used up a try */
+ int tries;
+ if (GetEntrySuccessful(e)) {
+ /*
+ * Successfully booted this partition, so tries field
+ * is ignored.
+ */
+ return GPT_SUCCESS;
+ }
+ tries = GetEntryTries(e);
+ if (tries > 1) {
+ /* Still have tries left */
+ SetEntryTries(e, tries - 1);
+ break;
+ }
+ /* Out of tries, so drop through and mark partition bad. */
+ }
+ case GPT_UPDATE_ENTRY_BAD: {
+ /* Giving up on this partition entirely. */
+ if (!GetEntrySuccessful(e)) {
+ /*
+ * Only clear tries and priority if the successful bit
+ * is not set.
+ */
+ e->attrs.fields.gpt_att = previous_attr &
+ ~(CGPT_ATTRIBUTE_TRIES_MASK |
+ CGPT_ATTRIBUTE_PRIORITY_MASK);
+ }
+ break;
+ }
+ default:
+ return GPT_ERROR_INVALID_UPDATE_TYPE;
+ }
+
+ /* If no change to attributes, we're done */
+ if (e->attrs.fields.gpt_att == previous_attr)
+ return GPT_SUCCESS;
+
+ /* Update the CRCs */
+ header->entries_crc32 = Crc32((const uint8_t *)entries,
+ header->size_of_entry *
+ header->number_of_entries);
+ header->header_crc32 = HeaderCrc(header);
+ gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
+
+ /*
+ * Use the repair function to update the other copy of the GPT. This
+ * is a tad inefficient, but is much faster than the disk I/O to update
+ * the GPT on disk so it doesn't matter.
+ */
+ gpt->valid_headers = MASK_PRIMARY;
+ gpt->valid_entries = MASK_PRIMARY;
+ GptRepair(gpt);
+
+ return GPT_SUCCESS;
}
diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c
index 86b2c151..d51ce33b 100644
--- a/firmware/lib/cgptlib/cgptlib_internal.c
+++ b/firmware/lib/cgptlib/cgptlib_internal.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -10,396 +10,410 @@
#include "utility.h"
-int CheckParameters(GptData *gpt) {
- /* Currently, we only support 512-byte sector. In the future, we may support
- * larger sector. */
- if (gpt->sector_bytes != 512)
- return GPT_ERROR_INVALID_SECTOR_SIZE;
-
- /* The sector number of a drive should be reasonable. If the given value is
- * too small to contain basic GPT structure (PMBR + Headers + Entries),
- * the value is wrong. */
- if (gpt->drive_sectors < (1 + 2 * (1 + GPT_ENTRIES_SECTORS)))
- return GPT_ERROR_INVALID_SECTOR_NUMBER;
-
- return GPT_SUCCESS;
+int CheckParameters(GptData *gpt)
+{
+ /* Currently, we only support 512-byte sectors. */
+ if (gpt->sector_bytes != 512)
+ return GPT_ERROR_INVALID_SECTOR_SIZE;
+
+ /*
+ * Sector count of a drive should be reasonable. If the given value is
+ * too small to contain basic GPT structure (PMBR + Headers + Entries),
+ * the value is wrong.
+ */
+ if (gpt->drive_sectors < (1 + 2 * (1 + GPT_ENTRIES_SECTORS)))
+ return GPT_ERROR_INVALID_SECTOR_NUMBER;
+
+ return GPT_SUCCESS;
}
+uint32_t HeaderCrc(GptHeader *h)
+{
+ uint32_t crc32, original_crc32;
-uint32_t HeaderCrc(GptHeader* h) {
- uint32_t crc32, original_crc32;
-
- /* Original CRC is calculated with the CRC field 0. */
- original_crc32 = h->header_crc32;
- h->header_crc32 = 0;
- crc32 = Crc32((const uint8_t *)h, h->size);
- h->header_crc32 = original_crc32;
+ /* Original CRC is calculated with the CRC field 0. */
+ original_crc32 = h->header_crc32;
+ h->header_crc32 = 0;
+ crc32 = Crc32((const uint8_t *)h, h->size);
+ h->header_crc32 = original_crc32;
- return crc32;
+ return crc32;
}
-
-int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors) {
- if (!h)
- return 1;
-
- /* Make sure we're looking at a header of reasonable size before
- * attempting to calculate CRC. */
- if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, GPT_HEADER_SIGNATURE_SIZE) &&
- Memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE))
- return 1;
- if (h->revision != GPT_HEADER_REVISION)
- return 1;
- if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
- return 1;
-
- /* Check CRC before looking at remaining fields */
- if (HeaderCrc(h) != h->header_crc32)
- return 1;
-
- /* Reserved fields must be zero. */
- if (h->reserved_zero)
- return 1;
-
- /* Could check that padding is zero, but that doesn't matter to us. */
-
- /* If entry size is different than our struct, we won't be able to
- * parse it. Technically, any size 2^N where N>=7 is valid. */
- if (h->size_of_entry != sizeof(GptEntry))
- return 1;
- if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
- (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
- (h->number_of_entries * h->size_of_entry != TOTAL_ENTRIES_SIZE))
- return 1;
-
- /* Check locations for the header and its entries. The primary
- * immediately follows the PMBR, and is followed by its entries.
- * The secondary is at the end of the drive, preceded by its
- * entries. */
- if (is_secondary) {
- if (h->my_lba != drive_sectors - 1)
- return 1;
- if (h->entries_lba != h->my_lba - GPT_ENTRIES_SECTORS)
- return 1;
- } else {
- if (h->my_lba != 1)
- return 1;
- if (h->entries_lba != h->my_lba + 1)
- return 1;
- }
-
- /* FirstUsableLBA must be after the end of the primary GPT table
- * array. LastUsableLBA must be before the start of the secondary
- * GPT table array. FirstUsableLBA <= LastUsableLBA. */
- if (h->first_usable_lba < 2 + GPT_ENTRIES_SECTORS)
- return 1;
- if (h->last_usable_lba >= drive_sectors - 1 - GPT_ENTRIES_SECTORS)
- return 1;
- if (h->first_usable_lba > h->last_usable_lba)
- return 1;
-
- /* Success */
- return 0;
+int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors)
+{
+ if (!h)
+ return 1;
+
+ /*
+ * Make sure we're looking at a header of reasonable size before
+ * attempting to calculate CRC.
+ */
+ if (Memcmp(h->signature, GPT_HEADER_SIGNATURE,
+ GPT_HEADER_SIGNATURE_SIZE) &&
+ Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
+ GPT_HEADER_SIGNATURE_SIZE))
+ return 1;
+ if (h->revision != GPT_HEADER_REVISION)
+ return 1;
+ if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER)
+ return 1;
+
+ /* Check CRC before looking at remaining fields */
+ if (HeaderCrc(h) != h->header_crc32)
+ return 1;
+
+ /* Reserved fields must be zero. */
+ if (h->reserved_zero)
+ return 1;
+
+ /* Could check that padding is zero, but that doesn't matter to us. */
+
+ /*
+ * If entry size is different than our struct, we won't be able to
+ * parse it. Technically, any size 2^N where N>=7 is valid.
+ */
+ if (h->size_of_entry != sizeof(GptEntry))
+ return 1;
+ if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) ||
+ (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) ||
+ (h->number_of_entries * h->size_of_entry != TOTAL_ENTRIES_SIZE))
+ return 1;
+
+ /*
+ * Check locations for the header and its entries. The primary
+ * immediately follows the PMBR, and is followed by its entries. The
+ * secondary is at the end of the drive, preceded by its entries.
+ */
+ if (is_secondary) {
+ if (h->my_lba != drive_sectors - 1)
+ return 1;
+ if (h->entries_lba != h->my_lba - GPT_ENTRIES_SECTORS)
+ return 1;
+ } else {
+ if (h->my_lba != 1)
+ return 1;
+ if (h->entries_lba != h->my_lba + 1)
+ return 1;
+ }
+
+ /*
+ * FirstUsableLBA must be after the end of the primary GPT table array.
+ * LastUsableLBA must be before the start of the secondary GPT table
+ * array. FirstUsableLBA <= LastUsableLBA.
+ */
+ if (h->first_usable_lba < 2 + GPT_ENTRIES_SECTORS)
+ return 1;
+ if (h->last_usable_lba >= drive_sectors - 1 - GPT_ENTRIES_SECTORS)
+ return 1;
+ if (h->first_usable_lba > h->last_usable_lba)
+ return 1;
+
+ /* Success */
+ return 0;
}
-
-/* Return non-zero if the entry is unused, 0 if it is used. */
-int IsUnusedEntry(const GptEntry* e) {
- static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
- return !Memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
+int IsUnusedEntry(const GptEntry *e)
+{
+ static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
+ return !Memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
}
-/* Returns non-zero if the entry is a Chrome OS kernel partition, else 0. */
-int IsKernelEntry(const GptEntry* e) {
- static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
- return !Memcmp(&e->type, &chromeos_kernel, sizeof(Guid));
+int IsKernelEntry(const GptEntry *e)
+{
+ static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL;
+ return !Memcmp(&e->type, &chromeos_kernel, sizeof(Guid));
}
-
-int CheckEntries(GptEntry* entries, GptHeader* h) {
-
- GptEntry* entry;
- uint32_t crc32;
- uint32_t i;
-
- /* Check CRC before examining entries. */
- crc32 = Crc32((const uint8_t *)entries,
- h->size_of_entry * h->number_of_entries);
- if (crc32 != h->entries_crc32)
- return GPT_ERROR_CRC_CORRUPTED;
-
- /* Check all entries. */
- for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) {
- GptEntry* e2;
- uint32_t i2;
-
- if (IsUnusedEntry(entry))
- continue;
-
- /* Entry must be in valid region. */
- if ((entry->starting_lba < h->first_usable_lba) ||
- (entry->ending_lba > h->last_usable_lba) ||
- (entry->ending_lba < entry->starting_lba))
- return GPT_ERROR_OUT_OF_REGION;
-
- /* Entry must not overlap other entries. */
- for (i2 = 0, e2 = entries; i2 < h->number_of_entries; i2++, e2++) {
- if (i2 == i || IsUnusedEntry(e2))
- continue;
-
- if ((entry->starting_lba >= e2->starting_lba) &&
- (entry->starting_lba <= e2->ending_lba))
- return GPT_ERROR_START_LBA_OVERLAP;
- if ((entry->ending_lba >= e2->starting_lba) &&
- (entry->ending_lba <= e2->ending_lba))
- return GPT_ERROR_END_LBA_OVERLAP;
-
- /* UniqueGuid field must be unique. */
- if (0 == Memcmp(&entry->unique, &e2->unique, sizeof(Guid)))
- return GPT_ERROR_DUP_GUID;
- }
- }
-
- /* Success */
- return 0;
+int CheckEntries(GptEntry *entries, GptHeader *h)
+{
+ GptEntry *entry;
+ uint32_t crc32;
+ uint32_t i;
+
+ /* Check CRC before examining entries. */
+ crc32 = Crc32((const uint8_t *)entries,
+ h->size_of_entry * h->number_of_entries);
+ if (crc32 != h->entries_crc32)
+ return GPT_ERROR_CRC_CORRUPTED;
+
+ /* Check all entries. */
+ for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) {
+ GptEntry *e2;
+ uint32_t i2;
+
+ if (IsUnusedEntry(entry))
+ continue;
+
+ /* Entry must be in valid region. */
+ if ((entry->starting_lba < h->first_usable_lba) ||
+ (entry->ending_lba > h->last_usable_lba) ||
+ (entry->ending_lba < entry->starting_lba))
+ return GPT_ERROR_OUT_OF_REGION;
+
+ /* Entry must not overlap other entries. */
+ for (i2 = 0, e2 = entries; i2 < h->number_of_entries;
+ i2++, e2++) {
+ if (i2 == i || IsUnusedEntry(e2))
+ continue;
+
+ if ((entry->starting_lba >= e2->starting_lba) &&
+ (entry->starting_lba <= e2->ending_lba))
+ return GPT_ERROR_START_LBA_OVERLAP;
+ if ((entry->ending_lba >= e2->starting_lba) &&
+ (entry->ending_lba <= e2->ending_lba))
+ return GPT_ERROR_END_LBA_OVERLAP;
+
+ /* UniqueGuid field must be unique. */
+ if (0 == Memcmp(&entry->unique, &e2->unique,
+ sizeof(Guid)))
+ return GPT_ERROR_DUP_GUID;
+ }
+ }
+
+ /* Success */
+ return 0;
}
-
-/* Returns 0 if the GptHeaders are the same for all fields which don't
- * differ between the primary and secondary headers - that is, all
- * fields other than:
- *
- * my_lba
- * alternate_lba
- * entries_lba */
-int HeaderFieldsSame(GptHeader *h1, GptHeader *h2) {
- if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature)))
- return 1;
- if (h1->revision != h2->revision)
- return 1;
- if (h1->size != h2->size)
- return 1;
- if (h1->reserved_zero != h2->reserved_zero)
- return 1;
- if (h1->first_usable_lba != h2->first_usable_lba)
- return 1;
- if (h1->last_usable_lba != h2->last_usable_lba)
- return 1;
- if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid)))
- return 1;
- if (h1->number_of_entries != h2->number_of_entries)
- return 1;
- if (h1->size_of_entry != h2->size_of_entry)
- return 1;
- if (h1->entries_crc32 != h2->entries_crc32)
- return 1;
-
- return 0;
+int HeaderFieldsSame(GptHeader *h1, GptHeader *h2)
+{
+ if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature)))
+ return 1;
+ if (h1->revision != h2->revision)
+ return 1;
+ if (h1->size != h2->size)
+ return 1;
+ if (h1->reserved_zero != h2->reserved_zero)
+ return 1;
+ if (h1->first_usable_lba != h2->first_usable_lba)
+ return 1;
+ if (h1->last_usable_lba != h2->last_usable_lba)
+ return 1;
+ if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid)))
+ return 1;
+ if (h1->number_of_entries != h2->number_of_entries)
+ return 1;
+ if (h1->size_of_entry != h2->size_of_entry)
+ return 1;
+ if (h1->entries_crc32 != h2->entries_crc32)
+ return 1;
+
+ return 0;
}
-
-int GptSanityCheck(GptData *gpt) {
- int retval;
- GptHeader* header1 = (GptHeader*)(gpt->primary_header);
- GptHeader* header2 = (GptHeader*)(gpt->secondary_header);
- GptEntry* entries1 = (GptEntry*)(gpt->primary_entries);
- GptEntry* entries2 = (GptEntry*)(gpt->secondary_entries);
- GptHeader* goodhdr = NULL;
-
- gpt->valid_headers = 0;
- gpt->valid_entries = 0;
-
- retval = CheckParameters(gpt);
- if (retval != GPT_SUCCESS)
- return retval;
-
- /* Check both headers; we need at least one valid header. */
- if (0 == CheckHeader(header1, 0, gpt->drive_sectors)) {
- gpt->valid_headers |= MASK_PRIMARY;
- goodhdr = header1;
- }
- if (0 == CheckHeader(header2, 1, gpt->drive_sectors)) {
- gpt->valid_headers |= MASK_SECONDARY;
- if (!goodhdr)
- goodhdr = header2;
- }
-
- if (!gpt->valid_headers)
- return GPT_ERROR_INVALID_HEADERS;
-
- /* Checks if entries are valid.
- *
- * Note that we use the same header in both checks. This way we'll
- * catch the case where (header1,entries1) and (header2,entries2)
- * are both valid, but (entries1 != entries2). */
- if (0 == CheckEntries(entries1, goodhdr))
- gpt->valid_entries |= MASK_PRIMARY;
- if (0 == CheckEntries(entries2, goodhdr))
- gpt->valid_entries |= MASK_SECONDARY;
-
- /* If both headers are good but neither entries were good, check the
- * entries with the secondary header. */
- if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
- if (0 == CheckEntries(entries1, header2))
- gpt->valid_entries |= MASK_PRIMARY;
- if (0 == CheckEntries(entries2, header2))
- gpt->valid_entries |= MASK_SECONDARY;
- if (gpt->valid_entries) {
- /* Sure enough, header2 had a good CRC for one of the entries. Mark
- * header1 invalid, so we'll update its entries CRC. */
- gpt->valid_headers &= ~MASK_PRIMARY;
- goodhdr = header2;
- }
- }
-
- if (!gpt->valid_entries)
- return GPT_ERROR_INVALID_ENTRIES;
-
- /* Now that we've determined which header contains a good CRC for
- * the entries, make sure the headers are otherwise identical. */
- if (MASK_BOTH == gpt->valid_headers &&
- 0 != HeaderFieldsSame(header1, header2))
- gpt->valid_headers &= ~MASK_SECONDARY;
-
- return GPT_SUCCESS;
+int GptSanityCheck(GptData *gpt)
+{
+ int retval;
+ GptHeader *header1 = (GptHeader *)(gpt->primary_header);
+ GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
+ GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
+ GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
+ GptHeader *goodhdr = NULL;
+
+ gpt->valid_headers = 0;
+ gpt->valid_entries = 0;
+
+ retval = CheckParameters(gpt);
+ if (retval != GPT_SUCCESS)
+ return retval;
+
+ /* Check both headers; we need at least one valid header. */
+ if (0 == CheckHeader(header1, 0, gpt->drive_sectors)) {
+ gpt->valid_headers |= MASK_PRIMARY;
+ goodhdr = header1;
+ }
+ if (0 == CheckHeader(header2, 1, gpt->drive_sectors)) {
+ gpt->valid_headers |= MASK_SECONDARY;
+ if (!goodhdr)
+ goodhdr = header2;
+ }
+
+ if (!gpt->valid_headers)
+ return GPT_ERROR_INVALID_HEADERS;
+
+ /*
+ * Check if entries are valid.
+ *
+ * Note that we use the same header in both checks. This way we'll
+ * catch the case where (header1,entries1) and (header2,entries2) are
+ * both valid, but (entries1 != entries2).
+ */
+ if (0 == CheckEntries(entries1, goodhdr))
+ gpt->valid_entries |= MASK_PRIMARY;
+ if (0 == CheckEntries(entries2, goodhdr))
+ gpt->valid_entries |= MASK_SECONDARY;
+
+ /*
+ * If both headers are good but neither entries were good, check the
+ * entries with the secondary header.
+ */
+ if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
+ if (0 == CheckEntries(entries1, header2))
+ gpt->valid_entries |= MASK_PRIMARY;
+ if (0 == CheckEntries(entries2, header2))
+ gpt->valid_entries |= MASK_SECONDARY;
+ if (gpt->valid_entries) {
+ /*
+ * Sure enough, header2 had a good CRC for one of the
+ * entries. Mark header1 invalid, so we'll update its
+ * entries CRC.
+ */
+ gpt->valid_headers &= ~MASK_PRIMARY;
+ goodhdr = header2;
+ }
+ }
+
+ if (!gpt->valid_entries)
+ return GPT_ERROR_INVALID_ENTRIES;
+
+ /*
+ * Now that we've determined which header contains a good CRC for
+ * the entries, make sure the headers are otherwise identical.
+ */
+ if (MASK_BOTH == gpt->valid_headers &&
+ 0 != HeaderFieldsSame(header1, header2))
+ gpt->valid_headers &= ~MASK_SECONDARY;
+
+ return GPT_SUCCESS;
}
-
-void GptRepair(GptData *gpt) {
- GptHeader* header1 = (GptHeader*)(gpt->primary_header);
- GptHeader* header2 = (GptHeader*)(gpt->secondary_header);
- GptEntry* entries1 = (GptEntry*)(gpt->primary_entries);
- GptEntry* entries2 = (GptEntry*)(gpt->secondary_entries);
- int entries_size;
-
- /* Need at least one good header and one good set of entries. */
- if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries)
- return;
-
- /* Repair headers if necessary */
- if (MASK_PRIMARY == gpt->valid_headers) {
- /* Primary is good, secondary is bad */
- Memcpy(header2, header1, sizeof(GptHeader));
- header2->my_lba = gpt->drive_sectors - 1;
- header2->alternate_lba = 1;
- header2->entries_lba = header2->my_lba - GPT_ENTRIES_SECTORS;
- header2->header_crc32 = HeaderCrc(header2);
- gpt->modified |= GPT_MODIFIED_HEADER2;
- }
- else if (MASK_SECONDARY == gpt->valid_headers) {
- /* Secondary is good, primary is bad */
- Memcpy(header1, header2, sizeof(GptHeader));
- header1->my_lba = 1;
- header1->alternate_lba = gpt->drive_sectors - 1;
- header1->entries_lba = header1->my_lba + 1;
- header1->header_crc32 = HeaderCrc(header1);
- gpt->modified |= GPT_MODIFIED_HEADER1;
- }
- gpt->valid_headers = MASK_BOTH;
-
- /* Repair entries if necessary */
- entries_size = header1->size_of_entry * header1->number_of_entries;
- if (MASK_PRIMARY == gpt->valid_entries) {
- /* Primary is good, secondary is bad */
- Memcpy(entries2, entries1, entries_size);
- gpt->modified |= GPT_MODIFIED_ENTRIES2;
- }
- else if (MASK_SECONDARY == gpt->valid_entries) {
- /* Secondary is good, primary is bad */
- Memcpy(entries1, entries2, entries_size);
- gpt->modified |= GPT_MODIFIED_ENTRIES1;
- }
- gpt->valid_entries = MASK_BOTH;
+void GptRepair(GptData *gpt)
+{
+ GptHeader *header1 = (GptHeader *)(gpt->primary_header);
+ GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
+ GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
+ GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
+ int entries_size;
+
+ /* Need at least one good header and one good set of entries. */
+ if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries)
+ return;
+
+ /* Repair headers if necessary */
+ if (MASK_PRIMARY == gpt->valid_headers) {
+ /* Primary is good, secondary is bad */
+ Memcpy(header2, header1, sizeof(GptHeader));
+ header2->my_lba = gpt->drive_sectors - 1;
+ header2->alternate_lba = 1;
+ header2->entries_lba = header2->my_lba - GPT_ENTRIES_SECTORS;
+ header2->header_crc32 = HeaderCrc(header2);
+ gpt->modified |= GPT_MODIFIED_HEADER2;
+ }
+ else if (MASK_SECONDARY == gpt->valid_headers) {
+ /* Secondary is good, primary is bad */
+ Memcpy(header1, header2, sizeof(GptHeader));
+ header1->my_lba = 1;
+ header1->alternate_lba = gpt->drive_sectors - 1;
+ header1->entries_lba = header1->my_lba + 1;
+ header1->header_crc32 = HeaderCrc(header1);
+ gpt->modified |= GPT_MODIFIED_HEADER1;
+ }
+ gpt->valid_headers = MASK_BOTH;
+
+ /* Repair entries if necessary */
+ entries_size = header1->size_of_entry * header1->number_of_entries;
+ if (MASK_PRIMARY == gpt->valid_entries) {
+ /* Primary is good, secondary is bad */
+ Memcpy(entries2, entries1, entries_size);
+ gpt->modified |= GPT_MODIFIED_ENTRIES2;
+ }
+ else if (MASK_SECONDARY == gpt->valid_entries) {
+ /* Secondary is good, primary is bad */
+ Memcpy(entries1, entries2, entries_size);
+ gpt->modified |= GPT_MODIFIED_ENTRIES1;
+ }
+ gpt->valid_entries = MASK_BOTH;
}
-
-int GetEntrySuccessful(const GptEntry* e) {
- return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
- CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
+int GetEntrySuccessful(const GptEntry *e)
+{
+ return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
+ CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
}
-
-int GetEntryPriority(const GptEntry* e) {
- return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
- CGPT_ATTRIBUTE_PRIORITY_OFFSET;
+int GetEntryPriority(const GptEntry *e)
+{
+ return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
+ CGPT_ATTRIBUTE_PRIORITY_OFFSET;
}
-
-int GetEntryTries(const GptEntry* e) {
- return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >>
- CGPT_ATTRIBUTE_TRIES_OFFSET;
+int GetEntryTries(const GptEntry *e)
+{
+ return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >>
+ CGPT_ATTRIBUTE_TRIES_OFFSET;
}
-
-void SetEntrySuccessful(GptEntry* e, int successful) {
- if (successful)
- e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
- else
- e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
+void SetEntrySuccessful(GptEntry *e, int successful)
+{
+ if (successful)
+ e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
+ else
+ e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK;
}
-
-void SetEntryPriority(GptEntry* e, int priority) {
- e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
- e->attrs.fields.gpt_att |= (priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) &
- CGPT_ATTRIBUTE_PRIORITY_MASK;
+void SetEntryPriority(GptEntry *e, int priority)
+{
+ e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK;
+ e->attrs.fields.gpt_att |=
+ (priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) &
+ CGPT_ATTRIBUTE_PRIORITY_MASK;
}
-
-void SetEntryTries(GptEntry* e, int tries) {
- e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK;
- e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET) &
- CGPT_ATTRIBUTE_TRIES_MASK;
+void SetEntryTries(GptEntry *e, int tries)
+{
+ e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK;
+ e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET) &
+ CGPT_ATTRIBUTE_TRIES_MASK;
}
-void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) {
- GptEntry* entries = (GptEntry*)gpt->primary_entries;
- GptEntry* e = entries + gpt->current_kernel;
- Memcpy(dest, &e->unique, sizeof(Guid));
+void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
+{
+ GptEntry *entries = (GptEntry *)gpt->primary_entries;
+ GptEntry *e = entries + gpt->current_kernel;
+ Memcpy(dest, &e->unique, sizeof(Guid));
}
-
-const char* GptErrorText(int error_code)
+const char *GptErrorText(int error_code)
{
- switch(error_code) {
- case GPT_SUCCESS:
- return "none";
+ switch(error_code) {
+ case GPT_SUCCESS:
+ return "none";
- case GPT_ERROR_NO_VALID_KERNEL:
- return "Invalid kernel";
+ case GPT_ERROR_NO_VALID_KERNEL:
+ return "Invalid kernel";
- case GPT_ERROR_INVALID_HEADERS:
- return "Invalid headers";
+ case GPT_ERROR_INVALID_HEADERS:
+ return "Invalid headers";
- case GPT_ERROR_INVALID_ENTRIES:
- return "Invalid entries";
+ case GPT_ERROR_INVALID_ENTRIES:
+ return "Invalid entries";
- case GPT_ERROR_INVALID_SECTOR_SIZE:
- return "Invalid sector size";
+ case GPT_ERROR_INVALID_SECTOR_SIZE:
+ return "Invalid sector size";
- case GPT_ERROR_INVALID_SECTOR_NUMBER:
- return "Invalid sector number";
+ case GPT_ERROR_INVALID_SECTOR_NUMBER:
+ return "Invalid sector number";
- case GPT_ERROR_INVALID_UPDATE_TYPE:
- return "Invalid update type";
+ case GPT_ERROR_INVALID_UPDATE_TYPE:
+ return "Invalid update type";
- case GPT_ERROR_CRC_CORRUPTED:
- return "Entries' crc corrupted";
+ case GPT_ERROR_CRC_CORRUPTED:
+ return "Entries' crc corrupted";
- case GPT_ERROR_OUT_OF_REGION:
- return "Entry outside of valid region";
+ case GPT_ERROR_OUT_OF_REGION:
+ return "Entry outside of valid region";
- case GPT_ERROR_START_LBA_OVERLAP:
- return "Starting LBA overlaps";
+ case GPT_ERROR_START_LBA_OVERLAP:
+ return "Starting LBA overlaps";
- case GPT_ERROR_END_LBA_OVERLAP:
- return "Ending LBA overlaps";
+ case GPT_ERROR_END_LBA_OVERLAP:
+ return "Ending LBA overlaps";
- case GPT_ERROR_DUP_GUID:
- return "Duplicated GUID";
+ case GPT_ERROR_DUP_GUID:
+ return "Duplicated GUID";
- default:
- break;
- };
- return "Unknown";
+ default:
+ break;
+ };
+ return "Unknown";
}
diff --git a/firmware/lib/cgptlib/crc32.c b/firmware/lib/cgptlib/crc32.c
index 9dacd178..002c5b9a 100755..100644
--- a/firmware/lib/cgptlib/crc32.c
+++ b/firmware/lib/cgptlib/crc32.c
@@ -42,67 +42,68 @@
#include "crc32.h"
static uint32_t crc32_tab[] = {
- 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
- 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
- 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
- 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
- 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
- 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
- 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
- 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
- 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
- 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
- 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
- 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
- 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
- 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
- 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
- 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
- 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
- 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
- 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
- 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
- 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
- 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
- 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
- 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
- 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
- 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
- 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
- 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
- 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
- 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
- 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
- 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
- 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
- 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
- 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
- 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
- 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
- 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
- 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
- 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
- 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
- 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
- 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
- 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
- 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
- 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
- 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
- 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
- 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
- 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
- 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
- 0x2d02ef8dU
+ 0x00000000U, 0x77073096U, 0xee0e612cU, 0x990951baU, 0x076dc419U,
+ 0x706af48fU, 0xe963a535U, 0x9e6495a3U, 0x0edb8832U, 0x79dcb8a4U,
+ 0xe0d5e91eU, 0x97d2d988U, 0x09b64c2bU, 0x7eb17cbdU, 0xe7b82d07U,
+ 0x90bf1d91U, 0x1db71064U, 0x6ab020f2U, 0xf3b97148U, 0x84be41deU,
+ 0x1adad47dU, 0x6ddde4ebU, 0xf4d4b551U, 0x83d385c7U, 0x136c9856U,
+ 0x646ba8c0U, 0xfd62f97aU, 0x8a65c9ecU, 0x14015c4fU, 0x63066cd9U,
+ 0xfa0f3d63U, 0x8d080df5U, 0x3b6e20c8U, 0x4c69105eU, 0xd56041e4U,
+ 0xa2677172U, 0x3c03e4d1U, 0x4b04d447U, 0xd20d85fdU, 0xa50ab56bU,
+ 0x35b5a8faU, 0x42b2986cU, 0xdbbbc9d6U, 0xacbcf940U, 0x32d86ce3U,
+ 0x45df5c75U, 0xdcd60dcfU, 0xabd13d59U, 0x26d930acU, 0x51de003aU,
+ 0xc8d75180U, 0xbfd06116U, 0x21b4f4b5U, 0x56b3c423U, 0xcfba9599U,
+ 0xb8bda50fU, 0x2802b89eU, 0x5f058808U, 0xc60cd9b2U, 0xb10be924U,
+ 0x2f6f7c87U, 0x58684c11U, 0xc1611dabU, 0xb6662d3dU, 0x76dc4190U,
+ 0x01db7106U, 0x98d220bcU, 0xefd5102aU, 0x71b18589U, 0x06b6b51fU,
+ 0x9fbfe4a5U, 0xe8b8d433U, 0x7807c9a2U, 0x0f00f934U, 0x9609a88eU,
+ 0xe10e9818U, 0x7f6a0dbbU, 0x086d3d2dU, 0x91646c97U, 0xe6635c01U,
+ 0x6b6b51f4U, 0x1c6c6162U, 0x856530d8U, 0xf262004eU, 0x6c0695edU,
+ 0x1b01a57bU, 0x8208f4c1U, 0xf50fc457U, 0x65b0d9c6U, 0x12b7e950U,
+ 0x8bbeb8eaU, 0xfcb9887cU, 0x62dd1ddfU, 0x15da2d49U, 0x8cd37cf3U,
+ 0xfbd44c65U, 0x4db26158U, 0x3ab551ceU, 0xa3bc0074U, 0xd4bb30e2U,
+ 0x4adfa541U, 0x3dd895d7U, 0xa4d1c46dU, 0xd3d6f4fbU, 0x4369e96aU,
+ 0x346ed9fcU, 0xad678846U, 0xda60b8d0U, 0x44042d73U, 0x33031de5U,
+ 0xaa0a4c5fU, 0xdd0d7cc9U, 0x5005713cU, 0x270241aaU, 0xbe0b1010U,
+ 0xc90c2086U, 0x5768b525U, 0x206f85b3U, 0xb966d409U, 0xce61e49fU,
+ 0x5edef90eU, 0x29d9c998U, 0xb0d09822U, 0xc7d7a8b4U, 0x59b33d17U,
+ 0x2eb40d81U, 0xb7bd5c3bU, 0xc0ba6cadU, 0xedb88320U, 0x9abfb3b6U,
+ 0x03b6e20cU, 0x74b1d29aU, 0xead54739U, 0x9dd277afU, 0x04db2615U,
+ 0x73dc1683U, 0xe3630b12U, 0x94643b84U, 0x0d6d6a3eU, 0x7a6a5aa8U,
+ 0xe40ecf0bU, 0x9309ff9dU, 0x0a00ae27U, 0x7d079eb1U, 0xf00f9344U,
+ 0x8708a3d2U, 0x1e01f268U, 0x6906c2feU, 0xf762575dU, 0x806567cbU,
+ 0x196c3671U, 0x6e6b06e7U, 0xfed41b76U, 0x89d32be0U, 0x10da7a5aU,
+ 0x67dd4accU, 0xf9b9df6fU, 0x8ebeeff9U, 0x17b7be43U, 0x60b08ed5U,
+ 0xd6d6a3e8U, 0xa1d1937eU, 0x38d8c2c4U, 0x4fdff252U, 0xd1bb67f1U,
+ 0xa6bc5767U, 0x3fb506ddU, 0x48b2364bU, 0xd80d2bdaU, 0xaf0a1b4cU,
+ 0x36034af6U, 0x41047a60U, 0xdf60efc3U, 0xa867df55U, 0x316e8eefU,
+ 0x4669be79U, 0xcb61b38cU, 0xbc66831aU, 0x256fd2a0U, 0x5268e236U,
+ 0xcc0c7795U, 0xbb0b4703U, 0x220216b9U, 0x5505262fU, 0xc5ba3bbeU,
+ 0xb2bd0b28U, 0x2bb45a92U, 0x5cb36a04U, 0xc2d7ffa7U, 0xb5d0cf31U,
+ 0x2cd99e8bU, 0x5bdeae1dU, 0x9b64c2b0U, 0xec63f226U, 0x756aa39cU,
+ 0x026d930aU, 0x9c0906a9U, 0xeb0e363fU, 0x72076785U, 0x05005713U,
+ 0x95bf4a82U, 0xe2b87a14U, 0x7bb12baeU, 0x0cb61b38U, 0x92d28e9bU,
+ 0xe5d5be0dU, 0x7cdcefb7U, 0x0bdbdf21U, 0x86d3d2d4U, 0xf1d4e242U,
+ 0x68ddb3f8U, 0x1fda836eU, 0x81be16cdU, 0xf6b9265bU, 0x6fb077e1U,
+ 0x18b74777U, 0x88085ae6U, 0xff0f6a70U, 0x66063bcaU, 0x11010b5cU,
+ 0x8f659effU, 0xf862ae69U, 0x616bffd3U, 0x166ccf45U, 0xa00ae278U,
+ 0xd70dd2eeU, 0x4e048354U, 0x3903b3c2U, 0xa7672661U, 0xd06016f7U,
+ 0x4969474dU, 0x3e6e77dbU, 0xaed16a4aU, 0xd9d65adcU, 0x40df0b66U,
+ 0x37d83bf0U, 0xa9bcae53U, 0xdebb9ec5U, 0x47b2cf7fU, 0x30b5ffe9U,
+ 0xbdbdf21cU, 0xcabac28aU, 0x53b39330U, 0x24b4a3a6U, 0xbad03605U,
+ 0xcdd70693U, 0x54de5729U, 0x23d967bfU, 0xb3667a2eU, 0xc4614ab8U,
+ 0x5d681b02U, 0x2a6f2b94U, 0xb40bbe37U, 0xc30c8ea1U, 0x5a05df1bU,
+ 0x2d02ef8dU
};
-/* Returns a 32-bit CRC of the contents of the buffer. */
-uint32_t Crc32(const void *buffer, uint32_t len) {
- uint8_t *byte = (uint8_t*)buffer;
- uint32_t i;
- uint32_t value = ~0U;
- for (i = 0; i < len; ++i)
- value = crc32_tab[(value ^ byte[i]) & 0xff] ^ (value >> 8);
- return value ^ ~0U;
+uint32_t Crc32(const void *buffer, uint32_t len)
+{
+ uint8_t *byte = (uint8_t *)buffer;
+ uint32_t i;
+ uint32_t value = ~0U;
+
+ for (i = 0; i < len; ++i)
+ value = crc32_tab[(value ^ byte[i]) & 0xff] ^ (value >> 8);
+ return value ^ ~0U;
}
diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h
index 6633733e..ccaa2beb 100644
--- a/firmware/lib/cgptlib/include/cgptlib.h
+++ b/firmware/lib/cgptlib/include/cgptlib.h
@@ -9,20 +9,20 @@
#include "sysincludes.h"
enum {
- GPT_SUCCESS = 0,
- GPT_ERROR_NO_VALID_KERNEL,
- GPT_ERROR_INVALID_HEADERS,
- GPT_ERROR_INVALID_ENTRIES,
- GPT_ERROR_INVALID_SECTOR_SIZE,
- GPT_ERROR_INVALID_SECTOR_NUMBER,
- GPT_ERROR_INVALID_UPDATE_TYPE,
- GPT_ERROR_CRC_CORRUPTED,
- GPT_ERROR_OUT_OF_REGION,
- GPT_ERROR_START_LBA_OVERLAP,
- GPT_ERROR_END_LBA_OVERLAP,
- GPT_ERROR_DUP_GUID,
- /* Number of errors */
- GPT_ERROR_COUNT
+ GPT_SUCCESS = 0,
+ GPT_ERROR_NO_VALID_KERNEL,
+ GPT_ERROR_INVALID_HEADERS,
+ GPT_ERROR_INVALID_ENTRIES,
+ GPT_ERROR_INVALID_SECTOR_SIZE,
+ GPT_ERROR_INVALID_SECTOR_NUMBER,
+ GPT_ERROR_INVALID_UPDATE_TYPE,
+ GPT_ERROR_CRC_CORRUPTED,
+ GPT_ERROR_OUT_OF_REGION,
+ GPT_ERROR_START_LBA_OVERLAP,
+ GPT_ERROR_END_LBA_OVERLAP,
+ GPT_ERROR_DUP_GUID,
+ /* Number of errors */
+ GPT_ERROR_COUNT
};
/* Bit masks for GptData.modified field. */
@@ -31,56 +31,64 @@ enum {
#define GPT_MODIFIED_ENTRIES1 0x04
#define GPT_MODIFIED_ENTRIES2 0x08
-#define TOTAL_ENTRIES_SIZE 16384 /* Size of GptData.primary_entries
- * and secondary_entries: 128
- * bytes/entry * 128 entries. */
+/*
+ * Size of GptData.primary_entries and secondary_entries: 128 bytes/entry * 128
+ * entries.
+ */
+#define TOTAL_ENTRIES_SIZE 16384
-/* The 'update_type' of GptUpdateKernelEntry()
- * We expose TRY and BAD only because those are what verified boot needs.
- * For more precise control on GPT attribute bits, please refer to
- * gpt_internal.h */
+/*
+ * The 'update_type' of GptUpdateKernelEntry(). We expose TRY and BAD only
+ * because those are what verified boot needs. For more precise control on GPT
+ * attribute bits, please refer to gpt_internal.h.
+ */
enum {
- GPT_UPDATE_ENTRY_TRY = 1,
- /* System will be trying to boot the currently selected kernel partition.
- * Update its try count if necessary. */
- GPT_UPDATE_ENTRY_BAD = 2,
- /* The currently selected kernel partition failed validation. Mark entry as
- * invalid. */
+ /*
+ * System will be trying to boot the currently selected kernel
+ * partition. Update its try count if necessary.
+ */
+ GPT_UPDATE_ENTRY_TRY = 1,
+ /*
+ * The currently selected kernel partition failed validation. Mark
+ * entry as invalid.
+ */
+ GPT_UPDATE_ENTRY_BAD = 2,
};
typedef struct {
- /* Fill in the following fields before calling GptInit() */
- uint8_t *primary_header; /* GPT primary header, from sector 1 of disk
- * (size: 512 bytes) */
- uint8_t *secondary_header; /* GPT secondary header, from last sector of
- * disk (size: 512 bytes) */
- uint8_t *primary_entries; /* primary GPT table, follows primary header
- * (size: 16 KB) */
- uint8_t *secondary_entries; /* secondary GPT table, precedes secondary
- * header (size: 16 KB) */
- uint32_t sector_bytes; /* Size of a LBA sector, in bytes */
- uint64_t drive_sectors; /* Size of drive in LBA sectors, in sectors */
+ /* Fill in the following fields before calling GptInit() */
+ /* GPT primary header, from sector 1 of disk (size: 512 bytes) */
+ uint8_t *primary_header;
+ /* GPT secondary header, from last sector of disk (size: 512 bytes) */
+ uint8_t *secondary_header;
+ /* Primary GPT table, follows primary header (size: 16 KB) */
+ uint8_t *primary_entries;
+ /* Secondary GPT table, precedes secondary header (size: 16 KB) */
+ uint8_t *secondary_entries;
+ /* Size of a LBA sector, in bytes */
+ uint32_t sector_bytes;
+ /* Size of drive in LBA sectors, in sectors */
+ uint64_t drive_sectors;
- /* Outputs */
- uint8_t modified; /* Which inputs have been modified?
- * 0x01 = header1
- * 0x02 = header2
- * 0x04 = table1
- * 0x08 = table2 */
- int current_kernel; /* the current chromeos kernel index in partition table.
- * -1 means not found on drive. Note that GPT partition
- * numbers are traditionally 1-based, but we're using
- * a zero-based index here.
- */
+ /* Outputs */
+ /* Which inputs have been modified? GPT_MODIFIED_* */
+ uint8_t modified;
+ /*
+ * The current chromeos kernel index in partition table. -1 means not
+ * found on drive. Note that GPT partition numbers are traditionally
+ * 1-based, but we're using a zero-based index here.
+ */
+ int current_kernel;
- /* Internal variables */
- uint32_t valid_headers, valid_entries;
- int current_priority;
+ /* Internal variables */
+ uint32_t valid_headers, valid_entries;
+ int current_priority;
} GptData;
-int GptInit(GptData* gpt);
-/* Initializes the GPT data structure's internal state. The following fields
- * must be filled before calling this function:
+/**
+ * Initializes the GPT data structure's internal state.
+ *
+ * The following fields must be filled before calling this function:
*
* primary_header
* secondary_header
@@ -100,19 +108,23 @@ int GptInit(GptData* gpt);
* GPT_ERROR_INVALID_SECTOR_SIZE, size of a sector is not supported,
* GPT_ERROR_INVALID_SECTOR_NUMBER, number of sectors in drive is invalid (too
* small) */
+int GptInit(GptData *gpt);
-int GptNextKernelEntry(GptData* gpt, uint64_t* start_sector, uint64_t* size);
-/* Provides the location of the next kernel partition, in order of decreasing
- * priority. On return the start_sector parameter contains the LBA sector
- * for the start of the kernel partition, and the size parameter contains the
- * size of the kernel partition in LBA sectors. gpt.current_kernel contains
- * the partition index of the current chromeos kernel partition.
+/**
+ * Provides the location of the next kernel partition, in order of decreasing
+ * priority.
+ *
+ * On return the start_sector parameter contains the LBA sector for the start
+ * of the kernel partition, and the size parameter contains the size of the
+ * kernel partition in LBA sectors. gpt.current_kernel contains the partition
+ * index of the current chromeos kernel partition.
*
* Returns GPT_SUCCESS if successful, else
* GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */
+int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size);
-int GptUpdateKernelEntry(GptData* gpt, uint32_t update_type);
-/* Updates the kernel entry with the specified index, using the specified type
+/**
+ * Updates the kernel entry with the specified index, using the specified type
* of update (GPT_UPDATE_ENTRY_*).
*
* On return the modified field may be set, if the GPT data has been modified
@@ -121,5 +133,6 @@ int GptUpdateKernelEntry(GptData* gpt, uint32_t update_type);
* Returns GPT_SUCCESS if successful, else
* GPT_ERROR_INVALID_UPDATE_TYPE, invalid 'update_type' is given.
*/
+int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type);
#endif /* VBOOT_REFERENCE_CGPTLIB_H_ */
diff --git a/firmware/lib/cgptlib/include/cgptlib_internal.h b/firmware/lib/cgptlib/include/cgptlib_internal.h
index 36e598c2..c7606287 100644
--- a/firmware/lib/cgptlib/include/cgptlib_internal.h
+++ b/firmware/lib/cgptlib/include/cgptlib_internal.h
@@ -10,13 +10,15 @@
#include "cgptlib.h"
#include "gpt.h"
-/* If gpt->current_kernel is this value, means either:
+/*
+ * If gpt->current_kernel is this value, means either:
* 1. an initial value before scanning GPT entries,
* 2. after scanning, no any valid kernel is found.
*/
#define CGPT_KERNEL_ENTRY_NOT_FOUND (-1)
-/* Bit definitions and masks for GPT attributes.
+/*
+ * Bit definitions and masks for GPT attributes.
*
* 63-61 -- (reserved)
* 60 -- read-only
@@ -55,80 +57,107 @@
/* Defines GPT sizes */
#define GPT_PMBR_SECTOR 1 /* size (in sectors) of PMBR */
#define GPT_HEADER_SECTOR 1
-#define GPT_ENTRIES_SECTORS 32 /* assume sector size if 512 bytes, then
- * (TOTAL_ENTRIES_SIZE / 512) = 32 */
+/*
+ * Entries sectors assumes sector size if 512 bytes; then (TOTAL_ENTRIES_SIZE /
+ * 512) = 32
+ */
+#define GPT_ENTRIES_SECTORS 32
-/* alias name of index in internal array for primary and secondary header and
- * entries. */
+/*
+ * Alias name of index in internal array for primary and secondary header and
+ * entries.
+ */
enum {
- /* constants for index */
- PRIMARY = 0,
- SECONDARY = 1,
- ANY_VALID = 9999, /* accept any between primary and secondary */
-
- /* constants for bit mask */
- MASK_NONE = 0,
- MASK_PRIMARY = 1,
- MASK_SECONDARY = 2,
- MASK_BOTH = 3,
+ /* constants for index */
+ PRIMARY = 0,
+ SECONDARY = 1,
+ ANY_VALID = 9999, /* accept any between primary and secondary */
+
+ /* constants for bit mask */
+ MASK_NONE = 0,
+ MASK_PRIMARY = 1,
+ MASK_SECONDARY = 2,
+ MASK_BOTH = 3,
};
-/* Verify GptData parameters are sane. */
+/**
+ * Verify GptData parameters are sane.
+ */
int CheckParameters(GptData* gpt);
-/* Check header fields.
+/**
+ * Check header fields.
*
- * Returns 0 if header is valid, 1 if invalid. */
-int CheckHeader(GptHeader* h, int is_secondary, uint64_t drive_sectors);
+ * Returns 0 if header is valid, 1 if invalid.
+ */
+int CheckHeader(GptHeader *h, int is_secondary, uint64_t drive_sectors);
-/* Calculate and return the header CRC. */
-uint32_t HeaderCrc(GptHeader* h);
+/**
+ * Calculate and return the header CRC.
+ */
+uint32_t HeaderCrc(GptHeader *h);
-/* Check entries.
+/**
+ * Check entries.
*
- * Returns 0 if entries are valid, 1 if invalid. */
-int CheckEntries(GptEntry* entries, GptHeader* h);
+ * Returns 0 if entries are valid, 1 if invalid.
+ */
+int CheckEntries(GptEntry *entries, GptHeader *h);
-/* Return 0 if the GptHeaders are the same for all fields which don't
- * differ between the primary and secondary headers - that is, all
- * fields other than:
+/**
+ * Return 0 if the GptHeaders are the same for all fields which don't differ
+ * between the primary and secondary headers - that is, all fields other than:
*
* my_lba
* alternate_lba
- * entries_lba */
+ * entries_lba
+ */
int HeaderFieldsSame(GptHeader *h1, GptHeader *h2);
-/* Check GptData, headers, entries.
+/**
+ * Check GptData, headers, entries.
*
* If successful, sets gpt->valid_headers and gpt->valid_entries and returns
* GPT_SUCCESS.
*
- * On error, returns a GPT_ERROR_* return code. */
-int GptSanityCheck(GptData* gpt);
+ * On error, returns a GPT_ERROR_* return code.
+ */
+int GptSanityCheck(GptData *gpt);
-/* Repairs GPT data by copying from one set of valid headers/entries to the
+/**
+ * Repair GPT data by copying from one set of valid headers/entries to the
* other. Assumes GptSanityCheck() has been run to determine which headers
- * and/or entries are already valid. */
-void GptRepair(GptData* gpt);
+ * and/or entries are already valid.
+ */
+void GptRepair(GptData *gpt);
/* Getters and setters for partition attribute fields. */
-int GetEntrySuccessful(const GptEntry* e);
-int GetEntryPriority(const GptEntry* e);
-int GetEntryTries(const GptEntry* e);
-void SetEntrySuccessful(GptEntry* e, int successful);
-void SetEntryPriority(GptEntry* e, int priority);
-void SetEntryTries(GptEntry* e, int tries);
-/* Return 1 if the entry is unused, 0 if it is used. */
-int IsUnusedEntry(const GptEntry* e);
+int GetEntrySuccessful(const GptEntry *e);
+int GetEntryPriority(const GptEntry *e);
+int GetEntryTries(const GptEntry *e);
+void SetEntrySuccessful(GptEntry *e, int successful);
+void SetEntryPriority(GptEntry *e, int priority);
+void SetEntryTries(GptEntry *e, int tries);
-/* Returns 1 if the entry is a Chrome OS kernel partition, else 0. */
-int IsKernelEntry(const GptEntry* e);
+/**
+ * Return 1 if the entry is unused, 0 if it is used.
+ */
+int IsUnusedEntry(const GptEntry *e);
-/* Copies the current kernel partition's UniquePartitionGuid to the dest */
+/**
+ * Return 1 if the entry is a Chrome OS kernel partition, else 0.
+ */
+int IsKernelEntry(const GptEntry *e);
+
+/**
+ * Copy the current kernel partition's UniquePartitionGuid to the dest.
+ */
void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest);
-/* Returns a pointer to text describing the passed in error */
-const char* GptErrorText(int error_code);
+/**
+ * Return a pointer to text describing the passed in error.
+ */
+const char *GptErrorText(int error_code);
#endif /* VBOOT_REFERENCE_CGPTLIB_INTERNAL_H_ */
diff --git a/firmware/lib/cgptlib/include/gpt.h b/firmware/lib/cgptlib/include/gpt.h
index 95b77145..5e60e957 100644
--- a/firmware/lib/cgptlib/include/gpt.h
+++ b/firmware/lib/cgptlib/include/gpt.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -19,97 +19,97 @@ __pragma(pack(push,1)) /* Support packing for MSVC. */
#define GPT_HEADER_SIGNATURE_SIZE sizeof(GPT_HEADER_SIGNATURE)
#define GPT_HEADER_REVISION 0x00010000
-/* The first 3 numbers should be stored in network-endian format
- * according to the GUID RFC. The UEFI spec appendix A claims they
- * should be stored in little-endian format. But they need to be
- * _displayed_ in network-endian format, which is also how they're
- * documented in the specs.
+/*
+ * The first 3 numbers should be stored in network-endian format according to
+ * the GUID RFC. The UEFI spec appendix A claims they should be stored in
+ * little-endian format. But they need to be _displayed_ in network-endian
+ * format, which is also how they're documented in the specs.
*
- * Since what we have here are little-endian constants, they're
- * byte-swapped from the normal display order. */
+ * Since what we have here are little-endian constants, they're byte-swapped
+ * from the normal display order.
+ */
#define GPT_ENT_TYPE_UNUSED \
- {{{0x00000000,0x0000,0x0000,0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}}}
+ {{{0x00000000,0x0000,0x0000,0x00,0x00,{0x00,0x00,0x00,0x00,0x00,0x00}}}}
#define GPT_ENT_TYPE_EFI \
- {{{0xc12a7328,0xf81f,0x11d2,0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}}}
+ {{{0xc12a7328,0xf81f,0x11d2,0xba,0x4b,{0x00,0xa0,0xc9,0x3e,0xc9,0x3b}}}}
#define GPT_ENT_TYPE_CHROMEOS_FIRMWARE \
- {{{0xcab6e88e,0xabf3,0x4102,0xa0,0x7a,{0xd4,0xbb,0x9b,0xe3,0xc1,0xd3}}}}
+ {{{0xcab6e88e,0xabf3,0x4102,0xa0,0x7a,{0xd4,0xbb,0x9b,0xe3,0xc1,0xd3}}}}
#define GPT_ENT_TYPE_CHROMEOS_KERNEL \
- {{{0xfe3a2a5d,0x4f32,0x41a7,0xb7,0x25,{0xac,0xcc,0x32,0x85,0xa3,0x09}}}}
+ {{{0xfe3a2a5d,0x4f32,0x41a7,0xb7,0x25,{0xac,0xcc,0x32,0x85,0xa3,0x09}}}}
#define GPT_ENT_TYPE_CHROMEOS_ROOTFS \
- {{{0x3cb8e202,0x3b7e,0x47dd,0x8a,0x3c,{0x7f,0xf2,0xa1,0x3c,0xfc,0xec}}}}
+ {{{0x3cb8e202,0x3b7e,0x47dd,0x8a,0x3c,{0x7f,0xf2,0xa1,0x3c,0xfc,0xec}}}}
#define GPT_ENT_TYPE_CHROMEOS_RESERVED \
- {{{0x2e0a753d,0x9e48,0x43b0,0x83,0x37,{0xb1,0x51,0x92,0xcb,0x1b,0x5e}}}}
+ {{{0x2e0a753d,0x9e48,0x43b0,0x83,0x37,{0xb1,0x51,0x92,0xcb,0x1b,0x5e}}}}
#define GPT_ENT_TYPE_LINUX_DATA \
- {{{0xebd0a0a2,0xb9e5,0x4433,0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}}}}
-
+ {{{0xebd0a0a2,0xb9e5,0x4433,0x87,0xc0,{0x68,0xb6,0xb7,0x26,0x99,0xc7}}}}
#define UUID_NODE_LEN 6
#define GUID_SIZE 16
-/* GUID definition.
- * Defined in appendix A of EFI standard.
- */
+/* GUID definition. Defined in appendix A of EFI standard. */
typedef struct {
- union {
- struct {
- uint32_t time_low;
- uint16_t time_mid;
- uint16_t time_high_and_version;
- uint8_t clock_seq_high_and_reserved;
- uint8_t clock_seq_low;
- uint8_t node[UUID_NODE_LEN];
- } Uuid;
- uint8_t raw[GUID_SIZE];
- } u;
+ union {
+ struct {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_high_and_version;
+ uint8_t clock_seq_high_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[UUID_NODE_LEN];
+ } Uuid;
+ uint8_t raw[GUID_SIZE];
+ } u;
} __attribute__((packed)) Guid;
#define GUID_EXPECTED_SIZE GUID_SIZE
-/* GPT header defines how many partitions exist on a drive and sectors managed.
- * For every drive device, there are 2 headers, primary and secondary.
- * Most of fields are duplicated except my_lba and entries_lba.
+/*
+ * GPT header defines how many partitions exist on a drive and sectors managed.
+ * For every drive device, there are 2 headers, primary and secondary. Most of
+ * fields are duplicated except my_lba and entries_lba.
*
* You may find more details in chapter 5 of EFI standard.
*/
typedef struct {
- char signature[8];
- uint32_t revision;
- uint32_t size;
- uint32_t header_crc32;
- uint32_t reserved_zero;
- uint64_t my_lba;
- uint64_t alternate_lba;
- uint64_t first_usable_lba;
- uint64_t last_usable_lba;
- Guid disk_uuid;
- uint64_t entries_lba;
- uint32_t number_of_entries;
- uint32_t size_of_entry;
- uint32_t entries_crc32;
- /* Remainder of sector is reserved and should be 0 */
+ char signature[8];
+ uint32_t revision;
+ uint32_t size;
+ uint32_t header_crc32;
+ uint32_t reserved_zero;
+ uint64_t my_lba;
+ uint64_t alternate_lba;
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ Guid disk_uuid;
+ uint64_t entries_lba;
+ uint32_t number_of_entries;
+ uint32_t size_of_entry;
+ uint32_t entries_crc32;
+ /* Remainder of sector is reserved and should be 0 */
} __attribute__((packed)) GptHeader;
#define GPTHEADER_EXPECTED_SIZE 92
-/* GPT partition entry defines the starting and ending LBAs of a partition.
- * It also contains the unique GUID, type, and attribute bits.
+/*
+ * GPT partition entry defines the starting and ending LBAs of a partition. It
+ * also contains the unique GUID, type, and attribute bits.
*
* You may find more details in chapter 5 of EFI standard.
*/
typedef struct {
- Guid type;
- Guid unique;
- uint64_t starting_lba;
- uint64_t ending_lba;
- union {
- struct {
- uint16_t reserved[3];
- uint16_t gpt_att;
- } __attribute__((packed)) fields;
- uint64_t whole;
- } attrs;
- uint16_t name[36]; /* UTF-16 encoded partition name */
- /* Remainder of entry is reserved and should be 0 */
+ Guid type;
+ Guid unique;
+ uint64_t starting_lba;
+ uint64_t ending_lba;
+ union {
+ struct {
+ uint16_t reserved[3];
+ uint16_t gpt_att;
+ } __attribute__((packed)) fields;
+ uint64_t whole;
+ } attrs;
+ uint16_t name[36]; /* UTF-16 encoded partition name */
+ /* Remainder of entry is reserved and should be 0 */
} __attribute__((packed)) GptEntry;
#define GPTENTRY_EXPECTED_SIZE 128
diff --git a/firmware/lib/crc8.c b/firmware/lib/crc8.c
index fa770253..b0ee8679 100644
--- a/firmware/lib/crc8.c
+++ b/firmware/lib/crc8.c
@@ -1,28 +1,28 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "crc8.h"
-/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A
- * table-based algorithm would be faster, but for only a few bytes it isn't
- * worth the code size. */
-uint8_t Crc8(const void* vptr, int len) {
- const uint8_t *data = vptr;
- unsigned crc = 0;
- int i, j;
+/**
+ * Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A table-based
+ * algorithm would be faster, but for only a few bytes it isn't worth the code
+ * size. */
+uint8_t Crc8(const void *vptr, int len)
+{
+ const uint8_t *data = vptr;
+ unsigned crc = 0;
+ int i, j;
- for (j = len; j; j--, data++) {
- crc ^= (*data << 8);
- for(i = 8; i; i--) {
- if (crc & 0x8000)
- crc ^= (0x1070 << 3);
- crc <<= 1;
- }
- }
+ for (j = len; j; j--, data++) {
+ crc ^= (*data << 8);
+ for(i = 8; i; i--) {
+ if (crc & 0x8000)
+ crc ^= (0x1070 << 3);
+ crc <<= 1;
+ }
+ }
- return (uint8_t)(crc >> 8);
+ return (uint8_t)(crc >> 8);
}
-
-
diff --git a/firmware/lib/include/vboot_display.h b/firmware/lib/include/vboot_display.h
index f8aa810b..52730b9e 100644
--- a/firmware/lib/include/vboot_display.h
+++ b/firmware/lib/include/vboot_display.h
@@ -8,6 +8,7 @@
#ifndef VBOOT_REFERENCE_VBOOT_DISPLAY_H_
#define VBOOT_REFERENCE_VBOOT_DISPLAY_H_
+#include "bmpblk_font.h"
#include "vboot_api.h"
#include "vboot_nvstorage.h"
@@ -20,7 +21,36 @@ VbError_t VbCheckDisplayKey(VbCommonParams *cparams, uint32_t key,
VbNvContext *vncptr);
/* Internal functions, for unit testing */
+
+typedef FontArrayHeader VbFont_t;
+
+VbFont_t *VbInternalizeFontData(FontArrayHeader *fonthdr);
+
+void VbDoneWithFontForNow(VbFont_t *ptr);
+
+ImageInfo *VbFindFontGlyph(VbFont_t *font, uint32_t ascii,
+ void **bufferptr, uint32_t *buffersize);
+
+/**
+ * Try to display the specified text at a particular position.
+ */
+void VbRenderTextAtPos(char *text, int right_to_left,
+ uint32_t x, uint32_t y, VbFont_t *font);
+
+/**
+ * Return a description of the recovery reason code.
+ */
const char *RecoveryReasonString(uint8_t code);
+/**
+ * Return a fixed string representing the HWID.
+ */
+char *VbHWID(VbCommonParams *cparams);
+
+/**
+ * Get the number of localizations in the GBB bitmap data.
+ */
+VbError_t VbGetLocalizationCount(VbCommonParams *cparams, uint32_t *count);
+
#endif /* VBOOT_REFERENCE_VBOOT_DISPLAY_H_ */
diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h
index 6e6c5dc3..e3a44190 100644
--- a/firmware/lib/include/vboot_kernel.h
+++ b/firmware/lib/include/vboot_kernel.h
@@ -10,7 +10,9 @@
#define VBOOT_REFERENCE_VBOOT_KERNEL_H_
#include "cgptlib.h"
+#include "load_firmware_fw.h"
#include "vboot_api.h"
+#include "vboot_kernel.h"
/**
* Allocate and read GPT data from the drive. The sector_bytes and
@@ -26,4 +28,47 @@ int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata);
*/
int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata);
+/**
+ * Accessors for unit tests only.
+ */
+VbNvContext *VbApiKernelGetVnc(void);
+
+/**
+ * Try to load a kernel.
+ */
+uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
+ uint32_t get_info_flags);
+
+/**
+ * Ask the user to confirm something.
+ *
+ * We should display whatever the question is first, then call this. ESC is
+ * always "no", ENTER is always "yes", and we'll specify what SPACE means. We
+ * don't return until one of those keys is pressed, or until asked to shut
+ * down.
+ *
+ * Returns: 1=yes, 0=no, -1 = shutdown.
+ */
+int VbUserConfirms(VbCommonParams *cparams, int space_means_no);
+
+/**
+ * Handle a normal boot.
+ */
+VbError_t VbBootNormal(VbCommonParams *cparams, LoadKernelParams *p);
+
+/**
+ * Handle a developer-mode boot.
+ */
+VbError_t VbBootDeveloper(VbCommonParams *cparams, LoadKernelParams *p);
+
+/**
+ * Handle a recovery-mode boot.
+ */
+VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p);
+
+/**
+ * Sync EC firmware to expected version.
+ */
+VbError_t VbEcSoftwareSync(VbCommonParams *cparams);
+
#endif /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */
diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c
index 82323235..a7b65510 100644
--- a/firmware/lib/rollback_index.c
+++ b/firmware/lib/rollback_index.c
@@ -18,9 +18,11 @@
#endif
#ifdef FOR_TEST
-/* Compiling for unit test, so we need the real implementations of
+/*
+ * Compiling for unit test, so we need the real implementations of
* rollback functions. The unit test mocks the underlying tlcl
- * functions, so this is ok to run on the host. */
+ * functions, so this is ok to run on the host.
+ */
#undef CHROMEOS_ENVIRONMENT
#undef DISABLE_ROLLBACK_TPM
#endif
@@ -30,13 +32,14 @@ static int g_rollback_recovery_mode = 0;
/* disable MSVC warning on const logical expression (as in } while(0);) */
__pragma(warning (disable: 4127))
-#define RETURN_ON_FAILURE(tpm_command) do { \
- uint32_t result; \
- if ((result = (tpm_command)) != TPM_SUCCESS) { \
- VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \
- return result; \
- } \
- } while (0)
+#define RETURN_ON_FAILURE(tpm_command) do { \
+ uint32_t result; \
+ if ((result = (tpm_command)) != TPM_SUCCESS) { \
+ VBDEBUG(("Rollback: %08x returned by " #tpm_command \
+ "\n", (int)result)); \
+ return result; \
+ } \
+ } while (0)
uint32_t TPMClearAndReenable(void)
diff --git a/firmware/lib/stateful_util.c b/firmware/lib/stateful_util.c
index 01a7d641..6db03fc5 100644
--- a/firmware/lib/stateful_util.c
+++ b/firmware/lib/stateful_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -6,65 +6,67 @@
*/
#include "stateful_util.h"
-
#include "utility.h"
-void StatefulInit(MemcpyState* state, void* buf, uint64_t len) {
- state->remaining_buf = buf;
- state->remaining_len = len;
- state->overrun = 0;
+void StatefulInit(MemcpyState *state, void *buf, uint64_t len)
+{
+ state->remaining_buf = buf;
+ state->remaining_len = len;
+ state->overrun = 0;
}
-void* StatefulSkip(MemcpyState* state, uint64_t len) {
- if (state->overrun)
- return NULL;
- if (len > state->remaining_len) {
- state->overrun = 1;
- return NULL;
- }
- state->remaining_buf += len;
- state->remaining_len -= len;
- return state; // have to return something non-NULL
+void *StatefulSkip(MemcpyState *state, uint64_t len)
+{
+ if (state->overrun)
+ return NULL;
+ if (len > state->remaining_len) {
+ state->overrun = 1;
+ return NULL;
+ }
+ state->remaining_buf += len;
+ state->remaining_len -= len;
+ return state; /* Must return something non-NULL. */
}
-void* StatefulMemcpy(MemcpyState* state, void* dst,
- uint64_t len) {
- if (state->overrun)
- return NULL;
- if (len > state->remaining_len) {
- state->overrun = 1;
- return NULL;
- }
- Memcpy(dst, state->remaining_buf, len);
- state->remaining_buf += len;
- state->remaining_len -= len;
- return dst;
+void *StatefulMemcpy(MemcpyState *state, void *dst, uint64_t len)
+{
+ if (state->overrun)
+ return NULL;
+ if (len > state->remaining_len) {
+ state->overrun = 1;
+ return NULL;
+ }
+ Memcpy(dst, state->remaining_buf, len);
+ state->remaining_buf += len;
+ state->remaining_len -= len;
+ return dst;
}
-const void* StatefulMemcpy_r(MemcpyState* state, const void* src,
- uint64_t len) {
- if (state->overrun)
- return NULL;
- if (len > state->remaining_len) {
- state->overrun = 1;
- return NULL;
- }
- Memcpy(state->remaining_buf, src, len);
- state->remaining_buf += len;
- state->remaining_len -= len;
- return src;
+const void *StatefulMemcpy_r(MemcpyState *state, const void *src, uint64_t len)
+{
+ if (state->overrun)
+ return NULL;
+ if (len > state->remaining_len) {
+ state->overrun = 1;
+ return NULL;
+ }
+ Memcpy(state->remaining_buf, src, len);
+ state->remaining_buf += len;
+ state->remaining_len -= len;
+ return src;
}
-const void* StatefulMemset_r(MemcpyState* state, const uint8_t val,
- uint64_t len) {
- if (state->overrun)
- return NULL;
- if (len > state->remaining_len) {
- state->overrun = 1;
- return NULL;
- }
- Memset(state->remaining_buf, val, len);
- state->remaining_buf += len;
- state->remaining_len -= len;
- return state; // have to return something non-NULL
+const void *StatefulMemset_r(MemcpyState *state, const uint8_t val,
+ uint64_t len)
+{
+ if (state->overrun)
+ return NULL;
+ if (len > state->remaining_len) {
+ state->overrun = 1;
+ return NULL;
+ }
+ Memset(state->remaining_buf, val, len);
+ state->remaining_buf += len;
+ state->remaining_len -= len;
+ return state; /* Must return something non-NULL. */
}
diff --git a/firmware/lib/tpm_bootmode.c b/firmware/lib/tpm_bootmode.c
index 0e0e084b..ec8fac7e 100644
--- a/firmware/lib/tpm_bootmode.c
+++ b/firmware/lib/tpm_bootmode.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -14,7 +14,8 @@
/* TPM PCR to use for storing boot mode measurements. */
#define BOOT_MODE_PCR 0
-/* Input digests for PCR extend.
+/*
+ * Input digests for PCR extend.
* These are calculated as:
* SHA1("|Developer_Mode||Recovery_Mode||Keyblock_Mode|").
* Developer_Mode can be 0 or 1.
@@ -31,105 +32,125 @@
*/
const char* kBootStateSHA1Digests[] = {
- /* SHA1("\x00\x00\x00") */
- "\x29\xe2\xdc\xfb\xb1\x6f\x63\xbb\x02\x54\xdf\x75\x85\xa1\x5b\xb6"
- "\xfb\x5e\x92\x7d",
+ /* SHA1("\x00\x00\x00") */
+ "\x29\xe2\xdc\xfb\xb1\x6f\x63\xbb\x02\x54\xdf\x75\x85\xa1\x5b\xb6"
+ "\xfb\x5e\x92\x7d",
- /* SHA1("\x00\x00\x01") */
- "\x25\x47\xcc\x73\x6e\x95\x1f\xa4\x91\x98\x53\xc4\x3a\xe8\x90\x86"
- "\x1a\x3b\x32\x64",
+ /* SHA1("\x00\x00\x01") */
+ "\x25\x47\xcc\x73\x6e\x95\x1f\xa4\x91\x98\x53\xc4\x3a\xe8\x90\x86"
+ "\x1a\x3b\x32\x64",
- /* SHA1("\x00\x00\x02") */
- "\x1e\xf6\x24\x48\x2d\x62\x0e\x43\xe6\xd3\x4d\xa1\xaf\xe4\x62\x67"
- "\xfc\x69\x5d\x9b",
+ /* SHA1("\x00\x00\x02") */
+ "\x1e\xf6\x24\x48\x2d\x62\x0e\x43\xe6\xd3\x4d\xa1\xaf\xe4\x62\x67"
+ "\xfc\x69\x5d\x9b",
- /* SHA1("\x00\x01\x00") */
- "\x62\x57\x18\x91\x21\x5b\x4e\xfc\x1c\xea\xb7\x44\xce\x59\xdd\x0b"
- "\x66\xea\x6f\x73",
+ /* SHA1("\x00\x01\x00") */
+ "\x62\x57\x18\x91\x21\x5b\x4e\xfc\x1c\xea\xb7\x44\xce\x59\xdd\x0b"
+ "\x66\xea\x6f\x73",
- /* SHA1("\x00\x01\x01") */
- "\xee\xe4\x47\xed\xc7\x9f\xea\x1c\xa7\xc7\xd3\x4e\x46\x32\x61\xcd"
- "\xa4\xba\x33\x9e",
+ /* SHA1("\x00\x01\x01") */
+ "\xee\xe4\x47\xed\xc7\x9f\xea\x1c\xa7\xc7\xd3\x4e\x46\x32\x61\xcd"
+ "\xa4\xba\x33\x9e",
- /* SHA1("\x00\x01\x02") */
- "\x0c\x7a\x62\x3f\xd2\xbb\xc0\x5b\x06\x42\x3b\xe3\x59\xe4\x02\x1d"
- "\x36\xe7\x21\xad",
+ /* SHA1("\x00\x01\x02") */
+ "\x0c\x7a\x62\x3f\xd2\xbb\xc0\x5b\x06\x42\x3b\xe3\x59\xe4\x02\x1d"
+ "\x36\xe7\x21\xad",
- /* SHA1("\x01\x00\x00") */
- "\x95\x08\xe9\x05\x48\xb0\x44\x0a\x4a\x61\xe5\x74\x3b\x76\xc1\xe3"
- "\x09\xb2\x3b\x7f",
+ /* SHA1("\x01\x00\x00") */
+ "\x95\x08\xe9\x05\x48\xb0\x44\x0a\x4a\x61\xe5\x74\x3b\x76\xc1\xe3"
+ "\x09\xb2\x3b\x7f",
- /* SHA1("\x01\x00\x01") */
- "\xc4\x2a\xc1\xc4\x6f\x1d\x4e\x21\x1c\x73\x5c\xc7\xdf\xad\x4f\xf8"
- "\x39\x11\x10\xe9",
+ /* SHA1("\x01\x00\x01") */
+ "\xc4\x2a\xc1\xc4\x6f\x1d\x4e\x21\x1c\x73\x5c\xc7\xdf\xad\x4f\xf8"
+ "\x39\x11\x10\xe9",
- /* SHA1("\x01\x00\x02") */
- "\xfa\x01\x0d\x26\x64\xcc\x5b\x3b\x82\xee\x48\x8f\xe2\xb9\xf5\x0f"
- "\x49\x32\xeb\x8f",
+ /* SHA1("\x01\x00\x02") */
+ "\xfa\x01\x0d\x26\x64\xcc\x5b\x3b\x82\xee\x48\x8f\xe2\xb9\xf5\x0f"
+ "\x49\x32\xeb\x8f",
- /* SHA1("\x01\x01\x00") */
- "\x47\xec\x8d\x98\x36\x64\x33\xdc\x00\x2e\x77\x21\xc9\xe3\x7d\x50"
- "\x67\x54\x79\x37",
+ /* SHA1("\x01\x01\x00") */
+ "\x47\xec\x8d\x98\x36\x64\x33\xdc\x00\x2e\x77\x21\xc9\xe3\x7d\x50"
+ "\x67\x54\x79\x37",
- /* SHA1("\x01\x01\x01") */
- "\x28\xd8\x6c\x56\xb3\xbf\x26\xd2\x36\x56\x9b\x8d\xc8\xc3\xf9\x1f"
- "\x32\xf4\x7b\xc7",
+ /* SHA1("\x01\x01\x01") */
+ "\x28\xd8\x6c\x56\xb3\xbf\x26\xd2\x36\x56\x9b\x8d\xc8\xc3\xf9\x1f"
+ "\x32\xf4\x7b\xc7",
- /* SHA1("\x01\x01\x02") */
- "\x12\xa3\x40\xd7\x89\x7f\xe7\x13\xfc\x8f\x02\xac\x53\x65\xb8\x6e"
- "\xbf\x35\x31\x78",
+ /* SHA1("\x01\x01\x02") */
+ "\x12\xa3\x40\xd7\x89\x7f\xe7\x13\xfc\x8f\x02\xac\x53\x65\xb8\x6e"
+ "\xbf\x35\x31\x78",
};
-#define MAX_BOOT_STATE_INDEX (sizeof(kBootStateSHA1Digests)/sizeof(char*))
+#define MAX_BOOT_STATE_INDEX (sizeof(kBootStateSHA1Digests)/sizeof(char *))
-/* Used for PCR extend when the passed-in boot state is invalid or
- * if there is an internal error. */
+/*
+ * Used for PCR extend when the passed-in boot state is invalid or if there is
+ * an internal error.
+ */
const uint8_t kBootInvalidSHA1Digest[] = {
- "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
- "\xff\xff\xff\xff"
+ "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
+ "\xff\xff\xff\xff"
};
-/* Given the boot state, return the correct SHA1 digest index for TPMExtend
- * in kBootStateSHA1Digests[]. */
-int GetBootStateIndex(int dev_mode, int rec_mode, uint64_t keyblock_flags) {
- int index = 0;
-
- /* Convert keyblock flags into keyblock mode which we use to index into
- * kBootStateSHA1Digest[]. */
- switch(keyblock_flags) {
- case 6: /* KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1 */
- /* Developer firmware. */
- index = 2;
- break;
- case 7: /* KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_0
- * | KEY_BLOCK_FLAGS_DEVELOPER_1 */
- index = 1;
- break;
- default:
- index = 0; /* Any other keyblock flags. */
- };
-
- if (rec_mode)
- index += 3;
- if (dev_mode)
- index += 6;
- return index;
+/**
+ * Given the boot state, return the correct SHA1 digest index for TPMExtend
+ * in kBootStateSHA1Digests[].
+ */
+int GetBootStateIndex(int dev_mode, int rec_mode, uint64_t keyblock_flags)
+{
+ int index = 0;
+
+ /*
+ * Convert keyblock flags into keyblock mode which we use to index into
+ * kBootStateSHA1Digest[].
+ */
+ switch(keyblock_flags) {
+ case 6:
+ /*
+ * KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1
+ *
+ * Developer firmware. */
+ index = 2;
+ break;
+ case 7:
+ /*
+ * KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_0
+ * | KEY_BLOCK_FLAGS_DEVELOPER_1
+ */
+ index = 1;
+ break;
+ default:
+ /* Any other keyblock flags. */
+ index = 0;
+ };
+
+ if (rec_mode)
+ index += 3;
+ if (dev_mode)
+ index += 6;
+ return index;
}
uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode,
- uint64_t fw_keyblock_flags) {
- uint32_t result;
- const uint8_t* in_digest = NULL;
- uint8_t out_digest[20]; /* For PCR extend output. */
- int digest_index = GetBootStateIndex(developer_mode, recovery_mode,
- fw_keyblock_flags);
-
- if (digest_index >= 0 && digest_index < MAX_BOOT_STATE_INDEX)
- in_digest = (const uint8_t*)kBootStateSHA1Digests[digest_index];
- else
- in_digest = kBootInvalidSHA1Digest; /* Internal out of bounds error. */
- result = TlclExtend(BOOT_MODE_PCR, in_digest, out_digest);
- VBDEBUG(("TPM: SetTPMBootModeState boot mode PCR out_digest %02x %02x %02x "
- "%02x\n", out_digest, out_digest+1, out_digest+2, out_digest+3));
- return result;
+ uint64_t fw_keyblock_flags)
+{
+ uint32_t result;
+ const uint8_t *in_digest = NULL;
+ uint8_t out_digest[20]; /* For PCR extend output. */
+ int digest_index = GetBootStateIndex(developer_mode, recovery_mode,
+ fw_keyblock_flags);
+
+ if (digest_index >= 0 && digest_index < MAX_BOOT_STATE_INDEX) {
+ in_digest = (const uint8_t*)
+ kBootStateSHA1Digests[digest_index];
+ } else {
+ /* Internal out of bounds error. */
+ in_digest = kBootInvalidSHA1Digest;
+ }
+
+ result = TlclExtend(BOOT_MODE_PCR, in_digest, out_digest);
+ VBDEBUG(("TPM: SetTPMBootModeState boot mode PCR out_digest "
+ "%02x %02x %02x %02x\n",
+ out_digest, out_digest+1, out_digest+2, out_digest+3));
+ return result;
}
diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c
index ce5614e1..7acca9a1 100644
--- a/firmware/lib/tpm_lite/tlcl.c
+++ b/firmware/lib/tpm_lite/tlcl.c
@@ -21,6 +21,11 @@
#include "utility.h"
#include "vboot_api.h"
+#ifdef FOR_TEST
+/* Allow unit testing implementation of TlclSendReceive() */
+#undef CHROMEOS_ENVIRONMENT
+#endif
+
/* Sets the size field of a TPM command. */
static INLINE void SetTpmCommandSize(uint8_t* buffer, uint32_t size) {
ToTpmUint32(buffer + sizeof(uint16_t), size);
diff --git a/firmware/lib/utility.c b/firmware/lib/utility.c
index 5e506f33..66b8eff3 100644
--- a/firmware/lib/utility.c
+++ b/firmware/lib/utility.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -8,18 +8,20 @@
#include "sysincludes.h"
#include "utility.h"
-int SafeMemcmp(const void* s1, const void* s2, size_t n) {
- const unsigned char* us1 = s1;
- const unsigned char* us2 = s2;
- int result = 0;
+int SafeMemcmp(const void *s1, const void *s2, size_t n) {
+ const unsigned char *us1 = s1;
+ const unsigned char *us2 = s2;
+ int result = 0;
- if (0 == n)
- return 0;
+ if (0 == n)
+ return 0;
- /* Code snippet without data-dependent branch due to
- * Nate Lawson (nate@root.org) of Root Labs. */
- while (n--)
- result |= *us1++ ^ *us2++;
+ /*
+ * Code snippet without data-dependent branch due to Nate Lawson
+ * (nate@root.org) of Root Labs.
+ */
+ while (n--)
+ result |= *us1++ ^ *us2++;
- return result != 0;
+ return result != 0;
}
diff --git a/firmware/lib/utility_string.c b/firmware/lib/utility_string.c
index 424c3e33..b1b1a391 100644
--- a/firmware/lib/utility_string.c
+++ b/firmware/lib/utility_string.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -10,62 +10,64 @@
uint32_t Uint64ToString(char *buf, uint32_t bufsize, uint64_t value,
- uint32_t radix, uint32_t zero_pad_width) {
- char ibuf[UINT64_TO_STRING_MAX];
- char *s;
- uint32_t usedsize = 1;
-
- if (!buf)
- return 0;
-
- /* Clear output buffer in case of error */
- *buf = '\0';
-
- /* Sanity-check input args */
- if (radix < 2 || radix > 36 || zero_pad_width >= UINT64_TO_STRING_MAX)
- return 0;
-
- /* Start at end of string and work backwards */
- s = ibuf + UINT64_TO_STRING_MAX - 1;
- *(s) = '\0';
- do {
- int v = value % radix;
- value /= radix;
-
- *(--s) = (char)(v < 10 ? v + '0' : v + 'a' - 10);
- if (++usedsize > bufsize)
- return 0; /* Result won't fit in buffer */
- } while (value);
-
- /* Zero-pad if necessary */
- while (usedsize <= zero_pad_width) {
- *(--s) = '0';
- if (++usedsize > bufsize)
- return 0; /* Result won't fit in buffer */
- }
-
- /* Now copy the string back to the input buffer. */
- Memcpy(buf, s, usedsize);
-
- /* Don't count the terminating null in the bytes used */
- return usedsize - 1;
+ uint32_t radix, uint32_t zero_pad_width)
+{
+ char ibuf[UINT64_TO_STRING_MAX];
+ char *s;
+ uint32_t usedsize = 1;
+
+ if (!buf)
+ return 0;
+
+ /* Clear output buffer in case of error */
+ *buf = '\0';
+
+ /* Sanity-check input args */
+ if (radix < 2 || radix > 36 || zero_pad_width >= UINT64_TO_STRING_MAX)
+ return 0;
+
+ /* Start at end of string and work backwards */
+ s = ibuf + UINT64_TO_STRING_MAX - 1;
+ *(s) = '\0';
+ do {
+ int v = value % radix;
+ value /= radix;
+
+ *(--s) = (char)(v < 10 ? v + '0' : v + 'a' - 10);
+ if (++usedsize > bufsize)
+ return 0; /* Result won't fit in buffer */
+ } while (value);
+
+ /* Zero-pad if necessary */
+ while (usedsize <= zero_pad_width) {
+ *(--s) = '0';
+ if (++usedsize > bufsize)
+ return 0; /* Result won't fit in buffer */
+ }
+
+ /* Now copy the string back to the input buffer. */
+ Memcpy(buf, s, usedsize);
+
+ /* Don't count the terminating null in the bytes used */
+ return usedsize - 1;
}
+uint32_t Strncat(char *dest, const char *src, uint32_t destlen)
+{
+ uint32_t used = 0;
-uint32_t Strncat(char *dest, const char *src, uint32_t destlen) {
- uint32_t used = 0;
+ if (!dest || !src)
+ return 0;
- if (!dest || !src)
- return 0;
+ /* Skip past existing string in destination.*/
+ while (dest[used] && used < destlen - 1)
+ used++;
- /* Skip past existing string in destination.*/
- while (dest[used] && used < destlen - 1)
- used++;
- /* Now copy source */
- while (*src && used < destlen - 1)
- dest[used++] = *src++;
+ /* Now copy source */
+ while (*src && used < destlen - 1)
+ dest[used++] = *src++;
- /* Terminate destination and return count of non-null characters */
- dest[used] = 0;
- return used;
+ /* Terminate destination and return count of non-null characters */
+ dest[used] = 0;
+ return used;
}
diff --git a/firmware/lib/vboot_api_firmware.c b/firmware/lib/vboot_api_firmware.c
index 1426c9ab..0d0c2262 100644
--- a/firmware/lib/vboot_api_firmware.c
+++ b/firmware/lib/vboot_api_firmware.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -14,99 +14,111 @@
#include "vboot_common.h"
#include "vboot_nvstorage.h"
-VbError_t VbSelectFirmware(VbCommonParams* cparams,
- VbSelectFirmwareParams* fparams) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- VbNvContext vnc;
- VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven successful */
- int is_rec = (shared->recovery_reason ? 1 : 0);
- int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
- uint32_t tpm_status = 0;
-
- /* Start timer */
- shared->timer_vb_select_firmware_enter = VbExGetTimer();
-
- /* Load NV storage */
- VbExNvStorageRead(vnc.raw);
- VbNvSetup(&vnc);
-
- if (is_rec) {
- /* Recovery is requested; go straight to recovery without checking the
- * RW firmware. */
- VBDEBUG(("VbSelectFirmware() detected recovery request\n"));
-
- /* Go directly to recovery mode */
- fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
-
- } else {
- /* Chain to LoadFirmware() */
- retval = LoadFirmware(cparams, fparams, &vnc);
-
- /* Exit if we failed to find an acceptable firmware */
- if (VBERROR_SUCCESS != retval)
- goto VbSelectFirmware_exit;
-
- /* Translate the selected firmware path */
- if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
- /* Request the read-only normal/dev code path */
- fparams->selected_firmware = VB_SELECT_FIRMWARE_READONLY;
- } else if (0 == shared->firmware_index)
- fparams->selected_firmware = VB_SELECT_FIRMWARE_A;
- else
- fparams->selected_firmware = VB_SELECT_FIRMWARE_B;
-
- /* Update TPM if necessary */
- if (shared->fw_version_tpm_start < shared->fw_version_tpm) {
- VBPERFSTART("VB_TPMU");
- tpm_status = RollbackFirmwareWrite(shared->fw_version_tpm);
- VBPERFEND("VB_TPMU");
- if (0 != tpm_status) {
- VBDEBUG(("Unable to write firmware version to TPM.\n"));
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_W_ERROR);
- retval = VBERROR_TPM_WRITE_FIRMWARE;
- goto VbSelectFirmware_exit;
- }
- }
-
- /* Lock firmware versions in TPM */
- VBPERFSTART("VB_TPML");
- tpm_status = RollbackFirmwareLock();
- VBPERFEND("VB_TPML");
- if (0 != tpm_status) {
- VBDEBUG(("Unable to lock firmware version in TPM.\n"));
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_L_ERROR);
- retval = VBERROR_TPM_LOCK_FIRMWARE;
- goto VbSelectFirmware_exit;
- }
- }
-
- /* At this point, we have a good idea of how we are going to
- * boot. Update the TPM with this state information. */
- tpm_status = SetTPMBootModeState(is_dev, is_rec, shared->fw_keyblock_flags);
- if (0 != tpm_status) {
- VBDEBUG(("Unable to update the TPM with boot mode information.\n"));
- if (!is_rec) {
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_U_ERROR);
- retval = VBERROR_TPM_SET_BOOT_MODE_STATE;
- goto VbSelectFirmware_exit;
- }
- }
-
- /* Success! */
- retval = VBERROR_SUCCESS;
-
-VbSelectFirmware_exit:
-
- /* Save NV storage */
- VbNvTeardown(&vnc);
- if (vnc.raw_changed)
- VbExNvStorageWrite(vnc.raw);
-
- /* Stop timer */
- shared->timer_vb_select_firmware_exit = VbExGetTimer();
-
- /* Should always have a known error code */
- VbAssert(VBERROR_UNKNOWN != retval);
-
- return retval;
+VbError_t VbSelectFirmware(VbCommonParams *cparams,
+ VbSelectFirmwareParams *fparams)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ VbNvContext vnc;
+ VbError_t retval = VBERROR_UNKNOWN; /* Default to error */
+ int is_rec = (shared->recovery_reason ? 1 : 0);
+ int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
+ uint32_t tpm_status = 0;
+
+ /* Start timer */
+ shared->timer_vb_select_firmware_enter = VbExGetTimer();
+
+ /* Load NV storage */
+ VbExNvStorageRead(vnc.raw);
+ VbNvSetup(&vnc);
+
+ if (is_rec) {
+ /*
+ * Recovery is requested; go straight to recovery without
+ * checking the RW firmware.
+ */
+ VBDEBUG(("VbSelectFirmware() detected recovery request\n"));
+
+ /* Go directly to recovery mode */
+ fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
+ } else {
+ /* Chain to LoadFirmware() */
+ retval = LoadFirmware(cparams, fparams, &vnc);
+
+ /* Exit if we failed to find an acceptable firmware */
+ if (VBERROR_SUCCESS != retval)
+ goto VbSelectFirmware_exit;
+
+ /* Translate the selected firmware path */
+ if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
+ /* Request the read-only normal/dev code path */
+ fparams->selected_firmware =
+ VB_SELECT_FIRMWARE_READONLY;
+ } else if (0 == shared->firmware_index)
+ fparams->selected_firmware = VB_SELECT_FIRMWARE_A;
+ else {
+ fparams->selected_firmware = VB_SELECT_FIRMWARE_B;
+ }
+
+ /* Update TPM if necessary */
+ if (shared->fw_version_tpm_start < shared->fw_version_tpm) {
+ VBPERFSTART("VB_TPMU");
+ tpm_status =
+ RollbackFirmwareWrite(shared->fw_version_tpm);
+ VBPERFEND("VB_TPMU");
+ if (0 != tpm_status) {
+ VBDEBUG(("Can't write FW version to TPM.\n"));
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_RO_TPM_W_ERROR);
+ retval = VBERROR_TPM_WRITE_FIRMWARE;
+ goto VbSelectFirmware_exit;
+ }
+ }
+
+ /* Lock firmware versions in TPM */
+ VBPERFSTART("VB_TPML");
+ tpm_status = RollbackFirmwareLock();
+ VBPERFEND("VB_TPML");
+ if (0 != tpm_status) {
+ VBDEBUG(("Unable to lock firmware version in TPM.\n"));
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_RO_TPM_L_ERROR);
+ retval = VBERROR_TPM_LOCK_FIRMWARE;
+ goto VbSelectFirmware_exit;
+ }
+ }
+
+ /*
+ * At this point, we have a good idea of how we are going to
+ * boot. Update the TPM with this state information.
+ */
+ tpm_status = SetTPMBootModeState(is_dev, is_rec,
+ shared->fw_keyblock_flags);
+ if (0 != tpm_status) {
+ VBDEBUG(("Can't update the TPM with boot mode information.\n"));
+ if (!is_rec) {
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_RO_TPM_U_ERROR);
+ retval = VBERROR_TPM_SET_BOOT_MODE_STATE;
+ goto VbSelectFirmware_exit;
+ }
+ }
+
+ /* Success! */
+ retval = VBERROR_SUCCESS;
+
+ VbSelectFirmware_exit:
+
+ /* Save NV storage */
+ VbNvTeardown(&vnc);
+ if (vnc.raw_changed)
+ VbExNvStorageWrite(vnc.raw);
+
+ /* Stop timer */
+ shared->timer_vb_select_firmware_exit = VbExGetTimer();
+
+ /* Should always have a known error code */
+ VbAssert(VBERROR_UNKNOWN != retval);
+
+ return retval;
}
diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c
index a77b230d..ec33f351 100644
--- a/firmware/lib/vboot_api_init.c
+++ b/firmware/lib/vboot_api_init.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -13,254 +13,303 @@
#include "vboot_common.h"
#include "vboot_nvstorage.h"
-
-VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- VbNvContext vnc;
- VbError_t retval = VBERROR_SUCCESS;
- uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
- int is_s3_resume = 0;
- uint32_t s3_debug_boot = 0;
- uint32_t require_official_os = 0;
- uint32_t tpm_version = 0;
- uint32_t tpm_status = 0;
- int has_virt_dev_switch = 0;
- int is_hw_dev = 0;
- int is_virt_dev = 0;
- uint32_t disable_dev_request = 0;
- uint32_t clear_tpm_owner_request = 0;
- int is_dev = 0;
-
- VBDEBUG(("VbInit() input flags 0x%x\n", iparams->flags));
-
- /* Initialize output flags */
- iparams->out_flags = 0;
-
- /* Set up NV storage */
- VbExNvStorageRead(vnc.raw);
- VbNvSetup(&vnc);
-
- /* Initialize shared data structure */
- if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) {
- VBDEBUG(("Shared data init error\n"));
- return VBERROR_INIT_SHARED_DATA;
- }
-
- shared->timer_vb_init_enter = VbExGetTimer();
-
- /* Copy some boot switch flags */
- /* TODO: in next refactor, just save in/out flags in VbSharedData */
- shared->flags = 0;
- if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
- shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
- if (iparams->flags & VB_INIT_FLAG_WP_ENABLED)
- shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
- if (iparams->flags & VB_INIT_FLAG_SW_WP_ENABLED)
- shared->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED;
- if (iparams->flags & VB_INIT_FLAG_S3_RESUME)
- shared->flags |= VBSD_BOOT_S3_RESUME;
- if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT)
- shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT;
- if (iparams->flags & VB_INIT_FLAG_EC_SOFTWARE_SYNC)
- shared->flags |= VBSD_EC_SOFTWARE_SYNC;
- if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE)
- shared->flags |= VBSD_EC_SLOW_UPDATE;
-
- is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);
-
- /* Check if the OS is requesting a debug S3 reset */
- VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot);
- if (s3_debug_boot) {
- if (is_s3_resume) {
- VBDEBUG(("VbInit() requesting S3 debug boot\n"));
- iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT;
- is_s3_resume = 0; /* Proceed as if this is a normal boot */
- }
-
- /* Clear the request even if this is a normal boot, since we don't
- * want the NEXT S3 resume to be a debug reset unless the OS
- * asserts the request again. */
- VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0);
- }
-
- /* If this isn't a S3 resume, read the current recovery request, then clear
- * it so we don't get stuck in recovery mode. */
- if (!is_s3_resume) {
- VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery);
- VBDEBUG(("VbInit sees recovery request = %d\n", recovery));
- if (VBNV_RECOVERY_NOT_REQUESTED != recovery)
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED);
- }
-
- /* If the previous boot failed in the firmware somewhere outside of verified
- * boot, and recovery is not requested for our own reasons, request recovery
- * mode. This gives the calling firmware a way to request recovery if it
- * finds something terribly wrong. */
- if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
- iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
- recovery = VBNV_RECOVERY_RO_FIRMWARE;
- }
-
- /* If recovery button is pressed, override recovery reason. Note that we
- * do this in the S3 resume path also. */
- if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
- recovery = VBNV_RECOVERY_RO_MANUAL;
-
- /* Copy current recovery reason to shared data. If we fail later on, it
- * won't matter, since we'll just reboot. */
- shared->recovery_reason = (uint8_t)recovery;
- VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));
-
- /* If this is a S3 resume, resume the TPM. */
- /* FIXME: I think U-Boot won't ever ask us to do this. Can we remove it? */
- if (is_s3_resume) {
- if (TPM_SUCCESS != RollbackS3Resume()) {
- /* If we can't resume, just do a full reboot. No need to go to recovery
- * mode here, since if the TPM is really broken we'll catch it on the
- * next boot. */
- retval = VBERROR_TPM_S3_RESUME;
- }
- } else {
- /* Should we pay attention to the TPM's virtual dev-switch? */
- if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) {
- shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
- has_virt_dev_switch = 1;
- }
- /* We always believe the HW dev-switch, since there's one attached to servo
- * which may be active even on systems without a physical switch. The EC
- * may also implement a fake dev-switch for testing. */
- if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
- is_hw_dev = 1;
- /* We may be asked to clear the virtual dev-switch at boot. */
- VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);
-
- /* Allow GBB flag to override dev switch */
- if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON)
- is_hw_dev = 1;
-
- /* Check if we've been explicitly asked to clear the TPM owner */
- VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, &clear_tpm_owner_request);
-
- VBPERFSTART("VB_TPMI");
- /* Initialize the TPM. If the developer mode state has changed since the
- * last boot, we need to clear TPM ownership. If the TPM space is
- * initialized by this call, the virtual dev-switch will be disabled by
- * default) */
- tpm_status = RollbackFirmwareSetup(recovery, is_hw_dev, disable_dev_request,
- clear_tpm_owner_request,
- /* two outputs on success */
- &is_virt_dev, &tpm_version);
- VBPERFEND("VB_TPMI");
- if (0 != tpm_status) {
- VBDEBUG(("Unable to setup TPM and read firmware version (0x%x)\n",
- tpm_status));
-
- if (TPM_E_MUST_REBOOT == tpm_status) {
- /* TPM wants to reboot into the same mode we're in now */
- VBDEBUG(("TPM requires a reboot.\n"));
- if (!recovery) {
- /* Not recovery mode. Just reboot (not into recovery). */
- retval = VBERROR_TPM_REBOOT_REQUIRED;
- goto VbInit_exit;
- } else if (VBNV_RECOVERY_RO_TPM_REBOOT != shared->recovery_reason) {
- /* In recovery mode now, and we haven't requested a TPM reboot yet,
- * so request one. */
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_REBOOT);
- retval = VBERROR_TPM_REBOOT_REQUIRED;
- goto VbInit_exit;
- }
- }
-
- if (!recovery) {
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_S_ERROR);
- VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE, tpm_status);
- retval = VBERROR_TPM_FIRMWARE_SETUP;
- goto VbInit_exit;
- }
- }
-
- /* TPM setup succeeded. What did we learn? */
- shared->fw_version_tpm_start = tpm_version;
- shared->fw_version_tpm = tpm_version;
- if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) {
- is_dev = 1;
- shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
- }
- if (disable_dev_request && !is_virt_dev)
- VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0);
- if (clear_tpm_owner_request) {
- VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0);
- VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1);
- }
- }
-
- /* Allow BIOS to load arbitrary option ROMs? */
- if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS)
- iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM;
-
- /* The factory may need to boot custom OSes whenever the dev-switch is on */
- if (is_dev && (gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS))
- iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
-
- /* Set output flags */
- if (VBNV_RECOVERY_NOT_REQUESTED != recovery) {
- /* Requesting recovery mode */
- iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY |
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE);
- }
- else if (is_dev) {
- /* Developer switch is on, so need to support dev mode */
- iparams->out_flags |= (VB_INIT_OUT_ENABLE_DEVELOPER |
- VB_INIT_OUT_CLEAR_RAM |
- VB_INIT_OUT_ENABLE_DISPLAY |
- VB_INIT_OUT_ENABLE_USB_STORAGE);
- /* ... which may or may not include custom OSes */
- VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
- if (!require_official_os)
- iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
-
- /* Dev-mode needs the VGA option ROM to be loaded so it can display the
- * scary boot screen. If we don't have it, we need to request it and
- * reboot so it can be loaded. */
- if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
- !(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
- VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
- retval = VBERROR_VGA_OPROM_MISMATCH;
- VBDEBUG(("VbInit() needs oprom, doesn't have it\n"));
- }
-
- } else {
- /* Normal mode, so disable dev_boot_* flags. This ensures they will be
- * initially disabled if the user later transitions back into developer
- * mode. */
- VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
- VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0);
- VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0);
-
- /* If we don't need the VGA option ROM but got it anyway, stop asking for
- * it and reboot in case there's some vulnerability in using it. */
- if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
- (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
- VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
- retval = VBERROR_VGA_OPROM_MISMATCH;
- VBDEBUG(("VbInit() has oprom, doesn't need it\n"));
- }
- }
-
-VbInit_exit:
-
- /* Tear down NV storage */
- VbNvTeardown(&vnc);
- if (vnc.raw_changed)
- VbExNvStorageWrite(vnc.raw);
-
- VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
-
- shared->timer_vb_init_exit = VbExGetTimer();
-
- VBDEBUG(("VbInit() returning 0x%x\n", retval));
- return retval;
+VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ VbNvContext vnc;
+ VbError_t retval = VBERROR_SUCCESS;
+ uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED;
+ int is_s3_resume = 0;
+ uint32_t s3_debug_boot = 0;
+ uint32_t require_official_os = 0;
+ uint32_t tpm_version = 0;
+ uint32_t tpm_status = 0;
+ int has_virt_dev_switch = 0;
+ int is_hw_dev = 0;
+ int is_virt_dev = 0;
+ uint32_t disable_dev_request = 0;
+ uint32_t clear_tpm_owner_request = 0;
+ int is_dev = 0;
+
+ VBDEBUG(("VbInit() input flags 0x%x\n", iparams->flags));
+
+ /* Initialize output flags */
+ iparams->out_flags = 0;
+
+ /* Set up NV storage */
+ VbExNvStorageRead(vnc.raw);
+ VbNvSetup(&vnc);
+
+ /* Initialize shared data structure */
+ if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) {
+ VBDEBUG(("Shared data init error\n"));
+ return VBERROR_INIT_SHARED_DATA;
+ }
+
+ shared->timer_vb_init_enter = VbExGetTimer();
+
+ /* Copy some boot switch flags */
+ /* TODO: in next refactor, just save in/out flags in VbSharedData */
+ shared->flags = 0;
+ if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
+ shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
+ if (iparams->flags & VB_INIT_FLAG_WP_ENABLED)
+ shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED;
+ if (iparams->flags & VB_INIT_FLAG_SW_WP_ENABLED)
+ shared->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED;
+ if (iparams->flags & VB_INIT_FLAG_S3_RESUME)
+ shared->flags |= VBSD_BOOT_S3_RESUME;
+ if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT)
+ shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT;
+ if (iparams->flags & VB_INIT_FLAG_EC_SOFTWARE_SYNC)
+ shared->flags |= VBSD_EC_SOFTWARE_SYNC;
+ if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE)
+ shared->flags |= VBSD_EC_SLOW_UPDATE;
+
+ is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);
+
+ /* Check if the OS is requesting a debug S3 reset */
+ VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot);
+ if (s3_debug_boot) {
+ if (is_s3_resume) {
+ VBDEBUG(("VbInit() requesting S3 debug boot\n"));
+ iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT;
+ is_s3_resume = 0; /* Proceed as if normal boot */
+ }
+
+ /*
+ * Clear the request even if this is a normal boot, since we
+ * don't want the NEXT S3 resume to be a debug reset unless the
+ * OS asserts the request again.
+ */
+ VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0);
+ }
+
+ /*
+ * If this isn't a S3 resume, read the current recovery request, then
+ * clear it so we don't get stuck in recovery mode.
+ */
+ if (!is_s3_resume) {
+ VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery);
+ VBDEBUG(("VbInit sees recovery request = %d\n", recovery));
+ if (VBNV_RECOVERY_NOT_REQUESTED != recovery)
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_NOT_REQUESTED);
+ }
+
+ /*
+ * If the previous boot failed in the firmware somewhere outside of
+ * verified boot, and recovery is not requested for our own reasons,
+ * request recovery mode. This gives the calling firmware a way to
+ * request recovery if it finds something terribly wrong.
+ */
+ if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
+ iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
+ recovery = VBNV_RECOVERY_RO_FIRMWARE;
+ }
+
+ /*
+ * If recovery button is pressed, override recovery reason. Note that
+ * we do this in the S3 resume path also.
+ */
+ if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
+ recovery = VBNV_RECOVERY_RO_MANUAL;
+
+ /*
+ * Copy current recovery reason to shared data. If we fail later on, it
+ * won't matter, since we'll just reboot.
+ */
+ shared->recovery_reason = (uint8_t)recovery;
+ VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));
+
+ /*
+ * If this is a S3 resume, resume the TPM.
+ *
+ * FIXME: I think U-Boot won't ever ask us to do this. Can we remove
+ * it?
+ */
+ if (is_s3_resume) {
+ if (TPM_SUCCESS != RollbackS3Resume()) {
+ /*
+ * If we can't resume, just do a full reboot. No need
+ * to go to recovery mode here, since if the TPM is
+ * really broken we'll catch it on the next boot.
+ */
+ retval = VBERROR_TPM_S3_RESUME;
+ }
+ } else {
+ /* Should we pay attention to the TPM's virtual dev-switch? */
+ if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) {
+ shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH;
+ has_virt_dev_switch = 1;
+ }
+
+ /*
+ * We always believe the HW dev-switch, since there's one
+ * attached to servo which may be active even on systems
+ * without a physical switch. The EC may also implement a fake
+ * dev-switch for testing.
+ */
+ if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
+ is_hw_dev = 1;
+
+ /* We may be asked to clear the virtual dev-switch at boot. */
+ VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);
+
+ /* Allow GBB flag to override dev switch */
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON)
+ is_hw_dev = 1;
+
+ /* Have we been explicitly asked to clear the TPM owner? */
+ VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST,
+ &clear_tpm_owner_request);
+
+ VBPERFSTART("VB_TPMI");
+ /*
+ * Initialize the TPM. If the developer mode state has changed
+ * since the last boot, we need to clear TPM ownership. If the
+ * TPM space is initialized by this call, the virtual
+ * dev-switch will be disabled by default)
+ */
+ tpm_status = RollbackFirmwareSetup(recovery, is_hw_dev,
+ disable_dev_request,
+ clear_tpm_owner_request,
+ /* two outputs on success */
+ &is_virt_dev, &tpm_version);
+ VBPERFEND("VB_TPMI");
+
+ if (0 != tpm_status) {
+ VBDEBUG(("Unable to setup TPM and read "
+ "firmware version (0x%x)\n", tpm_status));
+
+ if (TPM_E_MUST_REBOOT == tpm_status) {
+ /*
+ * TPM wants to reboot into the same mode we're
+ * in now
+ */
+ VBDEBUG(("TPM requires a reboot.\n"));
+ if (!recovery) {
+ /*
+ * Not recovery mode. Just reboot (not
+ * into recovery).
+ */
+ retval = VBERROR_TPM_REBOOT_REQUIRED;
+ goto VbInit_exit;
+ } else if (VBNV_RECOVERY_RO_TPM_REBOOT !=
+ shared->recovery_reason) {
+ /*
+ * In recovery mode now, and we haven't
+ * requested a TPM reboot yet, so
+ * request one.
+ */
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_RO_TPM_REBOOT);
+ retval = VBERROR_TPM_REBOOT_REQUIRED;
+ goto VbInit_exit;
+ }
+ }
+
+ if (!recovery) {
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
+ VBNV_RECOVERY_RO_TPM_S_ERROR);
+ VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE,
+ tpm_status);
+ retval = VBERROR_TPM_FIRMWARE_SETUP;
+ goto VbInit_exit;
+ }
+ }
+
+ /* TPM setup succeeded. What did we learn? */
+ shared->fw_version_tpm_start = tpm_version;
+ shared->fw_version_tpm = tpm_version;
+ if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) {
+ is_dev = 1;
+ shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
+ }
+ if (disable_dev_request && !is_virt_dev)
+ VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0);
+ if (clear_tpm_owner_request) {
+ VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0);
+ VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1);
+ }
+ }
+
+ /* Allow BIOS to load arbitrary option ROMs? */
+ if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS)
+ iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM;
+
+ /* Factory may need to boot custom OSes when the dev-switch is on */
+ if (is_dev && (gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS))
+ iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
+
+ /* Set output flags */
+ if (VBNV_RECOVERY_NOT_REQUESTED != recovery) {
+ /* Requesting recovery mode */
+ iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY |
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE);
+ } else if (is_dev) {
+ /* Developer switch is on, so need to support dev mode */
+ iparams->out_flags |= (VB_INIT_OUT_ENABLE_DEVELOPER |
+ VB_INIT_OUT_CLEAR_RAM |
+ VB_INIT_OUT_ENABLE_DISPLAY |
+ VB_INIT_OUT_ENABLE_USB_STORAGE);
+ /* ... which may or may not include custom OSes */
+ VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
+ if (!require_official_os)
+ iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
+
+ /*
+ * Dev-mode needs the VGA option ROM to be loaded so it can
+ * display the scary boot screen. If we don't have it, we need
+ * to request it and reboot so it can be loaded.
+ */
+ if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
+ !(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
+ VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1);
+ retval = VBERROR_VGA_OPROM_MISMATCH;
+ VBDEBUG(("VbInit() needs oprom, doesn't have it\n"));
+ }
+
+ } else {
+ /*
+ * Normal mode, so disable dev_boot_* flags. This ensures they
+ * will be initially disabled if the user later transitions
+ * back into developer mode.
+ */
+ VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0);
+ VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0);
+ VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0);
+
+ /*
+ * If we don't need the VGA option ROM but got it anyway, stop
+ * asking for it and reboot in case there's some vulnerability
+ * in using it.
+ */
+ if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
+ (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) {
+ VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0);
+ retval = VBERROR_VGA_OPROM_MISMATCH;
+ VBDEBUG(("VbInit() has oprom, doesn't need it\n"));
+ }
+ }
+
+ VbInit_exit:
+
+ /* Tear down NV storage */
+ VbNvTeardown(&vnc);
+ if (vnc.raw_changed)
+ VbExNvStorageWrite(vnc.raw);
+
+ VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
+
+ shared->timer_vb_init_exit = VbExGetTimer();
+
+ VBDEBUG(("VbInit() returning 0x%x\n", retval));
+
+ return retval;
}
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 70895ff7..a55d8064 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -15,764 +15,999 @@
#include "vboot_display.h"
#include "vboot_nvstorage.h"
-
/* Global variables */
static VbNvContext vnc;
-
#ifdef CHROMEOS_ENVIRONMENT
-/* Global variable accessors for unit tests */
-VbNvContext* VbApiKernelGetVnc(void) {
- return &vnc;
+/* Global variable accessor for unit tests */
+
+VbNvContext *VbApiKernelGetVnc(void)
+{
+ return &vnc;
}
#endif
-
-/* Set recovery request */
-static void VbSetRecoveryRequest(uint32_t recovery_request) {
- VBDEBUG(("VbSetRecoveryRequest(%d)\n", (int)recovery_request));
- VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request);
+/**
+ * Set recovery request (called from vboot_api_kernel.c functions only)
+ */
+static void VbSetRecoveryRequest(uint32_t recovery_request)
+{
+ VBDEBUG(("VbSetRecoveryRequest(%d)\n", (int)recovery_request));
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request);
}
-
-/* Attempt loading a kernel from the specified type(s) of disks. If
- * successful, sets p->disk_handle to the disk for the kernel and returns
+/**
+ * Attempt loading a kernel from the specified type(s) of disks.
+ *
+ * If successful, sets p->disk_handle to the disk for the kernel and returns
* VBERROR_SUCCESS.
*
* Returns VBERROR_NO_DISK_FOUND if no disks of the specified type were found.
*
- * May return other VBERROR_ codes for other failures. */
-uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
- uint32_t get_info_flags) {
- VbError_t retval = VBERROR_UNKNOWN;
- VbDiskInfo* disk_info = NULL;
- uint32_t disk_count = 0;
- uint32_t i;
-
- VBDEBUG(("VbTryLoadKernel() start, get_info_flags=0x%x\n",
- (unsigned)get_info_flags));
-
- p->disk_handle = NULL;
-
- /* Find disks */
- if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
- get_info_flags))
- disk_count = 0;
-
- VBDEBUG(("VbTryLoadKernel() found %d disks\n", (int)disk_count));
- if (0 == disk_count) {
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK);
- return VBERROR_NO_DISK_FOUND;
- }
-
- /* Loop over disks */
- for (i = 0; i < disk_count; i++) {
- VBDEBUG(("VbTryLoadKernel() trying disk %d\n", (int)i));
- /* Sanity-check what we can. FWIW, VbTryLoadKernel() is always called
- * with only a single bit set in get_info_flags
- */
- if (512 != disk_info[i].bytes_per_lba || /* cgptlib restriction */
- 32 > disk_info[i].lba_count || /* ditto */
- get_info_flags != disk_info[i].flags) { /* got only what we asked for */
- VBDEBUG((" skipping: bytes_per_lba=%lld lba_count=%lld flags=0x%x\n",
- disk_info[i].bytes_per_lba, disk_info[i].lba_count,
- disk_info[i].flags));
- continue;
- }
- p->disk_handle = disk_info[i].handle;
- p->bytes_per_lba = disk_info[i].bytes_per_lba;
- p->ending_lba = disk_info[i].lba_count - 1;
- retval = LoadKernel(p);
- VBDEBUG(("VbTryLoadKernel() LoadKernel() returned %d\n", retval));
-
- /* Stop now if we found a kernel */
- /* TODO: If recovery requested, should track the farthest we get, instead
- * of just returning the value from the last disk attempted. */
- if (VBERROR_SUCCESS == retval)
- break;
- }
-
- /* If we didn't find any good kernels, don't return a disk handle. */
- if (VBERROR_SUCCESS != retval) {
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_KERNEL);
- p->disk_handle = NULL;
- }
-
- VbExDiskFreeInfo(disk_info, p->disk_handle);
-
- /* Pass through return code. Recovery reason (if any) has already been set
- * by LoadKernel(). */
- return retval;
+ * May return other VBERROR_ codes for other failures.
+ */
+uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
+ uint32_t get_info_flags)
+{
+ VbError_t retval = VBERROR_UNKNOWN;
+ VbDiskInfo* disk_info = NULL;
+ uint32_t disk_count = 0;
+ uint32_t i;
+
+ VBDEBUG(("VbTryLoadKernel() start, get_info_flags=0x%x\n",
+ (unsigned)get_info_flags));
+
+ p->disk_handle = NULL;
+
+ /* Find disks */
+ if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
+ get_info_flags))
+ disk_count = 0;
+
+ VBDEBUG(("VbTryLoadKernel() found %d disks\n", (int)disk_count));
+ if (0 == disk_count) {
+ VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK);
+ return VBERROR_NO_DISK_FOUND;
+ }
+
+ /* Loop over disks */
+ for (i = 0; i < disk_count; i++) {
+ VBDEBUG(("VbTryLoadKernel() trying disk %d\n", (int)i));
+ /*
+ * Sanity-check what we can. FWIW, VbTryLoadKernel() is always
+ * called with only a single bit set in get_info_flags.
+ *
+ * Ensure 512-byte sectors and non-trivially sized disk (for
+ * cgptlib) and that we got a partition with only the flags we
+ * asked for.
+ */
+ if (512 != disk_info[i].bytes_per_lba ||
+ 32 > disk_info[i].lba_count ||
+ get_info_flags != disk_info[i].flags) {
+ VBDEBUG((" skipping: bytes_per_lba=%lld "
+ "lba_count=%lld flags=0x%x\n",
+ disk_info[i].bytes_per_lba,
+ disk_info[i].lba_count,
+ disk_info[i].flags));
+ continue;
+ }
+ p->disk_handle = disk_info[i].handle;
+ p->bytes_per_lba = disk_info[i].bytes_per_lba;
+ p->ending_lba = disk_info[i].lba_count - 1;
+ retval = LoadKernel(p);
+ VBDEBUG(("VbTryLoadKernel() LoadKernel() = %d\n", retval));
+
+ /*
+ * Stop now if we found a kernel.
+ *
+ * TODO: If recovery requested, should track the farthest we
+ * get, instead of just returning the value from the last disk
+ * attempted.
+ */
+ if (VBERROR_SUCCESS == retval)
+ break;
+ }
+
+ /* If we didn't find any good kernels, don't return a disk handle. */
+ if (VBERROR_SUCCESS != retval) {
+ VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_KERNEL);
+ p->disk_handle = NULL;
+ }
+
+ VbExDiskFreeInfo(disk_info, p->disk_handle);
+
+ /*
+ * Pass through return code. Recovery reason (if any) has already been
+ * set by LoadKernel().
+ */
+ return retval;
}
#define CONFIRM_KEY_DELAY 20 /* Check confirm screen keys every 20ms */
-/* Ask the user to confirm something. We should display whatever the question
- * is first, then call this. ESC is always "no", ENTER is always "yes", and
- * we'll specify what SPACE means. We don't return until one of those keys is
- * pressed, or until asked to shut down.
- *
- * Returns: 1=yes, 0=no, -1 = shutdown.
- */
-static int VbUserConfirms(VbCommonParams* cparams, int space_means_no) {
- uint32_t key;
-
- VBDEBUG(("Entering %s(%d)\n", __func__, space_means_no));
-
- /* Await further instructions */
- while (1) {
- if (VbExIsShutdownRequested())
- return -1;
- key = VbExKeyboardRead();
- switch (key) {
- case '\r':
- VBDEBUG(("%s() - Yes (1)\n", __func__));
- return 1;
- break;
- case ' ':
- VBDEBUG(("%s() - Space (%s)\n", __func__, space_means_no));
- if (space_means_no)
- return 0;
- break;
- case 0x1b:
- VBDEBUG(("%s() - No (0)\n", __func__));
- return 0;
- break;
- default:
- VbCheckDisplayKey(cparams, key, &vnc);
- }
- VbExSleepMs(CONFIRM_KEY_DELAY);
- }
- /* not reached, but compiler will complain without it */
- return -1;
+int VbUserConfirms(VbCommonParams *cparams, int space_means_no)
+{
+ uint32_t key;
+
+ VBDEBUG(("Entering %s(%d)\n", __func__, space_means_no));
+
+ /* Await further instructions */
+ while (1) {
+ if (VbExIsShutdownRequested())
+ return -1;
+ key = VbExKeyboardRead();
+ switch (key) {
+ case '\r':
+ VBDEBUG(("%s() - Yes (1)\n", __func__));
+ return 1;
+ break;
+ case ' ':
+ VBDEBUG(("%s() - Space (%s)\n", __func__,
+ space_means_no));
+ if (space_means_no)
+ return 0;
+ break;
+ case 0x1b:
+ VBDEBUG(("%s() - No (0)\n", __func__));
+ return 0;
+ break;
+ default:
+ VbCheckDisplayKey(cparams, key, &vnc);
+ }
+ VbExSleepMs(CONFIRM_KEY_DELAY);
+ }
+
+ /* Not reached, but compiler will complain without it */
+ return -1;
}
-/* Handle a normal boot. */
-VbError_t VbBootNormal(VbCommonParams* cparams, LoadKernelParams* p) {
- /* Boot from fixed disk only */
- VBDEBUG(("Entering %s()\n", __func__));
- return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
+VbError_t VbBootNormal(VbCommonParams *cparams, LoadKernelParams *p)
+{
+ /* Boot from fixed disk only */
+ VBDEBUG(("Entering %s()\n", __func__));
+ return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
}
-/* Handle a developer-mode boot */
-VbError_t VbBootDeveloper(VbCommonParams* cparams, LoadKernelParams* p) {
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- uint32_t allow_usb = 0, allow_legacy = 0;
- VbAudioContext* audio = 0;
-
- VBDEBUG(("Entering %s()\n", __func__));
-
- /* Check if USB booting is allowed */
- VbNvGet(&vnc, VBNV_DEV_BOOT_USB, &allow_usb);
- VbNvGet(&vnc, VBNV_DEV_BOOT_LEGACY, &allow_legacy);
- /* Handle GBB flag override */
- if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
- allow_usb = 1;
- if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
- allow_legacy = 1;
-
- /* Show the dev mode warning screen */
- VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
-
- /* Get audio/delay context */
- audio = VbAudioOpen(cparams);
-
- /* We'll loop until we finish the delay or are interrupted */
- do {
- uint32_t key;
-
- if (VbExIsShutdownRequested()) {
- VBDEBUG(("VbBootDeveloper() - shutdown is requested!\n"));
- VbAudioClose(audio);
- return VBERROR_SHUTDOWN_REQUESTED;
- }
-
- key = VbExKeyboardRead();
- switch (key) {
- case 0:
- /* nothing pressed */
- break;
- case '\r':
- /* Enter only disables the virtual dev switch if allowed by GBB */
- if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
- break;
- case ' ':
- /* See if we should disable the virtual dev-mode switch. */
- VBDEBUG(("%s shared->flags=0x%x\n", __func__, shared->flags));
- if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
- shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
- VbAudioClose(audio); /* Stop the countdown while we go ask... */
- if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
- /* TONORM won't work (only for non-shipping devices). */
- VBDEBUG(("%s() - TONORM rejected by GBB_FLAG_FORCE_DEV_SWITCH_ON\n",
- __func__));
- VbExDisplayDebugInfo("WARNING: TONORM is prohibited by "
- "GBB_FLAG_FORCE_DEV_SWITCH_ON.\n\n");
- VbExBeep(120, 400);
- break;
- }
- VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_TO_NORM, 0, &vnc);
- switch (VbUserConfirms(cparams, 0)) { /* Ignore space */
- case 1:
- VBDEBUG(("%s() - leaving dev-mode...\n", __func__));
- VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 1);
- VbDisplayScreen(cparams, VB_SCREEN_TO_NORM_CONFIRMED, 0, &vnc);
- VbExSleepMs(5000);
- return VBERROR_TPM_REBOOT_REQUIRED;
- case -1:
- VBDEBUG(("%s() - shutdown requested\n", __func__));
- return VBERROR_SHUTDOWN_REQUESTED;
- default: /* stay in dev-mode */
- VBDEBUG(("%s() - stay in dev-mode\n", __func__));
- VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
- audio = VbAudioOpen(cparams); /* Start new countdown */
- }
- } else {
- /* No virtual dev-mode switch, so go directly to recovery mode */
- VBDEBUG(("%s() - going to recovery\n", __func__));
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_SCREEN);
- VbAudioClose(audio);
- return VBERROR_LOAD_KERNEL_RECOVERY;
- }
- break;
- case 0x04:
- /* Ctrl+D = dismiss warning; advance to timeout */
- VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+D; skip delay\n"));
- goto fallout;
- break;
- case 0x0c:
- VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+L; Try legacy boot\n"));
- /* If VbExLegacy() succeeds, it will never return.
- * If it returns, beep.
- */
- if (allow_legacy)
- VbExLegacy();
- else
- VBDEBUG(("VbBootDeveloper() - Legacy boot is disabled\n"));
-
- VbExBeep(120, 400);
- VbExSleepMs(120);
- VbExBeep(120, 400);
- break;
- /* The Ctrl-Enter is special for Lumpy test purpose. */
- case VB_KEY_CTRL_ENTER:
- case 0x15:
- /* Ctrl+U = try USB boot, or beep if failure */
- VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+U; try USB\n"));
- if (!allow_usb) {
- VBDEBUG(("VbBootDeveloper() - USB booting is disabled\n"));
- VbExDisplayDebugInfo("WARNING: Booting from external media (USB/SD) "
- "has not been enabled. Refer to the "
- "developer-mode documentation for details.\n");
- VbExBeep(120, 400);
- VbExSleepMs(120);
- VbExBeep(120, 400);
- } else {
- /* Clear the screen to show we get the Ctrl+U key press. */
- VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
- if (VBERROR_SUCCESS ==
- VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE)) {
- VBDEBUG(("VbBootDeveloper() - booting USB\n"));
- VbAudioClose(audio);
- return VBERROR_SUCCESS;
- } else {
- VBDEBUG(("VbBootDeveloper() - no kernel found on USB\n"));
- VbExBeep(250, 200);
- VbExSleepMs(120);
- /* Clear recovery requests from failed kernel loading, so
- * that powering off at this point doesn't put us into
- * recovery mode. */
- VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
- /* Show the dev mode warning screen again */
- VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
- }
- }
- break;
- default:
- VBDEBUG(("VbBootDeveloper() - pressed key %d\n", key));
- VbCheckDisplayKey(cparams, key, &vnc);
- break;
- }
-
- } while( VbAudioLooping(audio) );
-
-fallout:
- /* Timeout or Ctrl+D; attempt loading from fixed disk */
- VBDEBUG(("VbBootDeveloper() - trying fixed disk\n"));
- VbAudioClose(audio);
- return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
+VbError_t VbBootDeveloper(VbCommonParams *cparams, LoadKernelParams *p)
+{
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ uint32_t allow_usb = 0, allow_legacy = 0;
+ VbAudioContext *audio = 0;
+
+ VBDEBUG(("Entering %s()\n", __func__));
+
+ /* Check if USB booting is allowed */
+ VbNvGet(&vnc, VBNV_DEV_BOOT_USB, &allow_usb);
+ VbNvGet(&vnc, VBNV_DEV_BOOT_LEGACY, &allow_legacy);
+
+ /* Handle GBB flag override */
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_USB)
+ allow_usb = 1;
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_LEGACY)
+ allow_legacy = 1;
+
+ /* Show the dev mode warning screen */
+ VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0, &vnc);
+
+ /* Get audio/delay context */
+ audio = VbAudioOpen(cparams);
+
+ /* We'll loop until we finish the delay or are interrupted */
+ do {
+ uint32_t key;
+
+ if (VbExIsShutdownRequested()) {
+ VBDEBUG(("VbBootDeveloper() - shutdown requested!\n"));
+ VbAudioClose(audio);
+ return VBERROR_SHUTDOWN_REQUESTED;
+ }
+
+ key = VbExKeyboardRead();
+ switch (key) {
+ case 0:
+ /* nothing pressed */
+ break;
+ case '\r':
+ /* Only disable virtual dev switch if allowed by GBB */
+ if (!(gbb->flags & GBB_FLAG_ENTER_TRIGGERS_TONORM))
+ break;
+ case ' ':
+ /* See if we should disable virtual dev-mode switch. */
+ VBDEBUG(("%s shared->flags=0x%x\n",
+ __func__, shared->flags));
+ if (shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
+ shared->flags & VBSD_BOOT_DEV_SWITCH_ON) {
+ /* Stop the countdown while we go ask... */
+ VbAudioClose(audio);
+ if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) {
+ /*
+ * TONORM won't work (only for
+ * non-shipping devices).
+ */
+ VBDEBUG(("%s() - TONORM rejected by "
+ "FORCE_DEV_SWITCH_ON\n",
+ __func__));
+ VbExDisplayDebugInfo(
+ "WARNING: TONORM prohibited by "
+ "GBB FORCE_DEV_SWITCH_ON.\n\n");
+ VbExBeep(120, 400);
+ break;
+ }
+ VbDisplayScreen(cparams,
+ VB_SCREEN_DEVELOPER_TO_NORM,
+ 0, &vnc);
+ /* Ignore space in VbUserConfirms()... */
+ switch (VbUserConfirms(cparams, 0)) {
+ case 1:
+ VBDEBUG(("%s() - leaving dev-mode.\n",
+ __func__));
+ VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST,
+ 1);
+ VbDisplayScreen(
+ cparams,
+ VB_SCREEN_TO_NORM_CONFIRMED,
+ 0, &vnc);
+ VbExSleepMs(5000);
+ return VBERROR_TPM_REBOOT_REQUIRED;
+ case -1:
+ VBDEBUG(("%s() - shutdown requested\n",
+ __func__));
+ return VBERROR_SHUTDOWN_REQUESTED;
+ default:
+ /* Stay in dev-mode */
+ VBDEBUG(("%s() - stay in dev-mode\n",
+ __func__));
+ VbDisplayScreen(
+ cparams,
+ VB_SCREEN_DEVELOPER_WARNING,
+ 0, &vnc);
+ /* Start new countdown */
+ audio = VbAudioOpen(cparams);
+ }
+ } else {
+ /*
+ * No virtual dev-mode switch, so go directly
+ * to recovery mode.
+ */
+ VBDEBUG(("%s() - going to recovery\n",
+ __func__));
+ VbSetRecoveryRequest(
+ VBNV_RECOVERY_RW_DEV_SCREEN);
+ VbAudioClose(audio);
+ return VBERROR_LOAD_KERNEL_RECOVERY;
+ }
+ break;
+ case 0x04:
+ /* Ctrl+D = dismiss warning; advance to timeout */
+ VBDEBUG(("VbBootDeveloper() - "
+ "user pressed Ctrl+D; skip delay\n"));
+ goto fallout;
+ break;
+ case 0x0c:
+ VBDEBUG(("VbBootDeveloper() - "
+ "user pressed Ctrl+L; Try legacy boot\n"));
+ /*
+ * If VbExLegacy() succeeds, it will never return. If
+ * it returns, beep.
+ */
+ if (allow_legacy)
+ VbExLegacy();
+ else
+ VBDEBUG(("VbBootDeveloper() - "
+ "Legacy boot is disabled\n"));
+
+ VbExBeep(120, 400);
+ VbExSleepMs(120);
+ VbExBeep(120, 400);
+ break;
+
+ case VB_KEY_CTRL_ENTER:
+ /*
+ * The Ctrl-Enter is special for Lumpy test purpose;
+ * fall through to Ctrl+U handler.
+ */
+ case 0x15:
+ /* Ctrl+U = try USB boot, or beep if failure */
+ VBDEBUG(("VbBootDeveloper() - "
+ "user pressed Ctrl+U; try USB\n"));
+ if (!allow_usb) {
+ VBDEBUG(("VbBootDeveloper() - "
+ "USB booting is disabled\n"));
+ VbExDisplayDebugInfo(
+ "WARNING: Booting from external media "
+ "(USB/SD) has not been enabled. Refer "
+ "to the developer-mode documentation "
+ "for details.\n");
+ VbExBeep(120, 400);
+ VbExSleepMs(120);
+ VbExBeep(120, 400);
+ } else {
+ /*
+ * Clear the screen to show we get the Ctrl+U
+ * key press.
+ */
+ VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0,
+ &vnc);
+ if (VBERROR_SUCCESS ==
+ VbTryLoadKernel(cparams, p,
+ VB_DISK_FLAG_REMOVABLE)) {
+ VBDEBUG(("VbBootDeveloper() - "
+ "booting USB\n"));
+ VbAudioClose(audio);
+ return VBERROR_SUCCESS;
+ } else {
+ VBDEBUG(("VbBootDeveloper() - "
+ "no kernel found on USB\n"));
+ VbExBeep(250, 200);
+ VbExSleepMs(120);
+ /*
+ * Clear recovery requests from failed
+ * kernel loading, so that powering off
+ * at this point doesn't put us into
+ * recovery mode.
+ */
+ VbSetRecoveryRequest(
+ VBNV_RECOVERY_NOT_REQUESTED);
+ /* Show dev mode warning screen again */
+ VbDisplayScreen(
+ cparams,
+ VB_SCREEN_DEVELOPER_WARNING,
+ 0, &vnc);
+ }
+ }
+ break;
+ default:
+ VBDEBUG(("VbBootDeveloper() - pressed key %d\n", key));
+ VbCheckDisplayKey(cparams, key, &vnc);
+ break;
+ }
+ } while(VbAudioLooping(audio));
+
+ fallout:
+ /* Timeout or Ctrl+D; attempt loading from fixed disk */
+ VBDEBUG(("VbBootDeveloper() - trying fixed disk\n"));
+ VbAudioClose(audio);
+ return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED);
}
/* Delay in recovery mode */
#define REC_DISK_DELAY 1000 /* Check disks every 1s */
#define REC_KEY_DELAY 20 /* Check keys every 20ms */
-/* Handle a recovery-mode boot */
-VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- uint32_t retval;
- uint32_t key;
- int i;
-
- VBDEBUG(("VbBootRecovery() start\n"));
-
- /* If the dev-mode switch is off and the user didn't press the recovery
- * button, require removal of all external media. */
- if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
- !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
- VbDiskInfo* disk_info = NULL;
- uint32_t disk_count = 0;
-
- VBDEBUG(("VbBootRecovery() forcing device removal\n"));
-
- while (1) {
- if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count,
- VB_DISK_FLAG_REMOVABLE))
- disk_count = 0;
- VbExDiskFreeInfo(disk_info, NULL);
-
- if (0 == disk_count) {
- VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
- break;
- }
-
- VBDEBUG(("VbBootRecovery() waiting for %d disks to be removed\n",
- (int)disk_count));
-
- VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_REMOVE, 0, &vnc);
-
- /* Scan keyboard more frequently than media, since x86 platforms
- * don't like to scan USB too rapidly. */
- for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
- VbCheckDisplayKey(cparams, VbExKeyboardRead(), &vnc);
- if (VbExIsShutdownRequested())
- return VBERROR_SHUTDOWN_REQUESTED;
- VbExSleepMs(REC_KEY_DELAY);
- }
- }
- }
-
- /* Loop and wait for a recovery image */
- while (1) {
- VBDEBUG(("VbBootRecovery() attempting to load kernel2\n"));
- retval = VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE);
-
- /* Clear recovery requests from failed kernel loading, since we're
- * already in recovery mode. Do this now, so that powering off after
- * inserting an invalid disk doesn't leave us stuck in recovery mode. */
- VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
-
- if (VBERROR_SUCCESS == retval)
- break; /* Found a recovery kernel */
-
- VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ?
- VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD,
- 0, &vnc);
-
- /* Scan keyboard more frequently than media, since x86 platforms don't like
- * to scan USB too rapidly. */
- for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
- key = VbExKeyboardRead();
- /* We might want to enter dev-mode from the Insert screen if... */
- if (key == 0x04 && /* user pressed Ctrl-D */
- shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH && /* we can do that */
- !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && /* not in dev-mode */
- (shared->flags & VBSD_BOOT_REC_SWITCH_ON) && /* user forced rec */
- VbExTrustEC()) { /* EC isn't pwned */
- /* Ask the user to confirm entering dev-mode */
- VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_TO_DEV, 0, &vnc);
- switch (VbUserConfirms(cparams, 1)) { /* SPACE means no */
- case 1:
- VBDEBUG(("%s() - Enabling dev-mode...\n", __func__));
- if (TPM_SUCCESS != SetVirtualDevMode(1))
- return VBERROR_TPM_SET_BOOT_MODE_STATE;
- VBDEBUG(("%s() - Reboot so it will take effect\n", __func__));
- return VBERROR_TPM_REBOOT_REQUIRED;
- case -1:
- VBDEBUG(("%s() - Shutdown requested\n", __func__));
- return VBERROR_SHUTDOWN_REQUESTED;
- default: /* zero, actually */
- VBDEBUG(("%s() - Not enabling dev-mode\n", __func__));
- /* Jump out of the outer loop to refresh the display quickly. */
- i = 4;
- break;
- }
- } else
- VbCheckDisplayKey(cparams, key, &vnc);
- if (VbExIsShutdownRequested())
- return VBERROR_SHUTDOWN_REQUESTED;
- VbExSleepMs(REC_KEY_DELAY);
- }
- }
-
- return VBERROR_SUCCESS;
+VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ uint32_t retval;
+ uint32_t key;
+ int i;
+
+ VBDEBUG(("VbBootRecovery() start\n"));
+
+ /*
+ * If the dev-mode switch is off and the user didn't press the recovery
+ * button, require removal of all external media.
+ */
+ if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
+ !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) {
+ VbDiskInfo *disk_info = NULL;
+ uint32_t disk_count = 0;
+
+ VBDEBUG(("VbBootRecovery() forcing device removal\n"));
+
+ while (1) {
+ if (VBERROR_SUCCESS !=
+ VbExDiskGetInfo(&disk_info, &disk_count,
+ VB_DISK_FLAG_REMOVABLE))
+ disk_count = 0;
+
+ VbExDiskFreeInfo(disk_info, NULL);
+
+ if (0 == disk_count) {
+ VbDisplayScreen(cparams, VB_SCREEN_BLANK,
+ 0, &vnc);
+ break;
+ }
+
+ VBDEBUG(("VbBootRecovery() "
+ "waiting for %d disks to be removed\n",
+ (int)disk_count));
+
+ VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_REMOVE,
+ 0, &vnc);
+
+ /*
+ * Scan keyboard more frequently than media, since x86
+ * platforms don't like to scan USB too rapidly.
+ */
+ for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
+ VbCheckDisplayKey(cparams, VbExKeyboardRead(),
+ &vnc);
+ if (VbExIsShutdownRequested())
+ return VBERROR_SHUTDOWN_REQUESTED;
+ VbExSleepMs(REC_KEY_DELAY);
+ }
+ }
+ }
+
+ /* Loop and wait for a recovery image */
+ while (1) {
+ VBDEBUG(("VbBootRecovery() attempting to load kernel2\n"));
+ retval = VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE);
+
+ /*
+ * Clear recovery requests from failed kernel loading, since
+ * we're already in recovery mode. Do this now, so that
+ * powering off after inserting an invalid disk doesn't leave
+ * us stuck in recovery mode.
+ */
+ VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
+
+ if (VBERROR_SUCCESS == retval)
+ break; /* Found a recovery kernel */
+
+ VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ?
+ VB_SCREEN_RECOVERY_INSERT :
+ VB_SCREEN_RECOVERY_NO_GOOD,
+ 0, &vnc);
+
+ /*
+ * Scan keyboard more frequently than media, since x86
+ * platforms don't like to scan USB too rapidly.
+ */
+ for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) {
+ key = VbExKeyboardRead();
+ /*
+ * We might want to enter dev-mode from the Insert
+ * screen if all of the following are true:
+ * - user pressed Ctrl-D
+ * - we can honor the virtual dev switch
+ * - not already in dev mode
+ * - user forced recovery mode
+ * - EC isn't pwned
+ */
+ if (key == 0x04 &&
+ shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH &&
+ !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) &&
+ (shared->flags & VBSD_BOOT_REC_SWITCH_ON) &&
+ VbExTrustEC()) {
+ /* Ask the user to confirm entering dev-mode */
+ VbDisplayScreen(cparams,
+ VB_SCREEN_RECOVERY_TO_DEV,
+ 0, &vnc);
+ /* SPACE means no... */
+ switch (VbUserConfirms(cparams, 1)) {
+ case 1:
+ VBDEBUG(("%s() Enabling dev-mode...\n",
+ __func__));
+ if (TPM_SUCCESS != SetVirtualDevMode(1))
+ return VBERROR_TPM_SET_BOOT_MODE_STATE;
+ VBDEBUG(("%s() Reboot so it will take "
+ "effect\n", __func__));
+ return VBERROR_TPM_REBOOT_REQUIRED;
+ case -1:
+ VBDEBUG(("%s() - Shutdown requested\n",
+ __func__));
+ return VBERROR_SHUTDOWN_REQUESTED;
+ default: /* zero, actually */
+ VBDEBUG(("%s() - Not enabling "
+ "dev-mode\n", __func__));
+ /*
+ * Jump out of the outer loop to
+ * refresh the display quickly.
+ */
+ i = 4;
+ break;
+ }
+ } else {
+ VbCheckDisplayKey(cparams, key, &vnc);
+ }
+ if (VbExIsShutdownRequested())
+ return VBERROR_SHUTDOWN_REQUESTED;
+ VbExSleepMs(REC_KEY_DELAY);
+ }
+ }
+
+ return VBERROR_SUCCESS;
}
-/* Wrapper around VbExEcProtectRW() which sets recovery reason on error */
-static VbError_t EcProtectRW(void) {
- int rv = VbExEcProtectRW();
-
- if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
- VBDEBUG(("VbExEcProtectRW() needs reboot\n"));
- } else if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbExEcProtectRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_PROTECT);
- }
- return rv;
+/**
+ * Wrapper around VbExEcProtectRW() which sets recovery reason on error.
+ */
+static VbError_t EcProtectRW(void)
+{
+ int rv = VbExEcProtectRW();
+
+ if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
+ VBDEBUG(("VbExEcProtectRW() needs reboot\n"));
+ } else if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbExEcProtectRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_PROTECT);
+ }
+ return rv;
}
-VbError_t VbEcSoftwareSync(VbCommonParams* cparams) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- int in_rw = 0;
- int rv;
- const uint8_t *ec_hash;
- int ec_hash_size;
- const uint8_t *expected;
- int expected_size;
- uint8_t expected_hash[SHA256_DIGEST_SIZE];
- int need_update;
- int i;
-
- /* Determine whether the EC is in RO or RW */
- rv = VbExEcRunningRW(&in_rw);
-
- if (shared->recovery_reason) {
- /* Recovery mode; just verify the EC is in RO code */
- if (rv == VBERROR_SUCCESS && in_rw == 1) {
- /* EC is definitely in RW firmware. We want it in read-only code, so
- * preserve the current recovery reason and reboot.
- *
- * We don't reboot on error or unknown EC code, because we could end
- * up in an endless reboot loop. If we had some way to track that we'd
- * already rebooted for this reason, we could retry only once. */
- VBDEBUG(("VbEcSoftwareSync() - want recovery but got EC-RW\n"));
- VbSetRecoveryRequest(shared->recovery_reason);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
- return VBERROR_SUCCESS;
- }
-
- /* Not in recovery. If we couldn't determine where the EC was,
- * reboot to recovery. */
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - VbEcSoftwareSync() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /* If AP is read-only normal, EC should be in its RO code also. */
- if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
- /* If EC is in RW code, request reboot back to RO */
- if (in_rw == 1) {
- VBDEBUG(("VbEcSoftwareSync() - want RO-normal but got EC-RW\n"));
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /* Protect the RW flash and stay in EC-RO */
- rv = EcProtectRW();
- if (rv != VBERROR_SUCCESS)
- return rv;
-
- rv = VbExEcStayInRO();
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - VbExEcStayInRO() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
-
- /* If shutdown is requested, just power the AP back off. This covers the
- * case where the lid is closed when then system boots. */
- if (VbExIsShutdownRequested()) {
- VBDEBUG(("VbEcSoftwareSync() sees shutdown-requested\n"));
- return VBERROR_SHUTDOWN_REQUESTED;
- }
-
- return VBERROR_SUCCESS;
- }
-
- /* Get hash of EC-RW */
- rv = VbExEcHashRW(&ec_hash, &ec_hash_size);
- if (rv) {
- VBDEBUG(("VbEcSoftwareSync() - VbExEcHashRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- if (ec_hash_size != SHA256_DIGEST_SIZE) {
- VBDEBUG(("VbEcSoftwareSync() - VbExEcHashRW() says size %d, not %d\n",
- ec_hash_size, SHA256_DIGEST_SIZE));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("EC hash:"));
- for (i = 0; i < SHA256_DIGEST_SIZE; i++)
- VBDEBUG(("%02x", ec_hash[i]));
- VBDEBUG(("\n"));
-
- /* Get expected EC-RW code. Note that we've already checked for RO_NORMAL,
- * so we know that the BIOS must be RW-A or RW-B, and therefore the EC must
- * match. */
- rv = VbExEcGetExpectedRW(
- shared->firmware_index ? VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
- &expected, &expected_size);
- if (rv) {
- VBDEBUG(("VbEcSoftwareSync() - VbExEcGetExpectedRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
- VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n", expected_size));
-
- /* Hash expected code */
- internal_SHA256(expected, expected_size, expected_hash);
- VBDEBUG(("Expected hash:"));
- for (i = 0; i < SHA256_DIGEST_SIZE; i++)
- VBDEBUG(("%02x", expected_hash[i]));
- VBDEBUG(("\n"));
-
- need_update = SafeMemcmp(ec_hash, expected_hash, SHA256_DIGEST_SIZE);
-
- /* TODO: GBB flag to override whether we need update; needed for EC
- * development */
-
- if (in_rw) {
- if (need_update) {
- /* EC is running the wrong RW code. Reboot the EC to RO so we can update
- * it on the next boot. */
- VBDEBUG(("VbEcSoftwareSync() - in RW, need to update RW, so reboot\n"));
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("VbEcSoftwareSync() in EC-RW and it matches\n"));
- return VBERROR_SUCCESS;
- }
-
- /* Update EC if necessary */
- if (need_update) {
- VBDEBUG(("VbEcSoftwareSync() updating EC-RW...\n"));
-
- if (shared->flags & VBSD_EC_SLOW_UPDATE) {
- VBDEBUG(("VbEcSoftwareSync() - EC is slow. Show WAIT screen.\n"));
- /* FIXME(crosbug.com/p/12257): Ensure the VGA Option ROM is loaded! */
- VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
- }
-
- rv = VbExEcUpdateRW(expected, expected_size);
- if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
- /* Reboot required. May need to unprotect RW before updating,
- * or may need to reboot after RW updated. Either way, it's not
- * an error requiring recovery mode. */
- VBDEBUG(("VbEcSoftwareSync() - VbExEcUpdateRW() needs reboot\n"));
- return rv;
- } else if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - VbExEcUpdateRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- /*
- * TODO: should ask EC to recompute its hash to verify it's correct
- * before continuing?
- */
- }
-
- /* Protect EC-RW flash */
- rv = EcProtectRW();
- if (rv != VBERROR_SUCCESS)
- return rv;
-
- /* Tell EC to jump to its RW code */
- VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
- rv = VbExEcJumpToRW();
- if (rv != VBERROR_SUCCESS) {
- VBDEBUG(("VbEcSoftwareSync() - VbExEcJumpToRW() returned %d\n", rv));
- VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
- return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
- }
-
- VBDEBUG(("VbEcSoftwareSync() in RW; done\n"));
-
- /* If shutdown is requested, just power the AP back off. This covers the
- * case where the lid is closed when then system boots. */
- if (VbExIsShutdownRequested()) {
- VBDEBUG(("VbEcSoftwareSync() sees shutdown-requested\n"));
- return VBERROR_SHUTDOWN_REQUESTED;
- }
-
- return VBERROR_SUCCESS;
+VbError_t VbEcSoftwareSync(VbCommonParams *cparams)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ int in_rw = 0;
+ int rv;
+ const uint8_t *ec_hash = NULL;
+ int ec_hash_size;
+ const uint8_t *rw_hash = NULL;
+ int rw_hash_size;
+ const uint8_t *expected = NULL;
+ int expected_size;
+ uint8_t expected_hash[SHA256_DIGEST_SIZE];
+ int need_update = 0;
+ int i;
+
+ /* Determine whether the EC is in RO or RW */
+ rv = VbExEcRunningRW(&in_rw);
+
+ if (shared->recovery_reason) {
+ /* Recovery mode; just verify the EC is in RO code */
+ if (rv == VBERROR_SUCCESS && in_rw == 1) {
+ /*
+ * EC is definitely in RW firmware. We want it in
+ * read-only code, so preserve the current recovery
+ * reason and reboot.
+ *
+ * We don't reboot on error or unknown EC code, because
+ * we could end up in an endless reboot loop. If we
+ * had some way to track that we'd already rebooted for
+ * this reason, we could retry only once.
+ */
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "want recovery but got EC-RW\n"));
+ VbSetRecoveryRequest(shared->recovery_reason);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() in recovery; EC-RO\n"));
+ return VBERROR_SUCCESS;
+ }
+
+ /*
+ * Not in recovery. If we couldn't determine where the EC was,
+ * reboot to recovery.
+ */
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbEcEcRunningRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_UNKNOWN_IMAGE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /* If AP is read-only normal, EC should be in its RO code also. */
+ if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
+ /* If EC is in RW code, request reboot back to RO */
+ if (in_rw == 1) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "want RO-normal but got EC-RW\n"));
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /* Protect the RW flash and stay in EC-RO */
+ rv = EcProtectRW();
+ if (rv != VBERROR_SUCCESS)
+ return rv;
+
+ rv = VbExEcStayInRO();
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcStayInRO() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_SOFTWARE_SYNC);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() in RO-Normal; EC-RO\n"));
+
+ /*
+ * If shutdown is requested, just power the AP back off. This
+ * covers the case where the lid is closed when then system
+ * boots.
+ */
+ if (VbExIsShutdownRequested()) {
+ VBDEBUG(("VbEcSoftwareSync() "
+ "sees shutdown-requested\n"));
+ return VBERROR_SHUTDOWN_REQUESTED;
+ }
+
+ return VBERROR_SUCCESS;
+ }
+
+ /* Get hash of EC-RW */
+ rv = VbExEcHashRW(&ec_hash, &ec_hash_size);
+ if (rv) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcHashRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_FAILED);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ if (ec_hash_size != SHA256_DIGEST_SIZE) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcHashRW() says size %d, not %d\n",
+ ec_hash_size, SHA256_DIGEST_SIZE));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_SIZE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("EC hash:"));
+ for (i = 0; i < SHA256_DIGEST_SIZE; i++)
+ VBDEBUG(("%02x", ec_hash[i]));
+ VBDEBUG(("\n"));
+
+ /*
+ * Get expected EC-RW hash. Note that we've already checked for
+ * RO_NORMAL, so we know that the BIOS must be RW-A or RW-B, and
+ * therefore the EC must match.
+ */
+ rv = VbExEcGetExpectedRWHash(shared->firmware_index ?
+ VB_SELECT_FIRMWARE_B : VB_SELECT_FIRMWARE_A,
+ &rw_hash, &rw_hash_size);
+
+ if (rv == VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE) {
+ /*
+ * BIOS has verified EC image but doesn't have a precomputed
+ * hash for it, so we must compute the hash ourselves.
+ */
+ rw_hash = NULL;
+ } else if (rv) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRWHash() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ } else if (rw_hash_size != SHA256_DIGEST_SIZE) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRWHash() says size %d, not %d\n",
+ rw_hash_size, SHA256_DIGEST_SIZE));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_HASH);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ } else {
+ VBDEBUG(("Expected hash:"));
+ for (i = 0; i < SHA256_DIGEST_SIZE; i++)
+ VBDEBUG(("%02x", rw_hash[i]));
+ VBDEBUG(("\n"));
+
+ need_update = SafeMemcmp(ec_hash, rw_hash, SHA256_DIGEST_SIZE);
+ }
+
+ /*
+ * Get expected EC-RW image if we're sure we need to update (because the
+ * expected hash didn't match the EC) or we still don't know (because
+ * there was no expected hash and we need the image to compute one
+ * ourselves).
+ */
+ if (need_update || !rw_hash) {
+ /* Get expected EC-RW image */
+ rv = VbExEcGetExpectedRW(shared->firmware_index ?
+ VB_SELECT_FIRMWARE_B :
+ VB_SELECT_FIRMWARE_A,
+ &expected, &expected_size);
+ if (rv) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_EXPECTED_IMAGE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+ VBDEBUG(("VbEcSoftwareSync() - expected len = %d\n",
+ expected_size));
+
+ /* Hash expected image */
+ internal_SHA256(expected, expected_size, expected_hash);
+ VBDEBUG(("Computed hash of expected image:"));
+ for (i = 0; i < SHA256_DIGEST_SIZE; i++)
+ VBDEBUG(("%02x", expected_hash[i]));
+ VBDEBUG(("\n"));
+ }
+
+ if (!rw_hash) {
+ /*
+ * BIOS didn't have expected EC hash, so check if we need
+ * update by comparing EC hash to the one we just computed.
+ */
+ need_update = SafeMemcmp(ec_hash, expected_hash,
+ SHA256_DIGEST_SIZE);
+ } else if (need_update &&
+ SafeMemcmp(rw_hash, expected_hash, SHA256_DIGEST_SIZE)) {
+ /*
+ * We need to update, but the expected EC image doesn't match
+ * the expected EC hash we were given.
+ */
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcGetExpectedRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_HASH_MISMATCH);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /*
+ * TODO: GBB flag to override whether we need update; needed for EC
+ * development.
+ */
+
+ if (in_rw) {
+ if (need_update) {
+ /*
+ * EC is running the wrong RW image. Reboot the EC to
+ * RO so we can update it on the next boot.
+ */
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "in RW, need to update RW, so reboot\n"));
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() in EC-RW and it matches\n"));
+
+ /*
+ * If shutdown is requested, just power the AP back off. This
+ * covers the case where the lid is closed when then system
+ * boots.
+ */
+ if (VbExIsShutdownRequested()) {
+ VBDEBUG(("VbEcSoftwareSync() "
+ "sees shutdown-requested\n"));
+ return VBERROR_SHUTDOWN_REQUESTED;
+ }
+
+ return VBERROR_SUCCESS;
+ }
+
+ /* Update EC if necessary */
+ if (need_update) {
+ VBDEBUG(("VbEcSoftwareSync() updating EC-RW...\n"));
+
+ if (shared->flags & VBSD_EC_SLOW_UPDATE) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "EC is slow. Show WAIT screen.\n"));
+ /*
+ * FIXME(crosbug.com/p/12257): Ensure the VGA Option
+ * ROM is loaded!
+ */
+ VbDisplayScreen(cparams, VB_SCREEN_WAIT, 0, &vnc);
+ }
+
+ rv = VbExEcUpdateRW(expected, expected_size);
+ if (rv == VBERROR_EC_REBOOT_TO_RO_REQUIRED) {
+ /*
+ * Reboot required. May need to unprotect RW before
+ * updating, or may need to reboot after RW updated.
+ * Either way, it's not an error requiring recovery
+ * mode.
+ */
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcUpdateRW() needs reboot\n"));
+ return rv;
+ } else if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcUpdateRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_UPDATE);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ /*
+ * TODO: should ask EC to recompute its hash to verify it's
+ * correct before continuing?
+ */
+ }
+
+ /* Protect EC-RW flash */
+ rv = EcProtectRW();
+ if (rv != VBERROR_SUCCESS)
+ return rv;
+
+ /* Tell EC to jump to its RW image */
+ VBDEBUG(("VbEcSoftwareSync() jumping to EC-RW\n"));
+ rv = VbExEcJumpToRW();
+ if (rv != VBERROR_SUCCESS) {
+ VBDEBUG(("VbEcSoftwareSync() - "
+ "VbExEcJumpToRW() returned %d\n", rv));
+ VbSetRecoveryRequest(VBNV_RECOVERY_EC_JUMP_RW);
+ return VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ }
+
+ VBDEBUG(("VbEcSoftwareSync() in RW; done\n"));
+
+ /*
+ * If shutdown is requested, just power the AP back off. This covers
+ * the case where the lid is closed when then system boots.
+ */
+ if (VbExIsShutdownRequested()) {
+ VBDEBUG(("VbEcSoftwareSync() sees shutdown-requested\n"));
+ return VBERROR_SHUTDOWN_REQUESTED;
+ }
+
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams,
- VbSelectAndLoadKernelParams* kparams) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- VbError_t retval = VBERROR_SUCCESS;
- LoadKernelParams p;
- uint32_t tpm_status = 0;
-
- /* Start timer */
- shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
-
- VbExNvStorageRead(vnc.raw);
- VbNvSetup(&vnc);
-
- /* Clear output params in case we fail */
- kparams->disk_handle = NULL;
- kparams->partition_number = 0;
- kparams->bootloader_address = 0;
- kparams->bootloader_size = 0;
- Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
-
- /* Do EC software sync if necessary */
- if (shared->flags & VBSD_EC_SOFTWARE_SYNC) {
- retval = VbEcSoftwareSync(cparams);
- if (retval != VBERROR_SUCCESS)
- goto VbSelectAndLoadKernel_exit;
- }
-
- /* Read the kernel version from the TPM. Ignore errors in recovery mode. */
- tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
- if (0 != tpm_status) {
- VBDEBUG(("Unable to get kernel versions from TPM\n"));
- if (!shared->recovery_reason) {
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_R_ERROR);
- retval = VBERROR_TPM_READ_KERNEL;
- goto VbSelectAndLoadKernel_exit;
- }
- }
- shared->kernel_version_tpm_start = shared->kernel_version_tpm;
-
- /* Fill in params for calls to LoadKernel() */
- Memset(&p, 0, sizeof(p));
- p.shared_data_blob = cparams->shared_data_blob;
- p.shared_data_size = cparams->shared_data_size;
- p.gbb_data = cparams->gbb_data;
- p.gbb_size = cparams->gbb_size;
-
- /*
- * this could be set to NULL, in which case the vboot header information
- * about the load address and size will be used
- */
- p.kernel_buffer = kparams->kernel_buffer;
- p.kernel_buffer_size = kparams->kernel_buffer_size;
-
- p.nv_context = &vnc;
- p.boot_flags = 0;
- if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON)
- p.boot_flags |= BOOT_FLAG_DEVELOPER;
-
- /* Handle separate normal and developer firmware builds. */
+VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
+ VbSelectAndLoadKernelParams *kparams)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ VbError_t retval = VBERROR_SUCCESS;
+ LoadKernelParams p;
+ uint32_t tpm_status = 0;
+
+ /* Start timer */
+ shared->timer_vb_select_and_load_kernel_enter = VbExGetTimer();
+
+ VbExNvStorageRead(vnc.raw);
+ VbNvSetup(&vnc);
+
+ /* Clear output params in case we fail */
+ kparams->disk_handle = NULL;
+ kparams->partition_number = 0;
+ kparams->bootloader_address = 0;
+ kparams->bootloader_size = 0;
+ Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
+
+ /* Do EC software sync if necessary */
+ if (shared->flags & VBSD_EC_SOFTWARE_SYNC) {
+ retval = VbEcSoftwareSync(cparams);
+ if (retval != VBERROR_SUCCESS)
+ goto VbSelectAndLoadKernel_exit;
+ }
+
+ /* Read kernel version from the TPM. Ignore errors in recovery mode. */
+ tpm_status = RollbackKernelRead(&shared->kernel_version_tpm);
+ if (0 != tpm_status) {
+ VBDEBUG(("Unable to get kernel versions from TPM\n"));
+ if (!shared->recovery_reason) {
+ VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_R_ERROR);
+ retval = VBERROR_TPM_READ_KERNEL;
+ goto VbSelectAndLoadKernel_exit;
+ }
+ }
+ shared->kernel_version_tpm_start = shared->kernel_version_tpm;
+
+ /* Fill in params for calls to LoadKernel() */
+ Memset(&p, 0, sizeof(p));
+ p.shared_data_blob = cparams->shared_data_blob;
+ p.shared_data_size = cparams->shared_data_size;
+ p.gbb_data = cparams->gbb_data;
+ p.gbb_size = cparams->gbb_size;
+
+ /*
+ * This could be set to NULL, in which case the vboot header
+ * information about the load address and size will be used.
+ */
+ p.kernel_buffer = kparams->kernel_buffer;
+ p.kernel_buffer_size = kparams->kernel_buffer_size;
+
+ p.nv_context = &vnc;
+ p.boot_flags = 0;
+ if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON)
+ p.boot_flags |= BOOT_FLAG_DEVELOPER;
+
+ /* Handle separate normal and developer firmware builds. */
#if defined(VBOOT_FIRMWARE_TYPE_NORMAL)
- /* Normal-type firmware always acts like the dev switch is off. */
- p.boot_flags &= ~BOOT_FLAG_DEVELOPER;
+ /* Normal-type firmware always acts like the dev switch is off. */
+ p.boot_flags &= ~BOOT_FLAG_DEVELOPER;
#elif defined(VBOOT_FIRMWARE_TYPE_DEVELOPER)
- /* Developer-type firmware fails if the dev switch is off. */
- if (!(p.boot_flags & BOOT_FLAG_DEVELOPER)) {
- /* Dev firmware should be signed with a key that only verifies
- * when the dev switch is on, so we should never get here. */
- VBDEBUG(("Developer firmware called with dev switch off!\n"));
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH);
- retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH;
- goto VbSelectAndLoadKernel_exit;
- }
+ /* Developer-type firmware fails if the dev switch is off. */
+ if (!(p.boot_flags & BOOT_FLAG_DEVELOPER)) {
+ /*
+ * Dev firmware should be signed with a key that only verifies
+ * when the dev switch is on, so we should never get here.
+ */
+ VBDEBUG(("Developer firmware called with dev switch off!\n"));
+ VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_MISMATCH);
+ retval = VBERROR_DEV_FIRMWARE_SWITCH_MISMATCH;
+ goto VbSelectAndLoadKernel_exit;
+ }
#else
- /* Recovery firmware, or merged normal+developer firmware. No
- * need to override flags. */
+ /*
+ * Recovery firmware, or merged normal+developer firmware. No need to
+ * override flags.
+ */
#endif
- /* Select boot path */
- if (shared->recovery_reason) {
- /* Recovery boot */
- p.boot_flags |= BOOT_FLAG_RECOVERY;
- retval = VbBootRecovery(cparams, &p);
- VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
-
- } else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
- /* Developer boot */
- retval = VbBootDeveloper(cparams, &p);
- VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
-
- } else {
- /* Normal boot */
- retval = VbBootNormal(cparams, &p);
-
- if ((1 == shared->firmware_index) && (shared->flags & VBSD_FWB_TRIED)) {
- /* Special cases for when we're trying a new firmware B. These are
- * needed because firmware updates also usually change the kernel key,
- * which means that the B firmware can only boot a new kernel, and the
- * old firmware in A can only boot the previous kernel. */
-
- /* Don't advance the TPM if we're trying a new firmware B, because we
- * don't yet know if the new kernel will successfully boot. We still
- * want to be able to fall back to the previous firmware+kernel if the
- * new firmware+kernel fails. */
-
- /* If we found only invalid kernels, reboot and try again. This allows
- * us to fall back to the previous firmware+kernel instead of giving up
- * and going to recovery mode right away. We'll still go to recovery
- * mode if we run out of tries and the old firmware can't find a kernel
- * it likes. */
- if (VBERROR_INVALID_KERNEL_FOUND == retval) {
- VBDEBUG(("Trying firmware B, and only found invalid kernels.\n"));
- VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
- goto VbSelectAndLoadKernel_exit;
- }
- } else {
- /* Not trying a new firmware B. */
- /* See if we need to update the TPM. */
- VBDEBUG(("Checking if TPM kernel version needs advancing\n"));
- if (shared->kernel_version_tpm > shared->kernel_version_tpm_start) {
- tpm_status = RollbackKernelWrite(shared->kernel_version_tpm);
- if (0 != tpm_status) {
- VBDEBUG(("Error writing kernel versions to TPM.\n"));
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_W_ERROR);
- retval = VBERROR_TPM_WRITE_KERNEL;
- goto VbSelectAndLoadKernel_exit;
- }
- }
- }
- }
-
- if (VBERROR_SUCCESS != retval)
- goto VbSelectAndLoadKernel_exit;
-
- /* Save disk parameters */
- kparams->disk_handle = p.disk_handle;
- kparams->partition_number = (uint32_t)p.partition_number;
- kparams->bootloader_address = p.bootloader_address;
- kparams->bootloader_size = (uint32_t)p.bootloader_size;
- Memcpy(kparams->partition_guid, p.partition_guid,
- sizeof(kparams->partition_guid));
-
- /* Lock the kernel versions. Ignore errors in recovery mode. */
- tpm_status = RollbackKernelLock();
- if (0 != tpm_status) {
- VBDEBUG(("Error locking kernel versions.\n"));
- if (!shared->recovery_reason) {
- VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_L_ERROR);
- retval = VBERROR_TPM_LOCK_KERNEL;
- goto VbSelectAndLoadKernel_exit;
- }
- }
-
-VbSelectAndLoadKernel_exit:
-
- VbNvTeardown(&vnc);
- if (vnc.raw_changed)
- VbExNvStorageWrite(vnc.raw);
-
- /* Stop timer */
- shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
-
- kparams->kernel_buffer = p.kernel_buffer;
- kparams->kernel_buffer_size = p.kernel_buffer_size;
-
- VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
-
- /* Pass through return value from boot path */
- return retval;
+ /* Select boot path */
+ if (shared->recovery_reason) {
+ /* Recovery boot */
+ p.boot_flags |= BOOT_FLAG_RECOVERY;
+ retval = VbBootRecovery(cparams, &p);
+ VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
+
+ } else if (p.boot_flags & BOOT_FLAG_DEVELOPER) {
+ /* Developer boot */
+ retval = VbBootDeveloper(cparams, &p);
+ VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc);
+
+ } else {
+ /* Normal boot */
+ retval = VbBootNormal(cparams, &p);
+
+ if ((1 == shared->firmware_index) &&
+ (shared->flags & VBSD_FWB_TRIED)) {
+ /*
+ * Special cases for when we're trying a new firmware
+ * B. These are needed because firmware updates also
+ * usually change the kernel key, which means that the
+ * B firmware can only boot a new kernel, and the old
+ * firmware in A can only boot the previous kernel.
+ *
+ * Don't advance the TPM if we're trying a new firmware
+ * B, because we don't yet know if the new kernel will
+ * successfully boot. We still want to be able to fall
+ * back to the previous firmware+kernel if the new
+ * firmware+kernel fails.
+ *
+ * If we found only invalid kernels, reboot and try
+ * again. This allows us to fall back to the previous
+ * firmware+kernel instead of giving up and going to
+ * recovery mode right away. We'll still go to
+ * recovery mode if we run out of tries and the old
+ * firmware can't find a kernel it likes.
+ */
+ if (VBERROR_INVALID_KERNEL_FOUND == retval) {
+ VBDEBUG(("Trying firmware B, "
+ "and only found invalid kernels.\n"));
+ VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED);
+ goto VbSelectAndLoadKernel_exit;
+ }
+ } else {
+ /* Not trying a new firmware B. */
+
+ /* See if we need to update the TPM. */
+ VBDEBUG(("Checking if TPM kernel version needs "
+ "advancing\n"));
+ if (shared->kernel_version_tpm >
+ shared->kernel_version_tpm_start) {
+ tpm_status = RollbackKernelWrite(
+ shared->kernel_version_tpm);
+ if (0 != tpm_status) {
+ VBDEBUG(("Error writing kernel "
+ "versions to TPM.\n"));
+ VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_W_ERROR);
+ retval = VBERROR_TPM_WRITE_KERNEL;
+ goto VbSelectAndLoadKernel_exit;
+ }
+ }
+ }
+ }
+
+ if (VBERROR_SUCCESS != retval)
+ goto VbSelectAndLoadKernel_exit;
+
+ /* Save disk parameters */
+ kparams->disk_handle = p.disk_handle;
+ kparams->partition_number = (uint32_t)p.partition_number;
+ kparams->bootloader_address = p.bootloader_address;
+ kparams->bootloader_size = (uint32_t)p.bootloader_size;
+ Memcpy(kparams->partition_guid, p.partition_guid,
+ sizeof(kparams->partition_guid));
+
+ /* Lock the kernel versions. Ignore errors in recovery mode. */
+ tpm_status = RollbackKernelLock();
+ if (0 != tpm_status) {
+ VBDEBUG(("Error locking kernel versions.\n"));
+ if (!shared->recovery_reason) {
+ VbSetRecoveryRequest(VBNV_RECOVERY_RW_TPM_L_ERROR);
+ retval = VBERROR_TPM_LOCK_KERNEL;
+ goto VbSelectAndLoadKernel_exit;
+ }
+ }
+
+ VbSelectAndLoadKernel_exit:
+
+ VbNvTeardown(&vnc);
+ if (vnc.raw_changed)
+ VbExNvStorageWrite(vnc.raw);
+
+ /* Stop timer */
+ shared->timer_vb_select_and_load_kernel_exit = VbExGetTimer();
+
+ kparams->kernel_buffer = p.kernel_buffer;
+ kparams->kernel_buffer_size = p.kernel_buffer_size;
+
+ VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval));
+
+ /* Pass through return value from boot path */
+ return retval;
}
diff --git a/firmware/lib/vboot_audio.c b/firmware/lib/vboot_audio.c
index 641bae0f..d89bc43f 100644
--- a/firmware/lib/vboot_audio.c
+++ b/firmware/lib/vboot_audio.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -18,8 +18,10 @@
#define UINT_MAX 4294967295U /* 0xffffffff */
#endif
-/* Need one second of noise in the first 22 seconds.
- * Total delay >= 30 seconds, <= 60 seconds. */
+/*
+ * Need one second of noise in the first 22 seconds.
+ * Total delay >= 30 seconds, <= 60 seconds.
+ */
#define REQUIRED_NOISE_TIME 1000
#define REQUIRED_NOISE_WITHIN 22000
#define REQUIRED_TOTAL_DELAY 30000
@@ -39,238 +41,261 @@ uint32_t short_count_ = sizeof(short_notes_) / sizeof(VbDevMusicNote);
/* No need to dynamically allocate this, is there? */
static VbAudioContext au;
-
/* Convert from msecs to VbExGetTimer() units. */
static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */
static uint64_t VbMsecToTicks(uint16_t msec) {
return ticks_per_msec * msec;
}
-/* Find and return a valid set of note events. We'll use the user's struct
- * if possible, but we will still enforce the 30-second timeout and require at
- * least a second of audible noise within that period. We allocate storage for
- * two reasons: the user's struct will be in flash, which is slow to read, and
- * we may need one extra note at the end to pad out the user's notes to a full
- * 30 seconds. The caller should free it when finished.
+/**
+ * Find and return a valid set of note events.
+ *
+ * We'll use the user's struct if possible, but we will still enforce the
+ * 30-second timeout and require at least a second of audible noise within that
+ * period. We allocate storage for two reasons: the user's struct will be in
+ * flash, which is slow to read, and we may need one extra note at the end to
+ * pad out the user's notes to a full 30 seconds. The caller should free it
+ * when finished.
*/
-static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short) {
- VbDevMusicNote *notebuf = 0;
- VbDevMusicNote *builtin = 0;
- VbDevMusic *hdr = CUSTOM_MUSIC_NOTES;
- uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */
- uint32_t maxnotes, mysum, mylen, i;
- uint32_t this_msecs, on_msecs, total_msecs;
- uint32_t count;
-
- VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, maxsize is %d\n",
- use_short, hdr, maxsize));
-
- if (use_short) {
- builtin = short_notes_;
- count = short_count_;
- goto nope;
- }
-
- builtin = default_notes_;
- count = default_count_;
-
- /* If we can't beep in the background, don't allow customization. */
- if (!audio->background_beep)
- goto nope;
-
- if (!hdr || maxsize < sizeof(VbDevMusic))
- goto nope;
-
- if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
- VBDEBUG(("VbGetDevMusicNotes: bad sig\n"));
- goto nope;
- }
-
- /* How many notes will fit in the flash region? One more than you'd think,
- * because there's one note in the header itself.
- */
- maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
- if (hdr->count == 0 || hdr->count > maxnotes) {
- VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
- hdr->count, maxnotes));
- goto nope;
- }
-
- /* CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash (around 8M
- * or so) so this isn't really necessary, but let's be safe anyway.
- */
- if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
- (sizeof(hdr->count) > UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) {
- VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n"));
- goto nope;
- }
-
- /* Now we know this won't overflow */
- mylen = (uint32_t)(sizeof(hdr->count) + hdr->count * sizeof(VbDevMusicNote));
- mysum = Crc32(&(hdr->count), mylen);
-
- if (mysum != hdr->checksum) {
- VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
- mysum, hdr->checksum));
- goto nope;
- }
-
- VBDEBUG(("VbGetDevMusicNotes: custom notes struct found at %lx\n", hdr));
-
- /* Measure the audible sound up to the first 22 seconds, being careful to
- * avoid rollover. The note time is 16 bits, and the note count is 32 bits.
- * The product should fit in 64 bits.
- */
- total_msecs = 0;
- on_msecs = 0;
- for (i=0; i < hdr->count; i++) {
- this_msecs = hdr->notes[i].msec ;
- if (this_msecs) {
- total_msecs += this_msecs;
- if (total_msecs <= REQUIRED_NOISE_WITHIN &&
- hdr->notes[i].frequency >= 100 && hdr->notes[i].frequency <= 2000)
- on_msecs += this_msecs;
- }
- }
-
- /* We require at least one second of noise in the first 22 seconds */
- VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n",
- on_msecs));
- if (on_msecs < REQUIRED_NOISE_TIME) {
- goto nope;
- }
-
- /* We'll also require that the total time be less than a minute. No real
- * reason, it just gives us less to worry about.
- */
- VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs));
- if (total_msecs > MAX_CUSTOM_DELAY) {
- goto nope;
- }
-
- /* One more check, just to be paranoid. */
- if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
- VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n"));
- goto nope;
- }
-
- /* Okay, it looks good. Allocate the space (plus one) and copy it over. */
- notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote));
- Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
- count = hdr->count;
-
- /* We also require at least 30 seconds of delay. */
- if (total_msecs < REQUIRED_TOTAL_DELAY) {
- /* If the total time is less than 30 seconds, the needed difference will
- * fit in 16 bits.
- */
- this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
- notebuf[hdr->count].msec = this_msecs;
- notebuf[hdr->count].frequency = 0;
- count++;
- VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n",
- this_msecs));
- }
-
- /* done */
- audio->music_notes = notebuf;
- audio->note_count = count;
- audio->free_notes_when_done = 1;
- return;
-
-nope:
- /* No custom notes, use the default. The count is already set. */
- VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count));
- audio->music_notes = builtin;
- audio->note_count = count;
- audio->free_notes_when_done = 0;
+static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short)
+{
+ VbDevMusicNote *notebuf = 0;
+ VbDevMusicNote *builtin = 0;
+ VbDevMusic *hdr = CUSTOM_MUSIC_NOTES;
+ uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */
+ uint32_t maxnotes, mysum, mylen, i;
+ uint32_t this_msecs, on_msecs, total_msecs;
+ uint32_t count;
+
+ VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, "
+ "maxsize is %d\n", use_short, hdr, maxsize));
+
+ if (use_short) {
+ builtin = short_notes_;
+ count = short_count_;
+ goto nope;
+ }
+
+ builtin = default_notes_;
+ count = default_count_;
+
+ /* If we can't beep in the background, don't allow customization. */
+ if (!audio->background_beep)
+ goto nope;
+
+ if (!hdr || maxsize < sizeof(VbDevMusic))
+ goto nope;
+
+ if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
+ VBDEBUG(("VbGetDevMusicNotes: bad sig\n"));
+ goto nope;
+ }
+
+ /*
+ * How many notes will fit in the flash region? One more than you'd
+ * think, because there's one note in the header itself.
+ */
+ maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
+ if (hdr->count == 0 || hdr->count > maxnotes) {
+ VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
+ hdr->count, maxnotes));
+ goto nope;
+ }
+
+ /*
+ * CUSTOM_MUSIC_MAXSIZE can't be larger than the size of the flash
+ * (around 8M or so) so this isn't really necessary, but let's be safe
+ * anyway.
+ */
+ if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
+ (sizeof(hdr->count) >
+ UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) {
+ VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n"));
+ goto nope;
+ }
+
+ /* Now we know this won't overflow */
+ mylen = (uint32_t)(sizeof(hdr->count) +
+ hdr->count * sizeof(VbDevMusicNote));
+ mysum = Crc32(&(hdr->count), mylen);
+
+ if (mysum != hdr->checksum) {
+ VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
+ mysum, hdr->checksum));
+ goto nope;
+ }
+
+ VBDEBUG(("VbGetDevMusicNotes: custom notes struct at %lx\n", hdr));
+
+ /*
+ * Measure the audible sound up to the first 22 seconds, being careful
+ * to avoid rollover. The note time is 16 bits, and the note count is
+ * 32 bits. The product should fit in 64 bits.
+ */
+ total_msecs = 0;
+ on_msecs = 0;
+ for (i=0; i < hdr->count; i++) {
+ this_msecs = hdr->notes[i].msec ;
+ if (this_msecs) {
+ total_msecs += this_msecs;
+ if (total_msecs <= REQUIRED_NOISE_WITHIN &&
+ hdr->notes[i].frequency >= 100 &&
+ hdr->notes[i].frequency <= 2000)
+ on_msecs += this_msecs;
+ }
+ }
+
+ /* We require at least one second of noise in the first 22 seconds */
+ VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n",
+ on_msecs));
+ if (on_msecs < REQUIRED_NOISE_TIME)
+ goto nope;
+
+ /*
+ * We'll also require that the total time be less than a minute. No
+ * real reason, it just gives us less to worry about.
+ */
+ VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs));
+ if (total_msecs > MAX_CUSTOM_DELAY) {
+ goto nope;
+ }
+
+ /* One more check, just to be paranoid. */
+ if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
+ VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n"));
+ goto nope;
+ }
+
+ /* Looks good. Allocate the space (plus one) and copy it over. */
+ notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote));
+ Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
+ count = hdr->count;
+
+ /* We also require at least 30 seconds of delay. */
+ if (total_msecs < REQUIRED_TOTAL_DELAY) {
+ /*
+ * If the total time is less than 30 seconds, the needed
+ * difference will fit in 16 bits.
+ */
+ this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
+ notebuf[hdr->count].msec = this_msecs;
+ notebuf[hdr->count].frequency = 0;
+ count++;
+ VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n",
+ this_msecs));
+ }
+
+ /* Done */
+ audio->music_notes = notebuf;
+ audio->note_count = count;
+ audio->free_notes_when_done = 1;
+ return;
+
+ nope:
+ /* No custom notes, use the default. The count is already set. */
+ VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count));
+ audio->music_notes = builtin;
+ audio->note_count = count;
+ audio->free_notes_when_done = 0;
}
-/* Initialization function. Returns context for processing dev-mode delay */
-VbAudioContext* VbAudioOpen(VbCommonParams* cparams) {
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- VbAudioContext* audio = &au;
- int use_short = 0;
- uint64_t a,b;
-
- /* Note: may need to allocate things here in future */
-
- /* Calibrate audio delay */
- a = VbExGetTimer();
- VbExSleepMs(10);
- b = VbExGetTimer();
- ticks_per_msec = (b - a) / 10ULL ;
- VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec));
-
- /* Initialize */
- Memset(audio, 0, sizeof(*audio));
- audio->background_beep = 1;
- audio->play_until = b; /* "zero" starts now */
-
- /* See if we have full background sound capability or not. */
- if (VBERROR_SUCCESS != VbExBeep(0,0)) {
- VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n"));
- audio->background_beep = 0;
- }
-
- /* Prepare to generate audio/delay event. Use a short developer screen delay
- * if indicated by GBB flags.
- */
- if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
- && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
- VBDEBUG(("VbAudioOpen() - using short developer screen delay\n"));
- use_short = 1;
- }
-
- VbGetDevMusicNotes(audio, use_short);
- VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count));
-
- return audio;
+/**
+ * Initialization function. Returns context for processing dev-mode delay.
+ */
+VbAudioContext *VbAudioOpen(VbCommonParams *cparams)
+{
+ GoogleBinaryBlockHeader* gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ VbAudioContext *audio = &au;
+ int use_short = 0;
+ uint64_t a, b;
+
+ /* Note: may need to allocate things here in future */
+
+ /* Calibrate audio delay */
+ a = VbExGetTimer();
+ VbExSleepMs(10);
+ b = VbExGetTimer();
+ ticks_per_msec = (b - a) / 10ULL ;
+ VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec));
+
+ /* Initialize */
+ Memset(audio, 0, sizeof(*audio));
+ audio->background_beep = 1;
+ audio->play_until = b; /* "zero" starts now */
+
+ /* See if we have full background sound capability or not. */
+ if (VBERROR_SUCCESS != VbExBeep(0,0)) {
+ VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n"));
+ audio->background_beep = 0;
+ }
+
+ /*
+ * Prepare to generate audio/delay event. Use a short developer screen
+ * delay if indicated by GBB flags.
+ */
+ if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
+ && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
+ VBDEBUG(("VbAudioOpen() - using short dev screen delay\n"));
+ use_short = 1;
+ }
+
+ VbGetDevMusicNotes(audio, use_short);
+ VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count));
+
+ return audio;
}
-/* Caller should loop without extra delay until this returns false */
-int VbAudioLooping(VbAudioContext* audio) {
- uint64_t now;
- uint16_t freq = audio->current_frequency;
- uint16_t msec = 0;
- int looping = 1;
+/**
+ * Caller should loop without extra delay until this returns false.
+ */
+int VbAudioLooping(VbAudioContext *audio)
+{
+ uint64_t now;
+ uint16_t freq = audio->current_frequency;
+ uint16_t msec = 0;
+ int looping = 1;
#if defined(CONFIG_SANDBOX)
- return 0;
+ return 0;
#endif
- now = VbExGetTimer();
- while (audio->next_note < audio->note_count && now >= audio->play_until) {
- freq = audio->music_notes[audio->next_note].frequency;
- msec = audio->music_notes[audio->next_note].msec;
- audio->play_until += VbMsecToTicks(msec);
- audio->next_note++;
- }
-
- if (now >= audio->play_until) {
- looping = 0;
- freq = 0;
- }
-
- // Do action here.
- if (audio->background_beep) {
- if (audio->current_frequency != freq) {
- VbExBeep(0, freq);
- audio->current_frequency = freq;
- }
- } else if (freq && msec) {
- VbExBeep(msec, freq);
- now = VbExGetTimer();
- }
-
- audio->last_time = now;
- return looping;
+ now = VbExGetTimer();
+ while (audio->next_note < audio->note_count &&
+ now >= audio->play_until) {
+ freq = audio->music_notes[audio->next_note].frequency;
+ msec = audio->music_notes[audio->next_note].msec;
+ audio->play_until += VbMsecToTicks(msec);
+ audio->next_note++;
+ }
+
+ if (now >= audio->play_until) {
+ looping = 0;
+ freq = 0;
+ }
+
+ /* Do action here. */
+ if (audio->background_beep) {
+ if (audio->current_frequency != freq) {
+ VbExBeep(0, freq);
+ audio->current_frequency = freq;
+ }
+ } else if (freq && msec) {
+ VbExBeep(msec, freq);
+ now = VbExGetTimer();
+ }
+
+ audio->last_time = now;
+ return looping;
}
-/* Caller should call this prior to booting */
-void VbAudioClose(VbAudioContext* audio) {
- VbExBeep(0,0);
- if (audio->free_notes_when_done)
- VbExFree(audio->music_notes);
+/**
+ * Caller should call this prior to booting.
+ */
+void VbAudioClose(VbAudioContext *audio)
+{
+ VbExBeep(0,0);
+ if (audio->free_notes_when_done)
+ VbExFree(audio->music_notes);
}
diff --git a/firmware/lib/vboot_display.c b/firmware/lib/vboot_display.c
index 929cacc2..7c916d01 100644
--- a/firmware/lib/vboot_display.c
+++ b/firmware/lib/vboot_display.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -16,671 +16,721 @@
static uint32_t disp_current_screen = VB_SCREEN_BLANK;
static uint32_t disp_width = 0, disp_height = 0;
-
-/* Get the number of localizations in the GBB bitmap data. */
-static VbError_t VbGetLocalizationCount(VbCommonParams* cparams,
- uint32_t* count) {
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- BmpBlockHeader* hdr;
-
- /* Default to 0 on error */
- *count = 0;
-
- /* Make sure the bitmap data is inside the GBB and is non-zero in size */
- if (0 == gbb->bmpfv_size ||
- gbb->bmpfv_offset > cparams->gbb_size ||
- gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) {
- return VBERROR_INVALID_GBB;
- }
-
- /* Sanity-check the bitmap block header */
- hdr = (BmpBlockHeader *)(((uint8_t*)gbb) + gbb->bmpfv_offset);
- if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
- BMPBLOCK_SIGNATURE_SIZE)) ||
- (hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
- ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
- (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
- return VBERROR_INVALID_BMPFV;
- }
-
- *count = hdr->number_of_localizations;
- return VBERROR_SUCCESS;
+VbError_t VbGetLocalizationCount(VbCommonParams *cparams, uint32_t *count)
+{
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ BmpBlockHeader *hdr;
+
+ /* Default to 0 on error */
+ *count = 0;
+
+ /* Make sure bitmap data is inside the GBB and is non-zero in size */
+ if (0 == gbb->bmpfv_size ||
+ gbb->bmpfv_offset > cparams->gbb_size ||
+ gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) {
+ return VBERROR_INVALID_GBB;
+ }
+
+ /* Sanity-check the bitmap block header */
+ hdr = (BmpBlockHeader *)(((uint8_t *)gbb) + gbb->bmpfv_offset);
+ if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
+ BMPBLOCK_SIGNATURE_SIZE)) ||
+ (hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
+ ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
+ (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
+ return VBERROR_INVALID_BMPFV;
+ }
+
+ *count = hdr->number_of_localizations;
+ return VBERROR_SUCCESS;
}
+char *VbHWID(VbCommonParams *cparams)
+{
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ if (0 == gbb->hwid_size ||
+ gbb->hwid_offset > cparams->gbb_size ||
+ gbb->hwid_offset + gbb->hwid_size > cparams->gbb_size) {
+ VBDEBUG(("VbHWID(): invalid hwid offset/size\n"));
+ return "{INVALID}";
+ }
-/* Return a fixed string representing the HWID */
-static char *VbHWID(VbCommonParams* cparams) {
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- if (0 == gbb->hwid_size ||
- gbb->hwid_offset > cparams->gbb_size ||
- gbb->hwid_offset + gbb->hwid_size > cparams->gbb_size) {
- VBDEBUG(("VbHWID(): invalid hwid offset/size\n"));
- return "{INVALID}";
- }
- return (char*)((uint8_t*)gbb + gbb->hwid_offset);
+ return (char *)((uint8_t *)gbb + gbb->hwid_offset);
}
-
-/* TODO: We could cache the font info to speed things up, by making the
+/*
+ * TODO: We could cache the font info to speed things up, by making the
* in-memory font structure distinct from the in-flash version. We'll do that
* Real Soon Now. Until then, we just repeat the same linear search every time.
*/
typedef FontArrayHeader VbFont_t;
-static VbFont_t *VbInternalizeFontData(FontArrayHeader *fonthdr) {
- /* Just return the raw data pointer for now. */
- return (VbFont_t *)fonthdr;
+VbFont_t *VbInternalizeFontData(FontArrayHeader *fonthdr)
+{
+ /* Just return the raw data pointer for now. */
+ return (VbFont_t *)fonthdr;
}
-static void VbDoneWithFontForNow(VbFont_t *ptr) {
- /* Nothing. */
+void VbDoneWithFontForNow(VbFont_t *ptr)
+{
+ /* Nothing. */
}
-static ImageInfo *VbFindFontGlyph(VbFont_t *font, uint32_t ascii,
- void **bufferptr, uint32_t *buffersize) {
- uint8_t *ptr, *firstptr;
- uint32_t max;
- uint32_t i;
- FontArrayEntryHeader *entry;
-
- ptr = (uint8_t *)font;
- max = ((FontArrayHeader *)ptr)->num_entries;
- ptr += sizeof(FontArrayHeader);
- firstptr = ptr;
-
- /* Simple linear search. */
- for(i=0; i<max; i++)
- {
- entry = (FontArrayEntryHeader *)ptr;
- if (entry->ascii == ascii) {
- /* Note: We're assuming the glpyh is uncompressed. That's true
- * because the bmpblk_font tool doesn't compress anything. The
- * bmpblk_utility does, but it compresses the entire font blob at once,
- * and we've already uncompressed that before we got here.
- */
- *bufferptr = ptr + sizeof(FontArrayEntryHeader);
- *buffersize = entry->info.original_size;
- return &(entry->info);
- }
- ptr += sizeof(FontArrayEntryHeader)+entry->info.compressed_size;
- }
-
- /* NOTE: We must return something valid. We'll just use the first glyph in the
- * font structure (so it should be something distinct).
- */
- entry = (FontArrayEntryHeader *)firstptr;
- *bufferptr = firstptr + sizeof(FontArrayEntryHeader);
- *buffersize = entry->info.original_size;
- return &(entry->info);
+ImageInfo *VbFindFontGlyph(VbFont_t *font, uint32_t ascii,
+ void **bufferptr, uint32_t *buffersize)
+{
+ uint8_t *ptr, *firstptr;
+ uint32_t max;
+ uint32_t i;
+ FontArrayEntryHeader *entry;
+
+ ptr = (uint8_t *)font;
+ max = ((FontArrayHeader *)ptr)->num_entries;
+ ptr += sizeof(FontArrayHeader);
+ firstptr = ptr;
+
+ /*
+ * Simple linear search.
+ *
+ * Note: We're assuming glpyhs are uncompressed. That's true because
+ * the bmpblk_font tool doesn't compress anything. The bmpblk_utility
+ * does, but it compresses the entire font blob at once, and we've
+ * already uncompressed that before we got here.
+ */
+ for(i=0; i<max; i++) {
+ entry = (FontArrayEntryHeader *)ptr;
+ if (entry->ascii == ascii) {
+ *bufferptr = ptr + sizeof(FontArrayEntryHeader);
+ *buffersize = entry->info.original_size;
+ return &(entry->info);
+ }
+ ptr += sizeof(FontArrayEntryHeader)+entry->info.compressed_size;
+ }
+
+ /*
+ * We must return something valid. We'll just use the first glyph in
+ * the font structure (so it should be something distinct).
+ */
+ entry = (FontArrayEntryHeader *)firstptr;
+ *bufferptr = firstptr + sizeof(FontArrayEntryHeader);
+ *buffersize = entry->info.original_size;
+ return &(entry->info);
}
-/* Try to display the specified text at a particular position. */
-static void VbRenderTextAtPos(char *text, int right_to_left,
- uint32_t x, uint32_t y, VbFont_t *font) {
- int i;
- ImageInfo *image_info = 0;
- void *buffer;
- uint32_t buffersize;
- uint32_t cur_x = x, cur_y = y;
-
- if (!text || !font) {
- VBDEBUG((" VbRenderTextAtPos: invalid args\n"));
- return;
- }
-
- for (i=0; text[i]; i++) {
-
- if (text[i] == '\n') {
- if (!image_info)
- image_info = VbFindFontGlyph(font, text[i], &buffer, &buffersize);
- cur_x = x;
- cur_y += image_info->height;
- continue;
- }
-
- image_info = VbFindFontGlyph(font, text[i], &buffer, &buffersize);
-
- if (right_to_left) {
- cur_x -= image_info->width;
- }
-
- if (VBERROR_SUCCESS != VbExDisplayImage(cur_x, cur_y, buffer, buffersize)) {
- VBDEBUG((" VbRenderTextAtPos: can't display ascii 0x%x\n", text[i]));
- }
-
- if (!right_to_left) {
- cur_x += image_info->width;
- }
- }
+void VbRenderTextAtPos(char *text, int right_to_left,
+ uint32_t x, uint32_t y, VbFont_t *font)
+{
+ int i;
+ ImageInfo *image_info = 0;
+ void *buffer;
+ uint32_t buffersize;
+ uint32_t cur_x = x, cur_y = y;
+
+ if (!text || !font) {
+ VBDEBUG((" VbRenderTextAtPos: invalid args\n"));
+ return;
+ }
+
+ for (i=0; text[i]; i++) {
+
+ if (text[i] == '\n') {
+ if (!image_info)
+ image_info = VbFindFontGlyph(font, text[i],
+ &buffer,
+ &buffersize);
+ cur_x = x;
+ cur_y += image_info->height;
+ continue;
+ }
+
+ image_info = VbFindFontGlyph(font, text[i], &buffer,
+ &buffersize);
+
+ if (right_to_left)
+ cur_x -= image_info->width;
+
+ if (VBERROR_SUCCESS != VbExDisplayImage(cur_x, cur_y, buffer,
+ buffersize)) {
+ VBDEBUG((" VbRenderTextAtPos: "
+ "can't display ascii 0x%x\n", text[i]));
+ }
+
+ if (!right_to_left)
+ cur_x += image_info->width;
+ }
}
-
-/* Display a screen from the GBB. */
#define OUTBUF_LEN 128
-VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, uint32_t screen,
- VbNvContext *vncptr) {
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- static uint8_t* bmpfv;
- void* fullimage = NULL;
- BmpBlockHeader* hdr;
- ScreenLayout* layout;
- ImageInfo* image_info;
- uint32_t screen_index;
- uint32_t localization = 0;
- VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven ok */
- uint32_t inoutsize;
- uint32_t offset;
- uint32_t i;
- VbFont_t *font;
- char *text_to_show;
- int rtol = 0;
- char outbuf[OUTBUF_LEN] = "";
- uint32_t used = 0;
-
- /* Make sure the bitmap data is inside the GBB and is non-zero in size */
- if (0 == gbb->bmpfv_size ||
- gbb->bmpfv_offset > cparams->gbb_size ||
- gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) {
- VBDEBUG(("VbDisplayScreenFromGBB(): invalid bmpfv offset/size\n"));
- return VBERROR_INVALID_GBB;
- }
- /* Copy bitmap data from GBB into RAM for speed */
- if (!bmpfv) {
+VbError_t VbDisplayScreenFromGBB(VbCommonParams *cparams, uint32_t screen,
+ VbNvContext *vncptr)
+{
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ static uint8_t *bmpfv;
+ void *fullimage = NULL;
+ BmpBlockHeader *hdr;
+ ScreenLayout *layout;
+ ImageInfo *image_info;
+ uint32_t screen_index;
+ uint32_t localization = 0;
+ VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven ok */
+ uint32_t inoutsize;
+ uint32_t offset;
+ uint32_t i;
+ VbFont_t *font;
+ char *text_to_show;
+ int rtol = 0;
+ char outbuf[OUTBUF_LEN] = "";
+ uint32_t used = 0;
+
+ /* Make sure bitmap data is inside the GBB and is non-zero in size */
+ if (0 == gbb->bmpfv_size ||
+ gbb->bmpfv_offset > cparams->gbb_size ||
+ gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) {
+ VBDEBUG(("VbDisplayScreenFromGBB(): "
+ "invalid bmpfv offset/size\n"));
+ return VBERROR_INVALID_GBB;
+ }
+
+ /* Copy bitmap data from GBB into RAM for speed */
+ if (!bmpfv) {
#ifdef COPY_BMP_DATA
- bmpfv = (uint8_t*)VbExMalloc(gbb->bmpfv_size);
- Memcpy(bmpfv, ((uint8_t*)gbb) + gbb->bmpfv_offset, gbb->bmpfv_size);
+ bmpfv = (uint8_t *)VbExMalloc(gbb->bmpfv_size);
+ Memcpy(bmpfv, ((uint8_t *)gbb) + gbb->bmpfv_offset,
+ gbb->bmpfv_size);
#else
- bmpfv = ((uint8_t *)gbb) + gbb->bmpfv_offset;
+ bmpfv = ((uint8_t *)gbb) + gbb->bmpfv_offset;
#endif
- }
-
- /* Sanity-check the bitmap block header */
- hdr = (BmpBlockHeader *)bmpfv;
- if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
- BMPBLOCK_SIGNATURE_SIZE)) ||
- (hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
- ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
- (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
- VBDEBUG(("VbDisplayScreenFromGBB(): invalid/too new bitmap header\n"));
- retval = VBERROR_INVALID_BMPFV;
- goto VbDisplayScreenFromGBB_exit;
- }
-
- /* Translate screen ID into index. Note that not all screens are in the
- * GBB. */
- /* TODO: ensure screen IDs match indices? Having this translation
- * here is awful. */
- switch (screen) {
- case VB_SCREEN_DEVELOPER_WARNING:
- screen_index = SCREEN_DEVELOPER_WARNING;
- break;
- case VB_SCREEN_RECOVERY_REMOVE:
- screen_index = SCREEN_RECOVERY_REMOVE;
- break;
- case VB_SCREEN_RECOVERY_NO_GOOD:
- screen_index = SCREEN_RECOVERY_NO_GOOD;
- break;
- case VB_SCREEN_RECOVERY_INSERT:
- screen_index = SCREEN_RECOVERY_INSERT;
- break;
- case VB_SCREEN_RECOVERY_TO_DEV:
- screen_index = SCREEN_RECOVERY_TO_DEV;
- break;
- case VB_SCREEN_DEVELOPER_TO_NORM:
- screen_index = SCREEN_DEVELOPER_TO_NORM;
- break;
- case VB_SCREEN_WAIT:
- screen_index = SCREEN_WAIT;
- break;
- case VB_SCREEN_TO_NORM_CONFIRMED:
- screen_index = SCREEN_TO_NORM_CONFIRMED;
- break;
- case VB_SCREEN_BLANK:
- case VB_SCREEN_DEVELOPER_EGG:
- default:
- /* Screens which aren't in the GBB */
- VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n",
- (int)screen));
- retval = VBERROR_INVALID_SCREEN_INDEX;
- goto VbDisplayScreenFromGBB_exit;
- }
- if (screen_index >= hdr->number_of_screenlayouts) {
- VBDEBUG(("VbDisplayScreenFromGBB(): screen %d index %d not in the GBB\n",
- (int)screen, (int)screen_index));
- retval = VBERROR_INVALID_SCREEN_INDEX;
- goto VbDisplayScreenFromGBB_exit;
- }
-
- /* Clip localization to the number of localizations present in the GBB */
- VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &localization);
- if (localization >= hdr->number_of_localizations) {
- localization = 0;
- VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, localization);
- }
-
- /* Calculate offset of screen layout = start of screen stuff +
- * correct locale + correct screen. */
- offset = sizeof(BmpBlockHeader) +
- localization * hdr->number_of_screenlayouts * sizeof(ScreenLayout) +
- screen_index * sizeof(ScreenLayout);
- layout = (ScreenLayout*)(bmpfv + offset);
-
- /* Display all bitmaps for the image */
- for (i = 0; i < MAX_IMAGE_IN_LAYOUT; i++) {
- if (layout->images[i].image_info_offset) {
- offset = layout->images[i].image_info_offset;
- image_info = (ImageInfo*)(bmpfv + offset);
- fullimage = bmpfv + offset + sizeof(ImageInfo);
- inoutsize = image_info->original_size;
- if (inoutsize && image_info->compression != COMPRESS_NONE) {
- fullimage = VbExMalloc(inoutsize);
- retval = VbExDecompress(bmpfv + offset + sizeof(ImageInfo),
- image_info->compressed_size,
- image_info->compression,
- fullimage, &inoutsize);
- if (VBERROR_SUCCESS != retval) {
- VbExFree(fullimage);
- goto VbDisplayScreenFromGBB_exit;
- }
- }
-
- switch(image_info->format) {
- case FORMAT_BMP:
- retval = VbExDisplayImage(layout->images[i].x, layout->images[i].y,
- fullimage, inoutsize);
- break;
-
- case FORMAT_FONT:
- /* The uncompressed blob is our font structure. Cache it as needed. */
- font = VbInternalizeFontData(fullimage);
-
- /* TODO: handle text in general here */
- if (TAG_HWID == image_info->tag || TAG_HWID_RTOL == image_info->tag) {
- text_to_show = VbHWID(cparams);
- rtol = (TAG_HWID_RTOL == image_info->tag);
- } else {
- text_to_show = "";
- rtol = 0;
- }
-
- VbRenderTextAtPos(text_to_show, rtol,
- layout->images[i].x, layout->images[i].y, font);
-
- VbDoneWithFontForNow(font);
- break;
-
- default:
- VBDEBUG(("VbDisplayScreenFromGBB(): unsupported ImageFormat %d\n",
- image_info->format));
- retval = VBERROR_INVALID_GBB;
- }
-
- if (COMPRESS_NONE != image_info->compression)
- VbExFree(fullimage);
-
- if (VBERROR_SUCCESS != retval)
- goto VbDisplayScreenFromGBB_exit;
-
- }
- }
-
- /* Successful if all bitmaps displayed */
- retval = VBERROR_SUCCESS;
-
- /* If GBB flags is nonzero, complain because that's something that the
- * factory MUST fix before shipping. We only have to do this here, because
- * it's obvious that something is wrong if we're not displaying screens from
- * the GBB.
- */
- if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 &&
- (gbb->flags != 0)) {
- used += Strncat(outbuf + used, "gbb.flags is nonzero: 0x",
- OUTBUF_LEN - used);
- used += Uint64ToString(outbuf + used, OUTBUF_LEN - used, gbb->flags, 16, 8);
- used += Strncat(outbuf + used, "\n", OUTBUF_LEN - used);
- (void)VbExDisplayDebugInfo(outbuf);
- }
-
-
-VbDisplayScreenFromGBB_exit:
-
- VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval));
- return retval;
+ }
+
+ /* Sanity-check the bitmap block header */
+ hdr = (BmpBlockHeader *)bmpfv;
+ if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE,
+ BMPBLOCK_SIGNATURE_SIZE)) ||
+ (hdr->major_version > BMPBLOCK_MAJOR_VERSION) ||
+ ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) &&
+ (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) {
+ VBDEBUG(("VbDisplayScreenFromGBB(): "
+ "invalid/too new bitmap header\n"));
+ retval = VBERROR_INVALID_BMPFV;
+ goto VbDisplayScreenFromGBB_exit;
+ }
+
+ /*
+ * Translate screen ID into index. Note that not all screens are in
+ * the GBB.
+ *
+ * TODO: ensure screen IDs match indices? Having this translation here
+ * is awful.
+ */
+ switch (screen) {
+ case VB_SCREEN_DEVELOPER_WARNING:
+ screen_index = SCREEN_DEVELOPER_WARNING;
+ break;
+ case VB_SCREEN_RECOVERY_REMOVE:
+ screen_index = SCREEN_RECOVERY_REMOVE;
+ break;
+ case VB_SCREEN_RECOVERY_NO_GOOD:
+ screen_index = SCREEN_RECOVERY_NO_GOOD;
+ break;
+ case VB_SCREEN_RECOVERY_INSERT:
+ screen_index = SCREEN_RECOVERY_INSERT;
+ break;
+ case VB_SCREEN_RECOVERY_TO_DEV:
+ screen_index = SCREEN_RECOVERY_TO_DEV;
+ break;
+ case VB_SCREEN_DEVELOPER_TO_NORM:
+ screen_index = SCREEN_DEVELOPER_TO_NORM;
+ break;
+ case VB_SCREEN_WAIT:
+ screen_index = SCREEN_WAIT;
+ break;
+ case VB_SCREEN_TO_NORM_CONFIRMED:
+ screen_index = SCREEN_TO_NORM_CONFIRMED;
+ break;
+ case VB_SCREEN_BLANK:
+ case VB_SCREEN_DEVELOPER_EGG:
+ default:
+ /* Screens which aren't in the GBB */
+ VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n",
+ (int)screen));
+ retval = VBERROR_INVALID_SCREEN_INDEX;
+ goto VbDisplayScreenFromGBB_exit;
+ }
+
+ if (screen_index >= hdr->number_of_screenlayouts) {
+ VBDEBUG(("VbDisplayScreenFromGBB(): "
+ "screen %d index %d not in the GBB\n",
+ (int)screen, (int)screen_index));
+ retval = VBERROR_INVALID_SCREEN_INDEX;
+ goto VbDisplayScreenFromGBB_exit;
+ }
+
+ /* Clip localization to number of localizations present in the GBB */
+ VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &localization);
+ if (localization >= hdr->number_of_localizations) {
+ localization = 0;
+ VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, localization);
+ }
+
+ /*
+ * Calculate offset of screen layout = start of screen stuff + correct
+ * locale + correct screen.
+ */
+ offset = sizeof(BmpBlockHeader) +
+ localization * hdr->number_of_screenlayouts *
+ sizeof(ScreenLayout) +
+ screen_index * sizeof(ScreenLayout);
+ layout = (ScreenLayout *)(bmpfv + offset);
+
+ /* Display all bitmaps for the image */
+ for (i = 0; i < MAX_IMAGE_IN_LAYOUT; i++) {
+ if (!layout->images[i].image_info_offset)
+ continue;
+
+ offset = layout->images[i].image_info_offset;
+ image_info = (ImageInfo *)(bmpfv + offset);
+ fullimage = bmpfv + offset + sizeof(ImageInfo);
+ inoutsize = image_info->original_size;
+ if (inoutsize &&
+ image_info->compression != COMPRESS_NONE) {
+ fullimage = VbExMalloc(inoutsize);
+ retval = VbExDecompress(
+ bmpfv + offset + sizeof(ImageInfo),
+ image_info->compressed_size,
+ image_info->compression,
+ fullimage, &inoutsize);
+ if (VBERROR_SUCCESS != retval) {
+ VbExFree(fullimage);
+ goto VbDisplayScreenFromGBB_exit;
+ }
+ }
+
+ switch(image_info->format) {
+ case FORMAT_BMP:
+ retval = VbExDisplayImage(layout->images[i].x,
+ layout->images[i].y,
+ fullimage, inoutsize);
+ break;
+
+ case FORMAT_FONT:
+ /*
+ * The uncompressed blob is our font structure. Cache
+ * it as needed.
+ */
+ font = VbInternalizeFontData(fullimage);
+
+ /* TODO: handle text in general here */
+ if (TAG_HWID == image_info->tag ||
+ TAG_HWID_RTOL == image_info->tag) {
+ text_to_show = VbHWID(cparams);
+ rtol = (TAG_HWID_RTOL == image_info->tag);
+ } else {
+ text_to_show = "";
+ rtol = 0;
+ }
+
+ VbRenderTextAtPos(text_to_show, rtol,
+ layout->images[i].x,
+ layout->images[i].y, font);
+
+ VbDoneWithFontForNow(font);
+ break;
+
+ default:
+ VBDEBUG(("VbDisplayScreenFromGBB(): "
+ "unsupported ImageFormat %d\n",
+ image_info->format));
+ retval = VBERROR_INVALID_GBB;
+ }
+
+ if (COMPRESS_NONE != image_info->compression)
+ VbExFree(fullimage);
+
+ if (VBERROR_SUCCESS != retval)
+ goto VbDisplayScreenFromGBB_exit;
+ }
+
+ /* Successful if all bitmaps displayed */
+ retval = VBERROR_SUCCESS;
+
+ /*
+ * If GBB flags is nonzero, complain because that's something that the
+ * factory MUST fix before shipping. We only have to do this here,
+ * because it's obvious that something is wrong if we're not displaying
+ * screens from the GBB.
+ */
+ if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1 &&
+ (gbb->flags != 0)) {
+ used += Strncat(outbuf + used, "gbb.flags is nonzero: 0x",
+ OUTBUF_LEN - used);
+ used += Uint64ToString(outbuf + used, OUTBUF_LEN - used,
+ gbb->flags, 16, 8);
+ used += Strncat(outbuf + used, "\n", OUTBUF_LEN - used);
+ (void)VbExDisplayDebugInfo(outbuf);
+ }
+
+ VbDisplayScreenFromGBB_exit:
+ VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval));
+ return retval;
}
+VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, int force,
+ VbNvContext *vncptr)
+{
+ VbError_t retval;
-/* Display a screen, initializing the display if necessary. If force!=0,
- * redisplays the screen even if it's the same as the current screen. */
-VbError_t VbDisplayScreen(VbCommonParams* cparams, uint32_t screen, int force,
- VbNvContext *vncptr) {
- VbError_t retval;
-
- /* Initialize display if necessary */
- if (!disp_width) {
- retval = VbExDisplayInit(&disp_width, &disp_height);
- if (VBERROR_SUCCESS != retval)
- return retval;
- }
+ /* Initialize display if necessary */
+ if (!disp_width) {
+ retval = VbExDisplayInit(&disp_width, &disp_height);
+ if (VBERROR_SUCCESS != retval)
+ return retval;
+ }
- /* If the requested screen is the same as the current one, we're done. */
- if (disp_current_screen == screen && 0 == force)
- return VBERROR_SUCCESS;
+ /* If requested screen is the same as the current one, we're done. */
+ if (disp_current_screen == screen && 0 == force)
+ return VBERROR_SUCCESS;
- /* If the screen is blank, turn off the backlight; else turn it on. */
- VbExDisplayBacklight(VB_SCREEN_BLANK == screen ? 0 : 1);
+ /* If the screen is blank, turn off the backlight; else turn it on. */
+ VbExDisplayBacklight(VB_SCREEN_BLANK == screen ? 0 : 1);
- /* Request the screen */
- disp_current_screen = screen;
+ /* Request the screen */
+ disp_current_screen = screen;
- /* Look in the GBB first */
- if (VBERROR_SUCCESS == VbDisplayScreenFromGBB(cparams, screen, vncptr))
- return VBERROR_SUCCESS;
+ /* Look in the GBB first */
+ if (VBERROR_SUCCESS == VbDisplayScreenFromGBB(cparams, screen, vncptr))
+ return VBERROR_SUCCESS;
- /* If the screen wasn't in the GBB bitmaps, fall back to a default screen. */
- return VbExDisplayScreen(screen);
+ /* If screen wasn't in the GBB bitmaps, fall back to a default */
+ return VbExDisplayScreen(screen);
}
-
-static void Uint8ToString(char *buf, uint8_t val) {
- const char *trans = "0123456789abcdef";
- *buf++ = trans[val >> 4];
- *buf = trans[val & 0xF];
+static void Uint8ToString(char *buf, uint8_t val)
+{
+ const char *trans = "0123456789abcdef";
+ *buf++ = trans[val >> 4];
+ *buf = trans[val & 0xF];
}
-static void FillInSha1Sum(char *outbuf, VbPublicKey* key) {
- uint8_t* buf = ((uint8_t *)key) + key->key_offset;
- uint64_t buflen = key->key_size;
- uint8_t* digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM);
- int i;
- for (i=0; i<SHA1_DIGEST_SIZE; i++) {
- Uint8ToString(outbuf, digest[i]);
- outbuf += 2;
- }
- *outbuf = '\0';
- VbExFree(digest);
+static void FillInSha1Sum(char *outbuf, VbPublicKey *key)
+{
+ uint8_t *buf = ((uint8_t *)key) + key->key_offset;
+ uint64_t buflen = key->key_size;
+ uint8_t *digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM);
+ int i;
+ for (i = 0; i < SHA1_DIGEST_SIZE; i++) {
+ Uint8ToString(outbuf, digest[i]);
+ outbuf += 2;
+ }
+ *outbuf = '\0';
+ VbExFree(digest);
}
-const char *RecoveryReasonString(uint8_t code) {
- switch(code) {
- case VBNV_RECOVERY_NOT_REQUESTED:
- return "Recovery not requested";
- case VBNV_RECOVERY_LEGACY:
- return "Recovery requested from legacy utility";
- case VBNV_RECOVERY_RO_MANUAL:
- return "recovery button pressed";
- case VBNV_RECOVERY_RO_INVALID_RW:
- return "RW firmware failed signature check";
- case VBNV_RECOVERY_RO_S3_RESUME:
- return "S3 resume failed";
- case VBNV_RECOVERY_DEP_RO_TPM_ERROR:
- return "TPM error in read-only firmware";
- case VBNV_RECOVERY_RO_SHARED_DATA:
- return "Shared data error in read-only firmware";
- case VBNV_RECOVERY_RO_TEST_S3:
- return "Test error from S3Resume()";
- case VBNV_RECOVERY_RO_TEST_LFS:
- return "Test error from LoadFirmwareSetup()";
- case VBNV_RECOVERY_RO_TEST_LF:
- return "Test error from LoadFirmware()";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_NOT_DONE:
- return "RW firmware check not done";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_DEV_MISMATCH:
- return "RW firmware developer flag mismatch";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_REC_MISMATCH:
- return "RW firmware recovery flag mismatch";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_VERIFY_KEYBLOCK:
- return "RW firmware unable to verify key block";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_KEY_ROLLBACK:
- return "RW firmware key version rollback detected";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_DATA_KEY_PARSE:
- return "RW firmware unable to parse data key";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_VERIFY_PREAMBLE:
- return "RW firmware unable to verify preamble";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_FW_ROLLBACK:
- return "RW firmware version rollback detected";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_GET_FW_BODY:
- return "RW firmware unable to get firmware body";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_HASH_WRONG_SIZE:
- return "RW firmware hash is wrong size";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_VERIFY_BODY:
- return "RW firmware unable to verify firmware body";
- case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_NO_RO_NORMAL:
- return "RW firmware read-only normal path is not supported";
- case VBNV_RECOVERY_RO_FIRMWARE:
- return "Firmware problem outside of verified boot";
- case VBNV_RECOVERY_RO_TPM_REBOOT:
- return "TPM requires a system reboot (should be transient)";
- case VBNV_RECOVERY_EC_SOFTWARE_SYNC:
- return "EC software sync error";
- case VBNV_RECOVERY_EC_UNKNOWN_IMAGE:
- return "EC software sync unable to determine active EC image";
- case VBNV_RECOVERY_DEP_EC_HASH:
- return "EC software sync error obtaining EC image hash";
- case VBNV_RECOVERY_EC_EXPECTED_IMAGE:
- return "EC software sync error obtaining expected EC image from BIOS";
- case VBNV_RECOVERY_EC_UPDATE:
- return "EC software sync error updating EC";
- case VBNV_RECOVERY_EC_JUMP_RW:
- return "EC software sync unable to jump to EC-RW";
- case VBNV_RECOVERY_EC_PROTECT:
- return "EC software sync protection error";
- case VBNV_RECOVERY_RO_UNSPECIFIED:
- return "Unspecified/unknown error in RO firmware";
- case VBNV_RECOVERY_RW_DEV_SCREEN:
- return "User requested recovery from dev-mode warning screen";
- case VBNV_RECOVERY_RW_NO_OS:
- return "No OS kernel detected (or kernel rollback attempt?)";
- case VBNV_RECOVERY_RW_INVALID_OS:
- return "OS kernel failed signature check";
- case VBNV_RECOVERY_DEP_RW_TPM_ERROR:
- return "TPM error in rewritable firmware";
- case VBNV_RECOVERY_RW_DEV_MISMATCH:
- return "RW firmware in dev mode, but dev switch is off";
- case VBNV_RECOVERY_RW_SHARED_DATA:
- return "Shared data error in rewritable firmware";
- case VBNV_RECOVERY_RW_TEST_LK:
- return "Test error from LoadKernel()";
- case VBNV_RECOVERY_DEP_RW_NO_DISK:
- return "No bootable disk found";
- case VBNV_RECOVERY_TPM_E_FAIL:
- return "TPM error that was not fixed by reboot";
- case VBNV_RECOVERY_RO_TPM_S_ERROR:
- return "TPM setup error in read-only firmware";
- case VBNV_RECOVERY_RO_TPM_W_ERROR:
- return "TPM write error in read-only firmware";
- case VBNV_RECOVERY_RO_TPM_L_ERROR:
- return "TPM lock error in read-only firmware";
- case VBNV_RECOVERY_RO_TPM_U_ERROR:
- return "TPM update error in read-only firmware";
- case VBNV_RECOVERY_RW_TPM_R_ERROR:
- return "TPM read error in rewritable firmware";
- case VBNV_RECOVERY_RW_TPM_W_ERROR:
- return "TPM write error in rewritable firmware";
- case VBNV_RECOVERY_RW_TPM_L_ERROR:
- return "TPM lock error in rewritable firmware";
- case VBNV_RECOVERY_EC_HASH_FAILED:
- return "EC software sync unable to get EC image hash";
- case VBNV_RECOVERY_EC_HASH_SIZE:
- return "EC software sync invalid image hash size";
- case VBNV_RECOVERY_LK_UNSPECIFIED:
- return "Unspecified error while trying to load kernel";
- case VBNV_RECOVERY_RW_NO_DISK:
- return "No bootable storage device in system";
- case VBNV_RECOVERY_RW_NO_KERNEL:
- return "No bootable kernel found on disk";
- case VBNV_RECOVERY_RW_UNSPECIFIED:
- return "Unspecified/unknown error in RW firmware";
- case VBNV_RECOVERY_KE_DM_VERITY:
- return "DM-verity error";
- case VBNV_RECOVERY_KE_UNSPECIFIED:
- return "Unspecified/unknown error in kernel";
- case VBNV_RECOVERY_US_TEST:
- return "Recovery mode test from user-mode";
- case VBNV_RECOVERY_US_UNSPECIFIED:
- return "Unspecified/unknown error in user-mode";
- }
- return "We have no idea what this means";
+const char *RecoveryReasonString(uint8_t code)
+{
+ switch(code) {
+ case VBNV_RECOVERY_NOT_REQUESTED:
+ return "Recovery not requested";
+ case VBNV_RECOVERY_LEGACY:
+ return "Recovery requested from legacy utility";
+ case VBNV_RECOVERY_RO_MANUAL:
+ return "recovery button pressed";
+ case VBNV_RECOVERY_RO_INVALID_RW:
+ return "RW firmware failed signature check";
+ case VBNV_RECOVERY_RO_S3_RESUME:
+ return "S3 resume failed";
+ case VBNV_RECOVERY_DEP_RO_TPM_ERROR:
+ return "TPM error in read-only firmware";
+ case VBNV_RECOVERY_RO_SHARED_DATA:
+ return "Shared data error in read-only firmware";
+ case VBNV_RECOVERY_RO_TEST_S3:
+ return "Test error from S3Resume()";
+ case VBNV_RECOVERY_RO_TEST_LFS:
+ return "Test error from LoadFirmwareSetup()";
+ case VBNV_RECOVERY_RO_TEST_LF:
+ return "Test error from LoadFirmware()";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_NOT_DONE:
+ return "RW firmware check not done";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_DEV_MISMATCH:
+ return "RW firmware developer flag mismatch";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_REC_MISMATCH:
+ return "RW firmware recovery flag mismatch";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN +
+ VBSD_LF_CHECK_VERIFY_KEYBLOCK:
+ return "RW firmware unable to verify key block";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_KEY_ROLLBACK:
+ return "RW firmware key version rollback detected";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN +
+ VBSD_LF_CHECK_DATA_KEY_PARSE:
+ return "RW firmware unable to parse data key";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN +
+ VBSD_LF_CHECK_VERIFY_PREAMBLE:
+ return "RW firmware unable to verify preamble";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_FW_ROLLBACK:
+ return "RW firmware version rollback detected";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_GET_FW_BODY:
+ return "RW firmware unable to get firmware body";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN +
+ VBSD_LF_CHECK_HASH_WRONG_SIZE:
+ return "RW firmware hash is wrong size";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_VERIFY_BODY:
+ return "RW firmware unable to verify firmware body";
+ case VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN + VBSD_LF_CHECK_NO_RO_NORMAL:
+ return "RW firmware read-only normal path is not supported";
+ case VBNV_RECOVERY_RO_FIRMWARE:
+ return "Firmware problem outside of verified boot";
+ case VBNV_RECOVERY_RO_TPM_REBOOT:
+ return "TPM requires a system reboot (should be transient)";
+ case VBNV_RECOVERY_EC_SOFTWARE_SYNC:
+ return "EC software sync error";
+ case VBNV_RECOVERY_EC_UNKNOWN_IMAGE:
+ return "EC software sync unable to determine active EC image";
+ case VBNV_RECOVERY_DEP_EC_HASH:
+ return "EC software sync error obtaining EC image hash";
+ case VBNV_RECOVERY_EC_EXPECTED_IMAGE:
+ return "EC software sync error "
+ "obtaining expected EC image from BIOS";
+ case VBNV_RECOVERY_EC_EXPECTED_HASH:
+ return "EC software sync error "
+ "obtaining expected EC hash from BIOS";
+ case VBNV_RECOVERY_EC_HASH_MISMATCH:
+ return "EC software sync error "
+ "comparing expected EC hash and image";
+ case VBNV_RECOVERY_EC_UPDATE:
+ return "EC software sync error updating EC";
+ case VBNV_RECOVERY_EC_JUMP_RW:
+ return "EC software sync unable to jump to EC-RW";
+ case VBNV_RECOVERY_EC_PROTECT:
+ return "EC software sync protection error";
+ case VBNV_RECOVERY_RO_UNSPECIFIED:
+ return "Unspecified/unknown error in RO firmware";
+ case VBNV_RECOVERY_RW_DEV_SCREEN:
+ return "User requested recovery from dev-mode warning screen";
+ case VBNV_RECOVERY_RW_NO_OS:
+ return "No OS kernel detected (or kernel rollback attempt?)";
+ case VBNV_RECOVERY_RW_INVALID_OS:
+ return "OS kernel failed signature check";
+ case VBNV_RECOVERY_DEP_RW_TPM_ERROR:
+ return "TPM error in rewritable firmware";
+ case VBNV_RECOVERY_RW_DEV_MISMATCH:
+ return "RW firmware in dev mode, but dev switch is off";
+ case VBNV_RECOVERY_RW_SHARED_DATA:
+ return "Shared data error in rewritable firmware";
+ case VBNV_RECOVERY_RW_TEST_LK:
+ return "Test error from LoadKernel()";
+ case VBNV_RECOVERY_DEP_RW_NO_DISK:
+ return "No bootable disk found";
+ case VBNV_RECOVERY_TPM_E_FAIL:
+ return "TPM error that was not fixed by reboot";
+ case VBNV_RECOVERY_RO_TPM_S_ERROR:
+ return "TPM setup error in read-only firmware";
+ case VBNV_RECOVERY_RO_TPM_W_ERROR:
+ return "TPM write error in read-only firmware";
+ case VBNV_RECOVERY_RO_TPM_L_ERROR:
+ return "TPM lock error in read-only firmware";
+ case VBNV_RECOVERY_RO_TPM_U_ERROR:
+ return "TPM update error in read-only firmware";
+ case VBNV_RECOVERY_RW_TPM_R_ERROR:
+ return "TPM read error in rewritable firmware";
+ case VBNV_RECOVERY_RW_TPM_W_ERROR:
+ return "TPM write error in rewritable firmware";
+ case VBNV_RECOVERY_RW_TPM_L_ERROR:
+ return "TPM lock error in rewritable firmware";
+ case VBNV_RECOVERY_EC_HASH_FAILED:
+ return "EC software sync unable to get EC image hash";
+ case VBNV_RECOVERY_EC_HASH_SIZE:
+ return "EC software sync invalid image hash size";
+ case VBNV_RECOVERY_LK_UNSPECIFIED:
+ return "Unspecified error while trying to load kernel";
+ case VBNV_RECOVERY_RW_NO_DISK:
+ return "No bootable storage device in system";
+ case VBNV_RECOVERY_RW_NO_KERNEL:
+ return "No bootable kernel found on disk";
+ case VBNV_RECOVERY_RW_UNSPECIFIED:
+ return "Unspecified/unknown error in RW firmware";
+ case VBNV_RECOVERY_KE_DM_VERITY:
+ return "DM-verity error";
+ case VBNV_RECOVERY_KE_UNSPECIFIED:
+ return "Unspecified/unknown error in kernel";
+ case VBNV_RECOVERY_US_TEST:
+ return "Recovery mode test from user-mode";
+ case VBNV_RECOVERY_US_UNSPECIFIED:
+ return "Unspecified/unknown error in user-mode";
+ }
+ return "We have no idea what this means";
}
-
#define DEBUG_INFO_SIZE 512
-/* Display debug info to the screen */
-VbError_t VbDisplayDebugInfo(VbCommonParams* cparams, VbNvContext *vncptr) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- char buf[DEBUG_INFO_SIZE] = "";
- char sha1sum[SHA1_DIGEST_SIZE * 2 + 1];
- uint32_t used = 0;
- uint32_t i;
-
- /* Redisplay the current screen, to overwrite any previous debug output */
- VbDisplayScreen(cparams, disp_current_screen, 1, vncptr);
-
- /* Add hardware ID */
- used += Strncat(buf + used, "HWID: ", DEBUG_INFO_SIZE - used);
- if (0 == gbb->hwid_size ||
- gbb->hwid_offset > cparams->gbb_size ||
- gbb->hwid_offset + gbb->hwid_size > cparams->gbb_size) {
- VBDEBUG(("VbDisplayDebugInfo(): invalid hwid offset/size\n"));
- used += Strncat(buf + used, "(INVALID)", DEBUG_INFO_SIZE - used);
+VbError_t VbDisplayDebugInfo(VbCommonParams *cparams, VbNvContext *vncptr)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ char buf[DEBUG_INFO_SIZE] = "";
+ char sha1sum[SHA1_DIGEST_SIZE * 2 + 1];
+ uint32_t used = 0;
+ uint32_t i;
+
+ /* Redisplay current screen to overwrite any previous debug output */
+ VbDisplayScreen(cparams, disp_current_screen, 1, vncptr);
+
+ /* Add hardware ID */
+ used += Strncat(buf + used, "HWID: ", DEBUG_INFO_SIZE - used);
+ if (0 == gbb->hwid_size ||
+ gbb->hwid_offset > cparams->gbb_size ||
+ gbb->hwid_offset + gbb->hwid_size > cparams->gbb_size) {
+ VBDEBUG(("VbDisplayDebugInfo(): invalid hwid offset/size\n"));
+ used += Strncat(buf + used,
+ "(INVALID)", DEBUG_INFO_SIZE - used);
} else {
- used += Strncat(buf + used, (char*)((uint8_t*)gbb + gbb->hwid_offset),
- DEBUG_INFO_SIZE - used);
- }
-
- /* Add recovery reason */
- used += Strncat(buf + used, "\nrecovery_reason: 0x", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
- shared->recovery_reason, 16, 2);
- used += Strncat(buf + used, " ", DEBUG_INFO_SIZE - used);
- used += Strncat(buf + used, RecoveryReasonString(shared->recovery_reason),
- DEBUG_INFO_SIZE - used);
-
-
- /* Add VbSharedData flags */
- used += Strncat(buf + used, "\nVbSD.flags: 0x", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
- shared->flags, 16, 8);
-
- /* Add raw contents of VbNvStorage */
- used += Strncat(buf + used, "\nVbNv.raw:", DEBUG_INFO_SIZE - used);
- for (i = 0; i < VBNV_BLOCK_SIZE; i++) {
- used += Strncat(buf + used, " ", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
- vncptr->raw[i], 16, 2);
+ used += Strncat(buf + used,
+ (char *)((uint8_t *)gbb + gbb->hwid_offset),
+ DEBUG_INFO_SIZE - used);
}
- /* Add dev_boot_usb flag */
- VbNvGet(vncptr, VBNV_DEV_BOOT_USB, &i);
- used += Strncat(buf + used, "\ndev_boot_usb: ", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
-
- /* Add dev_boot_legacy flag */
- VbNvGet(vncptr, VBNV_DEV_BOOT_LEGACY, &i);
- used += Strncat(buf + used, "\ndev_boot_legacy: ", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
-
- /* Add dev_boot_signed_only flag */
- VbNvGet(vncptr, VBNV_DEV_BOOT_SIGNED_ONLY, &i);
- used += Strncat(buf + used, "\ndev_boot_signed_only: ",
- DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
-
- /* Add TPM versions */
- used += Strncat(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
- shared->fw_version_tpm, 16, 8);
- used += Strncat(buf + used, " kernver=0x", DEBUG_INFO_SIZE - used);
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
- shared->kernel_version_tpm, 16, 8);
-
- /* Add GBB flags */
- used += Strncat(buf + used, "\ngbb.flags: 0x", DEBUG_INFO_SIZE - used);
- if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1) {
- used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
- gbb->flags, 16, 8);
- } else {
- used += Strncat(buf + used, "0 (default)", DEBUG_INFO_SIZE - used);
- }
-
- /* Add sha1sum for Root & Recovery keys */
- FillInSha1Sum(sha1sum,
- (VbPublicKey*)((uint8_t*)gbb + gbb->rootkey_offset));
- used += Strncat(buf + used, "\ngbb.rootkey: ", DEBUG_INFO_SIZE - used);
- used += Strncat(buf + used, sha1sum, DEBUG_INFO_SIZE - used);
- FillInSha1Sum(sha1sum,
- (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset));
- used += Strncat(buf + used, "\ngbb.recovery_key: ", DEBUG_INFO_SIZE - used);
- used += Strncat(buf + used, sha1sum, DEBUG_INFO_SIZE - used);
-
- /* If we're in dev-mode, show the kernel subkey that we expect, too. */
- if (0 == shared->recovery_reason) {
- FillInSha1Sum(sha1sum, &shared->kernel_subkey);
- used += Strncat(buf + used, "\nkernel_subkey: ", DEBUG_INFO_SIZE - used);
- used += Strncat(buf + used, sha1sum, DEBUG_INFO_SIZE - used);
- }
-
- /* Make sure we finish with a newline */
- used += Strncat(buf + used, "\n", DEBUG_INFO_SIZE - used);
-
- /* TODO: add more interesting data:
- * - Information on current disks */
-
- buf[DEBUG_INFO_SIZE - 1] = '\0';
- return VbExDisplayDebugInfo(buf);
+ /* Add recovery reason */
+ used += Strncat(buf + used,
+ "\nrecovery_reason: 0x", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+ shared->recovery_reason, 16, 2);
+ used += Strncat(buf + used, " ", DEBUG_INFO_SIZE - used);
+ used += Strncat(buf + used,
+ RecoveryReasonString(shared->recovery_reason),
+ DEBUG_INFO_SIZE - used);
+
+ /* Add VbSharedData flags */
+ used += Strncat(buf + used, "\nVbSD.flags: 0x", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+ shared->flags, 16, 8);
+
+ /* Add raw contents of VbNvStorage */
+ used += Strncat(buf + used, "\nVbNv.raw:", DEBUG_INFO_SIZE - used);
+ for (i = 0; i < VBNV_BLOCK_SIZE; i++) {
+ used += Strncat(buf + used, " ", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+ vncptr->raw[i], 16, 2);
+ }
+
+ /* Add dev_boot_usb flag */
+ VbNvGet(vncptr, VBNV_DEV_BOOT_USB, &i);
+ used += Strncat(buf + used, "\ndev_boot_usb: ", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
+
+ /* Add dev_boot_legacy flag */
+ VbNvGet(vncptr, VBNV_DEV_BOOT_LEGACY, &i);
+ used += Strncat(buf + used,
+ "\ndev_boot_legacy: ", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
+
+ /* Add dev_boot_signed_only flag */
+ VbNvGet(vncptr, VBNV_DEV_BOOT_SIGNED_ONLY, &i);
+ used += Strncat(buf + used, "\ndev_boot_signed_only: ",
+ DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0);
+
+ /* Add TPM versions */
+ used += Strncat(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+ shared->fw_version_tpm, 16, 8);
+ used += Strncat(buf + used, " kernver=0x", DEBUG_INFO_SIZE - used);
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+ shared->kernel_version_tpm, 16, 8);
+
+ /* Add GBB flags */
+ used += Strncat(buf + used, "\ngbb.flags: 0x", DEBUG_INFO_SIZE - used);
+ if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1) {
+ used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used,
+ gbb->flags, 16, 8);
+ } else {
+ used += Strncat(buf + used,
+ "0 (default)", DEBUG_INFO_SIZE - used);
+ }
+
+ /* Add sha1sum for Root & Recovery keys */
+ FillInSha1Sum(sha1sum,
+ (VbPublicKey *)((uint8_t *)gbb + gbb->rootkey_offset));
+ used += Strncat(buf + used, "\ngbb.rootkey: ", DEBUG_INFO_SIZE - used);
+ used += Strncat(buf + used, sha1sum, DEBUG_INFO_SIZE - used);
+ FillInSha1Sum(sha1sum,
+ (VbPublicKey *)((uint8_t *)gbb + gbb->recovery_key_offset));
+ used += Strncat(buf + used,
+ "\ngbb.recovery_key: ", DEBUG_INFO_SIZE - used);
+ used += Strncat(buf + used, sha1sum, DEBUG_INFO_SIZE - used);
+
+ /* If we're in dev-mode, show the kernel subkey that we expect, too. */
+ if (0 == shared->recovery_reason) {
+ FillInSha1Sum(sha1sum, &shared->kernel_subkey);
+ used += Strncat(buf + used,
+ "\nkernel_subkey: ", DEBUG_INFO_SIZE - used);
+ used += Strncat(buf + used, sha1sum, DEBUG_INFO_SIZE - used);
+ }
+
+ /* Make sure we finish with a newline */
+ used += Strncat(buf + used, "\n", DEBUG_INFO_SIZE - used);
+
+ /* TODO: add more interesting data:
+ * - Information on current disks */
+
+ buf[DEBUG_INFO_SIZE - 1] = '\0';
+ return VbExDisplayDebugInfo(buf);
}
-
#define MAGIC_WORD_LEN 5
-#define MAGIC_WORD "xyzzy"
+#define MAGIC_WORD "xyzzy"
static uint8_t MagicBuffer[MAGIC_WORD_LEN];
-VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key,
- VbNvContext *vncptr) {
- int i;
-
- /* Update key buffer */
- for(i=1; i<MAGIC_WORD_LEN; i++)
- MagicBuffer[i-1] = MagicBuffer[i];
- /* Save as lower-case ASCII */
- MagicBuffer[MAGIC_WORD_LEN-1] = (key | 0x20) & 0xFF;
-
- if ('\t' == key) {
- /* Tab = display debug info */
- return VbDisplayDebugInfo(cparams, vncptr);
- } else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key ||
- VB_KEY_DOWN == key || VB_KEY_UP == key) {
- /* Arrow keys = change localization */
- uint32_t loc = 0;
- uint32_t count = 0;
-
- VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &loc);
- if (VBERROR_SUCCESS != VbGetLocalizationCount(cparams, &count))
- loc = 0; /* No localization count (bad GBB?), so set to 0 (default) */
- else if (VB_KEY_RIGHT == key || VB_KEY_UP == key)
- loc = (loc < count - 1 ? loc + 1 : 0);
- else
- loc = (loc > 0 ? loc - 1 : count - 1);
- VBDEBUG(("VbCheckDisplayKey() - change localization to %d\n", (int)loc));
- VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, loc);
+VbError_t VbCheckDisplayKey(VbCommonParams *cparams, uint32_t key,
+ VbNvContext *vncptr)
+{
+ int i;
+
+ /* Update key buffer */
+ for(i = 1; i < MAGIC_WORD_LEN; i++)
+ MagicBuffer[i - 1] = MagicBuffer[i];
+ /* Save as lower-case ASCII */
+ MagicBuffer[MAGIC_WORD_LEN - 1] = (key | 0x20) & 0xFF;
+
+ if ('\t' == key) {
+ /* Tab = display debug info */
+ return VbDisplayDebugInfo(cparams, vncptr);
+ } else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key ||
+ VB_KEY_DOWN == key || VB_KEY_UP == key) {
+ /* Arrow keys = change localization */
+ uint32_t loc = 0;
+ uint32_t count = 0;
+
+ VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &loc);
+ if (VBERROR_SUCCESS != VbGetLocalizationCount(cparams, &count))
+ loc = 0; /* No localization count (bad GBB?) */
+ else if (VB_KEY_RIGHT == key || VB_KEY_UP == key)
+ loc = (loc < count - 1 ? loc + 1 : 0);
+ else
+ loc = (loc > 0 ? loc - 1 : count - 1);
+ VBDEBUG(("VbCheckDisplayKey() - change localization to %d\n",
+ (int)loc));
+ VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, loc);
#ifdef SAVE_LOCALE_IMMEDIATELY
- VbNvTeardown(vncptr); /* really only computes checksum */
- if (vncptr->raw_changed)
- VbExNvStorageWrite(vncptr->raw);
+ VbNvTeardown(vncptr); /* really only computes checksum */
+ if (vncptr->raw_changed)
+ VbExNvStorageWrite(vncptr->raw);
#endif
- /* Force redraw of current screen */
- return VbDisplayScreen(cparams, disp_current_screen, 1, vncptr);
- }
+ /* Force redraw of current screen */
+ return VbDisplayScreen(cparams, disp_current_screen, 1, vncptr);
+ }
- if (0 == Memcmp(MagicBuffer, MAGIC_WORD, MAGIC_WORD_LEN)) {
- if (VBEASTEREGG)
- (void)VbDisplayScreen(cparams, disp_current_screen, 1, vncptr);
- }
+ if (0 == Memcmp(MagicBuffer, MAGIC_WORD, MAGIC_WORD_LEN)) {
+ if (VBEASTEREGG)
+ (void)VbDisplayScreen(cparams, disp_current_screen,
+ 1, vncptr);
+ }
return VBERROR_SUCCESS;
}
diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c
index ed9d3bc0..c2e8293f 100644
--- a/firmware/lib/vboot_firmware.c
+++ b/firmware/lib/vboot_firmware.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -13,311 +13,350 @@
#include "vboot_common.h"
#include "vboot_nvstorage.h"
-/* Static variables for UpdateFirmwareBodyHash(). It's less than
- * optimal to have static variables in a library, but in UEFI the
- * caller is deep inside a different firmware stack and doesn't have a
- * good way to pass the params struct back to us. */
+/*
+ * Static variables for UpdateFirmwareBodyHash(). It's less than optimal to
+ * have static variables in a library, but in UEFI the caller is deep inside a
+ * different firmware stack and doesn't have a good way to pass the params
+ * struct back to us.
+ */
typedef struct VbLoadFirmwareInternal {
- DigestContext body_digest_context;
- uint32_t body_size_accum;
+ DigestContext body_digest_context;
+ uint32_t body_size_accum;
} VbLoadFirmwareInternal;
+void VbUpdateFirmwareBodyHash(VbCommonParams *cparams, uint8_t *data,
+ uint32_t size)
+{
+ VbLoadFirmwareInternal *lfi =
+ (VbLoadFirmwareInternal*)cparams->vboot_context;
-void VbUpdateFirmwareBodyHash(VbCommonParams* cparams,
- uint8_t* data, uint32_t size) {
- VbLoadFirmwareInternal* lfi =
- (VbLoadFirmwareInternal*)cparams->vboot_context;
-
- DigestUpdate(&lfi->body_digest_context, data, size);
- lfi->body_size_accum += size;
+ DigestUpdate(&lfi->body_digest_context, data, size);
+ lfi->body_size_accum += size;
}
-
-int LoadFirmware(VbCommonParams* cparams, VbSelectFirmwareParams* fparams,
- VbNvContext* vnc) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob;
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data;
- VbPublicKey* root_key;
- VbLoadFirmwareInternal* lfi;
-
- uint32_t try_b_count;
- uint32_t lowest_version = 0xFFFFFFFF;
- int good_index = -1;
- int is_dev;
- int index;
- int i;
-
- int retval = VBERROR_UNKNOWN;
- int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
-
- /* Clear output params in case we fail */
- shared->firmware_index = 0xFF;
-
- VBDEBUG(("LoadFirmware started...\n"));
-
- /* Must have a root key from the GBB */
- if (!gbb) {
- VBDEBUG(("No GBB\n"));
- retval = VBERROR_INVALID_GBB;
- goto LoadFirmwareExit;
- }
- root_key = (VbPublicKey*)((uint8_t*)gbb + gbb->rootkey_offset);
-
- /* Parse flags */
- is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
- if (is_dev)
- shared->flags |= VBSD_LF_DEV_SWITCH_ON;
-
- /* Read try-b count and decrement if necessary */
- VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count);
- if (0 != try_b_count) {
- VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1);
- shared->flags |= VBSD_FWB_TRIED;
- }
-
- /* Allocate our internal data */
- lfi = (VbLoadFirmwareInternal*)VbExMalloc(sizeof(VbLoadFirmwareInternal));
- cparams->vboot_context = (void*)lfi;
-
- /* Loop over indices */
- for (i = 0; i < 2; i++) {
- VbKeyBlockHeader* key_block;
- uint32_t vblock_size;
- VbFirmwarePreambleHeader* preamble;
- RSAPublicKey* data_key;
- uint64_t key_version;
- uint32_t combined_version;
- uint8_t* body_digest;
- uint8_t* check_result;
-
- /* If try B count is non-zero try firmware B first */
- index = (try_b_count ? 1 - i : i);
- if (0 == index) {
- key_block = (VbKeyBlockHeader*)fparams->verification_block_A;
- vblock_size = fparams->verification_size_A;
- check_result = &shared->check_fw_a_result;
- } else {
- key_block = (VbKeyBlockHeader*)fparams->verification_block_B;
- vblock_size = fparams->verification_size_B;
- check_result = &shared->check_fw_b_result;
- }
-
- /* Check the key block flags against the current boot mode. Do this
- * before verifying the key block, since flags are faster to check than
- * the RSA signature. */
- if (!(key_block->key_block_flags &
- (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 :
- KEY_BLOCK_FLAG_DEVELOPER_0))) {
- VBDEBUG(("Developer flag mismatch.\n"));
- *check_result = VBSD_LF_CHECK_DEV_MISMATCH;
- continue;
- }
- /* RW firmware never runs in recovery mode. */
- if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)) {
- VBDEBUG(("Recovery flag mismatch.\n"));
- *check_result = VBSD_LF_CHECK_REC_MISMATCH;
- continue;
- }
-
- /* Verify the key block */
- VBPERFSTART("VB_VKB");
- if ((0 != KeyBlockVerify(key_block, vblock_size, root_key, 0))) {
- VBDEBUG(("Key block verification failed.\n"));
- *check_result = VBSD_LF_CHECK_VERIFY_KEYBLOCK;
- VBPERFEND("VB_VKB");
- continue;
- }
- VBPERFEND("VB_VKB");
-
- /* Check for rollback of key version. */
- key_version = key_block->data_key.key_version;
- if (!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
- if (key_version < (shared->fw_version_tpm >> 16)) {
- VBDEBUG(("Key rollback detected.\n"));
- *check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
- continue;
- }
- if (key_version > 0xFFFF) {
- /* Key version is stored in 16 bits in the TPM, so key versions greater
- * than 0xFFFF can't be stored properly. */
- VBDEBUG(("Key version > 0xFFFF.\n"));
- *check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
- continue;
- }
- }
-
- /* Get the key for preamble/data verification from the key block. */
- data_key = PublicKeyToRSA(&key_block->data_key);
- if (!data_key) {
- VBDEBUG(("Unable to parse data key.\n"));
- *check_result = VBSD_LF_CHECK_DATA_KEY_PARSE;
- continue;
- }
-
- /* Verify the preamble, which follows the key block. */
- VBPERFSTART("VB_VPB");
- preamble = (VbFirmwarePreambleHeader*)((uint8_t*)key_block +
- key_block->key_block_size);
- if ((0 != VerifyFirmwarePreamble(preamble,
- vblock_size - key_block->key_block_size,
- data_key))) {
- VBDEBUG(("Preamble verfication failed.\n"));
- *check_result = VBSD_LF_CHECK_VERIFY_PREAMBLE;
- RSAPublicKeyFree(data_key);
- VBPERFEND("VB_VPB");
- continue;
- }
- VBPERFEND("VB_VPB");
-
- /* Check for rollback of firmware version. */
- combined_version = (uint32_t)((key_version << 16) |
- (preamble->firmware_version & 0xFFFF));
- if (combined_version < shared->fw_version_tpm &&
- !(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
- VBDEBUG(("Firmware version rollback detected.\n"));
- *check_result = VBSD_LF_CHECK_FW_ROLLBACK;
- RSAPublicKeyFree(data_key);
- continue;
- }
-
- /* Header for this firmware is valid */
- *check_result = VBSD_LF_CHECK_HEADER_VALID;
-
- /* Check for lowest key version from a valid header. */
- if (lowest_version > combined_version)
- lowest_version = combined_version;
-
- /* If we already have good firmware, no need to read another one;
- * we only needed to look at the versions to check for
- * rollback. */
- if (-1 != good_index) {
- RSAPublicKeyFree(data_key);
- continue;
- }
-
- /* Handle preamble flag for using the RO normal/dev code path */
- if (VbGetFirmwarePreambleFlags(preamble) &
- VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
-
- /* Fail if calling firmware doesn't support RO normal */
- if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) {
- *check_result = VBSD_LF_CHECK_NO_RO_NORMAL;
- RSAPublicKeyFree(data_key);
- continue;
- }
-
- /* Indicate that we should use the RO normal code path */
- shared->flags |= VBSD_LF_USE_RO_NORMAL;
-
- } else {
- VbError_t rv;
-
- /* Read the firmware data */
- VBPERFSTART("VB_RFD");
- DigestInit(&lfi->body_digest_context, data_key->algorithm);
- lfi->body_size_accum = 0;
- rv = VbExHashFirmwareBody(cparams, (index ? VB_SELECT_FIRMWARE_B :
- VB_SELECT_FIRMWARE_A));
- if (VBERROR_SUCCESS != rv) {
- VBDEBUG(("VbExHashFirmwareBody() failed for index %d\n", index));
- *check_result = VBSD_LF_CHECK_GET_FW_BODY;
- RSAPublicKeyFree(data_key);
- VBPERFEND("VB_RFD");
- continue;
- }
- if (lfi->body_size_accum != preamble->body_signature.data_size) {
- VBDEBUG(("Hash updated %d bytes but expected %d\n",
- (int)lfi->body_size_accum,
- (int)preamble->body_signature.data_size));
- *check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE;
- RSAPublicKeyFree(data_key);
- VBPERFEND("VB_RFD");
- continue;
- }
- VBPERFEND("VB_RFD");
-
- /* Verify firmware data */
- VBPERFSTART("VB_VFD");
- body_digest = DigestFinal(&lfi->body_digest_context);
- if (0 != VerifyDigest(body_digest, &preamble->body_signature,
- data_key)) {
- VBDEBUG(("Firmware body verification failed.\n"));
- *check_result = VBSD_LF_CHECK_VERIFY_BODY;
- RSAPublicKeyFree(data_key);
- VbExFree(body_digest);
- VBPERFEND("VB_VFD");
- continue;
- }
- VbExFree(body_digest);
- VBPERFEND("VB_VFD");
- }
-
- /* Done with the data key, so can free it now */
- RSAPublicKeyFree(data_key);
-
- /* If we're still here, the firmware is valid. */
- VBDEBUG(("Firmware %d is valid.\n", index));
- *check_result = VBSD_LF_CHECK_VALID;
- if (-1 == good_index) {
- /* Save the key we actually used */
- if (0 != VbSharedDataSetKernelKey(shared, &preamble->kernel_subkey)) {
- VBDEBUG(("Unable to save kernel subkey to shared data.\n"));
- continue; /* The firmware signature was good, but the public
- * key was bigger that the caller can handle. */
- }
-
- /* Save the good index, now that we're sure we can actually use
- * this firmware. That's the one we'll boot. */
- good_index = index;
- shared->firmware_index = (uint8_t)index;
- shared->fw_keyblock_flags = key_block->key_block_flags;
-
- /* If the good firmware's key version is the same as the tpm,
- * then the TPM doesn't need updating; we can stop now.
- * Otherwise, we'll check all the other headers to see if they
- * contain a newer key. */
- if (combined_version == shared->fw_version_tpm)
- break;
- }
- }
-
- /* Free internal data */
- VbExFree(lfi);
- cparams->vboot_context = NULL;
-
- /* Handle finding good firmware */
- if (good_index >= 0) {
-
- /* Save versions we found */
- shared->fw_version_lowest = lowest_version;
- if (lowest_version > shared->fw_version_tpm)
- shared->fw_version_tpm = lowest_version;
-
- /* Success */
- VBDEBUG(("Will boot firmware index %d\n", (int)shared->firmware_index));
- retval = VBERROR_SUCCESS;
- } else {
- uint8_t a = shared->check_fw_a_result;
- uint8_t b = shared->check_fw_b_result;
- uint8_t best_check;
-
- /* No good firmware, so go to recovery mode. */
- VBDEBUG(("Alas, no good firmware.\n"));
- recovery = VBNV_RECOVERY_RO_INVALID_RW;
- retval = VBERROR_LOAD_FIRMWARE;
-
- /* If the best check result fits in the range of recovery reasons, provide
- * more detail on how far we got in validation. */
- best_check = (a > b ? a : b) + VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN;
- if (best_check >= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN &&
- best_check <= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX)
- recovery = best_check;
- }
-
-LoadFirmwareExit:
- /* Store recovery request, if any */
- VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
- recovery : VBNV_RECOVERY_NOT_REQUESTED);
-
- return retval;
+int LoadFirmware(VbCommonParams *cparams, VbSelectFirmwareParams *fparams,
+ VbNvContext *vnc)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)cparams->shared_data_blob;
+ GoogleBinaryBlockHeader *gbb =
+ (GoogleBinaryBlockHeader *)cparams->gbb_data;
+ VbPublicKey *root_key;
+ VbLoadFirmwareInternal *lfi;
+
+ uint32_t try_b_count;
+ uint32_t lowest_version = 0xFFFFFFFF;
+ int good_index = -1;
+ int is_dev;
+ int index;
+ int i;
+
+ int retval = VBERROR_UNKNOWN;
+ int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
+
+ /* Clear output params in case we fail */
+ shared->firmware_index = 0xFF;
+
+ VBDEBUG(("LoadFirmware started...\n"));
+
+ /* Must have a root key from the GBB */
+ if (!gbb) {
+ VBDEBUG(("No GBB\n"));
+ retval = VBERROR_INVALID_GBB;
+ goto LoadFirmwareExit;
+ }
+ root_key = (VbPublicKey *)((uint8_t *)gbb + gbb->rootkey_offset);
+
+ /* Parse flags */
+ is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
+ if (is_dev)
+ shared->flags |= VBSD_LF_DEV_SWITCH_ON;
+
+ /* Read try-b count and decrement if necessary */
+ VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count);
+ if (0 != try_b_count) {
+ VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1);
+ shared->flags |= VBSD_FWB_TRIED;
+ }
+
+ /* Allocate our internal data */
+ lfi = (VbLoadFirmwareInternal *)
+ VbExMalloc(sizeof(VbLoadFirmwareInternal));
+ cparams->vboot_context = lfi;
+
+ /* Loop over indices */
+ for (i = 0; i < 2; i++) {
+ VbKeyBlockHeader *key_block;
+ uint32_t vblock_size;
+ VbFirmwarePreambleHeader *preamble;
+ RSAPublicKey *data_key;
+ uint64_t key_version;
+ uint32_t combined_version;
+ uint8_t *body_digest;
+ uint8_t *check_result;
+
+ /* If try B count is non-zero try firmware B first */
+ index = (try_b_count ? 1 - i : i);
+ if (0 == index) {
+ key_block = (VbKeyBlockHeader *)
+ fparams->verification_block_A;
+ vblock_size = fparams->verification_size_A;
+ check_result = &shared->check_fw_a_result;
+ } else {
+ key_block = (VbKeyBlockHeader *)
+ fparams->verification_block_B;
+ vblock_size = fparams->verification_size_B;
+ check_result = &shared->check_fw_b_result;
+ }
+
+ /*
+ * Check the key block flags against the current boot mode. Do
+ * this before verifying the key block, since flags are faster
+ * to check than the RSA signature.
+ */
+ if (!(key_block->key_block_flags &
+ (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 :
+ KEY_BLOCK_FLAG_DEVELOPER_0))) {
+ VBDEBUG(("Developer flag mismatch.\n"));
+ *check_result = VBSD_LF_CHECK_DEV_MISMATCH;
+ continue;
+ }
+
+ /* RW firmware never runs in recovery mode. */
+ if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)) {
+ VBDEBUG(("Recovery flag mismatch.\n"));
+ *check_result = VBSD_LF_CHECK_REC_MISMATCH;
+ continue;
+ }
+
+ /* Verify the key block */
+ VBPERFSTART("VB_VKB");
+ if ((0 != KeyBlockVerify(key_block, vblock_size,
+ root_key, 0))) {
+ VBDEBUG(("Key block verification failed.\n"));
+ *check_result = VBSD_LF_CHECK_VERIFY_KEYBLOCK;
+ VBPERFEND("VB_VKB");
+ continue;
+ }
+ VBPERFEND("VB_VKB");
+
+ /* Check for rollback of key version. */
+ key_version = key_block->data_key.key_version;
+ if (!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
+ if (key_version < (shared->fw_version_tpm >> 16)) {
+ VBDEBUG(("Key rollback detected.\n"));
+ *check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
+ continue;
+ }
+ if (key_version > 0xFFFF) {
+ /*
+ * Key version is stored in 16 bits in the TPM,
+ * so key versions greater than 0xFFFF can't be
+ * stored properly.
+ */
+ VBDEBUG(("Key version > 0xFFFF.\n"));
+ *check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
+ continue;
+ }
+ }
+
+ /* Get key for preamble/data verification from the key block. */
+ data_key = PublicKeyToRSA(&key_block->data_key);
+ if (!data_key) {
+ VBDEBUG(("Unable to parse data key.\n"));
+ *check_result = VBSD_LF_CHECK_DATA_KEY_PARSE;
+ continue;
+ }
+
+ /* Verify the preamble, which follows the key block. */
+ VBPERFSTART("VB_VPB");
+ preamble = (VbFirmwarePreambleHeader *)
+ ((uint8_t *)key_block + key_block->key_block_size);
+ if ((0 != VerifyFirmwarePreamble(
+ preamble,
+ vblock_size - key_block->key_block_size,
+ data_key))) {
+ VBDEBUG(("Preamble verfication failed.\n"));
+ *check_result = VBSD_LF_CHECK_VERIFY_PREAMBLE;
+ RSAPublicKeyFree(data_key);
+ VBPERFEND("VB_VPB");
+ continue;
+ }
+ VBPERFEND("VB_VPB");
+
+ /* Check for rollback of firmware version. */
+ combined_version = (uint32_t)((key_version << 16) |
+ (preamble->firmware_version & 0xFFFF));
+ if (combined_version < shared->fw_version_tpm &&
+ !(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
+ VBDEBUG(("Firmware version rollback detected.\n"));
+ *check_result = VBSD_LF_CHECK_FW_ROLLBACK;
+ RSAPublicKeyFree(data_key);
+ continue;
+ }
+
+ /* Header for this firmware is valid */
+ *check_result = VBSD_LF_CHECK_HEADER_VALID;
+
+ /* Check for lowest key version from a valid header. */
+ if (lowest_version > combined_version)
+ lowest_version = combined_version;
+
+ /*
+ * If we already have good firmware, no need to read another
+ * one; we only needed to look at the versions to check for
+ * rollback.
+ */
+ if (-1 != good_index) {
+ RSAPublicKeyFree(data_key);
+ continue;
+ }
+
+ /* Handle preamble flag for using the RO normal/dev code path */
+ if (VbGetFirmwarePreambleFlags(preamble) &
+ VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
+
+ /* Fail if calling firmware doesn't support RO normal */
+ if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) {
+ *check_result = VBSD_LF_CHECK_NO_RO_NORMAL;
+ RSAPublicKeyFree(data_key);
+ continue;
+ }
+
+ /* Use the RO normal code path */
+ shared->flags |= VBSD_LF_USE_RO_NORMAL;
+
+ } else {
+ VbError_t rv;
+
+ /* Read the firmware data */
+ VBPERFSTART("VB_RFD");
+ DigestInit(&lfi->body_digest_context,
+ data_key->algorithm);
+ lfi->body_size_accum = 0;
+ rv = VbExHashFirmwareBody(
+ cparams,
+ (index ? VB_SELECT_FIRMWARE_B :
+ VB_SELECT_FIRMWARE_A));
+ if (VBERROR_SUCCESS != rv) {
+ VBDEBUG(("VbExHashFirmwareBody() failed for "
+ "index %d\n", index));
+ *check_result = VBSD_LF_CHECK_GET_FW_BODY;
+ RSAPublicKeyFree(data_key);
+ VBPERFEND("VB_RFD");
+ continue;
+ }
+ if (lfi->body_size_accum !=
+ preamble->body_signature.data_size) {
+ VBDEBUG(("Hashed %d bytes but expected %d\n",
+ (int)lfi->body_size_accum,
+ (int)preamble->body_signature.data_size));
+ *check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE;
+ RSAPublicKeyFree(data_key);
+ VBPERFEND("VB_RFD");
+ continue;
+ }
+ VBPERFEND("VB_RFD");
+
+ /* Verify firmware data */
+ VBPERFSTART("VB_VFD");
+ body_digest = DigestFinal(&lfi->body_digest_context);
+ if (0 != VerifyDigest(body_digest,
+ &preamble->body_signature,
+ data_key)) {
+ VBDEBUG(("FW body verification failed.\n"));
+ *check_result = VBSD_LF_CHECK_VERIFY_BODY;
+ RSAPublicKeyFree(data_key);
+ VbExFree(body_digest);
+ VBPERFEND("VB_VFD");
+ continue;
+ }
+ VbExFree(body_digest);
+ VBPERFEND("VB_VFD");
+ }
+
+ /* Done with the data key, so can free it now */
+ RSAPublicKeyFree(data_key);
+
+ /* If we're still here, the firmware is valid. */
+ VBDEBUG(("Firmware %d is valid.\n", index));
+ *check_result = VBSD_LF_CHECK_VALID;
+ if (-1 == good_index) {
+ /* Save the key we actually used */
+ if (0 != VbSharedDataSetKernelKey(
+ shared, &preamble->kernel_subkey)) {
+ /*
+ * The firmware signature was good, but the
+ * public key was bigger that the caller can
+ * handle.
+ */
+ VBDEBUG(("Unable to save kernel subkey.\n"));
+ continue;
+ }
+
+ /*
+ * Save the good index, now that we're sure we can
+ * actually use this firmware. That's the one we'll
+ * boot.
+ */
+ good_index = index;
+ shared->firmware_index = (uint8_t)index;
+ shared->fw_keyblock_flags = key_block->key_block_flags;
+
+ /*
+ * If the good firmware's key version is the same as
+ * the tpm, then the TPM doesn't need updating; we can
+ * stop now. Otherwise, we'll check all the other
+ * headers to see if they contain a newer key.
+ */
+ if (combined_version == shared->fw_version_tpm)
+ break;
+ }
+ }
+
+ /* Free internal data */
+ VbExFree(lfi);
+ cparams->vboot_context = NULL;
+
+ /* Handle finding good firmware */
+ if (good_index >= 0) {
+
+ /* Save versions we found */
+ shared->fw_version_lowest = lowest_version;
+ if (lowest_version > shared->fw_version_tpm)
+ shared->fw_version_tpm = lowest_version;
+
+ /* Success */
+ VBDEBUG(("Will boot firmware index %d\n",
+ (int)shared->firmware_index));
+ retval = VBERROR_SUCCESS;
+
+ } else {
+ uint8_t a = shared->check_fw_a_result;
+ uint8_t b = shared->check_fw_b_result;
+ uint8_t best_check;
+
+ /* No good firmware, so go to recovery mode. */
+ VBDEBUG(("Alas, no good firmware.\n"));
+ recovery = VBNV_RECOVERY_RO_INVALID_RW;
+ retval = VBERROR_LOAD_FIRMWARE;
+
+ /*
+ * If the best check result fits in the range of recovery
+ * reasons, provide more detail on how far we got in
+ * validation.
+ */
+ best_check = (a > b ? a : b) +
+ VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN;
+ if (best_check >= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN &&
+ best_check <= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX)
+ recovery = best_check;
+ }
+
+ LoadFirmwareExit:
+ /* Store recovery request, if any */
+ VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
+ recovery : VBNV_RECOVERY_NOT_REQUESTED);
+
+ return retval;
}
diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c
index ec77de36..26eba7e7 100644
--- a/firmware/lib/vboot_kernel.c
+++ b/firmware/lib/vboot_kernel.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -20,552 +20,621 @@
#define LOWEST_TPM_VERSION 0xffffffff
typedef enum BootMode {
- kBootRecovery = 0, /* Recovery firmware, regardless of dev switch position */
- kBootNormal = 1, /* Normal boot - kernel must be verified */
- kBootDev = 2 /* Developer boot - self-signed kernel ok */
+ kBootRecovery = 0, /* Recovery firmware, any dev switch position */
+ kBootNormal = 1, /* Normal boot - kernel must be verified */
+ kBootDev = 2 /* Developer boot - self-signed kernel ok */
} BootMode;
-
-/* Allocates and reads GPT data from the drive. The sector_bytes and
- * drive_sectors fields should be filled on input. The primary and
- * secondary header and entries are filled on output.
+/**
+ * Allocate and read GPT data from the drive.
+ *
+ * The sector_bytes and drive_sectors fields should be filled on input. The
+ * primary and secondary header and entries are filled on output.
*
- * Returns 0 if successful, 1 if error. */
-int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) {
-
- uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
-
- /* No data to be written yet */
- gptdata->modified = 0;
-
- /* Allocate all buffers */
- gptdata->primary_header = (uint8_t*)VbExMalloc(gptdata->sector_bytes);
- gptdata->secondary_header = (uint8_t*)VbExMalloc(gptdata->sector_bytes);
- gptdata->primary_entries = (uint8_t*)VbExMalloc(TOTAL_ENTRIES_SIZE);
- gptdata->secondary_entries = (uint8_t*)VbExMalloc(TOTAL_ENTRIES_SIZE);
-
- if (gptdata->primary_header == NULL || gptdata->secondary_header == NULL ||
- gptdata->primary_entries == NULL || gptdata->secondary_entries == NULL)
- return 1;
-
- /* Read data from the drive, skipping the protective MBR */
- if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header))
- return 1;
- if (0 != VbExDiskRead(disk_handle, 2, entries_sectors,
- gptdata->primary_entries))
- return 1;
- if (0 != VbExDiskRead(disk_handle,
- gptdata->drive_sectors - entries_sectors - 1,
- entries_sectors, gptdata->secondary_entries))
- return 1;
- if (0 != VbExDiskRead(disk_handle, gptdata->drive_sectors - 1, 1,
- gptdata->secondary_header))
- return 1;
-
- return 0;
+ * Returns 0 if successful, 1 if error.
+ */
+int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
+{
+ uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
+
+ /* No data to be written yet */
+ gptdata->modified = 0;
+
+ /* Allocate all buffers */
+ gptdata->primary_header = (uint8_t *)VbExMalloc(gptdata->sector_bytes);
+ gptdata->secondary_header =
+ (uint8_t *)VbExMalloc(gptdata->sector_bytes);
+ gptdata->primary_entries = (uint8_t *)VbExMalloc(TOTAL_ENTRIES_SIZE);
+ gptdata->secondary_entries = (uint8_t *)VbExMalloc(TOTAL_ENTRIES_SIZE);
+
+ if (gptdata->primary_header == NULL ||
+ gptdata->secondary_header == NULL ||
+ gptdata->primary_entries == NULL ||
+ gptdata->secondary_entries == NULL)
+ return 1;
+
+ /* Read data from the drive, skipping the protective MBR */
+ if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header))
+ return 1;
+ if (0 != VbExDiskRead(disk_handle, 2, entries_sectors,
+ gptdata->primary_entries))
+ return 1;
+ if (0 != VbExDiskRead(disk_handle,
+ gptdata->drive_sectors - entries_sectors - 1,
+ entries_sectors, gptdata->secondary_entries))
+ return 1;
+ if (0 != VbExDiskRead(disk_handle, gptdata->drive_sectors - 1, 1,
+ gptdata->secondary_header))
+ return 1;
+
+ return 0;
}
-
-/* Writes any changes for the GPT data back to the drive, then frees
- * the buffers.
+/**
+ * Write any changes for the GPT data back to the drive, then free the buffers.
*
- * Returns 0 if successful, 1 if error. */
-int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) {
-
- int legacy = 0;
- uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
-
- if (gptdata->primary_header) {
- GptHeader* h = (GptHeader*)(gptdata->primary_header);
- legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
- GPT_HEADER_SIGNATURE_SIZE);
- if (gptdata->modified & GPT_MODIFIED_HEADER1) {
- if (legacy) {
- VBDEBUG(("Not updating GPT header 1: legacy mode is enabled.\n"));
- } else {
- VBDEBUG(("Updating GPT header 1\n"));
- if (0 != VbExDiskWrite(disk_handle, 1, 1, gptdata->primary_header))
- return 1;
- }
- }
- VbExFree(gptdata->primary_header);
- }
-
- if (gptdata->primary_entries) {
- if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
- if (legacy) {
- VBDEBUG(("Not updating GPT entries 1: legacy mode is enabled.\n"));
- } else {
- VBDEBUG(("Updating GPT entries 1\n"));
- if (0 != VbExDiskWrite(disk_handle, 2, entries_sectors,
- gptdata->primary_entries))
- return 1;
- }
- }
- VbExFree(gptdata->primary_entries);
- }
-
- if (gptdata->secondary_entries) {
- if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
- VBDEBUG(("Updating GPT header 2\n"));
- if (0 != VbExDiskWrite(disk_handle,
- gptdata->drive_sectors - entries_sectors - 1,
- entries_sectors, gptdata->secondary_entries))
- return 1;
- }
- VbExFree(gptdata->secondary_entries);
- }
-
- if (gptdata->secondary_header) {
- if (gptdata->modified & GPT_MODIFIED_HEADER2) {
- VBDEBUG(("Updating GPT entries 2\n"));
- if (0 != VbExDiskWrite(disk_handle, gptdata->drive_sectors - 1, 1,
- gptdata->secondary_header))
- return 1;
- }
- VbExFree(gptdata->secondary_header);
- }
-
- /* Success */
- return 0;
+ * Returns 0 if successful, 1 if error.
+ */
+int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
+{
+ int legacy = 0;
+ uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes;
+
+ if (gptdata->primary_header) {
+ GptHeader *h = (GptHeader *)(gptdata->primary_header);
+ legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
+ GPT_HEADER_SIGNATURE_SIZE);
+ if (gptdata->modified & GPT_MODIFIED_HEADER1) {
+ if (legacy) {
+ VBDEBUG(("Not updating GPT header 1: "
+ "legacy mode is enabled.\n"));
+ } else {
+ VBDEBUG(("Updating GPT header 1\n"));
+ if (0 != VbExDiskWrite(disk_handle, 1, 1,
+ gptdata->primary_header))
+ return 1;
+ }
+ }
+ VbExFree(gptdata->primary_header);
+ }
+
+ if (gptdata->primary_entries) {
+ if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
+ if (legacy) {
+ VBDEBUG(("Not updating GPT entries 1: "
+ "legacy mode is enabled.\n"));
+ } else {
+ VBDEBUG(("Updating GPT entries 1\n"));
+ if (0 != VbExDiskWrite(disk_handle, 2,
+ entries_sectors,
+ gptdata->primary_entries))
+ return 1;
+ }
+ }
+ VbExFree(gptdata->primary_entries);
+ }
+
+ if (gptdata->secondary_entries) {
+ if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
+ VBDEBUG(("Updating GPT header 2\n"));
+ if (0 != VbExDiskWrite(disk_handle,
+ gptdata->drive_sectors - entries_sectors - 1,
+ entries_sectors, gptdata->secondary_entries))
+ return 1;
+ }
+ VbExFree(gptdata->secondary_entries);
+ }
+
+ if (gptdata->secondary_header) {
+ if (gptdata->modified & GPT_MODIFIED_HEADER2) {
+ VBDEBUG(("Updating GPT entries 2\n"));
+ if (0 != VbExDiskWrite(disk_handle,
+ gptdata->drive_sectors - 1, 1,
+ gptdata->secondary_header))
+ return 1;
+ }
+ VbExFree(gptdata->secondary_header);
+ }
+
+ /* Success */
+ return 0;
}
/* disable MSVC warning on const logical expression (as in } while(0);) */
__pragma(warning(disable: 4127))
-
-VbError_t LoadKernel(LoadKernelParams* params) {
- VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob;
- VbSharedDataKernelCall* shcall = NULL;
- VbNvContext* vnc = params->nv_context;
- GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data;
- VbPublicKey* kernel_subkey;
- GptData gpt;
- uint64_t part_start, part_size;
- uint64_t blba;
- uint64_t kbuf_sectors;
- uint8_t* kbuf = NULL;
- int found_partitions = 0;
- int good_partition = -1;
- int good_partition_key_block_valid = 0;
- uint32_t lowest_version = LOWEST_TPM_VERSION;
- int rec_switch, dev_switch;
- BootMode boot_mode;
- uint32_t require_official_os = 0;
-
- VbError_t retval = VBERROR_UNKNOWN;
- int recovery = VBNV_RECOVERY_LK_UNSPECIFIED;
-
- /* Sanity Checks */
- if (!params ||
- !params->bytes_per_lba ||
- !params->ending_lba) {
- VBDEBUG(("LoadKernel() called with invalid params\n"));
- retval = VBERROR_INVALID_PARAMETER;
- goto LoadKernelExit;
- }
-
- /* Clear output params in case we fail */
- params->partition_number = 0;
- params->bootloader_address = 0;
- params->bootloader_size = 0;
-
- /* Calculate switch positions and boot mode */
- rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
- dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
- if (rec_switch) {
- boot_mode = kBootRecovery;
- } else if (dev_switch) {
- boot_mode = kBootDev;
- VbNvGet(vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
- } else {
- boot_mode = kBootNormal;
- }
-
- /* Set up tracking for this call. This wraps around if called many times,
- * so we need to initialize the call entry each time. */
- shcall = shared->lk_calls + (shared->lk_call_count
- & (VBSD_MAX_KERNEL_CALLS - 1));
- Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
- shcall->boot_flags = (uint32_t)params->boot_flags;
- shcall->boot_mode = boot_mode;
- shcall->sector_size = (uint32_t)params->bytes_per_lba;
- shcall->sector_count = params->ending_lba + 1;
- shared->lk_call_count++;
-
- /* Initialization */
- blba = params->bytes_per_lba;
- kbuf_sectors = KBUF_SIZE / blba;
- if (0 == kbuf_sectors) {
- VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
- retval = VBERROR_INVALID_PARAMETER;
- goto LoadKernelExit;
- }
-
- if (kBootRecovery == boot_mode) {
- /* Use the recovery key to verify the kernel */
- kernel_subkey = (VbPublicKey*)((uint8_t*)gbb + gbb->recovery_key_offset);
- } else {
- /* Use the kernel subkey passed from LoadFirmware(). */
- kernel_subkey = &shared->kernel_subkey;
- }
-
- do {
- /* Read GPT data */
- gpt.sector_bytes = (uint32_t)blba;
- gpt.drive_sectors = params->ending_lba + 1;
- if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
- VBDEBUG(("Unable to read GPT data\n"));
- shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
- break;
- }
-
- /* Initialize GPT library */
- if (GPT_SUCCESS != GptInit(&gpt)) {
- VBDEBUG(("Error parsing GPT\n"));
- shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
- break;
- }
-
- /* Allocate kernel header buffers */
- kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE);
- if (!kbuf)
- break;
-
- /* Loop over candidate kernel partitions */
- while (GPT_SUCCESS == GptNextKernelEntry(&gpt, &part_start, &part_size)) {
- VbSharedDataKernelPart* shpart = NULL;
- VbKeyBlockHeader* key_block;
- VbKernelPreambleHeader* preamble;
- RSAPublicKey* data_key = NULL;
- uint64_t key_version;
- uint32_t combined_version;
- uint64_t body_offset;
- uint64_t body_offset_sectors;
- uint64_t body_sectors;
- int key_block_valid = 1;
-
- VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
- part_start, part_size));
-
- /* Set up tracking for this partition. This wraps around if called
- * many times, so initialize the partition entry each time. */
- shpart = shcall->parts + (shcall->kernel_parts_found
- & (VBSD_MAX_KERNEL_PARTS - 1));
- Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
- shpart->sector_start = part_start;
- shpart->sector_count = part_size;
- /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
- * Adjust here, until cgptlib is fixed. */
- shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
- shcall->kernel_parts_found++;
-
- /* Found at least one kernel partition. */
- found_partitions++;
-
- /* Read the first part of the kernel partition. */
- if (part_size < kbuf_sectors) {
- VBDEBUG(("Partition too small to hold kernel.\n"));
- shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
- goto bad_kernel;
- }
-
- if (0 != VbExDiskRead(params->disk_handle, part_start, kbuf_sectors,
- kbuf)) {
- VBDEBUG(("Unable to read start of partition.\n"));
- shpart->check_result = VBSD_LKP_CHECK_READ_START;
- goto bad_kernel;
- }
+VbError_t LoadKernel(LoadKernelParams *params)
+{
+ VbSharedDataHeader *shared =
+ (VbSharedDataHeader *)params->shared_data_blob;
+ VbSharedDataKernelCall *shcall = NULL;
+ VbNvContext* vnc = params->nv_context;
+ GoogleBinaryBlockHeader* gbb =
+ (GoogleBinaryBlockHeader *)params->gbb_data;
+ VbPublicKey* kernel_subkey;
+ GptData gpt;
+ uint64_t part_start, part_size;
+ uint64_t blba;
+ uint64_t kbuf_sectors;
+ uint8_t* kbuf = NULL;
+ int found_partitions = 0;
+ int good_partition = -1;
+ int good_partition_key_block_valid = 0;
+ uint32_t lowest_version = LOWEST_TPM_VERSION;
+ int rec_switch, dev_switch;
+ BootMode boot_mode;
+ uint32_t require_official_os = 0;
+
+ VbError_t retval = VBERROR_UNKNOWN;
+ int recovery = VBNV_RECOVERY_LK_UNSPECIFIED;
+
+ /* Sanity Checks */
+ if (!params->bytes_per_lba ||
+ !params->ending_lba) {
+ VBDEBUG(("LoadKernel() called with invalid params\n"));
+ retval = VBERROR_INVALID_PARAMETER;
+ goto LoadKernelExit;
+ }
+
+ /* Clear output params in case we fail */
+ params->partition_number = 0;
+ params->bootloader_address = 0;
+ params->bootloader_size = 0;
+
+ /* Calculate switch positions and boot mode */
+ rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
+ dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
+ if (rec_switch) {
+ boot_mode = kBootRecovery;
+ } else if (dev_switch) {
+ boot_mode = kBootDev;
+ VbNvGet(vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
+ } else {
+ boot_mode = kBootNormal;
+ }
+
+ /*
+ * Set up tracking for this call. This wraps around if called many
+ * times, so we need to initialize the call entry each time.
+ */
+ shcall = shared->lk_calls + (shared->lk_call_count
+ & (VBSD_MAX_KERNEL_CALLS - 1));
+ Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
+ shcall->boot_flags = (uint32_t)params->boot_flags;
+ shcall->boot_mode = boot_mode;
+ shcall->sector_size = (uint32_t)params->bytes_per_lba;
+ shcall->sector_count = params->ending_lba + 1;
+ shared->lk_call_count++;
+
+ /* Initialization */
+ blba = params->bytes_per_lba;
+ kbuf_sectors = KBUF_SIZE / blba;
+ if (0 == kbuf_sectors) {
+ VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
+ retval = VBERROR_INVALID_PARAMETER;
+ goto LoadKernelExit;
+ }
+
+ if (kBootRecovery == boot_mode) {
+ /* Use the recovery key to verify the kernel */
+ kernel_subkey = (VbPublicKey*)
+ ((uint8_t*)gbb + gbb->recovery_key_offset);
+ } else {
+ /* Use the kernel subkey passed from LoadFirmware(). */
+ kernel_subkey = &shared->kernel_subkey;
+ }
+
+ /* Read GPT data */
+ gpt.sector_bytes = (uint32_t)blba;
+ gpt.drive_sectors = params->ending_lba + 1;
+ if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
+ VBDEBUG(("Unable to read GPT data\n"));
+ shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
+ goto bad_gpt;
+ }
+
+ /* Initialize GPT library */
+ if (GPT_SUCCESS != GptInit(&gpt)) {
+ VBDEBUG(("Error parsing GPT\n"));
+ shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
+ goto bad_gpt;
+ }
+
+ /* Allocate kernel header buffers */
+ kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE);
+ if (!kbuf)
+ goto bad_gpt;
+
+ /* Loop over candidate kernel partitions */
+ while (GPT_SUCCESS ==
+ GptNextKernelEntry(&gpt, &part_start, &part_size)) {
+ VbSharedDataKernelPart *shpart = NULL;
+ VbKeyBlockHeader *key_block;
+ VbKernelPreambleHeader *preamble;
+ RSAPublicKey *data_key = NULL;
+ uint64_t key_version;
+ uint32_t combined_version;
+ uint64_t body_offset;
+ uint64_t body_offset_sectors;
+ uint64_t body_sectors;
+ int key_block_valid = 1;
+
+ VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
+ part_start, part_size));
+
+ /*
+ * Set up tracking for this partition. This wraps around if
+ * called many times, so initialize the partition entry each
+ * time.
+ */
+ shpart = shcall->parts + (shcall->kernel_parts_found
+ & (VBSD_MAX_KERNEL_PARTS - 1));
+ Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
+ shpart->sector_start = part_start;
+ shpart->sector_count = part_size;
+ /*
+ * TODO: GPT partitions start at 1, but cgptlib starts them at
+ * 0. Adjust here, until cgptlib is fixed.
+ */
+ shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
+ shcall->kernel_parts_found++;
+
+ /* Found at least one kernel partition. */
+ found_partitions++;
+
+ /* Read the first part of the kernel partition. */
+ if (part_size < kbuf_sectors) {
+ VBDEBUG(("Partition too small to hold kernel.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
+ goto bad_kernel;
+ }
+
+ if (0 != VbExDiskRead(params->disk_handle, part_start,
+ kbuf_sectors, kbuf)) {
+ VBDEBUG(("Unable to read start of partition.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_READ_START;
+ goto bad_kernel;
+ }
#if defined(CONFIG_SANDBOX)
- /* Silence compiler warnings */
- combined_version = 0;
- body_offset = body_offset;
- body_offset_sectors = body_offset_sectors;
- body_sectors = body_sectors;
- kernel_subkey = kernel_subkey;
- key_block = key_block;
- key_version = key_version;
- preamble = preamble;
+ /* Silence compiler warnings */
+ combined_version = 0;
+ body_offset = body_offset;
+ body_offset_sectors = body_offset_sectors;
+ body_sectors = body_sectors;
+ kernel_subkey = kernel_subkey;
+ key_block = key_block;
+ key_version = key_version;
+ preamble = preamble;
#else
- /* Verify the key block. */
- key_block = (VbKeyBlockHeader*)kbuf;
- if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 0)) {
- VBDEBUG(("Verifying key block signature failed.\n"));
- shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
-
- key_block_valid = 0;
-
- /* If we're not in developer mode, this kernel is bad. */
- if (kBootDev != boot_mode)
- goto bad_kernel;
-
- /* In developer mode, we can explictly disallow self-signed kernels */
- if (require_official_os) {
- VBDEBUG(("Self-signed custom kernels are not enabled.\n"));
- shpart->check_result = VBSD_LKP_CHECK_SELF_SIGNED;
- goto bad_kernel;
- }
-
- /* Allow the kernel if the SHA-512 hash of the key block is valid. */
- if (0 != KeyBlockVerify(key_block, KBUF_SIZE, kernel_subkey, 1)) {
- VBDEBUG(("Verifying key block hash failed.\n"));
- shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_HASH;
- goto bad_kernel;
- }
- }
-
- /* Check the key block flags against the current boot mode. */
- if (!(key_block->key_block_flags &
- (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
- KEY_BLOCK_FLAG_DEVELOPER_0))) {
- VBDEBUG(("Key block developer flag mismatch.\n"));
- shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
- key_block_valid = 0;
- }
- if (!(key_block->key_block_flags &
- (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
- KEY_BLOCK_FLAG_RECOVERY_0))) {
- VBDEBUG(("Key block recovery flag mismatch.\n"));
- shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
- key_block_valid = 0;
- }
-
- /* Check for rollback of key version except in recovery mode. */
- key_version = key_block->data_key.key_version;
- if (kBootRecovery != boot_mode) {
- if (key_version < (shared->kernel_version_tpm >> 16)) {
- VBDEBUG(("Key version too old.\n"));
- shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
- key_block_valid = 0;
- }
- if (key_version > 0xFFFF) {
- /* Key version is stored in 16 bits in the TPM, so key versions
- * greater than 0xFFFF can't be stored properly. */
- VBDEBUG(("Key version > 0xFFFF.\n"));
- shpart->check_result = VBSD_LKP_CHECK_KEY_ROLLBACK;
- key_block_valid = 0;
- }
- }
-
- /* If we're not in developer mode, require the key block to be valid. */
- if (kBootDev != boot_mode && !key_block_valid) {
- VBDEBUG(("Key block is invalid.\n"));
- goto bad_kernel;
- }
-
- /* Get the key for preamble/data verification from the key block. */
- data_key = PublicKeyToRSA(&key_block->data_key);
- if (!data_key) {
- VBDEBUG(("Data key bad.\n"));
- shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
- goto bad_kernel;
- }
-
- /* Verify the preamble, which follows the key block */
- preamble = (VbKernelPreambleHeader*)(kbuf + key_block->key_block_size);
- if ((0 != VerifyKernelPreamble(preamble,
- KBUF_SIZE - key_block->key_block_size,
- data_key))) {
- VBDEBUG(("Preamble verification failed.\n"));
- shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
- goto bad_kernel;
- }
-
- /* If the key block is valid and we're not in recovery mode, check for
- * rollback of the kernel version. */
- combined_version = (uint32_t)((key_version << 16) |
- (preamble->kernel_version & 0xFFFF));
- shpart->combined_version = combined_version;
- if (key_block_valid && kBootRecovery != boot_mode) {
- if (combined_version < shared->kernel_version_tpm) {
- VBDEBUG(("Kernel version too low.\n"));
- shpart->check_result = VBSD_LKP_CHECK_KERNEL_ROLLBACK;
- /* If we're not in developer mode, kernel version must be valid. */
- if (kBootDev != boot_mode)
- goto bad_kernel;
- }
- }
-
- VBDEBUG(("Kernel preamble is good.\n"));
- shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
-
- /* Check for lowest version from a valid header. */
- if (key_block_valid && lowest_version > combined_version)
- lowest_version = combined_version;
- else {
- VBDEBUG(("Key block valid: %d\n", key_block_valid));
- VBDEBUG(("Combined version: %u\n", (unsigned) combined_version));
- }
-
- /* If we already have a good kernel, no need to read another
- * one; we only needed to look at the versions to check for
- * rollback. So skip to the next kernel preamble. */
- if (-1 != good_partition)
- continue;
-
- /* Verify kernel body starts at a multiple of the sector size. */
- body_offset = key_block->key_block_size + preamble->preamble_size;
- if (0 != body_offset % blba) {
- VBDEBUG(("Kernel body not at multiple of sector size.\n"));
- shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
- goto bad_kernel;
- }
- body_offset_sectors = body_offset / blba;
-
- body_sectors = (preamble->body_signature.data_size + blba - 1) / blba;
- if (!params->kernel_buffer) {
- /* Get kernel load address and size from the header. */
- params->kernel_buffer = (void*) ((long)preamble->body_load_address);
- params->kernel_buffer_size = body_sectors * blba;
- } else {
- /* Verify kernel body fits in the buffer */
- if (body_sectors * blba > params->kernel_buffer_size) {
- VBDEBUG(("Kernel body doesn't fit in memory.\n"));
- shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
- goto bad_kernel;
- }
- }
-
- /* Verify kernel body fits in the partition */
- if (body_offset_sectors + body_sectors > part_size) {
- VBDEBUG(("Kernel body doesn't fit in partition.\n"));
- shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
- goto bad_kernel;
- }
-
- /* Read the kernel data */
- VBPERFSTART("VB_RKD");
- if (0 != VbExDiskRead(params->disk_handle,
- part_start + body_offset_sectors,
- body_sectors, params->kernel_buffer)) {
- VBDEBUG(("Unable to read kernel data.\n"));
- VBPERFEND("VB_RKD");
- shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
- goto bad_kernel;
- }
- VBPERFEND("VB_RKD");
-
- /* Verify kernel data */
- if (0 != VerifyData((const uint8_t*)params->kernel_buffer,
- params->kernel_buffer_size,
- &preamble->body_signature, data_key)) {
- VBDEBUG(("Kernel data verification failed.\n"));
- shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
- goto bad_kernel;
- }
-
- /* Done with the kernel signing key, so can free it now */
- RSAPublicKeyFree(data_key);
- data_key = NULL;
+ /* Verify the key block. */
+ key_block = (VbKeyBlockHeader*)kbuf;
+ if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
+ kernel_subkey, 0)) {
+ VBDEBUG(("Verifying key block signature failed.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
+ key_block_valid = 0;
+
+ /* If not in developer mode, this kernel is bad. */
+ if (kBootDev != boot_mode)
+ goto bad_kernel;
+
+ /*
+ * In developer mode, we can explictly disallow
+ * self-signed kernels
+ */
+ if (require_official_os) {
+ VBDEBUG(("Self-signed kernels not enabled.\n"));
+ shpart->check_result =
+ VBSD_LKP_CHECK_SELF_SIGNED;
+ goto bad_kernel;
+ }
+
+ /*
+ * Allow the kernel if the SHA-512 hash of the key
+ * block is valid.
+ */
+ if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
+ kernel_subkey, 1)) {
+ VBDEBUG(("Verifying key block hash failed.\n"));
+ shpart->check_result =
+ VBSD_LKP_CHECK_KEY_BLOCK_HASH;
+ goto bad_kernel;
+ }
+ }
+
+ /* Check the key block flags against the current boot mode. */
+ if (!(key_block->key_block_flags &
+ (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
+ KEY_BLOCK_FLAG_DEVELOPER_0))) {
+ VBDEBUG(("Key block developer flag mismatch.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
+ key_block_valid = 0;
+ }
+ if (!(key_block->key_block_flags &
+ (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
+ KEY_BLOCK_FLAG_RECOVERY_0))) {
+ VBDEBUG(("Key block recovery flag mismatch.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
+ key_block_valid = 0;
+ }
+
+ /* Check for rollback of key version except in recovery mode. */
+ key_version = key_block->data_key.key_version;
+ if (kBootRecovery != boot_mode) {
+ if (key_version < (shared->kernel_version_tpm >> 16)) {
+ VBDEBUG(("Key version too old.\n"));
+ shpart->check_result =
+ VBSD_LKP_CHECK_KEY_ROLLBACK;
+ key_block_valid = 0;
+ }
+ if (key_version > 0xFFFF) {
+ /*
+ * Key version is stored in 16 bits in the TPM,
+ * so key versions greater than 0xFFFF can't be
+ * stored properly.
+ */
+ VBDEBUG(("Key version > 0xFFFF.\n"));
+ shpart->check_result =
+ VBSD_LKP_CHECK_KEY_ROLLBACK;
+ key_block_valid = 0;
+ }
+ }
+
+ /* If not in developer mode, key block required to be valid. */
+ if (kBootDev != boot_mode && !key_block_valid) {
+ VBDEBUG(("Key block is invalid.\n"));
+ goto bad_kernel;
+ }
+
+ /* Get key for preamble/data verification from the key block. */
+ data_key = PublicKeyToRSA(&key_block->data_key);
+ if (!data_key) {
+ VBDEBUG(("Data key bad.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
+ goto bad_kernel;
+ }
+
+ /* Verify the preamble, which follows the key block */
+ preamble = (VbKernelPreambleHeader *)
+ (kbuf + key_block->key_block_size);
+ if ((0 != VerifyKernelPreamble(
+ preamble,
+ KBUF_SIZE - key_block->key_block_size,
+ data_key))) {
+ VBDEBUG(("Preamble verification failed.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
+ goto bad_kernel;
+ }
+
+ /*
+ * If the key block is valid and we're not in recovery mode,
+ * check for rollback of the kernel version.
+ */
+ combined_version = (uint32_t)(
+ (key_version << 16) |
+ (preamble->kernel_version & 0xFFFF));
+ shpart->combined_version = combined_version;
+ if (key_block_valid && kBootRecovery != boot_mode) {
+ if (combined_version < shared->kernel_version_tpm) {
+ VBDEBUG(("Kernel version too low.\n"));
+ shpart->check_result =
+ VBSD_LKP_CHECK_KERNEL_ROLLBACK;
+ /*
+ * If not in developer mode, kernel version
+ * must be valid.
+ */
+ if (kBootDev != boot_mode)
+ goto bad_kernel;
+ }
+ }
+
+ VBDEBUG(("Kernel preamble is good.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
+
+ /* Check for lowest version from a valid header. */
+ if (key_block_valid && lowest_version > combined_version)
+ lowest_version = combined_version;
+ else {
+ VBDEBUG(("Key block valid: %d\n", key_block_valid));
+ VBDEBUG(("Combined version: %u\n",
+ (unsigned) combined_version));
+ }
+
+ /*
+ * If we already have a good kernel, no need to read another
+ * one; we only needed to look at the versions to check for
+ * rollback. So skip to the next kernel preamble.
+ */
+ if (-1 != good_partition)
+ continue;
+
+ /* Verify kernel body starts at multiple of sector size. */
+ body_offset = key_block->key_block_size +
+ preamble->preamble_size;
+ if (0 != body_offset % blba) {
+ VBDEBUG(("Kernel body not at multiple of "
+ "sector size.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
+ goto bad_kernel;
+ }
+ body_offset_sectors = body_offset / blba;
+
+ body_sectors =
+ (preamble->body_signature.data_size + blba - 1) / blba;
+ if (!params->kernel_buffer) {
+ /* Get kernel load address and size from the header. */
+ params->kernel_buffer =
+ (void *)((long)preamble->body_load_address);
+ params->kernel_buffer_size = body_sectors * blba;
+ } else {
+ /* Verify kernel body fits in the buffer */
+ if (body_sectors * blba > params->kernel_buffer_size) {
+ VBDEBUG(("Kernel body doesn't "
+ "fit in memory.\n"));
+ shpart->check_result =
+ VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
+ goto bad_kernel;
+ }
+ }
+
+ /* Verify kernel body fits in the partition */
+ if (body_offset_sectors + body_sectors > part_size) {
+ VBDEBUG(("Kernel body doesn't fit in partition.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_PART;
+ goto bad_kernel;
+ }
+
+ /* Read the kernel data */
+ VBPERFSTART("VB_RKD");
+ if (0 != VbExDiskRead(params->disk_handle,
+ part_start + body_offset_sectors,
+ body_sectors, params->kernel_buffer)) {
+ VBDEBUG(("Unable to read kernel data.\n"));
+ VBPERFEND("VB_RKD");
+ shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
+ goto bad_kernel;
+ }
+ VBPERFEND("VB_RKD");
+
+ /* Verify kernel data */
+ if (0 != VerifyData((const uint8_t *)params->kernel_buffer,
+ params->kernel_buffer_size,
+ &preamble->body_signature, data_key)) {
+ VBDEBUG(("Kernel data verification failed.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
+ goto bad_kernel;
+ }
+
+ /* Done with the kernel signing key, so can free it now */
+ RSAPublicKeyFree(data_key);
+ data_key = NULL;
#endif
- /* If we're still here, the kernel is valid. */
- /* Save the first good partition we find; that's the one we'll boot */
- VBDEBUG(("Partition is good.\n"));
- shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
- if (key_block_valid)
- shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
-
- good_partition_key_block_valid = key_block_valid;
- /* TODO: GPT partitions start at 1, but cgptlib starts them at 0.
- * Adjust here, until cgptlib is fixed. */
- good_partition = gpt.current_kernel + 1;
- params->partition_number = gpt.current_kernel + 1;
- GetCurrentKernelUniqueGuid(&gpt, &params->partition_guid);
- /* TODO: GetCurrentKernelUniqueGuid() should take a destination size, or
- * the dest should be a struct, so we know it's big enough. */
+ /*
+ * If we're still here, the kernel is valid. Save the first
+ * good partition we find; that's the one we'll boot.
+ */
+ VBDEBUG(("Partition is good.\n"));
+ shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
+ if (key_block_valid)
+ shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
+
+ good_partition_key_block_valid = key_block_valid;
+ /*
+ * TODO: GPT partitions start at 1, but cgptlib starts them at
+ * 0. Adjust here, until cgptlib is fixed.
+ */
+ good_partition = gpt.current_kernel + 1;
+ params->partition_number = gpt.current_kernel + 1;
+ GetCurrentKernelUniqueGuid(&gpt, &params->partition_guid);
+ /*
+ * TODO: GetCurrentKernelUniqueGuid() should take a destination
+ * size, or the dest should be a struct, so we know it's big
+ * enough.
+ */
#if defined(CONFIG_SANDBOX)
- params->bootloader_address = 0;
- params->bootloader_size = 0;
+ params->bootloader_address = 0;
+ params->bootloader_size = 0;
#else
- params->bootloader_address = preamble->bootloader_address;
- params->bootloader_size = preamble->bootloader_size;
+ params->bootloader_address = preamble->bootloader_address;
+ params->bootloader_size = preamble->bootloader_size;
#endif
- /* Update GPT to note this is the kernel we're trying */
- GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY);
-
- /* If we're in recovery mode or we're about to boot a dev-signed kernel,
- * there's no rollback protection, so we can stop at the first valid
- * kernel. */
- if (kBootRecovery == boot_mode || !key_block_valid) {
- VBDEBUG(("In recovery mode or dev-signed kernel\n"));
- break;
- }
-
- /* Otherwise, we do care about the key index in the TPM. If the good
- * partition's key version is the same as the tpm, then the TPM doesn't
- * need updating; we can stop now. Otherwise, we'll check all the other
- * headers to see if they contain a newer key. */
- if (combined_version == shared->kernel_version_tpm) {
- VBDEBUG(("Same kernel version\n"));
- break;
- }
-
- /* Continue, so that we skip the error handling code below */
- continue;
-
- bad_kernel:
- /* Handle errors parsing this kernel */
- if (NULL != data_key)
- RSAPublicKeyFree(data_key);
-
- VBDEBUG(("Marking kernel as invalid.\n"));
- GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
-
-
- } /* while(GptNextKernelEntry) */
- } while(0);
-
- /* Free kernel buffer */
- if (kbuf)
- VbExFree(kbuf);
-
- /* Write and free GPT data */
- WriteAndFreeGptData(params->disk_handle, &gpt);
-
- /* Handle finding a good partition */
- if (good_partition >= 0) {
- VBDEBUG(("Good_partition >= 0\n"));
- shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
- shared->kernel_version_lowest = lowest_version;
- /* Sanity check - only store a new TPM version if we found one.
- * If lowest_version is still at its initial value, we didn't find
- * one; for example, we're in developer mode and just didn't look. */
- if (lowest_version != LOWEST_TPM_VERSION &&
- lowest_version > shared->kernel_version_tpm)
- shared->kernel_version_tpm = lowest_version;
-
- /* Success! */
- retval = VBERROR_SUCCESS;
- } else if (found_partitions > 0) {
- shcall->check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS;
- recovery = VBNV_RECOVERY_RW_INVALID_OS;
- retval = VBERROR_INVALID_KERNEL_FOUND;
- } else {
- shcall->check_result = VBSD_LKC_CHECK_NO_PARTITIONS;
- recovery = VBNV_RECOVERY_RW_NO_OS;
- retval = VBERROR_NO_KERNEL_FOUND;
- }
-
-LoadKernelExit:
-
- /* Store recovery request, if any */
- VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
- recovery : VBNV_RECOVERY_NOT_REQUESTED);
-
- /* If LoadKernel was called with bad parameters,
- * shcall may not be initialized. */
- if (shcall)
- shcall->return_code = (uint8_t)retval;
-
- /* Save whether the good partition's key block was fully verified */
- if (good_partition_key_block_valid)
- shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
-
- /* Store how much shared data we used, if any */
- params->shared_data_size = shared->data_used;
-
- return retval;
+ /* Update GPT to note this is the kernel we're trying */
+ GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY);
+
+ /*
+ * If we're in recovery mode or we're about to boot a
+ * dev-signed kernel, there's no rollback protection, so we can
+ * stop at the first valid kernel.
+ */
+ if (kBootRecovery == boot_mode || !key_block_valid) {
+ VBDEBUG(("In recovery mode or dev-signed kernel\n"));
+ break;
+ }
+
+ /*
+ * Otherwise, we do care about the key index in the TPM. If
+ * the good partition's key version is the same as the tpm,
+ * then the TPM doesn't need updating; we can stop now.
+ * Otherwise, we'll check all the other headers to see if they
+ * contain a newer key.
+ */
+ if (combined_version == shared->kernel_version_tpm) {
+ VBDEBUG(("Same kernel version\n"));
+ break;
+ }
+
+ /* Continue, so that we skip the error handling code below */
+ continue;
+
+ bad_kernel:
+ /* Handle errors parsing this kernel */
+ if (NULL != data_key)
+ RSAPublicKeyFree(data_key);
+
+ VBDEBUG(("Marking kernel as invalid.\n"));
+ GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
+
+
+ } /* while(GptNextKernelEntry) */
+
+ bad_gpt:
+
+ /* Free kernel buffer */
+ if (kbuf)
+ VbExFree(kbuf);
+
+ /* Write and free GPT data */
+ WriteAndFreeGptData(params->disk_handle, &gpt);
+
+ /* Handle finding a good partition */
+ if (good_partition >= 0) {
+ VBDEBUG(("Good_partition >= 0\n"));
+ shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
+ shared->kernel_version_lowest = lowest_version;
+ /*
+ * Sanity check - only store a new TPM version if we found one.
+ * If lowest_version is still at its initial value, we didn't
+ * find one; for example, we're in developer mode and just
+ * didn't look.
+ */
+ if (lowest_version != LOWEST_TPM_VERSION &&
+ lowest_version > shared->kernel_version_tpm)
+ shared->kernel_version_tpm = lowest_version;
+
+ /* Success! */
+ retval = VBERROR_SUCCESS;
+ } else if (found_partitions > 0) {
+ shcall->check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS;
+ recovery = VBNV_RECOVERY_RW_INVALID_OS;
+ retval = VBERROR_INVALID_KERNEL_FOUND;
+ } else {
+ shcall->check_result = VBSD_LKC_CHECK_NO_PARTITIONS;
+ recovery = VBNV_RECOVERY_RW_NO_OS;
+ retval = VBERROR_NO_KERNEL_FOUND;
+ }
+
+ LoadKernelExit:
+
+ /* Store recovery request, if any */
+ VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
+ recovery : VBNV_RECOVERY_NOT_REQUESTED);
+
+ /*
+ * If LoadKernel() was called with bad parameters, shcall may not be
+ * initialized.
+ */
+ if (shcall)
+ shcall->return_code = (uint8_t)retval;
+
+ /* Save whether the good partition's key block was fully verified */
+ if (good_partition_key_block_valid)
+ shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
+
+ /* Store how much shared data we used, if any */
+ params->shared_data_size = shared->data_used;
+
+ return retval;
}
diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c
index 3497392e..618c7124 100644
--- a/firmware/lib/vboot_nvstorage.c
+++ b/firmware/lib/vboot_nvstorage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@@ -11,9 +11,10 @@
#include "vboot_common.h"
#include "vboot_nvstorage.h"
-/* Constants for NV storage. We use this rather than structs and
- * bitfields so the data format is consistent across platforms and
- * compilers. */
+/*
+ * Constants for NV storage. We use this rather than structs and bitfields so
+ * the data format is consistent across platforms and compilers.
+ */
#define HEADER_OFFSET 0
#define HEADER_MASK 0xC0
#define HEADER_SIGNATURE 0x40
@@ -43,235 +44,241 @@
#define KERNEL_FIELD_OFFSET 11
#define CRC_OFFSET 15
+int VbNvSetup(VbNvContext *context)
+{
+ uint8_t *raw = context->raw;
-int VbNvSetup(VbNvContext* context) {
- uint8_t* raw = context->raw;
-
- /* Nothing has changed yet. */
- context->raw_changed = 0;
- context->regenerate_crc = 0;
-
- /* Check data for consistency */
- if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK))
- || (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) {
+ /* Nothing has changed yet. */
+ context->raw_changed = 0;
+ context->regenerate_crc = 0;
- /* Data is inconsistent (bad CRC or header), so reset defaults */
- Memset(raw, 0, VBNV_BLOCK_SIZE);
- raw[HEADER_OFFSET] = (HEADER_SIGNATURE | HEADER_FIRMWARE_SETTINGS_RESET |
- HEADER_KERNEL_SETTINGS_RESET);
+ /* Check data for consistency */
+ if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK))
+ || (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) {
+ /* Data is inconsistent (bad CRC or header); reset defaults */
+ Memset(raw, 0, VBNV_BLOCK_SIZE);
+ raw[HEADER_OFFSET] = (HEADER_SIGNATURE |
+ HEADER_FIRMWARE_SETTINGS_RESET |
+ HEADER_KERNEL_SETTINGS_RESET);
- /* Regenerate CRC on exit */
- context->regenerate_crc = 1;
- }
+ /* Regenerate CRC on exit */
+ context->regenerate_crc = 1;
+ }
- return 0;
+ return 0;
}
+int VbNvTeardown(VbNvContext *context)
+{
+ if (context->regenerate_crc) {
+ context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET);
+ context->regenerate_crc = 0;
+ context->raw_changed = 1;
+ }
-int VbNvTeardown(VbNvContext* context) {
-
- if (context->regenerate_crc) {
- context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET);
- context->regenerate_crc = 0;
- context->raw_changed = 1;
- }
-
- return 0;
+ return 0;
}
-
-int VbNvGet(VbNvContext* context, VbNvParam param, uint32_t* dest) {
- const uint8_t* raw = context->raw;
-
- switch (param) {
- case VBNV_FIRMWARE_SETTINGS_RESET:
- *dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ? 1 : 0);
- return 0;
-
- case VBNV_KERNEL_SETTINGS_RESET:
- *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ? 1 : 0);
- return 0;
-
- case VBNV_DEBUG_RESET_MODE:
- *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0);
- return 0;
-
- case VBNV_TRY_B_COUNT:
- *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK;
- return 0;
-
- case VBNV_RECOVERY_REQUEST:
- *dest = raw[RECOVERY_OFFSET];
- return 0;
-
- case VBNV_RECOVERY_SUBCODE:
- *dest = raw[RECOVERY_SUBCODE_OFFSET];
- return 0;
-
- case VBNV_LOCALIZATION_INDEX:
- *dest = raw[LOCALIZATION_OFFSET];
- return 0;
-
- case VBNV_KERNEL_FIELD:
- *dest = (raw[KERNEL_FIELD_OFFSET]
- | (raw[KERNEL_FIELD_OFFSET + 1] << 8)
- | (raw[KERNEL_FIELD_OFFSET + 2] << 16)
- | (raw[KERNEL_FIELD_OFFSET + 3] << 24));
- return 0;
-
- case VBNV_DEV_BOOT_USB:
- *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0);
- return 0;
-
- case VBNV_DEV_BOOT_LEGACY:
- *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0);
- return 0;
-
- case VBNV_DEV_BOOT_SIGNED_ONLY:
- *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ? 1 : 0);
- return 0;
-
- case VBNV_DISABLE_DEV_REQUEST:
- *dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0);
- return 0;
-
- case VBNV_OPROM_NEEDED:
- *dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0);
- return 0;
-
- case VBNV_CLEAR_TPM_OWNER_REQUEST:
- *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ? 1 : 0);
- return 0;
-
- case VBNV_CLEAR_TPM_OWNER_DONE:
- *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0);
- return 0;
-
- default:
- return 1;
- }
+int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest)
+{
+ const uint8_t *raw = context->raw;
+
+ switch (param) {
+ case VBNV_FIRMWARE_SETTINGS_RESET:
+ *dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ?
+ 1 : 0);
+ return 0;
+
+ case VBNV_KERNEL_SETTINGS_RESET:
+ *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ?
+ 1 : 0);
+ return 0;
+
+ case VBNV_DEBUG_RESET_MODE:
+ *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0);
+ return 0;
+
+ case VBNV_TRY_B_COUNT:
+ *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK;
+ return 0;
+
+ case VBNV_RECOVERY_REQUEST:
+ *dest = raw[RECOVERY_OFFSET];
+ return 0;
+
+ case VBNV_RECOVERY_SUBCODE:
+ *dest = raw[RECOVERY_SUBCODE_OFFSET];
+ return 0;
+
+ case VBNV_LOCALIZATION_INDEX:
+ *dest = raw[LOCALIZATION_OFFSET];
+ return 0;
+
+ case VBNV_KERNEL_FIELD:
+ *dest = (raw[KERNEL_FIELD_OFFSET]
+ | (raw[KERNEL_FIELD_OFFSET + 1] << 8)
+ | (raw[KERNEL_FIELD_OFFSET + 2] << 16)
+ | (raw[KERNEL_FIELD_OFFSET + 3] << 24));
+ return 0;
+
+ case VBNV_DEV_BOOT_USB:
+ *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0);
+ return 0;
+
+ case VBNV_DEV_BOOT_LEGACY:
+ *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0);
+ return 0;
+
+ case VBNV_DEV_BOOT_SIGNED_ONLY:
+ *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ?
+ 1 : 0);
+ return 0;
+
+ case VBNV_DISABLE_DEV_REQUEST:
+ *dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0);
+ return 0;
+
+ case VBNV_OPROM_NEEDED:
+ *dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0);
+ return 0;
+
+ case VBNV_CLEAR_TPM_OWNER_REQUEST:
+ *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ?
+ 1 : 0);
+ return 0;
+
+ case VBNV_CLEAR_TPM_OWNER_DONE:
+ *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0);
+ return 0;
+
+ default:
+ return 1;
+ }
}
-
-int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) {
- uint8_t* raw = context->raw;
- uint32_t current;
-
- /* If we're not changing the value, we don't need to regenerate the CRC. */
- if (0 == VbNvGet(context, param, &current) && current == value)
- return 0;
-
- switch (param) {
- case VBNV_FIRMWARE_SETTINGS_RESET:
- if (value)
- raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET;
- else
- raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET;
- break;
-
- case VBNV_KERNEL_SETTINGS_RESET:
- if (value)
- raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET;
- else
- raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET;
- break;
-
- case VBNV_DEBUG_RESET_MODE:
- if (value)
- raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE;
- else
- raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE;
- break;
-
- case VBNV_TRY_B_COUNT:
- /* Clip to valid range. */
- if (value > BOOT_TRY_B_COUNT_MASK)
- value = BOOT_TRY_B_COUNT_MASK;
-
- raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK;
- raw[BOOT_OFFSET] |= (uint8_t)value;
- break;
-
- case VBNV_RECOVERY_REQUEST:
- /* Map values outside the valid range to the legacy reason, since we
- * can't determine if we're called from kernel or user mode. */
- if (value > 0xFF)
- value = VBNV_RECOVERY_LEGACY;
- raw[RECOVERY_OFFSET] = (uint8_t)value;
- break;
-
- case VBNV_RECOVERY_SUBCODE:
- raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value;
- break;
-
- case VBNV_LOCALIZATION_INDEX:
- /* Map values outside the valid range to the default index. */
- if (value > 0xFF)
- value = 0;
- raw[LOCALIZATION_OFFSET] = (uint8_t)value;
- break;
-
- case VBNV_KERNEL_FIELD:
- raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value);
- raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8);
- raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16);
- raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24);
- break;
-
- case VBNV_DEV_BOOT_USB:
- if (value)
- raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK;
- else
- raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK;
- break;
-
- case VBNV_DEV_BOOT_LEGACY:
- if (value)
- raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK;
- else
- raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK;
- break;
-
- case VBNV_DEV_BOOT_SIGNED_ONLY:
- if (value)
- raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK;
- else
- raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK;
- break;
-
- case VBNV_DISABLE_DEV_REQUEST:
- if (value)
- raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST;
- else
- raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST;
- break;
-
- case VBNV_OPROM_NEEDED:
- if (value)
- raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED;
- else
- raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED;
- break;
-
- case VBNV_CLEAR_TPM_OWNER_REQUEST:
- if (value)
- raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST;
- else
- raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST;
- break;
-
- case VBNV_CLEAR_TPM_OWNER_DONE:
- if (value)
- raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE;
- else
- raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE;
- break;
-
- default:
- return 1;
- }
-
- /* Need to regenerate CRC, since the value changed. */
- context->regenerate_crc = 1;
- return 0;
+int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
+{
+ uint8_t *raw = context->raw;
+ uint32_t current;
+
+ /* If not changing the value, don't regenerate the CRC. */
+ if (0 == VbNvGet(context, param, &current) && current == value)
+ return 0;
+
+ switch (param) {
+ case VBNV_FIRMWARE_SETTINGS_RESET:
+ if (value)
+ raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET;
+ else
+ raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET;
+ break;
+
+ case VBNV_KERNEL_SETTINGS_RESET:
+ if (value)
+ raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET;
+ else
+ raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET;
+ break;
+
+ case VBNV_DEBUG_RESET_MODE:
+ if (value)
+ raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE;
+ else
+ raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE;
+ break;
+
+ case VBNV_TRY_B_COUNT:
+ /* Clip to valid range. */
+ if (value > BOOT_TRY_B_COUNT_MASK)
+ value = BOOT_TRY_B_COUNT_MASK;
+
+ raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK;
+ raw[BOOT_OFFSET] |= (uint8_t)value;
+ break;
+
+ case VBNV_RECOVERY_REQUEST:
+ /*
+ * Map values outside the valid range to the legacy reason,
+ * since we can't determine if we're called from kernel or user
+ * mode.
+ */
+ if (value > 0xFF)
+ value = VBNV_RECOVERY_LEGACY;
+ raw[RECOVERY_OFFSET] = (uint8_t)value;
+ break;
+
+ case VBNV_RECOVERY_SUBCODE:
+ raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value;
+ break;
+
+ case VBNV_LOCALIZATION_INDEX:
+ /* Map values outside the valid range to the default index. */
+ if (value > 0xFF)
+ value = 0;
+ raw[LOCALIZATION_OFFSET] = (uint8_t)value;
+ break;
+
+ case VBNV_KERNEL_FIELD:
+ raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value);
+ raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8);
+ raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16);
+ raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24);
+ break;
+
+ case VBNV_DEV_BOOT_USB:
+ if (value)
+ raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK;
+ else
+ raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK;
+ break;
+
+ case VBNV_DEV_BOOT_LEGACY:
+ if (value)
+ raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK;
+ else
+ raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK;
+ break;
+
+ case VBNV_DEV_BOOT_SIGNED_ONLY:
+ if (value)
+ raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK;
+ else
+ raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK;
+ break;
+
+ case VBNV_DISABLE_DEV_REQUEST:
+ if (value)
+ raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST;
+ else
+ raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST;
+ break;
+
+ case VBNV_OPROM_NEEDED:
+ if (value)
+ raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED;
+ else
+ raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED;
+ break;
+
+ case VBNV_CLEAR_TPM_OWNER_REQUEST:
+ if (value)
+ raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST;
+ else
+ raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST;
+ break;
+
+ case VBNV_CLEAR_TPM_OWNER_DONE:
+ if (value)
+ raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE;
+ else
+ raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE;
+ break;
+
+ default:
+ return 1;
+ }
+
+ /* Need to regenerate CRC, since the value changed. */
+ context->regenerate_crc = 1;
+ return 0;
}
diff --git a/firmware/stub/vboot_api_stub.c b/firmware/stub/vboot_api_stub.c
index 8521db0e..c71c38ac 100644
--- a/firmware/stub/vboot_api_stub.c
+++ b/firmware/stub/vboot_api_stub.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -22,174 +22,198 @@ __pragma(warning (disable: 4100))
/* U-Boot's printf uses '%L' for uint64_t. gcc uses '%l'. */
#define MAX_FMT 255
static char fmtbuf[MAX_FMT+1];
-static const char *fixfmt(const char *format) {
- int i;
- for(i=0; i<MAX_FMT && format[i]; i++) {
- fmtbuf[i] = format[i];
- if(format[i] == '%' && format[i+1] == 'L') {
- fmtbuf[i+1] = 'l';
- i++;
- }
- }
- fmtbuf[i] = '\0';
- return fmtbuf;
-}
-void VbExError(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "ERROR: ");
- vfprintf(stderr, fixfmt(format), ap);
- va_end(ap);
- exit(1);
+static const char *fixfmt(const char *format)
+{
+ int i;
+ for(i=0; i<MAX_FMT && format[i]; i++) {
+ fmtbuf[i] = format[i];
+ if(format[i] == '%' && format[i+1] == 'L') {
+ fmtbuf[i+1] = 'l';
+ i++;
+ }
+ }
+ fmtbuf[i] = '\0';
+ return fmtbuf;
+}
+
+void VbExError(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, fixfmt(format), ap);
+ va_end(ap);
+ exit(1);
}
-
-void VbExDebug(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- fprintf(stderr, "DEBUG: ");
- vfprintf(stderr, fixfmt(format), ap);
- va_end(ap);
+void VbExDebug(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "DEBUG: ");
+ vfprintf(stderr, fixfmt(format), ap);
+ va_end(ap);
}
-
-void* VbExMalloc(size_t size) {
- void* p = malloc(size);
- if (!p) {
- /* Fatal Error. We must abort. */
- abort();
- }
- return p;
+void *VbExMalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (!p) {
+ /* Fatal Error. We must abort. */
+ abort();
+ }
+ return p;
}
-
-void VbExFree(void* ptr) {
- free(ptr);
+void VbExFree(void *ptr)
+{
+ free(ptr);
}
-
-uint64_t VbExGetTimer(void) {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
+uint64_t VbExGetTimer(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
}
-
-void VbExSleepMs(uint32_t msec) {
+void VbExSleepMs(uint32_t msec)
+{
}
-
-VbError_t VbExBeep(uint32_t msec, uint32_t frequency) {
- return VBERROR_SUCCESS;
+VbError_t VbExBeep(uint32_t msec, uint32_t frequency)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExNvStorageRead(uint8_t* buf) {
- return VBERROR_SUCCESS;
+VbError_t VbExNvStorageRead(uint8_t *buf)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExNvStorageWrite(const uint8_t* buf) {
- return VBERROR_SUCCESS;
+VbError_t VbExNvStorageWrite(const uint8_t *buf)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExHashFirmwareBody(VbCommonParams* cparams,
- uint32_t firmware_index) {
- return VBERROR_SUCCESS;
+VbError_t VbExHashFirmwareBody(VbCommonParams *cparams,
+ uint32_t firmware_index)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExDisplayInit(uint32_t* width, uint32_t* height) {
- return VBERROR_SUCCESS;
+VbError_t VbExDisplayInit(uint32_t *width, uint32_t *height)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExDisplayBacklight(uint8_t enable) {
- return VBERROR_SUCCESS;
+VbError_t VbExDisplayBacklight(uint8_t enable)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExDisplayScreen(uint32_t screen_type) {
- return VBERROR_SUCCESS;
+VbError_t VbExDisplayScreen(uint32_t screen_type)
+{
+ return VBERROR_SUCCESS;
}
-
VbError_t VbExDisplayImage(uint32_t x, uint32_t y,
- void* buffer, uint32_t buffersize) {
- return VBERROR_SUCCESS;
+ void *buffer, uint32_t buffersize)
+{
+ return VBERROR_SUCCESS;
}
-
-VbError_t VbExDisplayDebugInfo(const char* info_str) {
- return VBERROR_SUCCESS;
+VbError_t VbExDisplayDebugInfo(const char *info_str)
+{
+ return VBERROR_SUCCESS;
}
-
-uint32_t VbExKeyboardRead(void) {
- return 0;
+uint32_t VbExKeyboardRead(void)
+{
+ return 0;
}
-
-uint32_t VbExIsShutdownRequested(void) {
- return 0;
+uint32_t VbExIsShutdownRequested(void)
+{
+ return 0;
}
VbError_t VbExDecompress(void *inbuf, uint32_t in_size,
uint32_t compression_type,
- void *outbuf, uint32_t *out_size) {
- return VBERROR_SUCCESS;
+ void *outbuf, uint32_t *out_size)
+{
+ return VBERROR_SUCCESS;
}
-int VbExTrustEC(void) {
- return 1;
+int VbExTrustEC(void)
+{
+ return 1;
}
-VbError_t VbExEcRunningRW(int *in_rw) {
- *in_rw = 0;
- return VBERROR_SUCCESS;
+VbError_t VbExEcRunningRW(int *in_rw)
+{
+ *in_rw = 0;
+ return VBERROR_SUCCESS;
}
-VbError_t VbExEcJumpToRW(void) {
- return VBERROR_SUCCESS;
+VbError_t VbExEcJumpToRW(void)
+{
+ return VBERROR_SUCCESS;
}
-VbError_t VbExEcRebootToRO(void) {
- /* Nothing to reboot, so all we can do is return failure. */
- return VBERROR_UNKNOWN;
+VbError_t VbExEcRebootToRO(void)
+{
+ /* Nothing to reboot, so all we can do is return failure. */
+ return VBERROR_UNKNOWN;
}
-VbError_t VbExEcStayInRO(void) {
- return VBERROR_SUCCESS;
+VbError_t VbExEcStayInRO(void)
+{
+ return VBERROR_SUCCESS;
}
#define SHA256_HASH_SIZE 32
-VbError_t VbExEcHashRW(const uint8_t **hash, int *hash_size) {
- static const uint8_t fake_hash[32] = {1, 2, 3, 4};
- *hash = fake_hash;
- *hash_size = sizeof(fake_hash);
- return VBERROR_SUCCESS;
+VbError_t VbExEcHashRW(const uint8_t **hash, int *hash_size)
+{
+ static const uint8_t fake_hash[32] = {1, 2, 3, 4};
+
+ *hash = fake_hash;
+ *hash_size = sizeof(fake_hash);
+ return VBERROR_SUCCESS;
}
VbError_t VbExEcGetExpectedRW(enum VbSelectFirmware_t select,
- const uint8_t **image, int *image_size) {
- static uint8_t fake_image[64] = {5, 6, 7, 8};
- *image = fake_image;
- *image_size = sizeof(fake_image);
- return VBERROR_SUCCESS;
+ const uint8_t **image, int *image_size)
+{
+ static uint8_t fake_image[64] = {5, 6, 7, 8};
+ *image = fake_image;
+ *image_size = sizeof(fake_image);
+ return VBERROR_SUCCESS;
}
-VbError_t VbExEcUpdateRW(const uint8_t *image, int image_size) {
- return VBERROR_SUCCESS;
+VbError_t VbExEcGetExpectedRWHash(enum VbSelectFirmware_t select,
+ const uint8_t **hash, int *hash_size)
+{
+ static const uint8_t fake_hash[32] = {1, 2, 3, 4};
+
+ *hash = fake_hash;
+ *hash_size = sizeof(fake_hash);
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExEcUpdateRW(const uint8_t *image, int image_size)
+{
+ return VBERROR_SUCCESS;
}
-VbError_t VbExEcProtectRW(void) {
- return VBERROR_SUCCESS;
+VbError_t VbExEcProtectRW(void)
+{
+ return VBERROR_SUCCESS;
}
int VbExLegacy(void)
{
- return 1;
+ return 1;
}
diff --git a/futility/futility.c b/futility/futility.c
index 483f4521..be8d3b08 100644
--- a/futility/futility.c
+++ b/futility/futility.c
@@ -102,9 +102,18 @@ static void log_str(char *str)
static void log_close(void)
{
- if (log_fd >= 0)
+ struct flock lock;
+
+ if (log_fd >= 0) {
+ memset(&lock, 0, sizeof(lock));
+ lock.l_type = F_UNLCK;
+ lock.l_whence = SEEK_SET;
+ if (fcntl(log_fd, F_SETLKW, &lock))
+ perror("Unable to unlock log file");
+
close(log_fd);
- log_fd = -1;
+ log_fd = -1;
+ }
}
static void log_open(void)
@@ -159,6 +168,7 @@ int main(int argc, char *argv[], char *envp[])
log_open();
for (i = 0; i < argc; i++)
log_str(argv[i]);
+ log_close();
/* How were we invoked? */
progname = strrchr(argv[0], '/');
diff --git a/futility/setup_futility_symlinks.sh b/futility/setup_futility_symlinks.sh
deleted file mode 100755
index d7db9a7e..00000000
--- a/futility/setup_futility_symlinks.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Fail on any unexpected nonsense.
-set -e -u
-
-# The one required argument is the directory where futility lives.
-BINDIR="$1"
-shift
-
-# We look here to see what names to use for the symlinks.
-OLDDIR="$BINDIR/old_bins"
-
-# Create the symlinks.
-for prog in $OLDDIR/*; do
- ln -sf futility "${BINDIR}/${prog##*/}"
-done
diff --git a/scripts/image_signing/common.sh b/scripts/image_signing/common.sh
index 599c9e1e..599c9e1e 100755..100644
--- a/scripts/image_signing/common.sh
+++ b/scripts/image_signing/common.sh
diff --git a/scripts/image_signing/common_minimal.sh b/scripts/image_signing/common_minimal.sh
index 576d2d8f..576d2d8f 100755..100644
--- a/scripts/image_signing/common_minimal.sh
+++ b/scripts/image_signing/common_minimal.sh
diff --git a/scripts/image_signing/sample-test-configs/ensure_no_nonrelease_files.config b/scripts/image_signing/sample-test-configs/ensure_no_nonrelease_files.config
index 1ca02f1a..1ca02f1a 100755..100644
--- a/scripts/image_signing/sample-test-configs/ensure_no_nonrelease_files.config
+++ b/scripts/image_signing/sample-test-configs/ensure_no_nonrelease_files.config
diff --git a/scripts/image_signing/sample-test-configs/ensure_secure_kernelparams.config b/scripts/image_signing/sample-test-configs/ensure_secure_kernelparams.config
index 9b78def0..9b78def0 100755..100644
--- a/scripts/image_signing/sample-test-configs/ensure_secure_kernelparams.config
+++ b/scripts/image_signing/sample-test-configs/ensure_secure_kernelparams.config
diff --git a/scripts/image_signing/set_lsb_release.sh b/scripts/image_signing/set_lsb_release.sh
index 5d859d81..9d0addd0 100755
--- a/scripts/image_signing/set_lsb_release.sh
+++ b/scripts/image_signing/set_lsb_release.sh
@@ -24,12 +24,9 @@ set_lsb_release_keyval() {
main() {
set -e
- local image=$1
- local key=$2
- local value=$3
- if [ $# -ne 1 ] && [ $# -ne 3 ]; then
+ if [[ $(( $# % 2 )) -eq 0 ]]; then
cat <<EOF
-Usage: $PROG <image.bin> [<key> <value>]
+Usage: $PROG <image.bin> [<key> <value> [<key> <value> ...]]
Examples:
@@ -47,15 +44,28 @@ EOF
exit 1
fi
+ local image=$1
+ shift
local rootfs=$(make_temp_dir)
- mount_image_partition_ro "$image" 3 "$rootfs"
- if [ -n "$key" ]; then
- sudo umount "$rootfs"
- mount_image_partition "$image" 3 "$rootfs"
- set_lsb_release_keyval "$rootfs" "$key" "$value"
- touch "$image" # Updates the image modification time.
+
+ # If there are no key/value pairs to process, we don't need write access.
+ if [[ $# -eq 0 ]]; then
+ mount_image_partition_ro "${image}" 3 "${rootfs}"
+ else
+ mount_image_partition "${image}" 3 "${rootfs}"
+ touch "${image}" # Updates the image modification time.
fi
- cat "$rootfs/etc/lsb-release"
+
+ # Process all the key/value pairs.
+ local key value
+ while [[ $# -ne 0 ]]; do
+ key=$1 value=$2
+ shift 2
+ set_lsb_release_keyval "${rootfs}" "${key}" "${value}"
+ done
+
+ # Dump the final state.
+ cat "${rootfs}/etc/lsb-release"
}
main "$@"
diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh
index eedfe622..492dd15b 100755
--- a/scripts/image_signing/sign_official_build.sh
+++ b/scripts/image_signing/sign_official_build.sh
@@ -129,7 +129,7 @@ get_dmparams_from_config() {
get_hash_from_config() {
local kernel_config=$1
local dm_config=$(get_dmparams_from_config "${kernel_config}")
- local vroot_dev=$(get_dm_args "${dm_config}" vroot)
+ local vroot_dev=$(get_dm_slave "${dm_config}" vroot)
if is_old_verity_argv "${vroot_dev}"; then
echo ${vroot_dev} | cut -f9 -d ' '
else
diff --git a/scripts/keygeneration/common.sh b/scripts/keygeneration/common.sh
index c3c1c25d..c3c1c25d 100755..100644
--- a/scripts/keygeneration/common.sh
+++ b/scripts/keygeneration/common.sh
diff --git a/tests/common.sh b/tests/common.sh
index 43cdf6d2..43cdf6d2 100755..100644
--- a/tests/common.sh
+++ b/tests/common.sh
diff --git a/tests/tlcl_tests.c b/tests/tlcl_tests.c
new file mode 100644
index 00000000..4765cff3
--- /dev/null
+++ b/tests/tlcl_tests.c
@@ -0,0 +1,351 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for TPM lite library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <tss/tcs.h>
+/* Don't use the vboot constants, since they conflict with the TCS lib */
+#define VBOOT_REFERENCE_TSS_CONSTANTS_H_
+
+#include "host_common.h"
+#include "test_common.h"
+#include "tlcl.h"
+#include "tlcl_internal.h"
+#include "vboot_common.h"
+
+/* Mock data */
+static char debug_info[4096];
+static VbError_t mock_retval;
+
+/* Call to mocked VbExTpmSendReceive() */
+struct srcall
+{
+ const uint8_t *req; /* Request */
+ uint8_t *rsp; /* Response */
+ uint8_t rsp_buf[32]; /* Default response buffer, if not overridden */
+ int req_size; /* Request size */
+ uint32_t req_cmd; /* Request command code */
+ int rsp_size; /* Response size */
+ VbError_t retval; /* Value to return */
+};
+
+#define MAXCALLS 8
+static struct srcall calls[MAXCALLS];
+static int ncalls;
+
+/**
+ * Reset mock data (for use before each test)
+ */
+static void ResetMocks(void)
+{
+ int i;
+
+ *debug_info = 0;
+ mock_retval = VBERROR_SUCCESS;
+
+ memset(calls, 0, sizeof(calls));
+ for (i = 0; i < MAXCALLS; i++)
+ calls[i].rsp = calls[i].rsp_buf;
+ ncalls = 0;
+}
+
+/**
+ * Set response code and length for call <call_idx>.
+ */
+static void SetResponse(int call_idx, uint32_t response_code, int rsp_size)
+{
+ struct srcall *c = calls + call_idx;
+
+ c->rsp_size = rsp_size;
+ ToTpmUint32(c->rsp_buf + 6, response_code);
+}
+
+/* Mocks */
+
+VbError_t VbExTpmInit(void)
+{
+ return mock_retval;
+}
+
+
+VbError_t VbExTpmClose(void)
+{
+ return mock_retval;
+}
+
+VbError_t VbExTpmSendReceive(const uint8_t *request, uint32_t request_length,
+ uint8_t *response, uint32_t *response_length)
+{
+ struct srcall *c = calls + ncalls++;
+
+ c->req = request;
+ c->req_size = request_length;
+
+ /* Parse out the command code */
+ FromTpmUint32(request + 6, &c->req_cmd);
+
+ // KLUDGE - remove
+ printf("TSR [%d] 0x%x\n", ncalls-1, c->req_cmd);
+
+ memset(response, 0, *response_length);
+ if (c->rsp_size)
+ memcpy(response, c->rsp, c->rsp_size);
+ *response_length = c->rsp_size;
+
+ return c->retval;
+}
+
+/**
+ * Test assorted tlcl functions
+ */
+static void TlclTest(void)
+{
+ uint8_t buf[32], buf2[32];
+
+ ResetMocks();
+ TEST_EQ(TlclLibInit(), VBERROR_SUCCESS, "Init");
+
+ ResetMocks();
+ mock_retval = VBERROR_SIMULATED;
+ TEST_EQ(TlclLibInit(), mock_retval, "Init bad");
+
+ ResetMocks();
+ TEST_EQ(TlclLibClose(), VBERROR_SUCCESS, "Close");
+
+ ResetMocks();
+ mock_retval = VBERROR_SIMULATED;
+ TEST_EQ(TlclLibClose(), mock_retval, "Close bad");
+
+ ResetMocks();
+ ToTpmUint32(buf + 2, 123);
+ TEST_EQ(TlclPacketSize(buf), 123, "TlclPacketSize");
+
+ ResetMocks();
+ ToTpmUint32(buf + 2, 10);
+ TEST_EQ(TlclSendReceive(buf, buf2, sizeof(buf2)), 0, "SendReceive");
+ TEST_PTR_EQ(calls[0].req, buf, "SendReceive req ptr");
+ TEST_EQ(calls[0].req_size, 10, "SendReceive size");
+
+ ResetMocks();
+ calls[0].retval = VBERROR_SIMULATED;
+ ToTpmUint32(buf + 2, 10);
+ TEST_EQ(TlclSendReceive(buf, buf2, sizeof(buf2)), VBERROR_SIMULATED,
+ "SendReceive fail");
+
+ ResetMocks();
+ SetResponse(0, 123, 10);
+ ToTpmUint32(buf + 2, 10);
+ TEST_EQ(TlclSendReceive(buf, buf2, sizeof(buf2)), 123,
+ "SendReceive error response");
+
+ // TODO: continue self test (if needed or doing)
+ // TODO: then retry doing self test
+
+}
+
+
+/**
+ * Test send-command functions
+ */
+static void SendCommandTest(void)
+{
+ ResetMocks();
+ TEST_EQ(TlclStartup(), 0, "SaveState");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_Startup, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclSaveState(), 0, "SaveState");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_SaveState, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclResume(), 0, "Resume");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_Startup, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclSelfTestFull(), 0, "SelfTestFull");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_SelfTestFull, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclContinueSelfTest(), 0, "ContinueSelfTest");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_ContinueSelfTest, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclAssertPhysicalPresence(), 0,
+ "AssertPhysicalPresence");
+ TEST_EQ(calls[0].req_cmd, TSC_ORD_PhysicalPresence, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclPhysicalPresenceCMDEnable(), 0,
+ "PhysicalPresenceCMDEnable");
+ TEST_EQ(calls[0].req_cmd, TSC_ORD_PhysicalPresence, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclFinalizePhysicalPresence(), 0,
+ "FinalizePhysicalPresence");
+ TEST_EQ(calls[0].req_cmd, TSC_ORD_PhysicalPresence, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclAssertPhysicalPresenceResult(), 0,
+ "AssertPhysicalPresenceResult");
+ TEST_EQ(calls[0].req_cmd, TSC_ORD_PhysicalPresence, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclLockPhysicalPresence(), 0,
+ "LockPhysicalPresence");
+ TEST_EQ(calls[0].req_cmd, TSC_ORD_PhysicalPresence, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclIsOwned(), 0, "IsOwned");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_ReadPubek, " cmd");
+ ResetMocks();
+ calls[0].retval = VBERROR_SIMULATED;
+ TEST_NEQ(TlclIsOwned(), 0, "IsOwned");
+
+ ResetMocks();
+ TEST_EQ(TlclForceClear(), 0, "ForceClear");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_ForceClear, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclSetEnable(), 0, "SetEnable");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_PhysicalEnable, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclClearEnable(), 0, "ClearEnable");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_PhysicalDisable, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclSetDeactivated(0), 0, "SetDeactivated");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_PhysicalSetDeactivated, " cmd");
+}
+
+/**
+ * NV spaces test
+ *
+ * TODO: check params/data read/written.
+ */
+static void ReadWriteTest(void)
+{
+ uint8_t buf[32];
+
+ ResetMocks();
+ TEST_EQ(TlclDefineSpace(1, 2, 3), 0, "DefineSpace");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_DefineSpace, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclSetNvLocked(), 0, "SetNvLocked");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_DefineSpace, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclWrite(1, buf, 3), 0, "Write");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_WriteValue, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclRead(1, buf, 3), 0, "Read");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_ReadValue, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclWriteLock(1), 0, "WriteLock");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_WriteValue, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclReadLock(1), 0, "ReadLock");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_ReadValue, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclSetGlobalLock(), 0, "SetGlobalLock");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_NV_WriteValue, " cmd");
+}
+
+/**
+ * Test PCR funcs
+ *
+ * TODO: check params/data read/written.
+ */
+static void PcrTest(void)
+{
+ uint8_t buf[kPcrDigestLength], buf2[kPcrDigestLength];
+
+ ResetMocks();
+ TEST_EQ(TlclPCRRead(1, buf, kPcrDigestLength), 0, "PCRRead");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_PcrRead, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclPCRRead(1, buf, kPcrDigestLength - 1), TPM_E_IOERROR,
+ "PCRRead too small");
+
+ ResetMocks();
+ TEST_EQ(TlclExtend(1, buf, buf2), 0, "Extend");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_Extend, " cmd");
+}
+
+/**
+ * Test flags / capabilities
+ *
+ * TODO: check params/data read/written.
+ */
+static void FlagsTest(void)
+{
+ TPM_PERMANENT_FLAGS pflags;
+ TPM_STCLEAR_FLAGS vflags;
+ uint8_t disable = 0, deactivated = 0, nvlocked = 0;
+ uint32_t u;
+ uint8_t buf[32];
+
+ ResetMocks();
+ TEST_EQ(TlclGetPermanentFlags(&pflags), 0, "GetPermanentFlags");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclGetSTClearFlags(&vflags), 0, "GetSTClearFlags");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclGetFlags(NULL, NULL, NULL), 0, "GetFlags NULL");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd");
+ ResetMocks();
+ TEST_EQ(TlclGetFlags(&disable, &deactivated, &nvlocked), 0, "GetFlags");
+
+ ResetMocks();
+ TEST_EQ(TlclGetPermissions(1, &u), 0, "GetPermissions");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd");
+
+ ResetMocks();
+ TEST_EQ(TlclGetOwnership(buf), 0, "GetOwnership");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_GetCapability, " cmd");
+}
+
+/**
+ * Test random
+ *
+ * TODO: check params/data read/written.
+ * TODO: check overflow tests.
+ */
+static void RandomTest(void)
+{
+ uint8_t buf[32];
+ uint32_t size;
+
+ ResetMocks();
+ size = sizeof(buf);
+ TEST_EQ(TlclGetRandom(buf, sizeof(buf), &size), 0, "GetRandom");
+ TEST_EQ(calls[0].req_cmd, TPM_ORD_GetRandom, " cmd");
+ TEST_EQ(size, 0, " size 0");
+}
+
+int main(void)
+{
+ TlclTest();
+ SendCommandTest();
+ ReadWriteTest();
+ PcrTest();
+ FlagsTest();
+ RandomTest();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_api_kernel2_tests.c b/tests/vboot_api_kernel2_tests.c
new file mode 100644
index 00000000..9b921cd2
--- /dev/null
+++ b/tests/vboot_api_kernel2_tests.c
@@ -0,0 +1,554 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for vboot_api_kernel, part 2
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gbb_header.h"
+#include "host_common.h"
+#include "load_kernel_fw.h"
+#include "rollback_index.h"
+#include "test_common.h"
+#include "vboot_audio.h"
+#include "vboot_common.h"
+#include "vboot_kernel.h"
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+/* Mock data */
+static VbCommonParams cparams;
+static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
+static GoogleBinaryBlockHeader gbb;
+static LoadKernelParams lkp;
+
+static int shutdown_request_calls_left;
+static int audio_looping_calls_left;
+static uint32_t vbtlk_retval;
+static int vbexlegacy_called;
+static int trust_ec;
+static int virtdev_set;
+static uint32_t virtdev_retval;
+
+static uint32_t mock_keypress[8];
+static uint32_t mock_keypress_count;
+static uint32_t screens_displayed[8];
+static uint32_t screens_count = 0;
+static uint32_t mock_num_disks[8];
+static uint32_t mock_num_disks_count;
+
+/* Reset mock data (for use before each test) */
+static void ResetMocks(void)
+{
+ Memset(&cparams, 0, sizeof(cparams));
+ cparams.shared_data_size = sizeof(shared_data);
+ cparams.shared_data_blob = shared_data;
+ cparams.gbb_data = &gbb;
+
+ Memset(&gbb, 0, sizeof(gbb));
+ gbb.major_version = GBB_MAJOR_VER;
+ gbb.minor_version = GBB_MINOR_VER;
+ gbb.flags = 0;
+
+ /*
+ * Only the outermost vboot_api_kernel call sets vboot_api_kernel's
+ * vnc. So clear it here too.
+ */
+ Memset(VbApiKernelGetVnc(), 0, sizeof(VbNvContext));
+ VbNvSetup(VbApiKernelGetVnc());
+ VbNvTeardown(VbApiKernelGetVnc()); /* So CRC gets generated */
+
+ Memset(&shared_data, 0, sizeof(shared_data));
+ VbSharedDataInit(shared, sizeof(shared_data));
+
+ Memset(&lkp, 0, sizeof(lkp));
+
+ shutdown_request_calls_left = -1;
+ audio_looping_calls_left = 30;
+ vbtlk_retval = 1000;
+ vbexlegacy_called = 0;
+ trust_ec = 0;
+ virtdev_set = 0;
+ virtdev_retval = 0;
+
+ Memset(screens_displayed, 0, sizeof(screens_displayed));
+ screens_count = 0;
+
+ Memset(mock_keypress, 0, sizeof(mock_keypress));
+ mock_keypress_count = 0;
+
+ Memset(mock_num_disks, 0, sizeof(mock_num_disks));
+ mock_num_disks_count = 0;
+}
+
+/* Mock functions */
+
+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;
+}
+
+uint32_t VbExKeyboardRead(void)
+{
+ if (mock_keypress_count < ARRAY_SIZE(mock_keypress))
+ return mock_keypress[mock_keypress_count++];
+ else
+ return 0;
+}
+
+int VbExLegacy(void)
+{
+ vbexlegacy_called++;
+ return 0;
+}
+
+VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count,
+ uint32_t disk_flags)
+{
+ if (mock_num_disks_count < ARRAY_SIZE(mock_num_disks)) {
+ if (mock_num_disks[mock_num_disks_count] == -1)
+ return VBERROR_SIMULATED;
+ else
+ *count = mock_num_disks[mock_num_disks_count++];
+ } else {
+ *count = 0;
+ }
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExDiskFreeInfo(VbDiskInfo *infos,
+ VbExDiskHandle_t preserve_handle)
+{
+ return VBERROR_SUCCESS;
+}
+
+int VbExTrustEC(void)
+{
+ return trust_ec;
+}
+
+int VbAudioLooping(VbAudioContext *audio)
+{
+ if (audio_looping_calls_left == 0)
+ return 0;
+ else if (audio_looping_calls_left > 0)
+ audio_looping_calls_left--;
+
+ return 1;
+}
+
+uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p,
+ uint32_t get_info_flags)
+{
+ return vbtlk_retval + get_info_flags;
+}
+
+VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, int force,
+ VbNvContext *vncptr)
+{
+ if (screens_count < ARRAY_SIZE(screens_displayed))
+ screens_displayed[screens_count++] = screen;
+
+ return VBERROR_SUCCESS;
+}
+
+uint32_t SetVirtualDevMode(int val)
+{
+ virtdev_set = val;
+ return virtdev_retval;
+}
+
+/* Tests */
+
+static void VbUserConfirmsTest(void)
+{
+ printf("Testing VbUserConfirms()...\n");
+
+ ResetMocks();
+ shutdown_request_calls_left = 1;
+ TEST_EQ(VbUserConfirms(&cparams, 0), -1, "Shutdown requested");
+
+ ResetMocks();
+ mock_keypress[0] = '\r';
+ TEST_EQ(VbUserConfirms(&cparams, 0), 1, "Enter");
+
+ ResetMocks();
+ mock_keypress[0] = 0x1b;
+ TEST_EQ(VbUserConfirms(&cparams, 0), 0, "Esc");
+
+ ResetMocks();
+ mock_keypress[0] = ' ';
+ shutdown_request_calls_left = 1;
+ TEST_EQ(VbUserConfirms(&cparams, 1), 0, "Space means no");
+
+ ResetMocks();
+ mock_keypress[0] = ' ';
+ shutdown_request_calls_left = 1;
+ TEST_EQ(VbUserConfirms(&cparams, 0), -1, "Space ignored");
+
+ printf("...done.\n");
+}
+
+static void VbBootTest(void)
+{
+ ResetMocks();
+ TEST_EQ(VbBootNormal(&cparams, &lkp), 1002, "VbBootNormal()");
+}
+
+static void VbBootDevTest(void)
+{
+ uint32_t u;
+
+ printf("Testing VbBootDeveloper()...\n");
+
+ /* Proceed after timeout */
+ ResetMocks();
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Timeout");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
+ " warning screen");
+ VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, 0, " recovery reason");
+ TEST_EQ(audio_looping_calls_left, 0, " used up audio");
+
+ /* Up arrow is uninteresting / passed to VbCheckDisplayKey() */
+ ResetMocks();
+ mock_keypress[0] = VB_KEY_UP;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Up arrow");
+
+ /* Shutdown requested in loop */
+ ResetMocks();
+ shutdown_request_calls_left = 2;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Shutdown requested");
+ TEST_NEQ(audio_looping_calls_left, 0, " aborts audio");
+
+ /* Space goes straight to recovery if no virtual dev switch */
+ ResetMocks();
+ mock_keypress[0] = ' ';
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_LOAD_KERNEL_RECOVERY,
+ "Space = recovery");
+ VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, VBNV_RECOVERY_RW_DEV_SCREEN, " recovery reason");
+
+ /* Space asks to disable virtual dev switch */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
+ mock_keypress[0] = ' ';
+ mock_keypress[1] = '\r';
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_TPM_REBOOT_REQUIRED,
+ "Space = tonorm");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
+ " warning screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_DEVELOPER_TO_NORM,
+ " tonorm screen");
+ TEST_EQ(screens_displayed[2], VB_SCREEN_TO_NORM_CONFIRMED,
+ " confirm screen");
+ VbNvGet(VbApiKernelGetVnc(), VBNV_DISABLE_DEV_REQUEST, &u);
+ TEST_EQ(u, 1, " disable dev request");
+
+ /* Space-space doesn't disable it */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
+ mock_keypress[0] = ' ';
+ mock_keypress[1] = ' ';
+ mock_keypress[2] = 0x1b;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Space-space");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
+ " warning screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_DEVELOPER_TO_NORM,
+ " tonorm screen");
+ TEST_EQ(screens_displayed[2], VB_SCREEN_DEVELOPER_WARNING,
+ " warning screen");
+
+ /* Enter doesn't by default */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
+ mock_keypress[0] = '\r';
+ mock_keypress[1] = '\r';
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Enter ignored");
+
+ /* Enter does if GBB flag set */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
+ gbb.flags |= GBB_FLAG_ENTER_TRIGGERS_TONORM;
+ mock_keypress[0] = '\r';
+ mock_keypress[1] = '\r';
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_TPM_REBOOT_REQUIRED,
+ "Enter = tonorm");
+
+ /* Tonorm ignored if GBB forces dev switch on */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
+ gbb.flags |= GBB_FLAG_FORCE_DEV_SWITCH_ON;
+ mock_keypress[0] = ' ';
+ mock_keypress[1] = '\r';
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Can't tonorm gbb-dev");
+
+ /* Shutdown requested at tonorm screen */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_DEV_SWITCH_ON;
+ mock_keypress[0] = ' ';
+ shutdown_request_calls_left = 2;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Shutdown requested at tonorm");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_DEVELOPER_WARNING,
+ " warning screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_DEVELOPER_TO_NORM,
+ " tonorm screen");
+
+ /* Ctrl+D dismisses warning */
+ ResetMocks();
+ mock_keypress[0] = 0x04;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+D");
+ VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, 0, " recovery reason");
+ TEST_NEQ(audio_looping_calls_left, 0, " aborts audio");
+
+ /* Ctrl+L tries legacy boot mode only if enabled */
+ ResetMocks();
+ mock_keypress[0] = 0x0c;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+L normal");
+ TEST_EQ(vbexlegacy_called, 0, " not legacy");
+
+ ResetMocks();
+
+ gbb.flags |= GBB_FLAG_FORCE_DEV_BOOT_LEGACY;
+ mock_keypress[0] = 0x0c;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+L force legacy");
+ TEST_EQ(vbexlegacy_called, 1, " try legacy");
+
+ ResetMocks();
+ VbNvSet(VbApiKernelGetVnc(), VBNV_DEV_BOOT_LEGACY, 1);
+ mock_keypress[0] = 0x0c;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+L nv legacy");
+ TEST_EQ(vbexlegacy_called, 1, " try legacy");
+
+ /* Ctrl+U boots USB only if enabled */
+ ResetMocks();
+ mock_keypress[0] = 0x15;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+U normal");
+
+ /* Ctrl+U enabled, with good USB boot */
+ ResetMocks();
+ VbNvSet(VbApiKernelGetVnc(), VBNV_DEV_BOOT_USB, 1);
+ mock_keypress[0] = 0x15;
+ vbtlk_retval = VBERROR_SUCCESS - VB_DISK_FLAG_REMOVABLE;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 0, "Ctrl+U USB");
+
+ /* Ctrl+U enabled via GBB */
+ ResetMocks();
+ gbb.flags |= GBB_FLAG_FORCE_DEV_BOOT_USB;
+ mock_keypress[0] = 0x15;
+ vbtlk_retval = VBERROR_SUCCESS - VB_DISK_FLAG_REMOVABLE;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 0, "Ctrl+U force USB");
+
+ /* If no USB, eventually times out and tries fixed disk */
+ ResetMocks();
+ VbNvSet(VbApiKernelGetVnc(), VBNV_DEV_BOOT_USB, 1);
+ mock_keypress[0] = 0x15;
+ TEST_EQ(VbBootDeveloper(&cparams, &lkp), 1002, "Ctrl+U enabled");
+ TEST_EQ(vbexlegacy_called, 0, " not legacy");
+ VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, 0, " recovery reason");
+ TEST_EQ(audio_looping_calls_left, 0, " used up audio");
+
+ printf("...done.\n");
+}
+
+static void VbBootRecTest(void)
+{
+ uint32_t u;
+
+ printf("Testing VbBootRecovery()...\n");
+
+ /* Shutdown requested in loop */
+ ResetMocks();
+ shutdown_request_calls_left = 10;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Shutdown requested");
+ VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, 0, " recovery reason");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,
+ " blank screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_NO_GOOD,
+ " no good screen");
+
+ /* Disk inserted after start */
+ ResetMocks();
+ vbtlk_retval = VBERROR_SUCCESS - VB_DISK_FLAG_REMOVABLE;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), 0, "Good");
+
+ /* No disk inserted */
+ ResetMocks();
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ shutdown_request_calls_left = 10;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Bad disk");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,
+ " blank screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+
+ /* Remove disks */
+ ResetMocks();
+ shutdown_request_calls_left = 100;
+ mock_num_disks[0] = 1;
+ mock_num_disks[1] = 1;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Remove");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_REMOVE,
+ " remove screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_REMOVE,
+ " remove screen");
+ TEST_EQ(screens_displayed[2], VB_SCREEN_BLANK,
+ " blank screen");
+ TEST_EQ(screens_displayed[3], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+
+ /* No removal if dev switch is on */
+ ResetMocks();
+ shutdown_request_calls_left = 100;
+ mock_num_disks[0] = 1;
+ mock_num_disks[1] = 1;
+ shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "No remove in dev");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+
+ /* No removal if recovery button physically pressed */
+ ResetMocks();
+ shutdown_request_calls_left = 100;
+ mock_num_disks[0] = 1;
+ mock_num_disks[1] = 1;
+ shared->flags |= VBSD_BOOT_REC_SWITCH_ON;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "No remove in rec");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+
+ /* Bad disk count doesn't require removal */
+ ResetMocks();
+ mock_num_disks[0] = -1;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ shutdown_request_calls_left = 10;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Bad disk count");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_BLANK,
+ " blank screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+
+ /* Ctrl+D ignored for many reasons... */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
+ shutdown_request_calls_left = 100;
+ mock_keypress[0] = 0x04;
+ trust_ec = 0;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Ctrl+D ignored if EC not trusted");
+ TEST_EQ(virtdev_set, 0, " virtual dev mode off");
+ TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
+ " todev screen");
+
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON |
+ VBSD_BOOT_DEV_SWITCH_ON;
+ trust_ec = 1;
+ shutdown_request_calls_left = 100;
+ mock_keypress[0] = 0x04;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Ctrl+D ignored if already in dev mode");
+ TEST_EQ(virtdev_set, 0, " virtual dev mode off");
+ TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
+ " todev screen");
+
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH;
+ trust_ec = 1;
+ shutdown_request_calls_left = 100;
+ mock_keypress[0] = 0x04;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Ctrl+D ignored if recovery not manually triggered");
+ TEST_EQ(virtdev_set, 0, " virtual dev mode off");
+ TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
+ " todev screen");
+
+ ResetMocks();
+ shared->flags = VBSD_BOOT_REC_SWITCH_ON;
+ trust_ec = 1;
+ shutdown_request_calls_left = 100;
+ mock_keypress[0] = 0x04;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Ctrl+D ignored if no virtual dev switch");
+ TEST_EQ(virtdev_set, 0, " virtual dev mode off");
+ TEST_NEQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
+ " todev screen");
+
+ /* Ctrl+D then space means don't enable */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
+ shutdown_request_calls_left = 100;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ trust_ec = 1;
+ mock_keypress[0] = 0x04;
+ mock_keypress[1] = ' ';
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_SHUTDOWN_REQUESTED,
+ "Ctrl+D todev abort");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+ TEST_EQ(screens_displayed[1], VB_SCREEN_RECOVERY_TO_DEV,
+ " todev screen");
+ TEST_EQ(screens_displayed[2], VB_SCREEN_RECOVERY_INSERT,
+ " insert screen");
+ TEST_EQ(virtdev_set, 0, " virtual dev mode off");
+
+ /* Ctrl+D then enter means enable */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
+ shutdown_request_calls_left = 100;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ trust_ec = 1;
+ mock_keypress[0] = 0x04;
+ mock_keypress[1] = '\r';
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_TPM_REBOOT_REQUIRED,
+ "Ctrl+D todev confirm");
+ TEST_EQ(virtdev_set, 1, " virtual dev mode on");
+
+ /* Handle TPM error in enabling dev mode */
+ ResetMocks();
+ shared->flags = VBSD_HONOR_VIRT_DEV_SWITCH | VBSD_BOOT_REC_SWITCH_ON;
+ shutdown_request_calls_left = 100;
+ vbtlk_retval = VBERROR_NO_DISK_FOUND - VB_DISK_FLAG_REMOVABLE;
+ trust_ec = 1;
+ mock_keypress[0] = 0x04;
+ mock_keypress[1] = '\r';
+ virtdev_retval = VBERROR_SIMULATED;
+ TEST_EQ(VbBootRecovery(&cparams, &lkp), VBERROR_TPM_SET_BOOT_MODE_STATE,
+ "Ctrl+D todev failure");
+
+ printf("...done.\n");
+}
+
+
+int main(void)
+{
+ VbUserConfirmsTest();
+ VbBootTest();
+ VbBootDevTest();
+ VbBootRecTest();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_api_kernel3_tests.c b/tests/vboot_api_kernel3_tests.c
new file mode 100644
index 00000000..9ec6f19b
--- /dev/null
+++ b/tests/vboot_api_kernel3_tests.c
@@ -0,0 +1,362 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for vboot_api_kernel, part 3 - software sync
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gbb_header.h"
+#include "host_common.h"
+#include "load_kernel_fw.h"
+#include "rollback_index.h"
+#include "test_common.h"
+#include "vboot_audio.h"
+#include "vboot_common.h"
+#include "vboot_kernel.h"
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+/* Mock data */
+static VbCommonParams cparams;
+static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
+static GoogleBinaryBlockHeader gbb;
+
+static int trust_ec;
+static int mock_in_rw;
+static VbError_t in_rw_retval;
+static int protect_retval;
+static int ec_protected;
+static int run_retval;
+static int ec_run_image;
+static int update_retval;
+static int ec_updated;
+static int get_expected_retval;
+static int shutdown_request_calls_left;
+
+static uint8_t mock_ec_hash[32];
+static int mock_ec_hash_size;
+static uint8_t want_ec_hash[32];
+static int want_ec_hash_size;
+static uint8_t mock_sha[32];
+
+static uint32_t screens_displayed[8];
+static uint32_t screens_count = 0;
+
+/* Reset mock data (for use before each test) */
+static void ResetMocks(void)
+{
+ Memset(&cparams, 0, sizeof(cparams));
+ cparams.shared_data_size = sizeof(shared_data);
+ cparams.shared_data_blob = shared_data;
+ cparams.gbb_data = &gbb;
+
+ Memset(&gbb, 0, sizeof(gbb));
+ gbb.major_version = GBB_MAJOR_VER;
+ gbb.minor_version = GBB_MINOR_VER;
+ gbb.flags = 0;
+
+ /*
+ * Only the outermost vboot_api_kernel call sets vboot_api_kernel's
+ * vnc. So clear it here too.
+ */
+ Memset(VbApiKernelGetVnc(), 0, sizeof(VbNvContext));
+ VbNvSetup(VbApiKernelGetVnc());
+ VbNvTeardown(VbApiKernelGetVnc()); /* So CRC gets generated */
+
+ Memset(&shared_data, 0, sizeof(shared_data));
+ VbSharedDataInit(shared, sizeof(shared_data));
+
+ trust_ec = 0;
+ mock_in_rw = 0;
+ ec_protected = 0;
+ ec_run_image = -1; /* 0 = RO, 1 = RW */
+ ec_updated = 0;
+ in_rw_retval = VBERROR_SUCCESS;
+ protect_retval = VBERROR_SUCCESS;
+ update_retval = VBERROR_SUCCESS;
+ run_retval = VBERROR_SUCCESS;
+ get_expected_retval = VBERROR_SUCCESS;
+ shutdown_request_calls_left = -1;
+
+ Memset(mock_ec_hash, 0, sizeof(mock_ec_hash));
+ mock_ec_hash[0] = 42;
+ mock_ec_hash_size = sizeof(mock_ec_hash);
+
+ Memset(want_ec_hash, 0, sizeof(want_ec_hash));
+ want_ec_hash[0] = 42;
+ want_ec_hash_size = sizeof(want_ec_hash);
+
+ Memset(mock_sha, 0, sizeof(want_ec_hash));
+ mock_sha[0] = 42;
+
+ // TODO: ensure these are actually needed
+
+ Memset(screens_displayed, 0, sizeof(screens_displayed));
+ screens_count = 0;
+}
+
+/* Mock functions */
+
+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 VbExTrustEC(void)
+{
+ return trust_ec;
+}
+
+VbError_t VbExEcRunningRW(int *in_rw)
+{
+ *in_rw = mock_in_rw;
+ return in_rw_retval;
+}
+
+VbError_t VbExEcProtectRW(void)
+{
+ ec_protected = 1;
+ return protect_retval;
+}
+
+VbError_t VbExEcStayInRO(void)
+{
+ ec_run_image = 0;
+ return run_retval;
+}
+
+VbError_t VbExEcJumpToRW(void)
+{
+ ec_run_image = 1;
+ return run_retval;
+}
+
+VbError_t VbExEcHashRW(const uint8_t **hash, int *hash_size)
+{
+ *hash = mock_ec_hash;
+ *hash_size = mock_ec_hash_size;
+ return mock_ec_hash_size ? VBERROR_SUCCESS : VBERROR_SIMULATED;
+}
+
+VbError_t VbExEcGetExpectedRW(enum VbSelectFirmware_t select,
+ const uint8_t **image, int *image_size)
+{
+ static uint8_t fake_image[64] = {5, 6, 7, 8};
+ *image = fake_image;
+ *image_size = sizeof(fake_image);
+ return get_expected_retval;
+}
+
+VbError_t VbExEcGetExpectedRWHash(enum VbSelectFirmware_t select,
+ const uint8_t **hash, int *hash_size)
+{
+ *hash = want_ec_hash;
+ *hash_size = want_ec_hash_size;
+
+ if (want_ec_hash_size == -1)
+ return VBERROR_EC_GET_EXPECTED_HASH_FROM_IMAGE;
+ else
+ return want_ec_hash_size ? VBERROR_SUCCESS : VBERROR_SIMULATED;
+}
+
+uint8_t *internal_SHA256(const uint8_t *data, uint64_t len, uint8_t *digest)
+{
+ Memcpy(digest, mock_sha, sizeof(mock_sha));
+ return digest;
+}
+
+VbError_t VbExEcUpdateRW(const uint8_t *image, int image_size)
+{
+ ec_updated = 1;
+ return update_retval;
+}
+
+VbError_t VbDisplayScreen(VbCommonParams *cparams, uint32_t screen, int force,
+ VbNvContext *vncptr)
+{
+ if (screens_count < ARRAY_SIZE(screens_displayed))
+ screens_displayed[screens_count++] = screen;
+
+ return VBERROR_SUCCESS;
+}
+
+static void test_ssync(VbError_t retval, int recovery_reason, const char *desc)
+{
+ uint32_t u;
+
+ TEST_EQ(VbEcSoftwareSync(&cparams), retval, desc);
+ VbNvGet(VbApiKernelGetVnc(), VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, recovery_reason, " recovery reason");
+}
+
+/* Tests */
+
+static void VbSoftwareSyncTest(void)
+{
+ /* Recovery cases */
+ ResetMocks();
+ shared->recovery_reason = 123;
+ test_ssync(0, 0, "In recovery, EC-RO");
+ TEST_EQ(ec_protected, 0, " ec protected");
+
+ ResetMocks();
+ shared->recovery_reason = 123;
+ mock_in_rw = 1;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ 123, "Recovery needs EC-RO");
+
+ /* AP-RO cases */
+ ResetMocks();
+ in_rw_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_UNKNOWN_IMAGE, "Unknown EC image");
+
+ ResetMocks();
+ shared->flags |= VBSD_LF_USE_RO_NORMAL;
+ mock_in_rw = 1;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ 0, "AP-RO needs EC-RO");
+
+ ResetMocks();
+ shared->flags |= VBSD_LF_USE_RO_NORMAL;
+ test_ssync(0, 0, "AP-RO, EC-RO");
+ TEST_EQ(ec_protected, 1, " ec protected");
+ TEST_EQ(ec_run_image, 0, " ec run image");
+
+ ResetMocks();
+ shared->flags |= VBSD_LF_USE_RO_NORMAL;
+ run_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_SOFTWARE_SYNC, "Stay in RO fail");
+
+ ResetMocks();
+ shared->flags |= VBSD_LF_USE_RO_NORMAL;
+ protect_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_SIMULATED,
+ VBNV_RECOVERY_EC_PROTECT, "Protect error");
+
+ ResetMocks();
+ shared->flags |= VBSD_LF_USE_RO_NORMAL;
+ shutdown_request_calls_left = 0;
+ test_ssync(VBERROR_SHUTDOWN_REQUESTED, 0, "AP-RO shutdown requested");
+
+ /* Calculate hashes */
+ ResetMocks();
+ mock_ec_hash_size = 0;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_HASH_FAILED, "Bad EC hash");
+
+ ResetMocks();
+ mock_ec_hash_size = 16;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_HASH_SIZE, "Bad EC hash size");
+
+ ResetMocks();
+ want_ec_hash_size = 0;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_EXPECTED_HASH, "Bad precalculated hash");
+
+ ResetMocks();
+ want_ec_hash_size = 16;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_EXPECTED_HASH,
+ "Bad precalculated hash size");
+
+ ResetMocks();
+ mock_in_rw = 1;
+ want_ec_hash_size = -1;
+ test_ssync(0, 0, "No precomputed hash");
+
+ ResetMocks();
+ want_ec_hash_size = -1;
+ get_expected_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_EXPECTED_IMAGE, "Can't fetch image");
+
+ /* Updates required */
+ ResetMocks();
+ mock_in_rw = 1;
+ want_ec_hash[0]++;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_HASH_MISMATCH,
+ "Precalculated hash mismatch");
+
+ ResetMocks();
+ mock_in_rw = 1;
+ mock_ec_hash[0]++;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ 0, "Pending update needs reboot");
+
+ ResetMocks();
+ mock_ec_hash[0]++;
+ test_ssync(0, 0, "Update without reboot");
+ TEST_EQ(ec_protected, 1, " ec protected");
+ TEST_EQ(ec_run_image, 1, " ec run image");
+ TEST_EQ(ec_updated, 1, " ec updated");
+
+ ResetMocks();
+ mock_ec_hash[0]++;
+ update_retval = VBERROR_EC_REBOOT_TO_RO_REQUIRED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ 0, "Reboot after update");
+ TEST_EQ(ec_updated, 1, " ec updated");
+
+ ResetMocks();
+ mock_ec_hash[0]++;
+ update_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_UPDATE, "Update failed");
+
+ ResetMocks();
+ mock_ec_hash[0]++;
+ shared->flags |= VBSD_EC_SLOW_UPDATE;
+ test_ssync(0, 0, "Slow update");
+ TEST_EQ(screens_displayed[0], VB_SCREEN_WAIT, " wait screen");
+
+ /* RW cases, no update */
+ ResetMocks();
+ mock_in_rw = 1;
+ test_ssync(0, 0, "AP-RW, EC-RW");
+
+ ResetMocks();
+ test_ssync(0, 0, "AP-RW, EC-RO -> EC-RW");
+ TEST_EQ(ec_protected, 1, " ec protected");
+ TEST_EQ(ec_run_image, 1, " ec run image");
+ TEST_EQ(ec_updated, 0, " ec updated");
+
+ ResetMocks();
+ run_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_EC_REBOOT_TO_RO_REQUIRED,
+ VBNV_RECOVERY_EC_JUMP_RW, "Jump to RW fail");
+
+ ResetMocks();
+ protect_retval = VBERROR_SIMULATED;
+ test_ssync(VBERROR_SIMULATED,
+ VBNV_RECOVERY_EC_PROTECT, "Protect error");
+
+ ResetMocks();
+ shutdown_request_calls_left = 0;
+ test_ssync(VBERROR_SHUTDOWN_REQUESTED, 0,
+ "AP-RW, EC-RO -> EC-RW shutdown requested");
+
+ ResetMocks();
+ mock_in_rw = 1;
+ shutdown_request_calls_left = 0;
+ test_ssync(VBERROR_SHUTDOWN_REQUESTED, 0, "AP-RW shutdown requested");
+}
+
+int main(void)
+{
+ VbSoftwareSyncTest();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_api_kernel4_tests.c b/tests/vboot_api_kernel4_tests.c
new file mode 100644
index 00000000..414279e5
--- /dev/null
+++ b/tests/vboot_api_kernel4_tests.c
@@ -0,0 +1,241 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for vboot_api_kernel, part 4 - select and load kernel
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gbb_header.h"
+#include "host_common.h"
+#include "load_kernel_fw.h"
+#include "rollback_index.h"
+#include "test_common.h"
+#include "vboot_audio.h"
+#include "vboot_common.h"
+#include "vboot_kernel.h"
+#include "vboot_nvstorage.h"
+#include "vboot_struct.h"
+
+/* Mock data */
+static VbCommonParams cparams;
+static VbSelectAndLoadKernelParams kparams;
+static VbNvContext vnc;
+static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
+static GoogleBinaryBlockHeader gbb;
+
+static int ecsync_retval;
+static uint32_t rkr_version;
+static uint32_t new_version;
+static int rkr_retval, rkw_retval, rkl_retval;
+static VbError_t vbboot_retval;
+
+/* Reset mock data (for use before each test) */
+static void ResetMocks(void)
+{
+ Memset(&cparams, 0, sizeof(cparams));
+ cparams.shared_data_size = sizeof(shared_data);
+ cparams.shared_data_blob = shared_data;
+ cparams.gbb_data = &gbb;
+
+ Memset(&kparams, 0, sizeof(kparams));
+
+ Memset(&gbb, 0, sizeof(gbb));
+ gbb.major_version = GBB_MAJOR_VER;
+ gbb.minor_version = GBB_MINOR_VER;
+ gbb.flags = 0;
+
+ Memset(&vnc, 0, sizeof(vnc));
+ VbNvSetup(&vnc);
+ VbNvTeardown(&vnc); /* So CRC gets generated */
+
+ Memset(&shared_data, 0, sizeof(shared_data));
+ VbSharedDataInit(shared, sizeof(shared_data));
+
+ ecsync_retval = VBERROR_SUCCESS;
+ rkr_version = new_version = 0x10002;
+ rkr_retval = rkw_retval = rkl_retval = VBERROR_SUCCESS;
+ vbboot_retval = VBERROR_SUCCESS;
+}
+
+/* Mock functions */
+
+VbError_t VbExNvStorageRead(uint8_t *buf)
+{
+ Memcpy(buf, vnc.raw, sizeof(vnc.raw));
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExNvStorageWrite(const uint8_t *buf)
+{
+ Memcpy(vnc.raw, buf, sizeof(vnc.raw));
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbEcSoftwareSync(VbCommonParams *cparams)
+{
+ return ecsync_retval;
+}
+
+uint32_t RollbackKernelRead(uint32_t *version)
+{
+ *version = rkr_version;
+ return rkr_retval;
+}
+
+uint32_t RollbackKernelWrite(uint32_t version)
+{
+ TEST_EQ(version, new_version, "RollbackKernelWrite new version");
+ rkr_version = version;
+ return rkw_retval;
+}
+
+uint32_t RollbackKernelLock(void)
+{
+ return rkl_retval;
+}
+
+VbError_t VbBootNormal(VbCommonParams *cparams, LoadKernelParams *p)
+{
+ shared->kernel_version_tpm = new_version;
+
+ if (vbboot_retval == -1)
+ return VBERROR_SIMULATED;
+
+ return vbboot_retval;
+}
+
+VbError_t VbBootDeveloper(VbCommonParams *cparams, LoadKernelParams *p)
+{
+ shared->kernel_version_tpm = new_version;
+
+ if (vbboot_retval == -2)
+ return VBERROR_SIMULATED;
+
+ return vbboot_retval;
+}
+
+VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p)
+{
+ shared->kernel_version_tpm = new_version;
+
+ if (vbboot_retval == -3)
+ return VBERROR_SIMULATED;
+
+ return vbboot_retval;
+}
+
+static void test_slk(VbError_t retval, int recovery_reason, const char *desc)
+{
+ uint32_t u;
+
+ TEST_EQ(VbSelectAndLoadKernel(&cparams, &kparams), retval, desc);
+ VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, recovery_reason, " recovery reason");
+}
+
+/* Tests */
+
+static void VbSlkTest(void)
+{
+ ResetMocks();
+ test_slk(0, 0, "Normal");
+
+ /* Software sync */
+ ResetMocks();
+ shared->flags |= VBSD_EC_SOFTWARE_SYNC;
+ ecsync_retval = VBERROR_SIMULATED;
+ test_slk(VBERROR_SIMULATED, 0, "EC sync bad");
+
+ ResetMocks();
+ ecsync_retval = VBERROR_SIMULATED;
+ test_slk(0, 0, "EC sync not done");
+
+ /* Rollback kernel version */
+ ResetMocks();
+ rkr_retval = 123;
+ test_slk(VBERROR_TPM_READ_KERNEL,
+ VBNV_RECOVERY_RW_TPM_R_ERROR, "Read kernel rollback");
+
+ ResetMocks();
+ new_version = 0x20003;
+ test_slk(0, 0, "Roll forward");
+ TEST_EQ(rkr_version, 0x20003, " version");
+
+ ResetMocks();
+ new_version = 0x20003;
+ shared->flags |= VBSD_FWB_TRIED;
+ shared->firmware_index = 1;
+ test_slk(0, 0, "Don't roll forward during try B");
+ TEST_EQ(rkr_version, 0x10002, " version");
+
+ ResetMocks();
+ vbboot_retval = VBERROR_INVALID_KERNEL_FOUND;
+ VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 123);
+ VbNvTeardown(&vnc);
+ shared->flags |= VBSD_FWB_TRIED;
+ shared->firmware_index = 1;
+ test_slk(VBERROR_INVALID_KERNEL_FOUND,
+ 0, "Don't go to recovery if try b fails to find a kernel");
+
+ ResetMocks();
+ new_version = 0x20003;
+ rkw_retval = 123;
+ test_slk(VBERROR_TPM_WRITE_KERNEL,
+ VBNV_RECOVERY_RW_TPM_W_ERROR, "Write kernel rollback");
+
+ ResetMocks();
+ rkl_retval = 123;
+ test_slk(VBERROR_TPM_LOCK_KERNEL,
+ VBNV_RECOVERY_RW_TPM_L_ERROR, "Lock kernel rollback");
+
+ /* Boot normal */
+ ResetMocks();
+ vbboot_retval = -1;
+ test_slk(VBERROR_SIMULATED, 0, "Normal boot bad");
+
+ /* Boot dev */
+ ResetMocks();
+ shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
+ vbboot_retval = -2;
+ test_slk(VBERROR_SIMULATED, 0, "Dev boot bad");
+
+ ResetMocks();
+ shared->flags |= VBSD_BOOT_DEV_SWITCH_ON;
+ new_version = 0x20003;
+ test_slk(0, 0, "Dev doesn't roll forward");
+ TEST_EQ(rkr_version, 0x10002, " version");
+
+ /* Boot recovery */
+ ResetMocks();
+ shared->recovery_reason = 123;
+ vbboot_retval = -3;
+ test_slk(VBERROR_SIMULATED, 0, "Recovery boot bad");
+
+ ResetMocks();
+ shared->recovery_reason = 123;
+ new_version = 0x20003;
+ test_slk(0, 0, "Recovery doesn't roll forward");
+ TEST_EQ(rkr_version, 0x10002, " version");
+
+ ResetMocks();
+ shared->recovery_reason = 123;
+ rkr_retval = rkw_retval = rkl_retval = VBERROR_SIMULATED;
+ test_slk(0, 0, "Recovery ignore TPM errors");
+
+
+
+ // todo: rkr/w/l fail ignored if recovery
+
+
+}
+
+int main(void)
+{
+ VbSlkTest();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vboot_api_kernel_tests.c b/tests/vboot_api_kernel_tests.c
index 444cff7c..8c04814e 100644
--- a/tests/vboot_api_kernel_tests.c
+++ b/tests/vboot_api_kernel_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
@@ -15,33 +15,33 @@
#include "test_common.h"
#include "utility.h"
#include "vboot_api.h"
-
+#include "vboot_kernel.h"
#define MAX_TEST_DISKS 10
#define DEFAULT_COUNT -1
typedef struct {
- uint64_t bytes_per_lba;
- uint64_t lba_count;
- uint32_t flags;
- const char *diskname;
+ uint64_t bytes_per_lba;
+ uint64_t lba_count;
+ uint32_t flags;
+ const char *diskname;
} disk_desc_t;
typedef struct {
- char *name;
+ char *name;
- /* inputs for test case */
- uint32_t want_flags;
- VbError_t diskgetinfo_return_val;
- disk_desc_t disks_to_provide[MAX_TEST_DISKS];
- int disk_count_to_return;
- VbError_t loadkernel_return_val[MAX_TEST_DISKS];
+ /* inputs for test case */
+ uint32_t want_flags;
+ VbError_t diskgetinfo_return_val;
+ disk_desc_t disks_to_provide[MAX_TEST_DISKS];
+ int disk_count_to_return;
+ VbError_t loadkernel_return_val[MAX_TEST_DISKS];
- /* outputs from test */
- uint32_t expected_recovery_request_val;
- const char *expected_to_find_disk;
- const char *expected_to_load_disk;
- uint32_t expected_return_val;
+ /* outputs from test */
+ uint32_t expected_recovery_request_val;
+ const char *expected_to_find_disk;
+ const char *expected_to_load_disk;
+ uint32_t expected_return_val;
} test_case_t;
@@ -52,110 +52,124 @@ static const char pickme[] = "correct choice";
#define DONT_CARE ((const char *)42)
test_case_t test[] = {
-
- {
- .name = "first removable drive",
- .want_flags = VB_DISK_FLAG_REMOVABLE,
- .disks_to_provide = {
- {512, 10, VB_DISK_FLAG_REMOVABLE, 0 }, /* too small */
- {2048, 100, VB_DISK_FLAG_REMOVABLE, 0 }, /* wrong LBA */
- {512, 100, VB_DISK_FLAG_FIXED, 0 }, /* wrong type */
- {512, 100, 0, 0 }, /* wrong flags */
- {512, 100, -1, 0 }, /* still wrong flags */
- {512, 100, VB_DISK_FLAG_REMOVABLE, pickme},
- {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"}, /* already got one */
- },
- .disk_count_to_return = DEFAULT_COUNT,
- .diskgetinfo_return_val = VBERROR_SUCCESS,
- .loadkernel_return_val = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
-
- .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
- .expected_to_find_disk = pickme,
- .expected_to_load_disk = pickme,
- .expected_return_val = VBERROR_SUCCESS
- },
-
- {
- .name = "second removable drive",
- .want_flags = VB_DISK_FLAG_REMOVABLE,
- .disks_to_provide = {
- {512, 100, 0, 0 }, /* wrong flags */
- {512, 100, VB_DISK_FLAG_REMOVABLE, "not yet"},
- {512, 100, VB_DISK_FLAG_REMOVABLE, pickme},
- },
- .disk_count_to_return = DEFAULT_COUNT,
- .diskgetinfo_return_val = VBERROR_SUCCESS,
- .loadkernel_return_val = { 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, },
-
- .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
- .expected_to_find_disk = pickme,
- .expected_to_load_disk = pickme,
- .expected_return_val = VBERROR_SUCCESS
- },
-
- {
- .name = "first fixed drive",
- .want_flags = VB_DISK_FLAG_FIXED,
- .disks_to_provide = {
- {512, 10, VB_DISK_FLAG_FIXED, 0 }, /* too small */
- {2048, 100, VB_DISK_FLAG_FIXED, 0 }, /* wrong LBA */
- {512, 100, VB_DISK_FLAG_REMOVABLE, 0 }, /* wrong type */
- {512, 100, 0, 0 }, /* wrong flags */
- {512, 100, -1, 0 }, /* still wrong flags */
- {512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED, 0 }, /* flags */
- {512, 100, VB_DISK_FLAG_FIXED, pickme},
- {512, 100, VB_DISK_FLAG_FIXED, "holygrail"}, /* already got one */
- },
- .disk_count_to_return = DEFAULT_COUNT,
- .diskgetinfo_return_val = VBERROR_SUCCESS,
- .loadkernel_return_val = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
-
- .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
- .expected_to_find_disk = pickme,
- .expected_to_load_disk = pickme,
- .expected_return_val = VBERROR_SUCCESS
- },
-
- {
- .name = "no drives at all",
- .want_flags = VB_DISK_FLAG_FIXED,
- .disks_to_provide = {
- },
- .disk_count_to_return = DEFAULT_COUNT,
- .diskgetinfo_return_val = VBERROR_SUCCESS,
- .loadkernel_return_val = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
-
- .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_DISK,
- .expected_to_find_disk = 0,
- .expected_to_load_disk = 0,
- .expected_return_val = VBERROR_NO_DISK_FOUND
- },
-
- {
- .name = "no valid drives",
- .want_flags = VB_DISK_FLAG_FIXED,
- .disks_to_provide = {
- {512, 10, VB_DISK_FLAG_FIXED, 0 }, /* too small */
- {2048, 100, VB_DISK_FLAG_FIXED, 0 }, /* wrong LBA */
- {512, 100, VB_DISK_FLAG_REMOVABLE, 0 }, /* wrong type */
- {512, 100, 0, 0 }, /* wrong flags */
- {512, 100, -1, 0 }, /* still wrong flags */
- {512, 100, VB_DISK_FLAG_FIXED, "bad1"}, /* doesn't load */
- {512, 100, VB_DISK_FLAG_FIXED, "bad2"}, /* doesn't load */
- },
- .disk_count_to_return = DEFAULT_COUNT,
- .diskgetinfo_return_val = VBERROR_SUCCESS,
- .loadkernel_return_val = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
-
- .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_DISK,
- .expected_to_find_disk = DONT_CARE,
- .expected_to_load_disk = 0,
- .expected_return_val = 1
- },
-
+ {
+ .name = "first removable drive",
+ .want_flags = VB_DISK_FLAG_REMOVABLE,
+ .disks_to_provide = {
+ /* too small */
+ {512, 10, VB_DISK_FLAG_REMOVABLE, 0},
+ /* wrong LBA */
+ {2048, 100, VB_DISK_FLAG_REMOVABLE, 0},
+ /* wrong type */
+ {512, 100, VB_DISK_FLAG_FIXED, 0},
+ /* wrong flags */
+ {512, 100, 0, 0},
+ /* still wrong flags */
+ {512, 100, -1, 0},
+ {512, 100, VB_DISK_FLAG_REMOVABLE, pickme},
+ /* already got one */
+ {512, 100, VB_DISK_FLAG_REMOVABLE, "holygrail"},
+ },
+ .disk_count_to_return = DEFAULT_COUNT,
+ .diskgetinfo_return_val = VBERROR_SUCCESS,
+ .loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
+
+ .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
+ .expected_to_find_disk = pickme,
+ .expected_to_load_disk = pickme,
+ .expected_return_val = VBERROR_SUCCESS
+ },
+ {
+ .name = "second removable drive",
+ .want_flags = VB_DISK_FLAG_REMOVABLE,
+ .disks_to_provide = {
+ /* wrong flags */
+ {512, 100, 0, 0},
+ {512, 100, VB_DISK_FLAG_REMOVABLE, "not yet"},
+ {512, 100, VB_DISK_FLAG_REMOVABLE, pickme},
+ },
+ .disk_count_to_return = DEFAULT_COUNT,
+ .diskgetinfo_return_val = VBERROR_SUCCESS,
+ .loadkernel_return_val = {1, 0, 1, 1, 1, 1, 1, 1, 1, 1,},
+
+ .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
+ .expected_to_find_disk = pickme,
+ .expected_to_load_disk = pickme,
+ .expected_return_val = VBERROR_SUCCESS
+ },
+ {
+ .name = "first fixed drive",
+ .want_flags = VB_DISK_FLAG_FIXED,
+ .disks_to_provide = {
+ /* too small */
+ {512, 10, VB_DISK_FLAG_FIXED, 0},
+ /* wrong LBA */
+ {2048, 100, VB_DISK_FLAG_FIXED, 0},
+ /* wrong type */
+ {512, 100, VB_DISK_FLAG_REMOVABLE, 0},
+ /* wrong flags */
+ {512, 100, 0, 0},
+ /* still wrong flags */
+ {512, 100, -1, 0},
+ /* flags */
+ {512, 100, VB_DISK_FLAG_REMOVABLE|VB_DISK_FLAG_FIXED,
+ 0},
+ {512, 100, VB_DISK_FLAG_FIXED, pickme},
+ /* already got one */
+ {512, 100, VB_DISK_FLAG_FIXED, "holygrail"},
+ },
+ .disk_count_to_return = DEFAULT_COUNT,
+ .diskgetinfo_return_val = VBERROR_SUCCESS,
+ .loadkernel_return_val = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
+
+ .expected_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED,
+ .expected_to_find_disk = pickme,
+ .expected_to_load_disk = pickme,
+ .expected_return_val = VBERROR_SUCCESS
+ },
+ {
+ .name = "no drives at all",
+ .want_flags = VB_DISK_FLAG_FIXED,
+ .disks_to_provide = {},
+ .disk_count_to_return = DEFAULT_COUNT,
+ .diskgetinfo_return_val = VBERROR_SUCCESS,
+ .loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
+
+ .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_DISK,
+ .expected_to_find_disk = 0,
+ .expected_to_load_disk = 0,
+ .expected_return_val = VBERROR_NO_DISK_FOUND
+ },
+ {
+ .name = "no valid drives",
+ .want_flags = VB_DISK_FLAG_FIXED,
+ .disks_to_provide = {
+ /* too small */
+ {512, 10, VB_DISK_FLAG_FIXED, 0},
+ /* wrong LBA */
+ {2048, 100, VB_DISK_FLAG_FIXED, 0},
+ /* wrong type */
+ {512, 100, VB_DISK_FLAG_REMOVABLE, 0},
+ /* wrong flags */
+ {512, 100, 0, 0},
+ /* still wrong flags */
+ {512, 100, -1, 0},
+ /* doesn't load */
+ {512, 100, VB_DISK_FLAG_FIXED, "bad1"},
+ /* doesn't load */
+ {512, 100, VB_DISK_FLAG_FIXED, "bad2"},
+ },
+ .disk_count_to_return = DEFAULT_COUNT,
+ .diskgetinfo_return_val = VBERROR_SUCCESS,
+ .loadkernel_return_val = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
+
+ .expected_recovery_request_val = VBNV_RECOVERY_RW_NO_KERNEL,
+ .expected_to_find_disk = DONT_CARE,
+ .expected_to_load_disk = 0,
+ .expected_return_val = 1
+ },
};
-
/****************************************************************************/
/* Mock data */
@@ -168,153 +182,134 @@ static const char *got_find_disk;
static const char *got_load_disk;
static uint32_t got_return_val;
-/* Reset mock data (for use before each test) */
-static void ResetMocks(int i) {
- Memset(&lkparams, 0, sizeof(lkparams));
- Memset(&mock_disks, 0, sizeof(mock_disks));
- load_kernel_calls = 0;
-
- got_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED;
- got_find_disk = 0;
- got_load_disk = 0;
- got_return_val = 0xdeadbeef;
-
- t = test+i;
+/**
+ * Reset mock data (for use before each test)
+ */
+static void ResetMocks(int i)
+{
+ Memset(&lkparams, 0, sizeof(lkparams));
+ Memset(&mock_disks, 0, sizeof(mock_disks));
+ load_kernel_calls = 0;
+
+ got_recovery_request_val = VBNV_RECOVERY_NOT_REQUESTED;
+ got_find_disk = 0;
+ got_load_disk = 0;
+ got_return_val = 0xdeadbeef;
+
+ t = test + i;
}
-int is_nonzero(const void *vptr, size_t count) {
- const char *p = (const char *)vptr;
- while (count--)
- if (*p++)
- return 1;
-
- return 0;
-}
+int is_nonzero(const void *vptr, size_t count)
+{
+ const char *p = (const char *)vptr;
+ while (count--)
+ if (*p++)
+ return 1;
-int CheckResults(void) {
- VBDEBUG(("%s()\n", __FUNCTION__));
- VBDEBUG((" recovery_request: %x %x\n",
- t->expected_recovery_request_val, got_recovery_request_val));
- VBDEBUG((" find_disk: (%s) (%s)\n",
- (t->expected_to_find_disk == DONT_CARE
- ? "DONT CARE"
- : t->expected_to_find_disk),
- got_find_disk));
- VBDEBUG((" load_disk: (%s) (%s)\n",
- (t->expected_to_load_disk == DONT_CARE
- ? "DONT CARE"
- : t->expected_to_load_disk),
- got_load_disk));
- VBDEBUG((" return_val: %x %x\n",
- t->expected_return_val, got_return_val));
- return (t->expected_recovery_request_val == got_recovery_request_val &&
- (t->expected_to_find_disk == DONT_CARE ||
- t->expected_to_find_disk == got_find_disk) &&
- (t->expected_to_load_disk == DONT_CARE ||
- t->expected_to_load_disk == got_load_disk) &&
- t->expected_return_val == got_return_val);
+ return 0;
}
/****************************************************************************/
/* Mocked verification functions */
-VbError_t VbExDiskGetInfo(VbDiskInfo** infos_ptr, uint32_t* count,
- uint32_t disk_flags) {
- int i;
- int num_disks = 0;
-
- VBDEBUG(("My %s\n", __FUNCTION__));
-
- *infos_ptr = mock_disks;
-
- for(i=0; i<MAX_TEST_DISKS; i++) {
- if (is_nonzero(&t->disks_to_provide[i], sizeof(t->disks_to_provide[i]))) {
- mock_disks[num_disks].bytes_per_lba =
- t->disks_to_provide[i].bytes_per_lba;
- mock_disks[num_disks].lba_count = t->disks_to_provide[i].lba_count;
- mock_disks[num_disks].flags = t->disks_to_provide[i].flags;
- mock_disks[num_disks].handle =
- (VbExDiskHandle_t)t->disks_to_provide[i].diskname;
- VBDEBUG((" mock_disk[%d] %lld %lld 0x%x %s\n", i,
- mock_disks[num_disks].bytes_per_lba,
- mock_disks[num_disks].lba_count,
- mock_disks[num_disks].flags,
- (mock_disks[num_disks].handle
- ? (char *)mock_disks[num_disks].handle
- : "0")));
- num_disks++;
- } else {
- mock_disks[num_disks].handle = (VbExDiskHandle_t)"INVALID";
- }
- }
-
- if (t->disk_count_to_return >= 0)
- *count = t->disk_count_to_return;
- else
- *count = num_disks;
-
- VBDEBUG((" *count=%lld\n", *count));
- VBDEBUG((" return 0x%x\n", t->diskgetinfo_return_val));
-
- return t->diskgetinfo_return_val;
+VbError_t VbExDiskGetInfo(VbDiskInfo **infos_ptr, uint32_t *count,
+ uint32_t disk_flags)
+{
+ int i;
+ int num_disks = 0;
+
+ VBDEBUG(("My %s\n", __FUNCTION__));
+
+ *infos_ptr = mock_disks;
+
+ for(i = 0; i < MAX_TEST_DISKS; i++) {
+ if (is_nonzero(&t->disks_to_provide[i],
+ sizeof(t->disks_to_provide[i]))) {
+ mock_disks[num_disks].bytes_per_lba =
+ t->disks_to_provide[i].bytes_per_lba;
+ mock_disks[num_disks].lba_count =
+ t->disks_to_provide[i].lba_count;
+ mock_disks[num_disks].flags =
+ t->disks_to_provide[i].flags;
+ mock_disks[num_disks].handle = (VbExDiskHandle_t)
+ t->disks_to_provide[i].diskname;
+ VBDEBUG((" mock_disk[%d] %lld %lld 0x%x %s\n", i,
+ mock_disks[num_disks].bytes_per_lba,
+ mock_disks[num_disks].lba_count,
+ mock_disks[num_disks].flags,
+ (mock_disks[num_disks].handle
+ ? (char *)mock_disks[num_disks].handle
+ : "0")));
+ num_disks++;
+ } else {
+ mock_disks[num_disks].handle =
+ (VbExDiskHandle_t)"INVALID";
+ }
+ }
+
+ if (t->disk_count_to_return >= 0)
+ *count = t->disk_count_to_return;
+ else
+ *count = num_disks;
+
+ VBDEBUG((" *count=%lld\n", *count));
+ VBDEBUG((" return 0x%x\n", t->diskgetinfo_return_val));
+
+ return t->diskgetinfo_return_val;
}
-VbError_t VbExDiskFreeInfo(VbDiskInfo* infos,
- VbExDiskHandle_t preserve_handle) {
- got_load_disk = (const char *)preserve_handle;
- VBDEBUG(("%s(): got_load_disk = %s\n", __FUNCTION__,
- got_load_disk ? got_load_disk : "0"));
- return VBERROR_SUCCESS;
+VbError_t VbExDiskFreeInfo(VbDiskInfo *infos,
+ VbExDiskHandle_t preserve_handle)
+{
+ got_load_disk = (const char *)preserve_handle;
+ VBDEBUG(("%s(): got_load_disk = %s\n", __FUNCTION__,
+ got_load_disk ? got_load_disk : "0"));
+ return VBERROR_SUCCESS;
}
-VbError_t LoadKernel(LoadKernelParams* params) {
- got_find_disk = (const char *)params->disk_handle;
- VBDEBUG(("%s(%d): got_find_disk = %s\n", __FUNCTION__,
- load_kernel_calls,
- got_find_disk ? got_find_disk : "0"));
- return t->loadkernel_return_val[load_kernel_calls++];
+VbError_t LoadKernel(LoadKernelParams *params)
+{
+ got_find_disk = (const char *)params->disk_handle;
+ VBDEBUG(("%s(%d): got_find_disk = %s\n", __FUNCTION__,
+ load_kernel_calls,
+ got_find_disk ? got_find_disk : "0"));
+ return t->loadkernel_return_val[load_kernel_calls++];
}
-int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) {
- VBDEBUG(("%s(): got_recovery_request_val = %d (0x%x)\n", __FUNCTION__,
- value, value));
- got_recovery_request_val = value;
- return 0;
+int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
+{
+ VBDEBUG(("%s(): got_recovery_request_val = %d (0x%x)\n", __FUNCTION__,
+ value, value));
+ got_recovery_request_val = value;
+ return 0;
}
/****************************************************************************/
-
-
-/* This is not declared in any headers, so declare it here. */
-uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p,
- uint32_t get_info_flags);
-
-
-static void VbTryLoadKernelTest(void) {
- int i;
- int num_tests = sizeof(test) / sizeof(test[0]);
-
- for (i=0; i<num_tests; i++) {
- VBDEBUG(("STARTING %s ...\n", test[i].name));
- ResetMocks(i);
- got_return_val = VbTryLoadKernel(0, &lkparams, test[i].want_flags);
- VBDEBUG(("VbTryLoadKernel(): got_return_val = 0x%x\n", got_return_val));
- TEST_TRUE(CheckResults(), test[i].name);
- }
+static void VbTryLoadKernelTest(void)
+{
+ int i;
+ int num_tests = sizeof(test) / sizeof(test[0]);
+
+ for (i = 0; i < num_tests; i++) {
+ printf("Test case: %s ...\n", test[i].name);
+ ResetMocks(i);
+ TEST_EQ(VbTryLoadKernel(0, &lkparams, test[i].want_flags),
+ t->expected_return_val, " return value");
+ TEST_EQ(got_recovery_request_val,
+ t->expected_recovery_request_val, " recovery_request");
+ if (t->expected_to_find_disk != DONT_CARE) {
+ TEST_PTR_EQ(got_find_disk, t->expected_to_find_disk,
+ " find disk");
+ TEST_PTR_EQ(got_load_disk, t->expected_to_load_disk,
+ " load disk");
+ }
+ }
}
+int main(void)
+{
+ VbTryLoadKernelTest();
-/* disable MSVC warnings on unused arguments */
-__pragma(warning (disable: 4100))
-
-int main(int argc, char* argv[]) {
- int error_code = 0;
-
- VbTryLoadKernelTest();
-
- if (!gTestSuccess)
- error_code = 255;
-
- return error_code;
+ return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_display_tests.c b/tests/vboot_display_tests.c
index 5713667b..3093534d 100644
--- a/tests/vboot_display_tests.c
+++ b/tests/vboot_display_tests.c
@@ -9,6 +9,7 @@
#include <stdlib.h>
#include <string.h>
+#include "bmpblk_font.h"
#include "gbb_header.h"
#include "host_common.h"
#include "test_common.h"
@@ -21,21 +22,41 @@ static VbCommonParams cparams;
static VbNvContext vnc;
static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
-static GoogleBinaryBlockHeader gbb;
+static char gbb_data[4096 + sizeof(GoogleBinaryBlockHeader)];
+static GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)gbb_data;
+static BmpBlockHeader *bhdr;
static char debug_info[4096];
/* Reset mock data (for use before each test) */
static void ResetMocks(void)
{
+ int gbb_used;
+
+ Memset(gbb_data, 0, sizeof(gbb_data));
+ gbb->major_version = GBB_MAJOR_VER;
+ gbb->minor_version = GBB_MINOR_VER;
+ gbb->flags = 0;
+ gbb_used = sizeof(GoogleBinaryBlockHeader);
+
+ gbb->hwid_offset = gbb_used;
+ strcpy(gbb_data + gbb->hwid_offset, "Test HWID");
+ gbb->hwid_size = strlen(gbb_data + gbb->hwid_offset) + 1;
+ gbb_used = (gbb_used + gbb->hwid_size + 7) & ~7;
+
+ gbb->bmpfv_offset = gbb_used;
+ bhdr = (BmpBlockHeader *)(gbb_data + gbb->bmpfv_offset);
+ gbb->bmpfv_size = sizeof(BmpBlockHeader);
+ gbb_used = (gbb_used + gbb->bmpfv_size + 7) & ~7;
+ memcpy(bhdr->signature, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE);
+ bhdr->major_version = BMPBLOCK_MAJOR_VERSION;
+ bhdr->minor_version = BMPBLOCK_MINOR_VERSION;
+ bhdr->number_of_localizations = 3;
+
Memset(&cparams, 0, sizeof(cparams));
cparams.shared_data_size = sizeof(shared_data);
cparams.shared_data_blob = shared_data;
- cparams.gbb_data = &gbb;
-
- Memset(&gbb, 0, sizeof(gbb));
- gbb.major_version = GBB_MAJOR_VER;
- gbb.minor_version = GBB_MINOR_VER;
- gbb.flags = 0;
+ cparams.gbb_data = gbb;
+ cparams.gbb_size = sizeof(gbb_data);
Memset(&vnc, 0, sizeof(vnc));
VbNvSetup(&vnc);
@@ -65,19 +86,149 @@ static void DebugInfoTest(void)
for (i = 0; i < 0x100; i++)
TEST_PTR_NEQ(RecoveryReasonString(i), NULL, "Non-null reason");
+ /* HWID should come from the gbb */
+ ResetMocks();
+ TEST_EQ(strcmp(VbHWID(&cparams), "Test HWID"), 0, "HWID");
+
+ ResetMocks();
+ cparams.gbb_size = 0;
+ TEST_EQ(strcmp(VbHWID(&cparams), "{INVALID}"), 0, "HWID bad gbb");
+
+ ResetMocks();
+ gbb->hwid_size = 0;
+ TEST_EQ(strcmp(VbHWID(&cparams), "{INVALID}"), 0, "HWID missing");
+
+ ResetMocks();
+ gbb->hwid_offset = cparams.gbb_size + 1;
+ TEST_EQ(strcmp(VbHWID(&cparams), "{INVALID}"), 0, "HWID past end");
+
+ ResetMocks();
+ gbb->hwid_size = cparams.gbb_size;
+ TEST_EQ(strcmp(VbHWID(&cparams), "{INVALID}"), 0, "HWID overflow");
+
/* Display debug info */
+ ResetMocks();
VbDisplayDebugInfo(&cparams, &vnc);
TEST_NEQ(*debug_info, '\0', "Some debug info was displayed");
}
-/* disable MSVC warnings on unused arguments */
-__pragma(warning (disable: 4100))
+/* Test localization */
+static void LocalizationTest(void)
+{
+ uint32_t count = 6;
+
+ ResetMocks();
+ gbb->bmpfv_size = 0;
+ TEST_EQ(VbGetLocalizationCount(&cparams, &count),
+ VBERROR_INVALID_GBB, "VbGetLocalizationCount bad gbb");
+ TEST_EQ(count, 0, " count");
+
+ ResetMocks();
+ bhdr->signature[0] ^= 0x5a;
+ TEST_EQ(VbGetLocalizationCount(&cparams, &count),
+ VBERROR_INVALID_BMPFV, "VbGetLocalizationCount bad bmpfv");
+
+ ResetMocks();
+ TEST_EQ(VbGetLocalizationCount(&cparams, &count), 0,
+ "VbGetLocalizationCount()");
+ TEST_EQ(count, 3, " count");
+
+}
+
+/* Test display key checking */
+static void DisplayKeyTest(void)
+{
+ uint32_t u;
+
+ ResetMocks();
+ VbCheckDisplayKey(&cparams, 'q', &vnc);
+ TEST_EQ(*debug_info, '\0', "DisplayKey q = does nothing");
+
+ ResetMocks();
+ VbCheckDisplayKey(&cparams, '\t', &vnc);
+ TEST_NEQ(*debug_info, '\0', "DisplayKey tab = display");
+
+ /* Toggle localization */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_LOCALIZATION_INDEX, 0);
+ VbNvTeardown(&vnc);
+ VbCheckDisplayKey(&cparams, VB_KEY_DOWN, &vnc);
+ VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
+ TEST_EQ(u, 2, "DisplayKey up");
+ VbCheckDisplayKey(&cparams, VB_KEY_LEFT, &vnc);
+ VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
+ TEST_EQ(u, 1, "DisplayKey left");
+ VbCheckDisplayKey(&cparams, VB_KEY_RIGHT, &vnc);
+ VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
+ TEST_EQ(u, 2, "DisplayKey right");
+ VbCheckDisplayKey(&cparams, VB_KEY_UP, &vnc);
+ VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
+ TEST_EQ(u, 0, "DisplayKey up");
+
+ /* Reset localization if localization count is invalid */
+ ResetMocks();
+ VbNvSet(&vnc, VBNV_LOCALIZATION_INDEX, 1);
+ VbNvTeardown(&vnc);
+ bhdr->signature[0] ^= 0x5a;
+ VbCheckDisplayKey(&cparams, VB_KEY_UP, &vnc);
+ VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &u);
+ TEST_EQ(u, 0, "DisplayKey invalid");
+
+}
-int main(int argc, char* argv[])
+static void FontTest(void)
{
- ResetMocks(); // KLUDGE
+ FontArrayHeader h;
+ FontArrayEntryHeader eh[3] = {
+ {
+ .ascii = 'A',
+ .info.original_size = 10,
+ },
+ {
+ .ascii = 'B',
+ .info.original_size = 20,
+ },
+ {
+ .ascii = 'C',
+ .info.original_size = 30,
+ },
+ };
+ FontArrayEntryHeader *eptr;
+ uint8_t buf[sizeof(h) + sizeof(eh)];
+ VbFont_t *fptr;
+ void *bufferptr;
+ uint32_t buffersize;
+
+ /* Create font data */
+ h.num_entries = ARRAY_SIZE(eh);
+ Memcpy(buf, &h, sizeof(h));
+ eptr = (FontArrayEntryHeader *)(buf + sizeof(h));
+ Memcpy(eptr, eh, sizeof(eh));
+
+ fptr = VbInternalizeFontData((FontArrayHeader *)buf);
+ TEST_PTR_EQ(fptr, buf, "Internalize");
+
+ TEST_PTR_EQ(VbFindFontGlyph(fptr, 'B', &bufferptr, &buffersize),
+ &eptr[1].info, "Glyph found");
+ TEST_EQ(buffersize, eptr[1].info.original_size, " size");
+ TEST_PTR_EQ(VbFindFontGlyph(fptr, 'X', &bufferptr, &buffersize),
+ &eptr[0].info, "Glyph not found");
+ TEST_EQ(buffersize, eptr[0].info.original_size, " size");
+
+ /* Test invalid rendering params */
+ VbRenderTextAtPos(NULL, 0, 0, 0, fptr);
+ VbRenderTextAtPos("ABC", 0, 0, 0, NULL);
+
+ VbDoneWithFontForNow(fptr);
+}
+
+int main(void)
+{
DebugInfoTest();
+ LocalizationTest();
+ DisplayKeyTest();
+ FontTest();
return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vboot_kernel_tests.c b/tests/vboot_kernel_tests.c
new file mode 100644
index 00000000..1ee1528f
--- /dev/null
+++ b/tests/vboot_kernel_tests.c
@@ -0,0 +1,538 @@
+/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Tests for vboot_kernel.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cgptlib.h"
+#include "gbb_header.h"
+#include "gpt.h"
+#include "host_common.h"
+#include "load_kernel_fw.h"
+#include "test_common.h"
+#include "vboot_api.h"
+#include "vboot_common.h"
+#include "vboot_kernel.h"
+#include "vboot_nvstorage.h"
+
+#define LOGCALL(fmt, args...) sprintf(call_log + strlen(call_log), fmt, ##args)
+#define TEST_CALLS(expect_log) TEST_STR_EQ(call_log, expect_log, " calls")
+
+/* Mock kernel partition */
+struct mock_part {
+ uint32_t start;
+ uint32_t size;
+};
+
+/* Partition list; ends with a 0-size partition. */
+#define MOCK_PART_COUNT 8
+static struct mock_part mock_parts[MOCK_PART_COUNT];
+static int mock_part_next;
+
+/* Mock data */
+static char call_log[4096];
+static uint8_t kernel_buffer[80000];
+static int disk_read_to_fail;
+static int disk_write_to_fail;
+static int gpt_init_fail;
+static int key_block_verify_fail; /* 0=ok, 1=sig, 2=hash */
+static int preamble_verify_fail;
+static int verify_data_fail;
+static RSAPublicKey *mock_data_key;
+static int mock_data_key_allocated;
+
+static GoogleBinaryBlockHeader gbb;
+static VbExDiskHandle_t handle;
+static VbNvContext vnc;
+static uint8_t shared_data[VB_SHARED_DATA_MIN_SIZE];
+static VbSharedDataHeader *shared = (VbSharedDataHeader *)shared_data;
+static LoadKernelParams lkp;
+static VbKeyBlockHeader kbh;
+static VbKernelPreambleHeader kph;
+
+static void ResetCallLog(void)
+{
+ *call_log = 0;
+}
+
+/**
+ * Reset mock data (for use before each test)
+ */
+static void ResetMocks(void)
+{
+ ResetCallLog();
+
+ disk_read_to_fail = -1;
+ disk_write_to_fail = -1;
+
+ gpt_init_fail = 0;
+ key_block_verify_fail = 0;
+ preamble_verify_fail = 0;
+ verify_data_fail = 0;
+
+ mock_data_key = (RSAPublicKey *)"TestDataKey";
+ mock_data_key_allocated = 0;
+
+ memset(&gbb, 0, sizeof(gbb));
+ gbb.major_version = GBB_MAJOR_VER;
+ gbb.minor_version = GBB_MINOR_VER;
+ gbb.flags = 0;
+
+ memset(&vnc, 0, sizeof(vnc));
+ VbNvSetup(&vnc);
+ VbNvTeardown(&vnc); /* So CRC gets generated */
+
+ memset(&shared_data, 0, sizeof(shared_data));
+ VbSharedDataInit(shared, sizeof(shared_data));
+ shared->kernel_version_tpm = 0x20001;
+
+ memset(&lkp, 0, sizeof(lkp));
+ lkp.nv_context = &vnc;
+ lkp.shared_data_blob = shared;
+ lkp.gbb_data = &gbb;
+ lkp.bytes_per_lba = 512;
+ lkp.ending_lba = 1023;
+ lkp.kernel_buffer = kernel_buffer;
+ lkp.kernel_buffer_size = sizeof(kernel_buffer);
+
+ memset(&kbh, 0, sizeof(kbh));
+ kbh.data_key.key_version = 2;
+ kbh.key_block_flags = -1;
+ kbh.key_block_size = sizeof(kbh);
+
+ memset(&kph, 0, sizeof(kph));
+ kph.kernel_version = 1;
+ kph.preamble_size = 4096 - kbh.key_block_size;
+ kph.body_signature.data_size = 70000;
+ kph.bootloader_address = 0xbeadd008;
+ kph.bootloader_size = 0x1234;
+
+ memset(mock_parts, 0, sizeof(mock_parts));
+ mock_parts[0].start = 100;
+ mock_parts[0].size = 150; /* 75 KB */
+ mock_part_next = 0;
+}
+
+/* Mocks */
+
+VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
+ uint64_t lba_count, void *buffer)
+{
+ LOGCALL("VbExDiskRead(h, %d, %d)\n", (int)lba_start, (int)lba_count);
+
+ if ((int)lba_start == disk_read_to_fail)
+ return VBERROR_SIMULATED;
+
+ return VBERROR_SUCCESS;
+}
+
+VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
+ uint64_t lba_count, const void *buffer)
+{
+ LOGCALL("VbExDiskWrite(h, %d, %d)\n", (int)lba_start, (int)lba_count);
+
+ if ((int)lba_start == disk_write_to_fail)
+ return VBERROR_SIMULATED;
+
+ return VBERROR_SUCCESS;
+}
+
+int GptInit(GptData *gpt)
+{
+ return gpt_init_fail;
+}
+
+int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size)
+{
+ struct mock_part *p = mock_parts + mock_part_next;
+
+ if (!p->size)
+ return GPT_ERROR_NO_VALID_KERNEL;
+
+ gpt->current_kernel = mock_part_next;
+ *start_sector = p->start;
+ *size = p->size;
+ mock_part_next++;
+ return GPT_SUCCESS;
+}
+
+void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
+{
+ static char fake_guid[] = "FakeGuid";
+
+ memcpy(dest, fake_guid, sizeof(fake_guid));
+}
+
+int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size,
+ const VbPublicKey *key, int hash_only) {
+
+ if (hash_only && key_block_verify_fail >= 2)
+ return VBERROR_SIMULATED;
+ else if (!hash_only && key_block_verify_fail >= 1)
+ return VBERROR_SIMULATED;
+
+ /* Use this as an opportunity to override the key block */
+ memcpy((void *)block, &kbh, sizeof(kbh));
+ return VBERROR_SUCCESS;
+}
+
+RSAPublicKey *PublicKeyToRSA(const VbPublicKey *key)
+{
+ TEST_EQ(mock_data_key_allocated, 0, " mock data key not allocated");
+
+ if (mock_data_key)
+ mock_data_key_allocated++;
+
+ return mock_data_key;
+}
+
+void RSAPublicKeyFree(RSAPublicKey* key)
+{
+ TEST_EQ(mock_data_key_allocated, 1, " mock data key allocated");
+ TEST_PTR_EQ(key, mock_data_key, " data key ptr");
+ mock_data_key_allocated--;
+}
+
+int VerifyKernelPreamble(const VbKernelPreambleHeader *preamble,
+ uint64_t size, const RSAPublicKey *key)
+{
+ if (preamble_verify_fail)
+ return VBERROR_SIMULATED;
+
+ /* Use this as an opportunity to override the preamble */
+ memcpy((void *)preamble, &kph, sizeof(kph));
+ return VBERROR_SUCCESS;
+}
+
+int VerifyData(const uint8_t *data, uint64_t size, const VbSignature *sig,
+ const RSAPublicKey *key)
+{
+ if (verify_data_fail)
+ return VBERROR_SIMULATED;
+
+ return VBERROR_SUCCESS;
+}
+
+
+/**
+ * Test reading/writing GPT
+ */
+static void ReadWriteGptTest(void)
+{
+ GptData g;
+ GptHeader *h;
+
+ g.sector_bytes = 512;
+ g.drive_sectors = 1024;
+
+ ResetMocks();
+ TEST_EQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead");
+ TEST_CALLS("VbExDiskRead(h, 1, 1)\n"
+ "VbExDiskRead(h, 2, 32)\n"
+ "VbExDiskRead(h, 991, 32)\n"
+ "VbExDiskRead(h, 1023, 1)\n");
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree");
+ TEST_CALLS("");
+
+ /* Data which is changed is written */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ g.modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1;
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod 1");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n");
+
+ /* Data which is changed is written */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
+ TEST_CALLS("VbExDiskWrite(h, 1, 1)\n"
+ "VbExDiskWrite(h, 2, 32)\n"
+ "VbExDiskWrite(h, 991, 32)\n"
+ "VbExDiskWrite(h, 1023, 1)\n");
+
+ /* If legacy signature, don't modify GPT header/entries 1 */
+ ResetMocks();
+ AllocAndReadGptData(handle, &g);
+ h = (GptHeader *)g.primary_header;
+ memcpy(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE);
+ g.modified = -1;
+ ResetCallLog();
+ TEST_EQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree mod all");
+ TEST_CALLS("VbExDiskWrite(h, 991, 32)\n"
+ "VbExDiskWrite(h, 1023, 1)\n");
+
+ /* Error reading */
+ ResetMocks();
+ disk_read_to_fail = 1;
+ TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ WriteAndFreeGptData(handle, &g);
+
+ ResetMocks();
+ disk_read_to_fail = 2;
+ TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ WriteAndFreeGptData(handle, &g);
+
+ ResetMocks();
+ disk_read_to_fail = 991;
+ TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ WriteAndFreeGptData(handle, &g);
+
+ ResetMocks();
+ disk_read_to_fail = 1023;
+ TEST_NEQ(AllocAndReadGptData(handle, &g), 0, "AllocAndRead disk fail");
+ WriteAndFreeGptData(handle, &g);
+
+ /* Error writing */
+ ResetMocks();
+ disk_write_to_fail = 1;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 2;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 991;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+ ResetMocks();
+ disk_write_to_fail = 1023;
+ AllocAndReadGptData(handle, &g);
+ g.modified = -1;
+ TEST_NEQ(WriteAndFreeGptData(handle, &g), 0, "WriteAndFree disk fail");
+
+}
+
+/**
+ * Trivial invalid calls to LoadKernel()
+ */
+static void InvalidParamsTest(void)
+{
+ ResetMocks();
+ lkp.bytes_per_lba = 0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Bad lba size");
+
+ ResetMocks();
+ lkp.ending_lba = 0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Bad lba count");
+
+ ResetMocks();
+ lkp.bytes_per_lba = 128*1024;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_PARAMETER, "Huge lba size");
+
+ ResetMocks();
+ disk_read_to_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Can't read disk");
+
+ ResetMocks();
+ gpt_init_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "Bad GPT");
+}
+
+static void LoadKernelTest(void)
+{
+ uint32_t u;
+
+ ResetMocks();
+ TEST_EQ(LoadKernel(&lkp), 0, "First kernel good");
+ TEST_EQ(lkp.partition_number, 1, " part num");
+ TEST_EQ(lkp.bootloader_address, 0xbeadd008, " bootloader addr");
+ TEST_EQ(lkp.bootloader_size, 0x1234, " bootloader size");
+ TEST_STR_EQ((char *)lkp.partition_guid, "FakeGuid", " guid");
+ VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, 0, " recovery request");
+
+ ResetMocks();
+ mock_parts[1].start = 300;
+ mock_parts[1].size = 150;
+ TEST_EQ(LoadKernel(&lkp), 0, "Two good kernels");
+ TEST_EQ(lkp.partition_number, 1, " part num");
+ TEST_EQ(mock_part_next, 1, " didn't read second one");
+
+ /* Fail if no kernels found */
+ ResetMocks();
+ mock_parts[0].size = 0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_NO_KERNEL_FOUND, "No kernels");
+ VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, VBNV_RECOVERY_RW_NO_OS, " recovery request");
+
+ /* Skip kernels which are too small */
+ ResetMocks();
+ mock_parts[0].size = 10;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Too small");
+ VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &u);
+ TEST_EQ(u, VBNV_RECOVERY_RW_INVALID_OS, " recovery request");
+
+ ResetMocks();
+ disk_read_to_fail = 100;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail reading kernel start");
+
+ ResetMocks();
+ key_block_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail key block sig");
+
+ /* In dev mode, fail if hash is bad too */
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ key_block_verify_fail = 2;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail key block dev hash");
+
+ /* But just bad sig is ok */
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ key_block_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), 0, "Succeed key block dev sig");
+
+ /* In dev mode and requiring signed kernel, fail if sig is bad */
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 1);
+ VbNvTeardown(&vnc);
+ key_block_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail key block dev sig");
+
+ /* Check key block flag mismatches */
+ ResetMocks();
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block dev flag mismatch");
+
+ ResetMocks();
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block rec flag mismatch");
+
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_RECOVERY;
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block recdev flag mismatch");
+
+ ResetMocks();
+ lkp.boot_flags |= BOOT_FLAG_RECOVERY | BOOT_FLAG_DEVELOPER;
+ kbh.key_block_flags =
+ KEY_BLOCK_FLAG_RECOVERY_1 | KEY_BLOCK_FLAG_DEVELOPER_0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block rec!dev flag mismatch");
+
+ ResetMocks();
+ kbh.data_key.key_version = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block kernel key rollback");
+
+ ResetMocks();
+ kbh.data_key.key_version = 0x10000;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Key block kernel key version too big");
+
+ ResetMocks();
+ kbh.data_key.key_version = 3;
+ TEST_EQ(LoadKernel(&lkp), 0, "Key block version roll forward");
+ TEST_EQ(shared->kernel_version_tpm, 0x30001, " shared version");
+
+ ResetMocks();
+ kbh.data_key.key_version = 3;
+ mock_parts[1].start = 300;
+ mock_parts[1].size = 150;
+ TEST_EQ(LoadKernel(&lkp), 0, "Two kernels roll forward");
+ TEST_EQ(mock_part_next, 2, " read both");
+ TEST_EQ(shared->kernel_version_tpm, 0x30001, " shared version");
+
+ ResetMocks();
+ kbh.data_key.key_version = 1;
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ TEST_EQ(LoadKernel(&lkp), 0, "Key version ignored in dev mode");
+
+ ResetMocks();
+ kbh.data_key.key_version = 1;
+ lkp.boot_flags |= BOOT_FLAG_RECOVERY;
+ TEST_EQ(LoadKernel(&lkp), 0, "Key version ignored in rec mode");
+
+ ResetMocks();
+ mock_data_key = NULL;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad data key");
+
+ ResetMocks();
+ preamble_verify_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad preamble");
+
+ ResetMocks();
+ kph.kernel_version = 0;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel version rollback");
+
+ ResetMocks();
+ kph.kernel_version = 0;
+ lkp.boot_flags |= BOOT_FLAG_DEVELOPER;
+ TEST_EQ(LoadKernel(&lkp), 0, "Kernel version ignored in dev mode");
+
+ ResetMocks();
+ kph.kernel_version = 0;
+ lkp.boot_flags |= BOOT_FLAG_RECOVERY;
+ TEST_EQ(LoadKernel(&lkp), 0, "Kernel version ignored in rec mode");
+
+ ResetMocks();
+ kph.preamble_size |= 0x07;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel body offset");
+
+ /* Check getting kernel load address from header */
+ ResetMocks();
+ kph.body_load_address = (size_t)kernel_buffer;
+ lkp.kernel_buffer = NULL;
+ TEST_EQ(LoadKernel(&lkp), 0, "Get load address from preamble");
+ TEST_PTR_EQ(lkp.kernel_buffer, kernel_buffer, " address");
+ /* Size is rounded up to nearest sector */
+ TEST_EQ(lkp.kernel_buffer_size, 70144, " size");
+
+ ResetMocks();
+ lkp.kernel_buffer_size = 8192;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel too big for buffer");
+
+ ResetMocks();
+ mock_parts[0].size = 130;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Kernel too big for partition");
+
+ ResetMocks();
+ disk_read_to_fail = 108;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND,
+ "Fail reading kernel data");
+
+ ResetMocks();
+ verify_data_fail = 1;
+ TEST_EQ(LoadKernel(&lkp), VBERROR_INVALID_KERNEL_FOUND, "Bad data");
+}
+
+int main(void)
+{
+ ReadWriteGptTest();
+ InvalidParamsTest();
+ LoadKernelTest();
+
+ return gTestSuccess ? 0 : 255;
+}