blob: 5c596501ff613150c372f40a03090f5aba0574af [file] [log] [blame]
/*
* 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 <common.h>
#include <command.h>
#include <tpm.h>
#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 <index> <number of bytes> - read data at location index\n"
"\tw <index> <data> [<data>] - 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);
}