mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-29 12:43:55 +00:00
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:
committed by
ChromeBot
parent
49cb0d3471
commit
7993f257af
6
PRESUBMIT.cfg
Normal file
6
PRESUBMIT.cfg
Normal 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
|
||||||
|
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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. */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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, ¤t) && 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, ¤t) && 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;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user