/* * 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. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. */ #include #include #include #define MAX_TRANSACTION_SIZE 100 static u8 tpm_response[MAX_TRANSACTION_SIZE]; static void report_error(const char *msg); /* * The following TPM command definitions were borrowed from the * vboot_reference package. */ const struct s_tpm_nv_read_cmd { u8 buffer[22]; u16 index; u16 length; } tpm_nv_read_cmnd = { { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, }, 10, 18, }; const struct s_tpm_nv_write_cmd { u8 buffer[MAX_TRANSACTION_SIZE]; u16 index; u16 length; u16 data; } tpm_nv_write_cmnd = { { 0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, }, 10, 18, 22, }; /* * paste_u32() * * Insert a 32 bit number in big endian representation at the supplied location. * */ static void paste_u32(u8 *location, u32 value) { u32 be = cpu_to_be32(value); memcpy(location, &be, sizeof(be)); } /* * tpm_read() expects two parameters, internal address of the tpm NVRAM, and * length of data to read. */ static int tpm_read(int argc, char * const argv[]) { u32 addr, size; char *p; struct s_tpm_nv_read_cmd cmd; int rv; if (argc != 2) { report_error("wrong number of parameters\n"); return ~0; } addr = simple_strtoul(argv[0], &p, 0); if (*p) { report_error("bad address value\n"); return ~0; } memcpy(&cmd, &tpm_nv_read_cmnd, sizeof(cmd)); size = simple_strtoul(argv[1], &p, 0); if (*p || (size >= (sizeof(cmd.buffer) - cmd.index))) { report_error("bad size value\n"); return ~0; } paste_u32(cmd.buffer + cmd.index, addr); paste_u32(cmd.buffer + cmd.length, size); size = sizeof(tpm_response); if (!tis_sendrecv(cmd.buffer, sizeof(cmd.buffer), tpm_response, &size)) { int i; for(i = 0; i < size; i++) printf(" %2.2x", tpm_response[i]); printf("\n"); rv = 0; } else { printf("tpm read command failed\n"); rv = ~0; } return rv; } /* * tpm_write() expects a variable number of parameters: the internal address * followed by data to write, byte by byte. * * Returns 0 on success or ~0 on errors (wrong arguments or TPM failure). */ static int tpm_write(int argc, char * const argv[]) { u32 addr, size, datum, total_length; char *p; struct s_tpm_nv_write_cmd cmd; int rv = ~0; if (argc < 2) { report_error("too few paramters\n"); return rv; } addr = simple_strtoul(argv[0], &p, 0); if (*p) { report_error("bad address value\n"); return rv; } memcpy(&cmd, &tpm_nv_write_cmnd, sizeof(cmd)); argc--; if (argc >= (sizeof(cmd.buffer) - cmd.data)) { report_error("too many arguments\n"); return rv; } for (size = 0; size < argc; size++) { datum = simple_strtoul(argv[size + 1], &p, 0); if (*p || (datum > 0xff)) { report_error("bad data value\n"); return rv; } cmd.buffer[cmd.data + size] = (u8)datum; } paste_u32(cmd.buffer + cmd.index, addr); paste_u32(cmd.buffer + cmd.length, size); /* this sets the total TPM command length at the appropriate offset. */ total_length = size + cmd.data; paste_u32(cmd.buffer + 2, total_length); if (!tis_sendrecv(cmd.buffer, total_length, tpm_response, &size)) { int i; for(i = 0; i < size; i++) printf(" %2.2x", tpm_response[i]); printf("\n"); rv = 0; } else { printf("tpm read command failed\n"); } return rv; } static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int rv = 0; /* * Verify that in case it is present, the first argument, it is * exactly one character in size. */ if ((argc > 1) && (argv[1][1] != '\0')) { report_error("bad parameter\n"); return ~0; } if (tis_init()) { printf("tis_init() failed!\n"); return ~0; } if (tis_open()) { printf("tis_open() failed!\n"); return ~0; } if (argc > 2) { switch (argv[1][0]) { case 'r': rv = tpm_read(argc - 2, argv + 2); break; case 'w': rv = tpm_write(argc - 2, argv + 2); break; default: report_error("unknown option\n"); rv = ~0; break; }; } if (tis_close()) { printf("tis_close() failed!\n"); rv = ~0; } return rv; } U_BOOT_CMD(tpm, 10, 1, do_tpm, "tpm debugging commands", "\tr - read data at location index\n" "\tw [] - write data at " "location index\n" ); static void report_error(const char *msg) { if (msg && *msg) printf("%s\n", msg); cmd_usage(&__u_boot_cmd_tpm); }