summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-01-29 15:01:12 -0800
committerChromeBot <chrome-bot@google.com>2013-01-31 09:38:28 -0800
commit7993f257af87c7c38cdc71b76bc67cde6c3cdbca (patch)
tree6f0153579ebf4d0ae327e7f11dda902c6494b4ce
parent49cb0d3471e768da11fe76b65769bd57dca38bd7 (diff)
downloadvboot-7993f257af87c7c38cdc71b76bc67cde6c3cdbca.tar.gz
Reformat to kernel style
No code changes, just reformatting. BUG=none BRANCH=none TEST=make runtests Change-Id: Id690c8334147970784db5ac54933ad1f5a58dcc1 Reviewed-on: https://gerrit.chromium.org/gerrit/42263 Tested-by: Randall Spangler <rspangler@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Commit-Queue: Randall Spangler <rspangler@chromium.org>
-rw-r--r--PRESUBMIT.cfg6
-rw-r--r--firmware/lib/crc8.c38
-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/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_audio.c463
-rw-r--r--firmware/lib/vboot_firmware.c643
-rw-r--r--firmware/lib/vboot_kernel.c1126
-rw-r--r--firmware/lib/vboot_nvstorage.c455
13 files changed, 2086 insertions, 1848 deletions
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/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/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/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_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_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 a9a6fdf3..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,551 +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->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;
- }
+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) */
-
- 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;
+ /* 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;
}