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>
This commit is contained in:
Randall Spangler
2013-01-29 15:01:12 -08:00
committed by ChromeBot
parent 49cb0d3471
commit 7993f257af
13 changed files with 1863 additions and 1625 deletions

6
PRESUBMIT.cfg Normal file
View File

@@ -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

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
*/ */
#include "crc8.h" #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 * Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A table-based
* worth the code size. */ * algorithm would be faster, but for only a few bytes it isn't worth the code
uint8_t Crc8(const void* vptr, int len) { * size. */
const uint8_t *data = vptr; uint8_t Crc8(const void *vptr, int len)
unsigned crc = 0; {
int i, j; const uint8_t *data = vptr;
unsigned crc = 0;
int i, j;
for (j = len; j; j--, data++) { for (j = len; j; j--, data++) {
crc ^= (*data << 8); crc ^= (*data << 8);
for(i = 8; i; i--) { for(i = 8; i; i--) {
if (crc & 0x8000) if (crc & 0x8000)
crc ^= (0x1070 << 3); crc ^= (0x1070 << 3);
crc <<= 1; crc <<= 1;
} }
} }
return (uint8_t)(crc >> 8); return (uint8_t)(crc >> 8);
} }

View File

@@ -18,9 +18,11 @@
#endif #endif
#ifdef FOR_TEST #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 * 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 CHROMEOS_ENVIRONMENT
#undef DISABLE_ROLLBACK_TPM #undef DISABLE_ROLLBACK_TPM
#endif #endif
@@ -30,13 +32,14 @@ static int g_rollback_recovery_mode = 0;
/* disable MSVC warning on const logical expression (as in } while(0);) */ /* disable MSVC warning on const logical expression (as in } while(0);) */
__pragma(warning (disable: 4127)) __pragma(warning (disable: 4127))
#define RETURN_ON_FAILURE(tpm_command) do { \ #define RETURN_ON_FAILURE(tpm_command) do { \
uint32_t result; \ uint32_t result; \
if ((result = (tpm_command)) != TPM_SUCCESS) { \ if ((result = (tpm_command)) != TPM_SUCCESS) { \
VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \ VBDEBUG(("Rollback: %08x returned by " #tpm_command \
return result; \ "\n", (int)result)); \
} \ return result; \
} while (0) } \
} while (0)
uint32_t TPMClearAndReenable(void) uint32_t TPMClearAndReenable(void)

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -6,65 +6,67 @@
*/ */
#include "stateful_util.h" #include "stateful_util.h"
#include "utility.h" #include "utility.h"
void StatefulInit(MemcpyState* state, void* buf, uint64_t len) { void StatefulInit(MemcpyState *state, void *buf, uint64_t len)
state->remaining_buf = buf; {
state->remaining_len = len; state->remaining_buf = buf;
state->overrun = 0; state->remaining_len = len;
state->overrun = 0;
} }
void* StatefulSkip(MemcpyState* state, uint64_t len) { void *StatefulSkip(MemcpyState *state, uint64_t len)
if (state->overrun) {
return NULL; if (state->overrun)
if (len > state->remaining_len) { return NULL;
state->overrun = 1; if (len > state->remaining_len) {
return NULL; state->overrun = 1;
} return NULL;
state->remaining_buf += len; }
state->remaining_len -= len; state->remaining_buf += len;
return state; // have to return something non-NULL state->remaining_len -= len;
return state; /* Must return something non-NULL. */
} }
void* StatefulMemcpy(MemcpyState* state, void* dst, void *StatefulMemcpy(MemcpyState *state, void *dst, uint64_t len)
uint64_t len) { {
if (state->overrun) if (state->overrun)
return NULL; return NULL;
if (len > state->remaining_len) { if (len > state->remaining_len) {
state->overrun = 1; state->overrun = 1;
return NULL; return NULL;
} }
Memcpy(dst, state->remaining_buf, len); Memcpy(dst, state->remaining_buf, len);
state->remaining_buf += len; state->remaining_buf += len;
state->remaining_len -= len; state->remaining_len -= len;
return dst; return dst;
} }
const void* StatefulMemcpy_r(MemcpyState* state, const void* src, const void *StatefulMemcpy_r(MemcpyState *state, const void *src, uint64_t len)
uint64_t len) { {
if (state->overrun) if (state->overrun)
return NULL; return NULL;
if (len > state->remaining_len) { if (len > state->remaining_len) {
state->overrun = 1; state->overrun = 1;
return NULL; return NULL;
} }
Memcpy(state->remaining_buf, src, len); Memcpy(state->remaining_buf, src, len);
state->remaining_buf += len; state->remaining_buf += len;
state->remaining_len -= len; state->remaining_len -= len;
return src; return src;
} }
const void* StatefulMemset_r(MemcpyState* state, const uint8_t val, const void *StatefulMemset_r(MemcpyState *state, const uint8_t val,
uint64_t len) { uint64_t len)
if (state->overrun) {
return NULL; if (state->overrun)
if (len > state->remaining_len) { return NULL;
state->overrun = 1; if (len > state->remaining_len) {
return NULL; state->overrun = 1;
} return NULL;
Memset(state->remaining_buf, val, len); }
state->remaining_buf += len; Memset(state->remaining_buf, val, len);
state->remaining_len -= len; state->remaining_buf += len;
return state; // have to return something non-NULL state->remaining_len -= len;
return state; /* Must return something non-NULL. */
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -14,7 +14,8 @@
/* TPM PCR to use for storing boot mode measurements. */ /* TPM PCR to use for storing boot mode measurements. */
#define BOOT_MODE_PCR 0 #define BOOT_MODE_PCR 0
/* Input digests for PCR extend. /*
* Input digests for PCR extend.
* These are calculated as: * These are calculated as:
* SHA1("|Developer_Mode||Recovery_Mode||Keyblock_Mode|"). * SHA1("|Developer_Mode||Recovery_Mode||Keyblock_Mode|").
* Developer_Mode can be 0 or 1. * Developer_Mode can be 0 or 1.
@@ -31,105 +32,125 @@
*/ */
const char* kBootStateSHA1Digests[] = { const char* kBootStateSHA1Digests[] = {
/* SHA1("\x00\x00\x00") */ /* SHA1("\x00\x00\x00") */
"\x29\xe2\xdc\xfb\xb1\x6f\x63\xbb\x02\x54\xdf\x75\x85\xa1\x5b\xb6" "\x29\xe2\xdc\xfb\xb1\x6f\x63\xbb\x02\x54\xdf\x75\x85\xa1\x5b\xb6"
"\xfb\x5e\x92\x7d", "\xfb\x5e\x92\x7d",
/* SHA1("\x00\x00\x01") */ /* SHA1("\x00\x00\x01") */
"\x25\x47\xcc\x73\x6e\x95\x1f\xa4\x91\x98\x53\xc4\x3a\xe8\x90\x86" "\x25\x47\xcc\x73\x6e\x95\x1f\xa4\x91\x98\x53\xc4\x3a\xe8\x90\x86"
"\x1a\x3b\x32\x64", "\x1a\x3b\x32\x64",
/* SHA1("\x00\x00\x02") */ /* SHA1("\x00\x00\x02") */
"\x1e\xf6\x24\x48\x2d\x62\x0e\x43\xe6\xd3\x4d\xa1\xaf\xe4\x62\x67" "\x1e\xf6\x24\x48\x2d\x62\x0e\x43\xe6\xd3\x4d\xa1\xaf\xe4\x62\x67"
"\xfc\x69\x5d\x9b", "\xfc\x69\x5d\x9b",
/* SHA1("\x00\x01\x00") */ /* SHA1("\x00\x01\x00") */
"\x62\x57\x18\x91\x21\x5b\x4e\xfc\x1c\xea\xb7\x44\xce\x59\xdd\x0b" "\x62\x57\x18\x91\x21\x5b\x4e\xfc\x1c\xea\xb7\x44\xce\x59\xdd\x0b"
"\x66\xea\x6f\x73", "\x66\xea\x6f\x73",
/* SHA1("\x00\x01\x01") */ /* SHA1("\x00\x01\x01") */
"\xee\xe4\x47\xed\xc7\x9f\xea\x1c\xa7\xc7\xd3\x4e\x46\x32\x61\xcd" "\xee\xe4\x47\xed\xc7\x9f\xea\x1c\xa7\xc7\xd3\x4e\x46\x32\x61\xcd"
"\xa4\xba\x33\x9e", "\xa4\xba\x33\x9e",
/* SHA1("\x00\x01\x02") */ /* SHA1("\x00\x01\x02") */
"\x0c\x7a\x62\x3f\xd2\xbb\xc0\x5b\x06\x42\x3b\xe3\x59\xe4\x02\x1d" "\x0c\x7a\x62\x3f\xd2\xbb\xc0\x5b\x06\x42\x3b\xe3\x59\xe4\x02\x1d"
"\x36\xe7\x21\xad", "\x36\xe7\x21\xad",
/* SHA1("\x01\x00\x00") */ /* SHA1("\x01\x00\x00") */
"\x95\x08\xe9\x05\x48\xb0\x44\x0a\x4a\x61\xe5\x74\x3b\x76\xc1\xe3" "\x95\x08\xe9\x05\x48\xb0\x44\x0a\x4a\x61\xe5\x74\x3b\x76\xc1\xe3"
"\x09\xb2\x3b\x7f", "\x09\xb2\x3b\x7f",
/* SHA1("\x01\x00\x01") */ /* SHA1("\x01\x00\x01") */
"\xc4\x2a\xc1\xc4\x6f\x1d\x4e\x21\x1c\x73\x5c\xc7\xdf\xad\x4f\xf8" "\xc4\x2a\xc1\xc4\x6f\x1d\x4e\x21\x1c\x73\x5c\xc7\xdf\xad\x4f\xf8"
"\x39\x11\x10\xe9", "\x39\x11\x10\xe9",
/* SHA1("\x01\x00\x02") */ /* SHA1("\x01\x00\x02") */
"\xfa\x01\x0d\x26\x64\xcc\x5b\x3b\x82\xee\x48\x8f\xe2\xb9\xf5\x0f" "\xfa\x01\x0d\x26\x64\xcc\x5b\x3b\x82\xee\x48\x8f\xe2\xb9\xf5\x0f"
"\x49\x32\xeb\x8f", "\x49\x32\xeb\x8f",
/* SHA1("\x01\x01\x00") */ /* SHA1("\x01\x01\x00") */
"\x47\xec\x8d\x98\x36\x64\x33\xdc\x00\x2e\x77\x21\xc9\xe3\x7d\x50" "\x47\xec\x8d\x98\x36\x64\x33\xdc\x00\x2e\x77\x21\xc9\xe3\x7d\x50"
"\x67\x54\x79\x37", "\x67\x54\x79\x37",
/* SHA1("\x01\x01\x01") */ /* SHA1("\x01\x01\x01") */
"\x28\xd8\x6c\x56\xb3\xbf\x26\xd2\x36\x56\x9b\x8d\xc8\xc3\xf9\x1f" "\x28\xd8\x6c\x56\xb3\xbf\x26\xd2\x36\x56\x9b\x8d\xc8\xc3\xf9\x1f"
"\x32\xf4\x7b\xc7", "\x32\xf4\x7b\xc7",
/* SHA1("\x01\x01\x02") */ /* SHA1("\x01\x01\x02") */
"\x12\xa3\x40\xd7\x89\x7f\xe7\x13\xfc\x8f\x02\xac\x53\x65\xb8\x6e" "\x12\xa3\x40\xd7\x89\x7f\xe7\x13\xfc\x8f\x02\xac\x53\x65\xb8\x6e"
"\xbf\x35\x31\x78", "\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[] = { 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[]. */ * Given the boot state, return the correct SHA1 digest index for TPMExtend
int GetBootStateIndex(int dev_mode, int rec_mode, uint64_t keyblock_flags) { * in kBootStateSHA1Digests[].
int index = 0; */
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[]. */ * Convert keyblock flags into keyblock mode which we use to index into
switch(keyblock_flags) { * kBootStateSHA1Digest[].
case 6: /* KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1 */ */
/* Developer firmware. */ switch(keyblock_flags) {
index = 2; case 6:
break; /*
case 7: /* KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_0 * KEY_BLOCK_FLAG_RECOVERY_0 | KEY_BLOCK_FLAG_DEVELOPER_1
* | KEY_BLOCK_FLAGS_DEVELOPER_1 */ *
index = 1; * Developer firmware. */
break; index = 2;
default: break;
index = 0; /* Any other keyblock flags. */ 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) if (rec_mode)
index += 3; index += 3;
if (dev_mode) if (dev_mode)
index += 6; index += 6;
return index; return index;
} }
uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode, uint32_t SetTPMBootModeState(int developer_mode, int recovery_mode,
uint64_t fw_keyblock_flags) { uint64_t fw_keyblock_flags)
uint32_t result; {
const uint8_t* in_digest = NULL; uint32_t result;
uint8_t out_digest[20]; /* For PCR extend output. */ const uint8_t *in_digest = NULL;
int digest_index = GetBootStateIndex(developer_mode, recovery_mode, uint8_t out_digest[20]; /* For PCR extend output. */
fw_keyblock_flags); int digest_index = GetBootStateIndex(developer_mode, recovery_mode,
fw_keyblock_flags);
if (digest_index >= 0 && digest_index < MAX_BOOT_STATE_INDEX) if (digest_index >= 0 && digest_index < MAX_BOOT_STATE_INDEX) {
in_digest = (const uint8_t*)kBootStateSHA1Digests[digest_index]; in_digest = (const uint8_t*)
else kBootStateSHA1Digests[digest_index];
in_digest = kBootInvalidSHA1Digest; /* Internal out of bounds error. */ } else {
result = TlclExtend(BOOT_MODE_PCR, in_digest, out_digest); /* Internal out of bounds error. */
VBDEBUG(("TPM: SetTPMBootModeState boot mode PCR out_digest %02x %02x %02x " in_digest = kBootInvalidSHA1Digest;
"%02x\n", out_digest, out_digest+1, out_digest+2, out_digest+3)); }
return result;
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;
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -8,18 +8,20 @@
#include "sysincludes.h" #include "sysincludes.h"
#include "utility.h" #include "utility.h"
int SafeMemcmp(const void* s1, const void* s2, size_t n) { int SafeMemcmp(const void *s1, const void *s2, size_t n) {
const unsigned char* us1 = s1; const unsigned char *us1 = s1;
const unsigned char* us2 = s2; const unsigned char *us2 = s2;
int result = 0; int result = 0;
if (0 == n) if (0 == n)
return 0; return 0;
/* Code snippet without data-dependent branch due to /*
* Nate Lawson (nate@root.org) of Root Labs. */ * Code snippet without data-dependent branch due to Nate Lawson
while (n--) * (nate@root.org) of Root Labs.
result |= *us1++ ^ *us2++; */
while (n--)
result |= *us1++ ^ *us2++;
return result != 0; return result != 0;
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -10,62 +10,64 @@
uint32_t Uint64ToString(char *buf, uint32_t bufsize, uint64_t value, uint32_t Uint64ToString(char *buf, uint32_t bufsize, uint64_t value,
uint32_t radix, uint32_t zero_pad_width) { uint32_t radix, uint32_t zero_pad_width)
char ibuf[UINT64_TO_STRING_MAX]; {
char *s; char ibuf[UINT64_TO_STRING_MAX];
uint32_t usedsize = 1; char *s;
uint32_t usedsize = 1;
if (!buf) if (!buf)
return 0; return 0;
/* Clear output buffer in case of error */ /* Clear output buffer in case of error */
*buf = '\0'; *buf = '\0';
/* Sanity-check input args */ /* Sanity-check input args */
if (radix < 2 || radix > 36 || zero_pad_width >= UINT64_TO_STRING_MAX) if (radix < 2 || radix > 36 || zero_pad_width >= UINT64_TO_STRING_MAX)
return 0; return 0;
/* Start at end of string and work backwards */ /* Start at end of string and work backwards */
s = ibuf + UINT64_TO_STRING_MAX - 1; s = ibuf + UINT64_TO_STRING_MAX - 1;
*(s) = '\0'; *(s) = '\0';
do { do {
int v = value % radix; int v = value % radix;
value /= radix; value /= radix;
*(--s) = (char)(v < 10 ? v + '0' : v + 'a' - 10); *(--s) = (char)(v < 10 ? v + '0' : v + 'a' - 10);
if (++usedsize > bufsize) if (++usedsize > bufsize)
return 0; /* Result won't fit in buffer */ return 0; /* Result won't fit in buffer */
} while (value); } while (value);
/* Zero-pad if necessary */ /* Zero-pad if necessary */
while (usedsize <= zero_pad_width) { while (usedsize <= zero_pad_width) {
*(--s) = '0'; *(--s) = '0';
if (++usedsize > bufsize) if (++usedsize > bufsize)
return 0; /* Result won't fit in buffer */ return 0; /* Result won't fit in buffer */
} }
/* Now copy the string back to the input buffer. */ /* Now copy the string back to the input buffer. */
Memcpy(buf, s, usedsize); Memcpy(buf, s, usedsize);
/* Don't count the terminating null in the bytes used */ /* Don't count the terminating null in the bytes used */
return usedsize - 1; 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) { if (!dest || !src)
uint32_t used = 0; return 0;
if (!dest || !src) /* Skip past existing string in destination.*/
return 0; while (dest[used] && used < destlen - 1)
used++;
/* Skip past existing string in destination.*/ /* Now copy source */
while (dest[used] && used < destlen - 1) while (*src && used < destlen - 1)
used++; dest[used++] = *src++;
/* Now copy source */
while (*src && used < destlen - 1)
dest[used++] = *src++;
/* Terminate destination and return count of non-null characters */ /* Terminate destination and return count of non-null characters */
dest[used] = 0; dest[used] = 0;
return used; return used;
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -14,99 +14,111 @@
#include "vboot_common.h" #include "vboot_common.h"
#include "vboot_nvstorage.h" #include "vboot_nvstorage.h"
VbError_t VbSelectFirmware(VbCommonParams* cparams, VbError_t VbSelectFirmware(VbCommonParams *cparams,
VbSelectFirmwareParams* fparams) { VbSelectFirmwareParams *fparams)
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; {
VbNvContext vnc; VbSharedDataHeader *shared =
VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven successful */ (VbSharedDataHeader *)cparams->shared_data_blob;
int is_rec = (shared->recovery_reason ? 1 : 0); VbNvContext vnc;
int is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0); VbError_t retval = VBERROR_UNKNOWN; /* Default to error */
uint32_t tpm_status = 0; 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 */ /* Start timer */
shared->timer_vb_select_firmware_enter = VbExGetTimer(); shared->timer_vb_select_firmware_enter = VbExGetTimer();
/* Load NV storage */ /* Load NV storage */
VbExNvStorageRead(vnc.raw); VbExNvStorageRead(vnc.raw);
VbNvSetup(&vnc); VbNvSetup(&vnc);
if (is_rec) { if (is_rec) {
/* Recovery is requested; go straight to recovery without checking the /*
* RW firmware. */ * Recovery is requested; go straight to recovery without
VBDEBUG(("VbSelectFirmware() detected recovery request\n")); * checking the RW firmware.
*/
VBDEBUG(("VbSelectFirmware() detected recovery request\n"));
/* Go directly to recovery mode */ /* Go directly to recovery mode */
fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY; fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY;
} else {
/* Chain to LoadFirmware() */
retval = LoadFirmware(cparams, fparams, &vnc);
} else { /* Exit if we failed to find an acceptable firmware */
/* Chain to LoadFirmware() */ if (VBERROR_SUCCESS != retval)
retval = LoadFirmware(cparams, fparams, &vnc); goto VbSelectFirmware_exit;
/* Exit if we failed to find an acceptable firmware */ /* Translate the selected firmware path */
if (VBERROR_SUCCESS != retval) if (shared->flags & VBSD_LF_USE_RO_NORMAL) {
goto VbSelectFirmware_exit; /* 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;
}
/* Translate the selected firmware path */ /* Update TPM if necessary */
if (shared->flags & VBSD_LF_USE_RO_NORMAL) { if (shared->fw_version_tpm_start < shared->fw_version_tpm) {
/* Request the read-only normal/dev code path */ VBPERFSTART("VB_TPMU");
fparams->selected_firmware = VB_SELECT_FIRMWARE_READONLY; tpm_status =
} else if (0 == shared->firmware_index) RollbackFirmwareWrite(shared->fw_version_tpm);
fparams->selected_firmware = VB_SELECT_FIRMWARE_A; VBPERFEND("VB_TPMU");
else if (0 != tpm_status) {
fparams->selected_firmware = VB_SELECT_FIRMWARE_B; 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;
}
}
/* Update TPM if necessary */ /* Lock firmware versions in TPM */
if (shared->fw_version_tpm_start < shared->fw_version_tpm) { VBPERFSTART("VB_TPML");
VBPERFSTART("VB_TPMU"); tpm_status = RollbackFirmwareLock();
tpm_status = RollbackFirmwareWrite(shared->fw_version_tpm); VBPERFEND("VB_TPML");
VBPERFEND("VB_TPMU"); if (0 != tpm_status) {
if (0 != tpm_status) { VBDEBUG(("Unable to lock firmware version in TPM.\n"));
VBDEBUG(("Unable to write firmware version to TPM.\n")); VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_W_ERROR); VBNV_RECOVERY_RO_TPM_L_ERROR);
retval = VBERROR_TPM_WRITE_FIRMWARE; retval = VBERROR_TPM_LOCK_FIRMWARE;
goto VbSelectFirmware_exit; goto VbSelectFirmware_exit;
} }
} }
/* Lock firmware versions in TPM */ /*
VBPERFSTART("VB_TPML"); * At this point, we have a good idea of how we are going to
tpm_status = RollbackFirmwareLock(); * boot. Update the TPM with this state information.
VBPERFEND("VB_TPML"); */
if (0 != tpm_status) { tpm_status = SetTPMBootModeState(is_dev, is_rec,
VBDEBUG(("Unable to lock firmware version in TPM.\n")); shared->fw_keyblock_flags);
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_L_ERROR); if (0 != tpm_status) {
retval = VBERROR_TPM_LOCK_FIRMWARE; VBDEBUG(("Can't update the TPM with boot mode information.\n"));
goto VbSelectFirmware_exit; if (!is_rec) {
} VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
} VBNV_RECOVERY_RO_TPM_U_ERROR);
retval = VBERROR_TPM_SET_BOOT_MODE_STATE;
goto VbSelectFirmware_exit;
}
}
/* At this point, we have a good idea of how we are going to /* Success! */
* boot. Update the TPM with this state information. */ retval = VBERROR_SUCCESS;
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! */ VbSelectFirmware_exit:
retval = VBERROR_SUCCESS;
VbSelectFirmware_exit: /* Save NV storage */
VbNvTeardown(&vnc);
if (vnc.raw_changed)
VbExNvStorageWrite(vnc.raw);
/* Save NV storage */ /* Stop timer */
VbNvTeardown(&vnc); shared->timer_vb_select_firmware_exit = VbExGetTimer();
if (vnc.raw_changed)
VbExNvStorageWrite(vnc.raw);
/* Stop timer */ /* Should always have a known error code */
shared->timer_vb_select_firmware_exit = VbExGetTimer(); VbAssert(VBERROR_UNKNOWN != retval);
/* Should always have a known error code */ return retval;
VbAssert(VBERROR_UNKNOWN != retval);
return retval;
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -13,254 +13,303 @@
#include "vboot_common.h" #include "vboot_common.h"
#include "vboot_nvstorage.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;
VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { VBDEBUG(("VbInit() input flags 0x%x\n", iparams->flags));
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;
/* Initialize output flags */ /* Set up NV storage */
iparams->out_flags = 0; VbExNvStorageRead(vnc.raw);
VbNvSetup(&vnc);
/* Set up NV storage */ /* Initialize shared data structure */
VbExNvStorageRead(vnc.raw); if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) {
VbNvSetup(&vnc); VBDEBUG(("Shared data init error\n"));
return VBERROR_INIT_SHARED_DATA;
}
/* Initialize shared data structure */ shared->timer_vb_init_enter = VbExGetTimer();
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;
/* Copy some boot switch flags */ is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0);
/* 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 */
}
/* Check if the OS is requesting a debug S3 reset */ /*
VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot); * Clear the request even if this is a normal boot, since we
if (s3_debug_boot) { * don't want the NEXT S3 resume to be a debug reset unless the
if (is_s3_resume) { * OS asserts the request again.
VBDEBUG(("VbInit() requesting S3 debug boot\n")); */
iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT; VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0);
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 * If this isn't a S3 resume, read the current recovery request, then
* asserts the request again. */ * clear it so we don't get stuck in recovery mode.
VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0); */
} 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 this isn't a S3 resume, read the current recovery request, then clear /*
* it so we don't get stuck in recovery mode. */ * If the previous boot failed in the firmware somewhere outside of
if (!is_s3_resume) { * verified boot, and recovery is not requested for our own reasons,
VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery); * request recovery mode. This gives the calling firmware a way to
VBDEBUG(("VbInit sees recovery request = %d\n", recovery)); * request recovery if it finds something terribly wrong.
if (VBNV_RECOVERY_NOT_REQUESTED != recovery) */
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED); if (VBNV_RECOVERY_NOT_REQUESTED == recovery &&
} iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) {
recovery = VBNV_RECOVERY_RO_FIRMWARE;
}
/* If the previous boot failed in the firmware somewhere outside of verified /*
* boot, and recovery is not requested for our own reasons, request recovery * If recovery button is pressed, override recovery reason. Note that
* mode. This gives the calling firmware a way to request recovery if it * we do this in the S3 resume path also.
* finds something terribly wrong. */ */
if (VBNV_RECOVERY_NOT_REQUESTED == recovery && if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED)
iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) { recovery = VBNV_RECOVERY_RO_MANUAL;
recovery = VBNV_RECOVERY_RO_FIRMWARE;
}
/* If recovery button is pressed, override recovery reason. Note that we /*
* do this in the S3 resume path also. */ * Copy current recovery reason to shared data. If we fail later on, it
if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) * won't matter, since we'll just reboot.
recovery = VBNV_RECOVERY_RO_MANUAL; */
shared->recovery_reason = (uint8_t)recovery;
VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery));
/* Copy current recovery reason to shared data. If we fail later on, it /*
* won't matter, since we'll just reboot. */ * If this is a S3 resume, resume the TPM.
shared->recovery_reason = (uint8_t)recovery; *
VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery)); * 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;
}
/* 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? */ * We always believe the HW dev-switch, since there's one
if (is_s3_resume) { * attached to servo which may be active even on systems
if (TPM_SUCCESS != RollbackS3Resume()) { * without a physical switch. The EC may also implement a fake
/* If we can't resume, just do a full reboot. No need to go to recovery * dev-switch for testing.
* mode here, since if the TPM is really broken we'll catch it on the */
* next boot. */ if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON)
retval = VBERROR_TPM_S3_RESUME; is_hw_dev = 1;
}
} 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 */ /* We may be asked to clear the virtual dev-switch at boot. */
if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request);
is_hw_dev = 1;
/* Check if we've been explicitly asked to clear the TPM owner */ /* Allow GBB flag to override dev switch */
VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, &clear_tpm_owner_request); if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON)
is_hw_dev = 1;
VBPERFSTART("VB_TPMI"); /* Have we been explicitly asked to clear the TPM owner? */
/* Initialize the TPM. If the developer mode state has changed since the VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST,
* last boot, we need to clear TPM ownership. If the TPM space is &clear_tpm_owner_request);
* 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) { VBPERFSTART("VB_TPMI");
/* TPM wants to reboot into the same mode we're in now */ /*
VBDEBUG(("TPM requires a reboot.\n")); * Initialize the TPM. If the developer mode state has changed
if (!recovery) { * since the last boot, we need to clear TPM ownership. If the
/* Not recovery mode. Just reboot (not into recovery). */ * TPM space is initialized by this call, the virtual
retval = VBERROR_TPM_REBOOT_REQUIRED; * dev-switch will be disabled by default)
goto VbInit_exit; */
} else if (VBNV_RECOVERY_RO_TPM_REBOOT != shared->recovery_reason) { tpm_status = RollbackFirmwareSetup(recovery, is_hw_dev,
/* In recovery mode now, and we haven't requested a TPM reboot yet, disable_dev_request,
* so request one. */ clear_tpm_owner_request,
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_REBOOT); /* two outputs on success */
retval = VBERROR_TPM_REBOOT_REQUIRED; &is_virt_dev, &tpm_version);
goto VbInit_exit; VBPERFEND("VB_TPMI");
}
}
if (!recovery) { if (0 != tpm_status) {
VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_RO_TPM_S_ERROR); VBDEBUG(("Unable to setup TPM and read "
VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE, tpm_status); "firmware version (0x%x)\n", tpm_status));
retval = VBERROR_TPM_FIRMWARE_SETUP;
goto VbInit_exit;
}
}
/* TPM setup succeeded. What did we learn? */ if (TPM_E_MUST_REBOOT == tpm_status) {
shared->fw_version_tpm_start = tpm_version; /*
shared->fw_version_tpm = tpm_version; * TPM wants to reboot into the same mode we're
if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) { * in now
is_dev = 1; */
shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; VBDEBUG(("TPM requires a reboot.\n"));
} if (!recovery) {
if (disable_dev_request && !is_virt_dev) /*
VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0); * Not recovery mode. Just reboot (not
if (clear_tpm_owner_request) { * into recovery).
VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0); */
VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1); 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;
}
}
/* Allow BIOS to load arbitrary option ROMs? */ if (!recovery) {
if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS) VbNvSet(&vnc, VBNV_RECOVERY_REQUEST,
iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM; VBNV_RECOVERY_RO_TPM_S_ERROR);
VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE,
tpm_status);
retval = VBERROR_TPM_FIRMWARE_SETUP;
goto VbInit_exit;
}
}
/* The factory may need to boot custom OSes whenever the dev-switch is on */ /* TPM setup succeeded. What did we learn? */
if (is_dev && (gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS)) shared->fw_version_tpm_start = tpm_version;
iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS; 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);
}
}
/* Set output flags */ /* Allow BIOS to load arbitrary option ROMs? */
if (VBNV_RECOVERY_NOT_REQUESTED != recovery) { if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS)
/* Requesting recovery mode */ iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM;
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 /* Factory may need to boot custom OSes when the dev-switch is on */
* scary boot screen. If we don't have it, we need to request it and if (is_dev && (gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS))
* reboot so it can be loaded. */ iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS;
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 { /* Set output flags */
/* Normal mode, so disable dev_boot_* flags. This ensures they will be if (VBNV_RECOVERY_NOT_REQUESTED != recovery) {
* initially disabled if the user later transitions back into developer /* Requesting recovery mode */
* mode. */ iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY |
VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0); VB_INIT_OUT_CLEAR_RAM |
VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0); VB_INIT_OUT_ENABLE_DISPLAY |
VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0); 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;
/* 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. */ * Dev-mode needs the VGA option ROM to be loaded so it can
if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) && * display the scary boot screen. If we don't have it, we need
(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) { * to request it and reboot so it can be loaded.
VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0); */
retval = VBERROR_VGA_OPROM_MISMATCH; if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) &&
VBDEBUG(("VbInit() has oprom, doesn't need it\n")); !(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"));
}
VbInit_exit: } 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);
/* Tear down NV storage */ /*
VbNvTeardown(&vnc); * If we don't need the VGA option ROM but got it anyway, stop
if (vnc.raw_changed) * asking for it and reboot in case there's some vulnerability
VbExNvStorageWrite(vnc.raw); * 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"));
}
}
VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags)); VbInit_exit:
shared->timer_vb_init_exit = VbExGetTimer(); /* Tear down NV storage */
VbNvTeardown(&vnc);
if (vnc.raw_changed)
VbExNvStorageWrite(vnc.raw);
VBDEBUG(("VbInit() returning 0x%x\n", retval)); VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags));
return retval;
shared->timer_vb_init_exit = VbExGetTimer();
VBDEBUG(("VbInit() returning 0x%x\n", retval));
return retval;
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -18,8 +18,10 @@
#define UINT_MAX 4294967295U /* 0xffffffff */ #define UINT_MAX 4294967295U /* 0xffffffff */
#endif #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_TIME 1000
#define REQUIRED_NOISE_WITHIN 22000 #define REQUIRED_NOISE_WITHIN 22000
#define REQUIRED_TOTAL_DELAY 30000 #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? */ /* No need to dynamically allocate this, is there? */
static VbAudioContext au; static VbAudioContext au;
/* Convert from msecs to VbExGetTimer() units. */ /* Convert from msecs to VbExGetTimer() units. */
static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */ static uint64_t ticks_per_msec = 0; /* Initialized by VbAudioOpen() */
static uint64_t VbMsecToTicks(uint16_t msec) { static uint64_t VbMsecToTicks(uint16_t msec) {
return ticks_per_msec * 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 * Find and return a valid set of note events.
* 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'll use the user's struct if possible, but we will still enforce the
* we may need one extra note at the end to pad out the user's notes to a full * 30-second timeout and require at least a second of audible noise within that
* 30 seconds. The caller should free it when finished. * 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) { static void VbGetDevMusicNotes(VbAudioContext *audio, int use_short)
VbDevMusicNote *notebuf = 0; {
VbDevMusicNote *builtin = 0; VbDevMusicNote *notebuf = 0;
VbDevMusic *hdr = CUSTOM_MUSIC_NOTES; VbDevMusicNote *builtin = 0;
uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */ VbDevMusic *hdr = CUSTOM_MUSIC_NOTES;
uint32_t maxnotes, mysum, mylen, i; uint32_t maxsize = CUSTOM_MUSIC_MAXSIZE; /* always <= flash size (8M) */
uint32_t this_msecs, on_msecs, total_msecs; uint32_t maxnotes, mysum, mylen, i;
uint32_t count; uint32_t this_msecs, on_msecs, total_msecs;
uint32_t count;
VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, maxsize is %d\n", VBDEBUG(("VbGetDevMusicNotes: use_short is %d, hdr is %lx, "
use_short, hdr, maxsize)); "maxsize is %d\n", use_short, hdr, maxsize));
if (use_short) { if (use_short) {
builtin = short_notes_; builtin = short_notes_;
count = short_count_; count = short_count_;
goto nope; goto nope;
} }
builtin = default_notes_; builtin = default_notes_;
count = default_count_; count = default_count_;
/* If we can't beep in the background, don't allow customization. */ /* If we can't beep in the background, don't allow customization. */
if (!audio->background_beep) if (!audio->background_beep)
goto nope; goto nope;
if (!hdr || maxsize < sizeof(VbDevMusic)) if (!hdr || maxsize < sizeof(VbDevMusic))
goto nope; goto nope;
if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) { if (0 != Memcmp(hdr->sig, "$SND", sizeof(hdr->sig))) {
VBDEBUG(("VbGetDevMusicNotes: bad sig\n")); VBDEBUG(("VbGetDevMusicNotes: bad sig\n"));
goto nope; 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. * 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) { maxnotes = 1 + (maxsize - sizeof(VbDevMusic)) / sizeof(VbDevMusicNote);
VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n", if (hdr->count == 0 || hdr->count > maxnotes) {
hdr->count, maxnotes)); VBDEBUG(("VbGetDevMusicNotes: count=%d maxnotes=%d\n",
goto nope; 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. * 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
if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) || * anyway.
(sizeof(hdr->count) > UINT_MAX - hdr->count * sizeof(VbDevMusicNote))) { */
VBDEBUG(("VbGetDevMusicNotes: count=%d, just isn't right\n")); if ((sizeof(VbDevMusicNote) > UINT_MAX / hdr->count) ||
goto nope; (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 */ /* Now we know this won't overflow */
mylen = (uint32_t)(sizeof(hdr->count) + hdr->count * sizeof(VbDevMusicNote)); mylen = (uint32_t)(sizeof(hdr->count) +
mysum = Crc32(&(hdr->count), mylen); hdr->count * sizeof(VbDevMusicNote));
mysum = Crc32(&(hdr->count), mylen);
if (mysum != hdr->checksum) { if (mysum != hdr->checksum) {
VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n", VBDEBUG(("VbGetDevMusicNotes: mysum=%08x, want=%08x\n",
mysum, hdr->checksum)); mysum, hdr->checksum));
goto nope; goto nope;
} }
VBDEBUG(("VbGetDevMusicNotes: custom notes struct found at %lx\n", hdr)); 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. * Measure the audible sound up to the first 22 seconds, being careful
* The product should fit in 64 bits. * 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; total_msecs = 0;
for (i=0; i < hdr->count; i++) { on_msecs = 0;
this_msecs = hdr->notes[i].msec ; for (i=0; i < hdr->count; i++) {
if (this_msecs) { this_msecs = hdr->notes[i].msec ;
total_msecs += this_msecs; if (this_msecs) {
if (total_msecs <= REQUIRED_NOISE_WITHIN && total_msecs += this_msecs;
hdr->notes[i].frequency >= 100 && hdr->notes[i].frequency <= 2000) if (total_msecs <= REQUIRED_NOISE_WITHIN &&
on_msecs += this_msecs; 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 */ /* We require at least one second of noise in the first 22 seconds */
VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n", VBDEBUG(("VbGetDevMusicNotes: with %ld msecs of sound to begin\n",
on_msecs)); on_msecs));
if (on_msecs < REQUIRED_NOISE_TIME) { if (on_msecs < REQUIRED_NOISE_TIME)
goto nope; 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. * 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) { VBDEBUG(("VbGetDevMusicNotes: lasting %ld msecs\n", total_msecs));
goto nope; if (total_msecs > MAX_CUSTOM_DELAY) {
} goto nope;
}
/* One more check, just to be paranoid. */ /* One more check, just to be paranoid. */
if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) { if (hdr->count > (UINT_MAX / sizeof(VbDevMusicNote) - 1)) {
VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n")); VBDEBUG(("VbGetDevMusicNotes: they're all out to get me!\n"));
goto nope; goto nope;
} }
/* Okay, it looks good. Allocate the space (plus one) and copy it over. */ /* Looks good. Allocate the space (plus one) and copy it over. */
notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote)); notebuf = VbExMalloc((hdr->count + 1) * sizeof(VbDevMusicNote));
Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote)); Memcpy(notebuf, hdr->notes, hdr->count * sizeof(VbDevMusicNote));
count = hdr->count; count = hdr->count;
/* We also require at least 30 seconds of delay. */ /* We also require at least 30 seconds of delay. */
if (total_msecs < REQUIRED_TOTAL_DELAY) { if (total_msecs < REQUIRED_TOTAL_DELAY) {
/* If the total time is less than 30 seconds, the needed difference will /*
* fit in 16 bits. * 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; this_msecs = (REQUIRED_TOTAL_DELAY - total_msecs) & 0xffff;
notebuf[hdr->count].frequency = 0; notebuf[hdr->count].msec = this_msecs;
count++; notebuf[hdr->count].frequency = 0;
VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n", count++;
this_msecs)); VBDEBUG(("VbGetDevMusicNotes: adding %ld msecs of silence\n",
} this_msecs));
}
/* done */ /* Done */
audio->music_notes = notebuf; audio->music_notes = notebuf;
audio->note_count = count; audio->note_count = count;
audio->free_notes_when_done = 1; audio->free_notes_when_done = 1;
return; return;
nope: nope:
/* No custom notes, use the default. The count is already set. */ /* No custom notes, use the default. The count is already set. */
VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count)); VBDEBUG(("VbGetDevMusicNotes: using %d default notes\n", count));
audio->music_notes = builtin; audio->music_notes = builtin;
audio->note_count = count; audio->note_count = count;
audio->free_notes_when_done = 0; audio->free_notes_when_done = 0;
} }
/* Initialization function. Returns context for processing dev-mode delay */ /**
VbAudioContext* VbAudioOpen(VbCommonParams* cparams) { * Initialization function. Returns context for processing dev-mode delay.
GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data; */
VbAudioContext* audio = &au; VbAudioContext *VbAudioOpen(VbCommonParams *cparams)
int use_short = 0; {
uint64_t a,b; 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 */ /* Note: may need to allocate things here in future */
/* Calibrate audio delay */ /* Calibrate audio delay */
a = VbExGetTimer(); a = VbExGetTimer();
VbExSleepMs(10); VbExSleepMs(10);
b = VbExGetTimer(); b = VbExGetTimer();
ticks_per_msec = (b - a) / 10ULL ; ticks_per_msec = (b - a) / 10ULL ;
VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec)); VBDEBUG(("VbAudioOpen() - ticks_per_msec is %llu\n", ticks_per_msec));
/* Initialize */ /* Initialize */
Memset(audio, 0, sizeof(*audio)); Memset(audio, 0, sizeof(*audio));
audio->background_beep = 1; audio->background_beep = 1;
audio->play_until = b; /* "zero" starts now */ audio->play_until = b; /* "zero" starts now */
/* See if we have full background sound capability or not. */ /* See if we have full background sound capability or not. */
if (VBERROR_SUCCESS != VbExBeep(0,0)) { if (VBERROR_SUCCESS != VbExBeep(0,0)) {
VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n")); VBDEBUG(("VbAudioOpen() - VbExBeep() is limited\n"));
audio->background_beep = 0; audio->background_beep = 0;
} }
/* Prepare to generate audio/delay event. Use a short developer screen delay /*
* if indicated by GBB flags. * 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)) { if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1
VBDEBUG(("VbAudioOpen() - using short developer screen delay\n")); && (gbb->flags & GBB_FLAG_DEV_SCREEN_SHORT_DELAY)) {
use_short = 1; VBDEBUG(("VbAudioOpen() - using short dev screen delay\n"));
} use_short = 1;
}
VbGetDevMusicNotes(audio, use_short); VbGetDevMusicNotes(audio, use_short);
VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count)); VBDEBUG(("VbAudioOpen() - note count %d\n", audio->note_count));
return audio; return audio;
} }
/* Caller should loop without extra delay until this returns false */ /**
int VbAudioLooping(VbAudioContext* audio) { * Caller should loop without extra delay until this returns false.
uint64_t now; */
uint16_t freq = audio->current_frequency; int VbAudioLooping(VbAudioContext *audio)
uint16_t msec = 0; {
int looping = 1; uint64_t now;
uint16_t freq = audio->current_frequency;
uint16_t msec = 0;
int looping = 1;
#if defined(CONFIG_SANDBOX) #if defined(CONFIG_SANDBOX)
return 0; return 0;
#endif #endif
now = VbExGetTimer(); now = VbExGetTimer();
while (audio->next_note < audio->note_count && now >= audio->play_until) { while (audio->next_note < audio->note_count &&
freq = audio->music_notes[audio->next_note].frequency; now >= audio->play_until) {
msec = audio->music_notes[audio->next_note].msec; freq = audio->music_notes[audio->next_note].frequency;
audio->play_until += VbMsecToTicks(msec); msec = audio->music_notes[audio->next_note].msec;
audio->next_note++; audio->play_until += VbMsecToTicks(msec);
} audio->next_note++;
}
if (now >= audio->play_until) { if (now >= audio->play_until) {
looping = 0; looping = 0;
freq = 0; freq = 0;
} }
// Do action here. /* Do action here. */
if (audio->background_beep) { if (audio->background_beep) {
if (audio->current_frequency != freq) { if (audio->current_frequency != freq) {
VbExBeep(0, freq); VbExBeep(0, freq);
audio->current_frequency = freq; audio->current_frequency = freq;
} }
} else if (freq && msec) { } else if (freq && msec) {
VbExBeep(msec, freq); VbExBeep(msec, freq);
now = VbExGetTimer(); now = VbExGetTimer();
} }
audio->last_time = now; audio->last_time = now;
return looping; return looping;
} }
/* Caller should call this prior to booting */ /**
void VbAudioClose(VbAudioContext* audio) { * Caller should call this prior to booting.
VbExBeep(0,0); */
if (audio->free_notes_when_done) void VbAudioClose(VbAudioContext *audio)
VbExFree(audio->music_notes); {
VbExBeep(0,0);
if (audio->free_notes_when_done)
VbExFree(audio->music_notes);
} }

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -13,311 +13,350 @@
#include "vboot_common.h" #include "vboot_common.h"
#include "vboot_nvstorage.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 * Static variables for UpdateFirmwareBodyHash(). It's less than optimal to
* caller is deep inside a different firmware stack and doesn't have a * have static variables in a library, but in UEFI the caller is deep inside a
* good way to pass the params struct back to us. */ * different firmware stack and doesn't have a good way to pass the params
* struct back to us.
*/
typedef struct VbLoadFirmwareInternal { typedef struct VbLoadFirmwareInternal {
DigestContext body_digest_context; DigestContext body_digest_context;
uint32_t body_size_accum; uint32_t body_size_accum;
} VbLoadFirmwareInternal; } VbLoadFirmwareInternal;
void VbUpdateFirmwareBodyHash(VbCommonParams *cparams, uint8_t *data,
uint32_t size)
{
VbLoadFirmwareInternal *lfi =
(VbLoadFirmwareInternal*)cparams->vboot_context;
void VbUpdateFirmwareBodyHash(VbCommonParams* cparams, DigestUpdate(&lfi->body_digest_context, data, size);
uint8_t* data, uint32_t size) { lfi->body_size_accum += size;
VbLoadFirmwareInternal* lfi =
(VbLoadFirmwareInternal*)cparams->vboot_context;
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;
int LoadFirmware(VbCommonParams* cparams, VbSelectFirmwareParams* fparams, uint32_t try_b_count;
VbNvContext* vnc) { uint32_t lowest_version = 0xFFFFFFFF;
VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; int good_index = -1;
GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data; int is_dev;
VbPublicKey* root_key; int index;
VbLoadFirmwareInternal* lfi; int i;
uint32_t try_b_count; int retval = VBERROR_UNKNOWN;
uint32_t lowest_version = 0xFFFFFFFF; int recovery = VBNV_RECOVERY_RO_UNSPECIFIED;
int good_index = -1;
int is_dev;
int index;
int i;
int retval = VBERROR_UNKNOWN; /* Clear output params in case we fail */
int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; shared->firmware_index = 0xFF;
/* Clear output params in case we fail */ VBDEBUG(("LoadFirmware started...\n"));
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);
/* Must have a root key from the GBB */ /* Parse flags */
if (!gbb) { is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0);
VBDEBUG(("No GBB\n")); if (is_dev)
retval = VBERROR_INVALID_GBB; shared->flags |= VBSD_LF_DEV_SWITCH_ON;
goto LoadFirmwareExit;
}
root_key = (VbPublicKey*)((uint8_t*)gbb + gbb->rootkey_offset);
/* Parse flags */ /* Read try-b count and decrement if necessary */
is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0); VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count);
if (is_dev) if (0 != try_b_count) {
shared->flags |= VBSD_LF_DEV_SWITCH_ON; VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1);
shared->flags |= VBSD_FWB_TRIED;
}
/* Read try-b count and decrement if necessary */ /* Allocate our internal data */
VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count); lfi = (VbLoadFirmwareInternal *)
if (0 != try_b_count) { VbExMalloc(sizeof(VbLoadFirmwareInternal));
VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1); cparams->vboot_context = lfi;
shared->flags |= VBSD_FWB_TRIED;
}
/* Allocate our internal data */ /* Loop over indices */
lfi = (VbLoadFirmwareInternal*)VbExMalloc(sizeof(VbLoadFirmwareInternal)); for (i = 0; i < 2; i++) {
cparams->vboot_context = (void*)lfi; 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;
/* Loop over indices */ /* If try B count is non-zero try firmware B first */
for (i = 0; i < 2; i++) { index = (try_b_count ? 1 - i : i);
VbKeyBlockHeader* key_block; if (0 == index) {
uint32_t vblock_size; key_block = (VbKeyBlockHeader *)
VbFirmwarePreambleHeader* preamble; fparams->verification_block_A;
RSAPublicKey* data_key; vblock_size = fparams->verification_size_A;
uint64_t key_version; check_result = &shared->check_fw_a_result;
uint32_t combined_version; } else {
uint8_t* body_digest; key_block = (VbKeyBlockHeader *)
uint8_t* check_result; fparams->verification_block_B;
vblock_size = fparams->verification_size_B;
check_result = &shared->check_fw_b_result;
}
/* If try B count is non-zero try firmware B first */ /*
index = (try_b_count ? 1 - i : i); * Check the key block flags against the current boot mode. Do
if (0 == index) { * this before verifying the key block, since flags are faster
key_block = (VbKeyBlockHeader*)fparams->verification_block_A; * to check than the RSA signature.
vblock_size = fparams->verification_size_A; */
check_result = &shared->check_fw_a_result; if (!(key_block->key_block_flags &
} else { (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 :
key_block = (VbKeyBlockHeader*)fparams->verification_block_B; KEY_BLOCK_FLAG_DEVELOPER_0))) {
vblock_size = fparams->verification_size_B; VBDEBUG(("Developer flag mismatch.\n"));
check_result = &shared->check_fw_b_result; *check_result = VBSD_LF_CHECK_DEV_MISMATCH;
} continue;
}
/* Check the key block flags against the current boot mode. Do this /* RW firmware never runs in recovery mode. */
* before verifying the key block, since flags are faster to check than if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)) {
* the RSA signature. */ VBDEBUG(("Recovery flag mismatch.\n"));
if (!(key_block->key_block_flags & *check_result = VBSD_LF_CHECK_REC_MISMATCH;
(is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 : continue;
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 */ /* Verify the key block */
VBPERFSTART("VB_VKB"); VBPERFSTART("VB_VKB");
if ((0 != KeyBlockVerify(key_block, vblock_size, root_key, 0))) { if ((0 != KeyBlockVerify(key_block, vblock_size,
VBDEBUG(("Key block verification failed.\n")); root_key, 0))) {
*check_result = VBSD_LF_CHECK_VERIFY_KEYBLOCK; VBDEBUG(("Key block verification failed.\n"));
VBPERFEND("VB_VKB"); *check_result = VBSD_LF_CHECK_VERIFY_KEYBLOCK;
continue; VBPERFEND("VB_VKB");
} continue;
VBPERFEND("VB_VKB"); }
VBPERFEND("VB_VKB");
/* Check for rollback of key version. */ /* Check for rollback of key version. */
key_version = key_block->data_key.key_version; key_version = key_block->data_key.key_version;
if (!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) { if (!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
if (key_version < (shared->fw_version_tpm >> 16)) { if (key_version < (shared->fw_version_tpm >> 16)) {
VBDEBUG(("Key rollback detected.\n")); VBDEBUG(("Key rollback detected.\n"));
*check_result = VBSD_LF_CHECK_KEY_ROLLBACK; *check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
continue; continue;
} }
if (key_version > 0xFFFF) { 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. */ * Key version is stored in 16 bits in the TPM,
VBDEBUG(("Key version > 0xFFFF.\n")); * so key versions greater than 0xFFFF can't be
*check_result = VBSD_LF_CHECK_KEY_ROLLBACK; * stored properly.
continue; */
} VBDEBUG(("Key version > 0xFFFF.\n"));
} *check_result = VBSD_LF_CHECK_KEY_ROLLBACK;
continue;
}
}
/* Get the key for preamble/data verification from the key block. */ /* Get key for preamble/data verification from the key block. */
data_key = PublicKeyToRSA(&key_block->data_key); data_key = PublicKeyToRSA(&key_block->data_key);
if (!data_key) { if (!data_key) {
VBDEBUG(("Unable to parse data key.\n")); VBDEBUG(("Unable to parse data key.\n"));
*check_result = VBSD_LF_CHECK_DATA_KEY_PARSE; *check_result = VBSD_LF_CHECK_DATA_KEY_PARSE;
continue; continue;
} }
/* Verify the preamble, which follows the key block. */ /* Verify the preamble, which follows the key block. */
VBPERFSTART("VB_VPB"); VBPERFSTART("VB_VPB");
preamble = (VbFirmwarePreambleHeader*)((uint8_t*)key_block + preamble = (VbFirmwarePreambleHeader *)
key_block->key_block_size); ((uint8_t *)key_block + key_block->key_block_size);
if ((0 != VerifyFirmwarePreamble(preamble, if ((0 != VerifyFirmwarePreamble(
vblock_size - key_block->key_block_size, preamble,
data_key))) { vblock_size - key_block->key_block_size,
VBDEBUG(("Preamble verfication failed.\n")); data_key))) {
*check_result = VBSD_LF_CHECK_VERIFY_PREAMBLE; VBDEBUG(("Preamble verfication failed.\n"));
RSAPublicKeyFree(data_key); *check_result = VBSD_LF_CHECK_VERIFY_PREAMBLE;
VBPERFEND("VB_VPB"); RSAPublicKeyFree(data_key);
continue; VBPERFEND("VB_VPB");
} continue;
VBPERFEND("VB_VPB"); }
VBPERFEND("VB_VPB");
/* Check for rollback of firmware version. */ /* Check for rollback of firmware version. */
combined_version = (uint32_t)((key_version << 16) | combined_version = (uint32_t)((key_version << 16) |
(preamble->firmware_version & 0xFFFF)); (preamble->firmware_version & 0xFFFF));
if (combined_version < shared->fw_version_tpm && if (combined_version < shared->fw_version_tpm &&
!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) { !(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) {
VBDEBUG(("Firmware version rollback detected.\n")); VBDEBUG(("Firmware version rollback detected.\n"));
*check_result = VBSD_LF_CHECK_FW_ROLLBACK; *check_result = VBSD_LF_CHECK_FW_ROLLBACK;
RSAPublicKeyFree(data_key); RSAPublicKeyFree(data_key);
continue; continue;
} }
/* Header for this firmware is valid */ /* Header for this firmware is valid */
*check_result = VBSD_LF_CHECK_HEADER_VALID; *check_result = VBSD_LF_CHECK_HEADER_VALID;
/* Check for lowest key version from a valid header. */ /* Check for lowest key version from a valid header. */
if (lowest_version > combined_version) if (lowest_version > combined_version)
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 * If we already have good firmware, no need to read another
* rollback. */ * one; we only needed to look at the versions to check for
if (-1 != good_index) { * rollback.
RSAPublicKeyFree(data_key); */
continue; if (-1 != good_index) {
} RSAPublicKeyFree(data_key);
continue;
}
/* Handle preamble flag for using the RO normal/dev code path */ /* Handle preamble flag for using the RO normal/dev code path */
if (VbGetFirmwarePreambleFlags(preamble) & if (VbGetFirmwarePreambleFlags(preamble) &
VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
/* Fail if calling firmware doesn't support RO normal */ /* Fail if calling firmware doesn't support RO normal */
if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) { if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) {
*check_result = VBSD_LF_CHECK_NO_RO_NORMAL; *check_result = VBSD_LF_CHECK_NO_RO_NORMAL;
RSAPublicKeyFree(data_key); RSAPublicKeyFree(data_key);
continue; continue;
} }
/* Indicate that we should use the RO normal code path */ /* Use the RO normal code path */
shared->flags |= VBSD_LF_USE_RO_NORMAL; shared->flags |= VBSD_LF_USE_RO_NORMAL;
} else { } else {
VbError_t rv; VbError_t rv;
/* Read the firmware data */ /* Read the firmware data */
VBPERFSTART("VB_RFD"); VBPERFSTART("VB_RFD");
DigestInit(&lfi->body_digest_context, data_key->algorithm); DigestInit(&lfi->body_digest_context,
lfi->body_size_accum = 0; data_key->algorithm);
rv = VbExHashFirmwareBody(cparams, (index ? VB_SELECT_FIRMWARE_B : lfi->body_size_accum = 0;
VB_SELECT_FIRMWARE_A)); rv = VbExHashFirmwareBody(
if (VBERROR_SUCCESS != rv) { cparams,
VBDEBUG(("VbExHashFirmwareBody() failed for index %d\n", index)); (index ? VB_SELECT_FIRMWARE_B :
*check_result = VBSD_LF_CHECK_GET_FW_BODY; VB_SELECT_FIRMWARE_A));
RSAPublicKeyFree(data_key); if (VBERROR_SUCCESS != rv) {
VBPERFEND("VB_RFD"); VBDEBUG(("VbExHashFirmwareBody() failed for "
continue; "index %d\n", index));
} *check_result = VBSD_LF_CHECK_GET_FW_BODY;
if (lfi->body_size_accum != preamble->body_signature.data_size) { RSAPublicKeyFree(data_key);
VBDEBUG(("Hash updated %d bytes but expected %d\n", VBPERFEND("VB_RFD");
(int)lfi->body_size_accum, continue;
(int)preamble->body_signature.data_size)); }
*check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE; if (lfi->body_size_accum !=
RSAPublicKeyFree(data_key); preamble->body_signature.data_size) {
VBPERFEND("VB_RFD"); VBDEBUG(("Hashed %d bytes but expected %d\n",
continue; (int)lfi->body_size_accum,
} (int)preamble->body_signature.data_size));
VBPERFEND("VB_RFD"); *check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE;
RSAPublicKeyFree(data_key);
VBPERFEND("VB_RFD");
continue;
}
VBPERFEND("VB_RFD");
/* Verify firmware data */ /* Verify firmware data */
VBPERFSTART("VB_VFD"); VBPERFSTART("VB_VFD");
body_digest = DigestFinal(&lfi->body_digest_context); body_digest = DigestFinal(&lfi->body_digest_context);
if (0 != VerifyDigest(body_digest, &preamble->body_signature, if (0 != VerifyDigest(body_digest,
data_key)) { &preamble->body_signature,
VBDEBUG(("Firmware body verification failed.\n")); data_key)) {
*check_result = VBSD_LF_CHECK_VERIFY_BODY; VBDEBUG(("FW body verification failed.\n"));
RSAPublicKeyFree(data_key); *check_result = VBSD_LF_CHECK_VERIFY_BODY;
VbExFree(body_digest); RSAPublicKeyFree(data_key);
VBPERFEND("VB_VFD"); VbExFree(body_digest);
continue; VBPERFEND("VB_VFD");
} continue;
VbExFree(body_digest); }
VBPERFEND("VB_VFD"); VbExFree(body_digest);
} VBPERFEND("VB_VFD");
}
/* Done with the data key, so can free it now */ /* Done with the data key, so can free it now */
RSAPublicKeyFree(data_key); RSAPublicKeyFree(data_key);
/* If we're still here, the firmware is valid. */ /* If we're still here, the firmware is valid. */
VBDEBUG(("Firmware %d is valid.\n", index)); VBDEBUG(("Firmware %d is valid.\n", index));
*check_result = VBSD_LF_CHECK_VALID; *check_result = VBSD_LF_CHECK_VALID;
if (-1 == good_index) { if (-1 == good_index) {
/* Save the key we actually used */ /* Save the key we actually used */
if (0 != VbSharedDataSetKernelKey(shared, &preamble->kernel_subkey)) { if (0 != VbSharedDataSetKernelKey(
VBDEBUG(("Unable to save kernel subkey to shared data.\n")); shared, &preamble->kernel_subkey)) {
continue; /* The firmware signature was good, but the public /*
* key was bigger that the caller can handle. */ * 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. */ * Save the good index, now that we're sure we can
good_index = index; * actually use this firmware. That's the one we'll
shared->firmware_index = (uint8_t)index; * boot.
shared->fw_keyblock_flags = key_block->key_block_flags; */
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. * If the good firmware's key version is the same as
* Otherwise, we'll check all the other headers to see if they * the tpm, then the TPM doesn't need updating; we can
* contain a newer key. */ * stop now. Otherwise, we'll check all the other
if (combined_version == shared->fw_version_tpm) * headers to see if they contain a newer key.
break; */
} if (combined_version == shared->fw_version_tpm)
} break;
}
}
/* Free internal data */ /* Free internal data */
VbExFree(lfi); VbExFree(lfi);
cparams->vboot_context = NULL; cparams->vboot_context = NULL;
/* Handle finding good firmware */ /* Handle finding good firmware */
if (good_index >= 0) { if (good_index >= 0) {
/* Save versions we found */ /* Save versions we found */
shared->fw_version_lowest = lowest_version; shared->fw_version_lowest = lowest_version;
if (lowest_version > shared->fw_version_tpm) if (lowest_version > shared->fw_version_tpm)
shared->fw_version_tpm = lowest_version; shared->fw_version_tpm = lowest_version;
/* Success */ /* Success */
VBDEBUG(("Will boot firmware index %d\n", (int)shared->firmware_index)); VBDEBUG(("Will boot firmware index %d\n",
retval = VBERROR_SUCCESS; (int)shared->firmware_index));
} else { retval = VBERROR_SUCCESS;
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. */ } else {
VBDEBUG(("Alas, no good firmware.\n")); uint8_t a = shared->check_fw_a_result;
recovery = VBNV_RECOVERY_RO_INVALID_RW; uint8_t b = shared->check_fw_b_result;
retval = VBERROR_LOAD_FIRMWARE; uint8_t best_check;
/* If the best check result fits in the range of recovery reasons, provide /* No good firmware, so go to recovery mode. */
* more detail on how far we got in validation. */ VBDEBUG(("Alas, no good firmware.\n"));
best_check = (a > b ? a : b) + VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN; recovery = VBNV_RECOVERY_RO_INVALID_RW;
if (best_check >= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN && retval = VBERROR_LOAD_FIRMWARE;
best_check <= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX)
recovery = best_check;
}
LoadFirmwareExit: /*
/* Store recovery request, if any */ * If the best check result fits in the range of recovery
VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ? * reasons, provide more detail on how far we got in
recovery : VBNV_RECOVERY_NOT_REQUESTED); * 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;
}
return retval; LoadFirmwareExit:
/* Store recovery request, if any */
VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
recovery : VBNV_RECOVERY_NOT_REQUESTED);
return retval;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
*/ */
@@ -11,9 +11,10 @@
#include "vboot_common.h" #include "vboot_common.h"
#include "vboot_nvstorage.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 * Constants for NV storage. We use this rather than structs and bitfields so
* compilers. */ * the data format is consistent across platforms and compilers.
*/
#define HEADER_OFFSET 0 #define HEADER_OFFSET 0
#define HEADER_MASK 0xC0 #define HEADER_MASK 0xC0
#define HEADER_SIGNATURE 0x40 #define HEADER_SIGNATURE 0x40
@@ -43,235 +44,241 @@
#define KERNEL_FIELD_OFFSET 11 #define KERNEL_FIELD_OFFSET 11
#define CRC_OFFSET 15 #define CRC_OFFSET 15
int VbNvSetup(VbNvContext *context)
{
uint8_t *raw = context->raw;
int VbNvSetup(VbNvContext* context) { /* Nothing has changed yet. */
uint8_t* raw = context->raw; context->raw_changed = 0;
context->regenerate_crc = 0;
/* Nothing has changed yet. */ /* Check data for consistency */
context->raw_changed = 0; if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK))
context->regenerate_crc = 0; || (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);
/* Check data for consistency */ /* Regenerate CRC on exit */
if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK)) context->regenerate_crc = 1;
|| (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) { }
/* Data is inconsistent (bad CRC or header), so reset defaults */ return 0;
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;
}
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) { return 0;
if (context->regenerate_crc) {
context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET);
context->regenerate_crc = 0;
context->raw_changed = 1;
}
return 0;
} }
int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest)
{
const uint8_t *raw = context->raw;
int VbNvGet(VbNvContext* context, VbNvParam param, uint32_t* dest) { switch (param) {
const uint8_t* raw = context->raw; case VBNV_FIRMWARE_SETTINGS_RESET:
*dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ?
1 : 0);
return 0;
switch (param) { case VBNV_KERNEL_SETTINGS_RESET:
case VBNV_FIRMWARE_SETTINGS_RESET: *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ?
*dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ? 1 : 0); 1 : 0);
return 0; return 0;
case VBNV_KERNEL_SETTINGS_RESET: case VBNV_DEBUG_RESET_MODE:
*dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ? 1 : 0); *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0);
return 0; return 0;
case VBNV_DEBUG_RESET_MODE: case VBNV_TRY_B_COUNT:
*dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0); *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK;
return 0; return 0;
case VBNV_TRY_B_COUNT: case VBNV_RECOVERY_REQUEST:
*dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK; *dest = raw[RECOVERY_OFFSET];
return 0; return 0;
case VBNV_RECOVERY_REQUEST: case VBNV_RECOVERY_SUBCODE:
*dest = raw[RECOVERY_OFFSET]; *dest = raw[RECOVERY_SUBCODE_OFFSET];
return 0; return 0;
case VBNV_RECOVERY_SUBCODE: case VBNV_LOCALIZATION_INDEX:
*dest = raw[RECOVERY_SUBCODE_OFFSET]; *dest = raw[LOCALIZATION_OFFSET];
return 0; return 0;
case VBNV_LOCALIZATION_INDEX: case VBNV_KERNEL_FIELD:
*dest = raw[LOCALIZATION_OFFSET]; *dest = (raw[KERNEL_FIELD_OFFSET]
return 0; | (raw[KERNEL_FIELD_OFFSET + 1] << 8)
| (raw[KERNEL_FIELD_OFFSET + 2] << 16)
| (raw[KERNEL_FIELD_OFFSET + 3] << 24));
return 0;
case VBNV_KERNEL_FIELD: case VBNV_DEV_BOOT_USB:
*dest = (raw[KERNEL_FIELD_OFFSET] *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0);
| (raw[KERNEL_FIELD_OFFSET + 1] << 8) return 0;
| (raw[KERNEL_FIELD_OFFSET + 2] << 16)
| (raw[KERNEL_FIELD_OFFSET + 3] << 24));
return 0;
case VBNV_DEV_BOOT_USB: case VBNV_DEV_BOOT_LEGACY:
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0); *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0);
return 0; return 0;
case VBNV_DEV_BOOT_LEGACY: case VBNV_DEV_BOOT_SIGNED_ONLY:
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0); *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ?
return 0; 1 : 0);
return 0;
case VBNV_DEV_BOOT_SIGNED_ONLY: case VBNV_DISABLE_DEV_REQUEST:
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ? 1 : 0); *dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0);
return 0; return 0;
case VBNV_DISABLE_DEV_REQUEST: case VBNV_OPROM_NEEDED:
*dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0); *dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0);
return 0; return 0;
case VBNV_OPROM_NEEDED: case VBNV_CLEAR_TPM_OWNER_REQUEST:
*dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0); *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ?
return 0; 1 : 0);
return 0;
case VBNV_CLEAR_TPM_OWNER_REQUEST: case VBNV_CLEAR_TPM_OWNER_DONE:
*dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ? 1 : 0); *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0);
return 0; return 0;
case VBNV_CLEAR_TPM_OWNER_DONE: default:
*dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0); return 1;
return 0; }
default:
return 1;
}
} }
int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
{
uint8_t *raw = context->raw;
uint32_t current;
int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) { /* If not changing the value, don't regenerate the CRC. */
uint8_t* raw = context->raw; if (0 == VbNvGet(context, param, &current) && current == value)
uint32_t current; return 0;
/* If we're not changing the value, we don't need to regenerate the CRC. */ switch (param) {
if (0 == VbNvGet(context, param, &current) && current == value) case VBNV_FIRMWARE_SETTINGS_RESET:
return 0; if (value)
raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET;
else
raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET;
break;
switch (param) { case VBNV_KERNEL_SETTINGS_RESET:
case VBNV_FIRMWARE_SETTINGS_RESET: if (value)
if (value) raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET;
raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET; else
else raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET;
raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET; break;
break;
case VBNV_KERNEL_SETTINGS_RESET: case VBNV_DEBUG_RESET_MODE:
if (value) if (value)
raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET; raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE;
else else
raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET; raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE;
break; break;
case VBNV_DEBUG_RESET_MODE: case VBNV_TRY_B_COUNT:
if (value) /* Clip to valid range. */
raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE; if (value > BOOT_TRY_B_COUNT_MASK)
else value = BOOT_TRY_B_COUNT_MASK;
raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE;
break;
case VBNV_TRY_B_COUNT: raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK;
/* Clip to valid range. */ raw[BOOT_OFFSET] |= (uint8_t)value;
if (value > BOOT_TRY_B_COUNT_MASK) break;
value = BOOT_TRY_B_COUNT_MASK;
raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK; case VBNV_RECOVERY_REQUEST:
raw[BOOT_OFFSET] |= (uint8_t)value; /*
break; * 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_REQUEST: case VBNV_RECOVERY_SUBCODE:
/* Map values outside the valid range to the legacy reason, since we raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value;
* can't determine if we're called from kernel or user mode. */ break;
if (value > 0xFF)
value = VBNV_RECOVERY_LEGACY;
raw[RECOVERY_OFFSET] = (uint8_t)value;
break;
case VBNV_RECOVERY_SUBCODE: case VBNV_LOCALIZATION_INDEX:
raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value; /* Map values outside the valid range to the default index. */
break; if (value > 0xFF)
value = 0;
raw[LOCALIZATION_OFFSET] = (uint8_t)value;
break;
case VBNV_LOCALIZATION_INDEX: case VBNV_KERNEL_FIELD:
/* Map values outside the valid range to the default index. */ raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value);
if (value > 0xFF) raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8);
value = 0; raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16);
raw[LOCALIZATION_OFFSET] = (uint8_t)value; raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24);
break; break;
case VBNV_KERNEL_FIELD: case VBNV_DEV_BOOT_USB:
raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value); if (value)
raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8); raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK;
raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16); else
raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24); raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK;
break; break;
case VBNV_DEV_BOOT_USB: case VBNV_DEV_BOOT_LEGACY:
if (value) if (value)
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK; raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK;
else else
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK; raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK;
break; break;
case VBNV_DEV_BOOT_LEGACY: case VBNV_DEV_BOOT_SIGNED_ONLY:
if (value) if (value)
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK; raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK;
else else
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK; raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK;
break; break;
case VBNV_DEV_BOOT_SIGNED_ONLY: case VBNV_DISABLE_DEV_REQUEST:
if (value) if (value)
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK; raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST;
else else
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK; raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST;
break; break;
case VBNV_DISABLE_DEV_REQUEST: case VBNV_OPROM_NEEDED:
if (value) if (value)
raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST; raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED;
else else
raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST; raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED;
break; break;
case VBNV_OPROM_NEEDED: case VBNV_CLEAR_TPM_OWNER_REQUEST:
if (value) if (value)
raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED; raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST;
else else
raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED; raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST;
break; break;
case VBNV_CLEAR_TPM_OWNER_REQUEST: case VBNV_CLEAR_TPM_OWNER_DONE:
if (value) if (value)
raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST; raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE;
else else
raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST; raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE;
break; break;
case VBNV_CLEAR_TPM_OWNER_DONE: default:
if (value) return 1;
raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE; }
else
raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE;
break;
default: /* Need to regenerate CRC, since the value changed. */
return 1; context->regenerate_crc = 1;
} return 0;
/* Need to regenerate CRC, since the value changed. */
context->regenerate_crc = 1;
return 0;
} }