diff options
Diffstat (limited to 'common/cmd_vboot.c')
-rw-r--r-- | common/cmd_vboot.c | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/common/cmd_vboot.c b/common/cmd_vboot.c new file mode 100644 index 00000000000..a99e35549e8 --- /dev/null +++ b/common/cmd_vboot.c @@ -0,0 +1,512 @@ +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <common.h> +#include <command.h> +#include <environment.h> +#include <tlcl.h> + +/* Prints error and returns on failure */ +#define TPM_CHECK(tpm_command) do { \ + uint32_t result; \ + if ((result = (tpm_command)) != TPM_SUCCESS) { \ + printf("TEST FAILED: line %d: " #tpm_command ": 0x%x\n", \ + __LINE__, result); \ + return result; \ + } \ +} while (0) + +#define INDEX0 0xda70 +#define INDEX1 0xda71 +#define INDEX2 0xda72 +#define INDEX3 0xda73 +#define INDEX_INITIALIZED 0xda80 + +static uint32_t TlclStartupIfNeeded(void) { + uint32_t result = TlclStartup(); + return result == TPM_E_INVALID_POSTINIT ? TPM_SUCCESS : result; +} + +/* vboot_reference/tests/tpm_lite tests + * + */ + +static int test_early_extend(void) +{ + uint8_t value_in[20]; + uint8_t value_out[20]; + printf("Testing earlyextend ..."); + TlclLibInit(); + TPM_CHECK(TlclStartup()); + TPM_CHECK(TlclContinueSelfTest()); + TPM_CHECK(TlclExtend(1, value_in, value_out)); + printf("done\n"); + return 0; +} + +static int test_early_nvram(void) +{ + uint32_t x; + printf("Testing earlynvram ..."); + TlclLibInit(); + TPM_CHECK(TlclStartup()); + TPM_CHECK(TlclContinueSelfTest()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclRead(INDEX0, (uint8_t*) &x, sizeof(x))); + printf("done\n"); + return 0; +} + +static int test_early_nvram2(void) +{ + uint32_t x; + printf("Testing earlynvram2 ..."); + TlclLibInit(); + TPM_CHECK(TlclStartup()); + TPM_CHECK(TlclContinueSelfTest()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclWrite(INDEX0, (uint8_t*) &x, sizeof(x))); + printf("done\n"); + return 0; +} + +static int test_enable(void) +{ + uint8_t disable, deactivated; + printf("Testing enable ...\n"); + TlclLibInit(); + TPM_CHECK(TlclStartupIfNeeded()); + TPM_CHECK(TlclSelfTestFull()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclGetFlags(&disable, &deactivated, NULL)); + printf("\tdisable is %d, deactivated is %d\n", disable, deactivated); + TPM_CHECK(TlclSetEnable()); + TPM_CHECK(TlclSetDeactivated(0)); + TPM_CHECK(TlclGetFlags(&disable, &deactivated, NULL)); + printf("\tdisable is %d, deactivated is %d\n", disable, deactivated); + if (disable == 1 || deactivated == 1) { + printf("\tfailed to enable or activate\n"); + } + printf("\tdone\n"); + return 0; +} + +#define assert(XCOND) do { \ + if (!(XCOND)) { \ + printf("\tassert : " #XCOND "\n"); \ + } \ +} while (0) + +#define reboot() do { \ + printf("\trebooting...\n"); \ + reset_cpu(0); \ +} while (0) + +static int test_fast_enable(void) +{ + uint8_t disable, deactivated; + int i; + printf("Testing fastenable ...\n"); + TlclLibInit(); + TPM_CHECK(TlclStartupIfNeeded()); + TPM_CHECK(TlclSelfTestFull()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclGetFlags(&disable, &deactivated, NULL)); + printf("\tdisable is %d, deactivated is %d\n", disable, deactivated); + for (i = 0; i < 2; i++) { + TPM_CHECK(TlclForceClear()); + TPM_CHECK(TlclGetFlags(&disable, &deactivated, NULL)); + printf("\tdisable is %d, deactivated is %d\n", disable, + deactivated); + assert(disable == 1 && deactivated == 1); + TPM_CHECK(TlclSetEnable()); + TPM_CHECK(TlclSetDeactivated(0)); + TPM_CHECK(TlclGetFlags(&disable, &deactivated, NULL)); + printf("\tdisable is %d, deactivated is %d\n", disable, + deactivated); + assert(disable == 0 && deactivated == 0); + } + printf("\tdone\n"); + return 0; +} + +static int test_global_lock(void) +{ + uint32_t zero = 0; + uint32_t result; + uint32_t x; + printf("Testing globallock ...\n"); + TlclLibInit(); + TPM_CHECK(TlclStartupIfNeeded()); + TPM_CHECK(TlclSelfTestFull()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclRead(INDEX0, (uint8_t*) &x, sizeof(x))); + TPM_CHECK(TlclWrite(INDEX0, (uint8_t*) &zero, sizeof(uint32_t))); + TPM_CHECK(TlclRead(INDEX1, (uint8_t*) &x, sizeof(x))); + TPM_CHECK(TlclWrite(INDEX1, (uint8_t*) &zero, sizeof(uint32_t))); + TPM_CHECK(TlclSetGlobalLock()); + // Verifies that write to index0 fails. + x = 1; + result = TlclWrite(INDEX0, (uint8_t*) &x, sizeof(x)); + assert(result == TPM_E_AREA_LOCKED); + TPM_CHECK(TlclRead(INDEX0, (uint8_t*) &x, sizeof(x))); + assert(x == 0); + // Verifies that write to index1 is still possible. + x = 2; + TPM_CHECK(TlclWrite(INDEX1, (uint8_t*) &x, sizeof(x))); + TPM_CHECK(TlclRead(INDEX1, (uint8_t*) &x, sizeof(x))); + assert(x == 2); + // Turns off PP. + TlclLockPhysicalPresence(); + // Verifies that write to index1 fails. + x = 3; + result = TlclWrite(INDEX1, (uint8_t*) &x, sizeof(x)); + assert(result == TPM_E_BAD_PRESENCE); + TPM_CHECK(TlclRead(INDEX1, (uint8_t*) &x, sizeof(x))); + assert(x == 2); + printf("\tdone\n"); + return 0; +} + +static int test_lock(void) +{ + printf("Testing lock ...\n"); + TlclLibInit(); + TlclStartup(); + TlclSelfTestFull(); + TlclAssertPhysicalPresence(); + TlclWriteLock(INDEX0); + printf("\tLocked 0x%x\n", INDEX0); + printf("\tdone\n"); + return 0; +} + +static void initialize_spaces(void) { + uint32_t zero = 0; + uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE; + + printf("\tInitializing spaces\n"); + TlclSetNvLocked(); /* useful only the first time */ + TlclDefineSpace(INDEX0, perm, 4); + TlclWrite(INDEX0, (uint8_t *) &zero, 4); + TlclDefineSpace(INDEX1, perm, 4); + TlclWrite(INDEX1, (uint8_t *) &zero, 4); + TlclDefineSpace(INDEX2, perm, 4); + TlclWrite(INDEX2, (uint8_t *) &zero, 4); + TlclDefineSpace(INDEX3, perm, 4); + TlclWrite(INDEX3, (uint8_t *) &zero, 4); + perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR | + TPM_NV_PER_PPWRITE; + TlclDefineSpace(INDEX_INITIALIZED, perm, 1); +} + + +static void enter_recovery_mode(void) { + printf("entering recovery mode"); + reboot(); +} + + +static int test_readonly(void) +{ + uint8_t c; + uint32_t index_0, index_1, index_2, index_3; + int read_0, read_1, read_2, read_3; + printf("Testing readonly ...\n"); + TlclLibInit(); + TlclStartup(); + TlclSelfTestFull(); + TlclAssertPhysicalPresence(); + /* Checks if initialization has completed by trying to read-lock a space + * that's created at the end of initialization. + */ + if (TlclRead(INDEX_INITIALIZED, &c, 0) == TPM_E_BADINDEX) { + /* The initialization did not complete. + */ + initialize_spaces(); + } + + /* Checks if spaces are OK or messed up. + */ + read_0 = TlclRead(INDEX0, (uint8_t*) &index_0, sizeof(index_0)); + read_1 = TlclRead(INDEX1, (uint8_t*) &index_1, sizeof(index_1)); + read_2 = TlclRead(INDEX2, (uint8_t*) &index_2, sizeof(index_2)); + read_3 = TlclRead(INDEX3, (uint8_t*) &index_3, sizeof(index_3)); + if (read_0 != TPM_SUCCESS || read_1 != TPM_SUCCESS || read_2 != + TPM_SUCCESS || read_3 != TPM_SUCCESS) { + enter_recovery_mode(); + } + + /* Writes space, and locks it. Then attempts to write again. + * I really wish I could use the imperative. + */ + index_0 += 1; + if (TlclWrite(INDEX0, (uint8_t*) &index_0, sizeof(index_0) != + TPM_SUCCESS)) { + error("\tcould not write index 0\n"); + } + TlclWriteLock(INDEX0); + if (TlclWrite(INDEX0, (uint8_t*) &index_0, sizeof(index_0)) == + TPM_SUCCESS) { + error("\tindex 0 is not locked\n"); + } + + printf("\tdone\n"); + return 0; +} + +static int test_redefine_unowned(void) +{ + uint32_t perm; + uint32_t result; + uint32_t x; + printf("Testing redefine_unowned ..."); + TlclLibInit(); + TPM_CHECK(TlclStartupIfNeeded()); + TPM_CHECK(TlclSelfTestFull()); + TPM_CHECK(TlclAssertPhysicalPresence()); + assert(!TlclIsOwned()); + + /* Ensures spaces exist. */ + TPM_CHECK(TlclRead(INDEX0, (uint8_t*) &x, sizeof(x))); + TPM_CHECK(TlclRead(INDEX1, (uint8_t*) &x, sizeof(x))); + + /* Redefines spaces a couple of times. */ + perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK; + TPM_CHECK(TlclDefineSpace(INDEX0, perm, 2 * sizeof(uint32_t))); + TPM_CHECK(TlclDefineSpace(INDEX0, perm, sizeof(uint32_t))); + perm = TPM_NV_PER_PPWRITE; + TPM_CHECK(TlclDefineSpace(INDEX1, perm, 2 * sizeof(uint32_t))); + TPM_CHECK(TlclDefineSpace(INDEX1, perm, sizeof(uint32_t))); + + // Sets the global lock. + TlclSetGlobalLock(); + + // Verifies that index0 cannot be redefined. + result = TlclDefineSpace(INDEX0, perm, sizeof(uint32_t)); + assert(result == TPM_E_AREA_LOCKED); + + // Checks that index1 can. + TPM_CHECK(TlclDefineSpace(INDEX1, perm, 2 * sizeof(uint32_t))); + TPM_CHECK(TlclDefineSpace(INDEX1, perm, sizeof(uint32_t))); + + // Turns off PP. + TlclLockPhysicalPresence(); + + // Verifies that neither index0 nor index1 can be redefined. + result = TlclDefineSpace(INDEX0, perm, sizeof(uint32_t)); + assert(result == TPM_E_BAD_PRESENCE); + result = TlclDefineSpace(INDEX1, perm, sizeof(uint32_t)); + assert(result == TPM_E_BAD_PRESENCE); + + printf("done\n"); + return 0; +} + +#define PERMPPGL (TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK) +#define PERMPP TPM_NV_PER_PPWRITE + +static int test_space_perm(void) +{ + uint32_t perm; + printf("Testing spaceperm ..."); + TlclLibInit(); + TPM_CHECK(TlclStartupIfNeeded()); + TPM_CHECK(TlclContinueSelfTest()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclGetPermissions(INDEX0, &perm)); + assert((perm & PERMPPGL) == PERMPPGL); + TPM_CHECK(TlclGetPermissions(INDEX1, &perm)); + assert((perm & PERMPP) == PERMPP); + printf("done\n"); + return 0; +} + +static int test_startup(void) +{ + uint32_t result; + printf("Testing startup ...\n"); + TlclLibInit(); + result = TlclStartup(); + if (result != 0) { + printf("\ttpm startup failed with 0x%x\n", result); + } + result = TlclGetFlags(NULL, NULL, NULL); + if (result != 0) { + printf("\ttpm getflags failed with 0x%x\n", result); + } + printf("\texecuting SelfTestFull\n"); + TlclSelfTestFull(); + result = TlclGetFlags(NULL, NULL, NULL); + if (result != 0) { + printf("\ttpm getflags failed with 0x%x\n", result); + } + printf("\tdone\n"); + return 0; +} + +/* Runs [op] and ensures it returns success and doesn't run longer than + * [time_limit] in milliseconds. + */ +#define TTPM_CHECK(op, time_limit) do { \ + ulong start; \ + ulong time_us, time; \ + uint32_t __result; \ + start = get_timer(0); \ + __result = op; \ + if (__result != TPM_SUCCESS) { \ + printf("\t" #op ": error 0x%x\n", __result); \ + return (-1); \ + } \ + time_us = get_timer(start); \ + time = time_us / 1000; \ + printf("\t" #op ": %lu ms\n", time); \ + if (time > (ulong)time_limit) { \ + printf("\t" #op " exceeded " #time_limit " ms\n"); \ + return (-1); \ + } \ +} while (0) + + +static int test_timing(void) +{ + uint32_t x; + uint8_t in[20], out[20]; + printf("Testing timing ..."); + TlclLibInit(); + TTPM_CHECK(TlclStartupIfNeeded(), 50); + TTPM_CHECK(TlclContinueSelfTest(), 100); + TTPM_CHECK(TlclSelfTestFull(), 1000); + TTPM_CHECK(TlclAssertPhysicalPresence(), 100); + TTPM_CHECK(TlclWrite(INDEX0, (uint8_t*) &x, sizeof(x)), 100); + TTPM_CHECK(TlclRead(INDEX0, (uint8_t*) &x, sizeof(x)), 100); + TTPM_CHECK(TlclExtend(0, in, out), 200); + TTPM_CHECK(TlclSetGlobalLock(), 50); + TTPM_CHECK(TlclLockPhysicalPresence(), 100); + printf("done\n"); + return 0; +} + +#define TPM_MAX_NV_WRITES_NOOWNER 64 + +static int test_write_limit(void) +{ + printf("Testing writelimit ...\n"); + int i; + uint32_t result; + TlclLibInit(); + + TPM_CHECK(TlclStartupIfNeeded()); + TPM_CHECK(TlclSelfTestFull()); + TPM_CHECK(TlclAssertPhysicalPresence()); + TPM_CHECK(TlclForceClear()); + TPM_CHECK(TlclSetEnable()); + TPM_CHECK(TlclSetDeactivated(0)); + + for (i = 0; i < TPM_MAX_NV_WRITES_NOOWNER + 2; i++) { + printf("\twriting %d\n", i); + if ((result = TlclWrite(INDEX0, (uint8_t*)&i, sizeof(i))) != + TPM_SUCCESS) { + switch (result) { + case TPM_E_MAXNVWRITES: + assert(i >= TPM_MAX_NV_WRITES_NOOWNER); + default: + error("\tunexpected error code %d (0x%x)\n", + result, result); + } + } + } + + /* Reset write count */ + TPM_CHECK(TlclForceClear()); + TPM_CHECK(TlclSetEnable()); + TPM_CHECK(TlclSetDeactivated(0)); + + /* Try writing again. */ + TPM_CHECK(TlclWrite(INDEX0, (uint8_t*)&i, sizeof(i))); + printf("\tdone\n"); + return 0; +} + +/* u-boot command table (include/command.h) + */ + +#define VOIDTEST(XFUNC) \ + int do_test_##XFUNC(cmd_tbl_t *cmd_tbl, int flag, int argc, \ + char * const argv[]) \ + { \ + return test_##XFUNC(); \ + } \ + + /* above blank line is a part of the macro */ + +#define VOIDENT(XNAME) \ + U_BOOT_CMD_MKENT(XNAME, 0, 1, do_test_##XNAME, "", "") + +VOIDTEST(early_extend) +VOIDTEST(early_nvram) +VOIDTEST(early_nvram2) +VOIDTEST(enable) +VOIDTEST(fast_enable) +VOIDTEST(global_lock) +VOIDTEST(lock) +VOIDTEST(readonly) +VOIDTEST(redefine_unowned) +VOIDTEST(space_perm) +VOIDTEST(startup) +VOIDTEST(timing) +VOIDTEST(write_limit) + +static cmd_tbl_t cmd_cros_tpm_sub[] = { + VOIDENT(early_extend), + VOIDENT(early_nvram), + VOIDENT(early_nvram2), + VOIDENT(enable), + VOIDENT(fast_enable), + VOIDENT(global_lock), + VOIDENT(lock), + VOIDENT(readonly), + VOIDENT(redefine_unowned), + VOIDENT(space_perm), + VOIDENT(startup), + VOIDENT(timing), + VOIDENT(write_limit) +}; + +/* u-boot shell commands + */ +static int do_cros_tpm_test(cmd_tbl_t * cmdtp, int flag, int argc, + char * const argv[]) +{ + cmd_tbl_t *c; + printf("argc = %d, argv = ", argc); + do { + int i = 0; + for (i = 0; i < argc; i++) + printf(" %s", argv[i]); + printf("\n------\n"); + } while(0); + argc--; + argv++; + c = find_cmd_tbl(argv[0], cmd_cros_tpm_sub, + ARRAY_SIZE(cmd_cros_tpm_sub)); + return c ? c->cmd(cmdtp, flag, argc, argv) : cmd_usage(cmdtp); +} + +U_BOOT_CMD(cros_tpm_test, 2, 1, do_cros_tpm_test, "TPM_Lite tests", + "\n\tearly_extend\n" + "\tearly_nvram\n" + "\tearly_nvram2\n" + "\tenable\n" + "\tfast_enable\n" + "\tglobal_lock\n" + "\tlock\n" + "\treadonly\n" + "\tredefine_unowned\n" + "\tspace_perm\n" + "\tstartup\n" + "\ttiming\n" + "\twrite_limit\n"); + |