tpm: disociate TPMv1.x specific and generic code

There are no changes in this commit but a new organization of the code
as follow.

* cmd/ directory:
        > move existing code from cmd/tpm.c in cmd/tpm-common.c
	> move specific code in cmd/tpm-v1.c
	> create a specific header file with generic definitions for
	  commands only called cmd/tpm-user-utils.h

* lib/ directory:
        > move existing code from lib/tpm.c in lib/tpm-common.c
	> move specific code in lib/tpm-v1.c
	> create a specific header file with generic definitions for
	  the library itself called lib/tpm-utils.h

* include/ directory:
        > move existing code from include/tpm.h in include/tpm-common.h
	> move specific code in include/tpm-v1.h

Code designated as 'common' is compiled if TPM are used. Code designated
as 'specific' is compiled only if the right specification has been
selected.

All files include tpm-common.h.
Files in cmd/ include tpm-user-utils.h.
Files in lib/ include tpm-utils.h.
Depending on the specification, files may include either (not both)
tpm-v1.h or tpm-v2.h.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
[trini: Fix a few more cases of tpm.h -> tpm-v1.h, some Kconfig logic]
Signed-off-by: Tom Rini <trini@konsulko.com>
lime2-spi
Miquel Raynal 6 years ago committed by Tom Rini
parent 9f9ce3c369
commit d677bfe2f7
  1. 2
      board/gdsys/a38x/controlcenterdc.c
  2. 2
      board/gdsys/a38x/hre.c
  3. 2
      board/gdsys/a38x/keyprogram.c
  4. 2
      board/gdsys/p1022/controlcenterd-id.c
  5. 3
      cmd/Makefile
  6. 288
      cmd/tpm-common.c
  7. 24
      cmd/tpm-user-utils.h
  8. 304
      cmd/tpm-v1.c
  9. 2
      cmd/tpm_test.c
  10. 3
      drivers/tpm/Kconfig
  11. 4
      drivers/tpm/tpm-uclass.c
  12. 2
      drivers/tpm/tpm_atmel_twi.c
  13. 2
      drivers/tpm/tpm_tis_infineon.c
  14. 2
      drivers/tpm/tpm_tis_lpc.c
  15. 2
      drivers/tpm/tpm_tis_sandbox.c
  16. 2
      drivers/tpm/tpm_tis_st33zp24_i2c.c
  17. 2
      drivers/tpm/tpm_tis_st33zp24_spi.c
  18. 210
      include/tpm-common.h
  19. 214
      include/tpm-v1.h
  20. 3
      lib/Makefile
  21. 188
      lib/tpm-common.c
  22. 95
      lib/tpm-utils.h
  23. 250
      lib/tpm-v1.c

@ -7,7 +7,7 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <miiphy.h> #include <miiphy.h>
#include <tpm.h> #include <tpm-v1.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/arch/cpu.h> #include <asm/arch/cpu.h>
#include <asm-generic/gpio.h> #include <asm-generic/gpio.h>

@ -9,7 +9,7 @@
#include <fs.h> #include <fs.h>
#include <i2c.h> #include <i2c.h>
#include <mmc.h> #include <mmc.h>
#include <tpm.h> #include <tpm-v1.h>
#include <u-boot/sha1.h> #include <u-boot/sha1.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>

@ -5,7 +5,7 @@
*/ */
#include <common.h> #include <common.h>
#include <tpm.h> #include <tpm-v1.h>
#include <malloc.h> #include <malloc.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>

@ -15,7 +15,7 @@
#include <fs.h> #include <fs.h>
#include <i2c.h> #include <i2c.h>
#include <mmc.h> #include <mmc.h>
#include <tpm.h> #include <tpm-v1.h>
#include <u-boot/sha1.h> #include <u-boot/sha1.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>

@ -120,7 +120,8 @@ obj-$(CONFIG_CMD_TERMINAL) += terminal.o
obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TIME) += time.o
obj-$(CONFIG_CMD_TRACE) += trace.o obj-$(CONFIG_CMD_TRACE) += trace.o
obj-$(CONFIG_HUSH_PARSER) += test.o obj-$(CONFIG_HUSH_PARSER) += test.o
obj-$(CONFIG_CMD_TPM_V1) += tpm.o obj-$(CONFIG_CMD_TPM) += tpm-common.o
obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o
obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o
obj-$(CONFIG_CMD_TSI148) += tsi148.o obj-$(CONFIG_CMD_TSI148) += tsi148.o

@ -0,0 +1,288 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013 The Chromium OS Authors.
*/
#include <common.h>
#include <command.h>
#include <dm.h>
#include <asm/unaligned.h>
#include <linux/string.h>
#include <tpm-common.h>
#include "tpm-user-utils.h"
/**
* Print a byte string in hexdecimal format, 16-bytes per line.
*
* @param data byte string to be printed
* @param count number of bytes to be printed
*/
void print_byte_string(u8 *data, size_t count)
{
int i, print_newline = 0;
for (i = 0; i < count; i++) {
printf(" %02x", data[i]);
print_newline = (i % 16 == 15);
if (print_newline)
putc('\n');
}
/* Avoid duplicated newline at the end */
if (!print_newline)
putc('\n');
}
/**
* Convert a text string of hexdecimal values into a byte string.
*
* @param bytes text string of hexdecimal values with no space
* between them
* @param data output buffer for byte string. The caller has to make
* sure it is large enough for storing the output. If
* NULL is passed, a large enough buffer will be allocated,
* and the caller must free it.
* @param count_ptr output variable for the length of byte string
* @return pointer to output buffer
*/
void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr)
{
char byte[3];
size_t count, length;
int i;
if (!bytes)
return NULL;
length = strlen(bytes);
count = length / 2;
if (!data)
data = malloc(count);
if (!data)
return NULL;
byte[2] = '\0';
for (i = 0; i < length; i += 2) {
byte[0] = bytes[i];
byte[1] = bytes[i + 1];
data[i / 2] = (u8)simple_strtoul(byte, NULL, 16);
}
if (count_ptr)
*count_ptr = count;
return data;
}
/**
* report_return_code() - Report any error and return failure or success
*
* @param return_code TPM command return code
* @return value of enum command_ret_t
*/
int report_return_code(int return_code)
{
if (return_code) {
printf("Error: %d\n", return_code);
return CMD_RET_FAILURE;
} else {
return CMD_RET_SUCCESS;
}
}
/**
* Return number of values defined by a type string.
*
* @param type_str type string
* @return number of values of type string
*/
int type_string_get_num_values(const char *type_str)
{
return strlen(type_str);
}
/**
* Return total size of values defined by a type string.
*
* @param type_str type string
* @return total size of values of type string, or 0 if type string
* contains illegal type character.
*/
size_t type_string_get_space_size(const char *type_str)
{
size_t size;
for (size = 0; *type_str; type_str++) {
switch (*type_str) {
case 'b':
size += 1;
break;
case 'w':
size += 2;
break;
case 'd':
size += 4;
break;
default:
return 0;
}
}
return size;
}
/**
* Allocate a buffer large enough to hold values defined by a type
* string. The caller has to free the buffer.
*
* @param type_str type string
* @param count pointer for storing size of buffer
* @return pointer to buffer or NULL on error
*/
void *type_string_alloc(const char *type_str, u32 *count)
{
void *data;
size_t size;
size = type_string_get_space_size(type_str);
if (!size)
return NULL;
data = malloc(size);
if (data)
*count = size;
return data;
}
/**
* Pack values defined by a type string into a buffer. The buffer must have
* large enough space.
*
* @param type_str type string
* @param values text strings of values to be packed
* @param data output buffer of values
* @return 0 on success, non-0 on error
*/
int type_string_pack(const char *type_str, char * const values[],
u8 *data)
{
size_t offset;
u32 value;
for (offset = 0; *type_str; type_str++, values++) {
value = simple_strtoul(values[0], NULL, 0);
switch (*type_str) {
case 'b':
data[offset] = value;
offset += 1;
break;
case 'w':
put_unaligned_be16(value, data + offset);
offset += 2;
break;
case 'd':
put_unaligned_be32(value, data + offset);
offset += 4;
break;
default:
return -1;
}
}
return 0;
}
/**
* Read values defined by a type string from a buffer, and write these values
* to environment variables.
*
* @param type_str type string
* @param data input buffer of values
* @param vars names of environment variables
* @return 0 on success, non-0 on error
*/
int type_string_write_vars(const char *type_str, u8 *data,
char * const vars[])
{
size_t offset;
u32 value;
for (offset = 0; *type_str; type_str++, vars++) {
switch (*type_str) {
case 'b':
value = data[offset];
offset += 1;
break;
case 'w':
value = get_unaligned_be16(data + offset);
offset += 2;
break;
case 'd':
value = get_unaligned_be32(data + offset);
offset += 4;
break;
default:
return -1;
}
if (env_set_ulong(*vars, value))
return -1;
}
return 0;
}
int get_tpm(struct udevice **devp)
{
int rc;
rc = uclass_first_device_err(UCLASS_TPM, devp);
if (rc) {
printf("Could not find TPM (ret=%d)\n", rc);
return CMD_RET_FAILURE;
}
return 0;
}
int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
struct udevice *dev;
char buf[80];
int rc;
rc = get_tpm(&dev);
if (rc)
return rc;
rc = tpm_get_desc(dev, buf, sizeof(buf));
if (rc < 0) {
printf("Couldn't get TPM info (%d)\n", rc);
return CMD_RET_FAILURE;
}
printf("%s\n", buf);
return 0;
}
int do_tpm_init(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
if (argc != 1)
return CMD_RET_USAGE;
return report_return_code(tpm_init());
}
int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
cmd_tbl_t *tpm_commands, *cmd;
unsigned int size;
if (argc < 2)
return CMD_RET_USAGE;
tpm_commands = get_tpm_commands(&size);
cmd = find_cmd_tbl(argv[1], tpm_commands, size);
if (!cmd)
return CMD_RET_USAGE;
return cmd->cmd(cmdtp, flag, argc - 1, argv + 1);
}

@ -0,0 +1,24 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2013 The Chromium OS Authors.
* Coypright (c) 2013 Guntermann & Drunck GmbH
*/
#ifndef __TPM_USER_UTILS_H
#define __TPM_USER_UTILS_H
void print_byte_string(u8 *data, size_t count);
void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr);
int report_return_code(int return_code);
int type_string_get_num_values(const char *type_str);
size_t type_string_get_space_size(const char *type_str);
void *type_string_alloc(const char *type_str, u32 *count);
int type_string_pack(const char *type_str, char * const values[], u8 *data);
int type_string_write_vars(const char *type_str, u8 *data, char * const vars[]);
int get_tpm(struct udevice **devp);
int do_tpm_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
#endif /* __TPM_USER_UTILS_H */

@ -4,238 +4,11 @@
*/ */
#include <common.h> #include <common.h>
#include <command.h>
#include <dm.h>
#include <malloc.h> #include <malloc.h>
#include <tpm.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/string.h> #include <tpm-common.h>
#include <tpm-v1.h>
/* Useful constants */ #include "tpm-user-utils.h"
enum {
DIGEST_LENGTH = 20,
/* max lengths, valid for RSA keys <= 2048 bits */
TPM_PUBKEY_MAX_LENGTH = 288,
};
/**
* Print a byte string in hexdecimal format, 16-bytes per line.
*
* @param data byte string to be printed
* @param count number of bytes to be printed
*/
static void print_byte_string(u8 *data, size_t count)
{
int i, print_newline = 0;
for (i = 0; i < count; i++) {
printf(" %02x", data[i]);
print_newline = (i % 16 == 15);
if (print_newline)
putc('\n');
}
/* Avoid duplicated newline at the end */
if (!print_newline)
putc('\n');
}
/**
* Convert a text string of hexdecimal values into a byte string.
*
* @param bytes text string of hexdecimal values with no space
* between them
* @param data output buffer for byte string. The caller has to make
* sure it is large enough for storing the output. If
* NULL is passed, a large enough buffer will be allocated,
* and the caller must free it.
* @param count_ptr output variable for the length of byte string
* @return pointer to output buffer
*/
static void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr)
{
char byte[3];
size_t count, length;
int i;
if (!bytes)
return NULL;
length = strlen(bytes);
count = length / 2;
if (!data)
data = malloc(count);
if (!data)
return NULL;
byte[2] = '\0';
for (i = 0; i < length; i += 2) {
byte[0] = bytes[i];
byte[1] = bytes[i + 1];
data[i / 2] = (u8)simple_strtoul(byte, NULL, 16);
}
if (count_ptr)
*count_ptr = count;
return data;
}
/**
* report_return_code() - Report any error and return failure or success
*
* @param return_code TPM command return code
* @return value of enum command_ret_t
*/
static int report_return_code(int return_code)
{
if (return_code) {
printf("Error: %d\n", return_code);
return CMD_RET_FAILURE;
} else {
return CMD_RET_SUCCESS;
}
}
/**
* Return number of values defined by a type string.
*
* @param type_str type string
* @return number of values of type string
*/
static int type_string_get_num_values(const char *type_str)
{
return strlen(type_str);
}
/**
* Return total size of values defined by a type string.
*
* @param type_str type string
* @return total size of values of type string, or 0 if type string
* contains illegal type character.
*/
static size_t type_string_get_space_size(const char *type_str)
{
size_t size;
for (size = 0; *type_str; type_str++) {
switch (*type_str) {
case 'b':
size += 1;
break;
case 'w':
size += 2;
break;
case 'd':
size += 4;
break;
default:
return 0;
}
}
return size;
}
/**
* Allocate a buffer large enough to hold values defined by a type
* string. The caller has to free the buffer.
*
* @param type_str type string
* @param count pointer for storing size of buffer
* @return pointer to buffer or NULL on error
*/
static void *type_string_alloc(const char *type_str, u32 *count)
{
void *data;
size_t size;
size = type_string_get_space_size(type_str);
if (!size)
return NULL;
data = malloc(size);
if (data)
*count = size;
return data;
}
/**
* Pack values defined by a type string into a buffer. The buffer must have
* large enough space.
*
* @param type_str type string
* @param values text strings of values to be packed
* @param data output buffer of values
* @return 0 on success, non-0 on error
*/
static int type_string_pack(const char *type_str, char * const values[],
u8 *data)
{
size_t offset;
u32 value;
for (offset = 0; *type_str; type_str++, values++) {
value = simple_strtoul(values[0], NULL, 0);
switch (*type_str) {
case 'b':
data[offset] = value;
offset += 1;
break;
case 'w':
put_unaligned_be16(value, data + offset);
offset += 2;
break;
case 'd':
put_unaligned_be32(value, data + offset);
offset += 4;
break;
default:
return -1;
}
}
return 0;
}
/**
* Read values defined by a type string from a buffer, and write these values
* to environment variables.
*
* @param type_str type string
* @param data input buffer of values
* @param vars names of environment variables
* @return 0 on success, non-0 on error
*/
static int type_string_write_vars(const char *type_str, u8 *data,
char * const vars[])
{
size_t offset;
u32 value;
for (offset = 0; *type_str; type_str++, vars++) {
switch (*type_str) {
case 'b':
value = data[offset];
offset += 1;
break;
case 'w':
value = get_unaligned_be16(data + offset);
offset += 2;
break;
case 'd':
value = get_unaligned_be32(data + offset);
offset += 4;
break;
default:
return -1;
}
if (env_set_ulong(*vars, value))
return -1;
}
return 0;
}
static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, int argc, static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[]) char * const argv[])
@ -426,54 +199,6 @@ static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, int argc,
return report_return_code(rc); return report_return_code(rc);
} }
#define TPM_COMMAND_NO_ARG(cmd) \
static int do_##cmd(cmd_tbl_t *cmdtp, int flag, \
int argc, char * const argv[]) \
{ \
if (argc != 1) \
return CMD_RET_USAGE; \
return report_return_code(cmd()); \
}
TPM_COMMAND_NO_ARG(tpm_init)
TPM_COMMAND_NO_ARG(tpm_self_test_full)
TPM_COMMAND_NO_ARG(tpm_continue_self_test)
TPM_COMMAND_NO_ARG(tpm_force_clear)
TPM_COMMAND_NO_ARG(tpm_physical_enable)
TPM_COMMAND_NO_ARG(tpm_physical_disable)
static int get_tpm(struct udevice **devp)
{
int rc;
rc = uclass_first_device_err(UCLASS_TPM, devp);
if (rc) {
printf("Could not find TPM (ret=%d)\n", rc);
return CMD_RET_FAILURE;
}
return 0;
}
static int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
struct udevice *dev;
char buf[80];
int rc;
rc = get_tpm(&dev);
if (rc)
return rc;
rc = tpm_get_desc(dev, buf, sizeof(buf));
if (rc < 0) {
printf("Couldn't get TPM info (%d)\n", rc);
return CMD_RET_FAILURE;
}
printf("%s\n", buf);
return 0;
}
static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, int argc, static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[]) char * const argv[])
{ {
@ -812,10 +537,13 @@ static int do_tpm_list(cmd_tbl_t *cmdtp, int flag, int argc,
} }
#endif /* CONFIG_TPM_LIST_RESOURCES */ #endif /* CONFIG_TPM_LIST_RESOURCES */
#define MAKE_TPM_CMD_ENTRY(cmd) \ TPM_COMMAND_NO_ARG(tpm_self_test_full)
U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") TPM_COMMAND_NO_ARG(tpm_continue_self_test)
TPM_COMMAND_NO_ARG(tpm_force_clear)
TPM_COMMAND_NO_ARG(tpm_physical_enable)
TPM_COMMAND_NO_ARG(tpm_physical_disable)
static cmd_tbl_t tpm_commands[] = { static cmd_tbl_t tpm1_commands[] = {
U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""), U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""), U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
U_BOOT_CMD_MKENT(startup, 0, 1, U_BOOT_CMD_MKENT(startup, 0, 1,
@ -880,21 +608,15 @@ static cmd_tbl_t tpm_commands[] = {
#endif /* CONFIG_TPM_LIST_RESOURCES */ #endif /* CONFIG_TPM_LIST_RESOURCES */
}; };
static int do_tpm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) cmd_tbl_t *get_tpm_commands(unsigned int *size)
{ {
cmd_tbl_t *tpm_cmd; *size = ARRAY_SIZE(tpm1_commands);
if (argc < 2)
return CMD_RET_USAGE;
tpm_cmd = find_cmd_tbl(argv[1], tpm_commands, ARRAY_SIZE(tpm_commands));
if (!tpm_cmd)
return CMD_RET_USAGE;
return tpm_cmd->cmd(cmdtp, flag, argc - 1, argv + 1); return tpm1_commands;
} }
U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm, U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
"Issue a TPM command", "Issue a TPMv1.x command",
"cmd args...\n" "cmd args...\n"
" - Issue TPM command <cmd> with arguments <args...>.\n" " - Issue TPM command <cmd> with arguments <args...>.\n"
"Admin Startup and State Commands:\n" "Admin Startup and State Commands:\n"

@ -6,7 +6,7 @@
#include <common.h> #include <common.h>
#include <command.h> #include <command.h>
#include <environment.h> #include <environment.h>
#include <tpm.h> #include <tpm-v1.h>
/* Prints error and returns on failure */ /* Prints error and returns on failure */
#define TPM_CHECK(tpm_command) do { \ #define TPM_CHECK(tpm_command) do { \

@ -46,7 +46,7 @@ config TPM_TIS_INFINEON
config TPM_TIS_I2C_BURST_LIMITATION config TPM_TIS_I2C_BURST_LIMITATION
bool "Enable I2C burst length limitation" bool "Enable I2C burst length limitation"
depends on TPM_V1 && TPM_TIS_INFINEON depends on TPM_TIS_INFINEON
help help
Some broken TPMs have a limitation on the number of bytes they can Some broken TPMs have a limitation on the number of bytes they can
receive in one message. Enable this option to allow you to set this receive in one message. Enable this option to allow you to set this
@ -62,6 +62,7 @@ config TPM_TIS_I2C_BURST_LIMITATION_LEN
config TPM_TIS_LPC config TPM_TIS_LPC
bool "Enable support for Infineon SLB9635/45 TPMs on LPC" bool "Enable support for Infineon SLB9635/45 TPMs on LPC"
depends on TPM_V1 && X86 depends on TPM_V1 && X86
select TPM_DRIVER_SELECTED
help help
This driver supports Infineon TPM devices connected on the LPC bus. This driver supports Infineon TPM devices connected on the LPC bus.
The usual tpm operations and the 'tpm' command can be used to talk The usual tpm operations and the 'tpm' command can be used to talk

@ -6,8 +6,10 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <tpm.h>
#include <linux/unaligned/be_byteshift.h> #include <linux/unaligned/be_byteshift.h>
#if defined(CONFIG_TPM_V1)
#include <tpm-v1.h>
#endif
#include "tpm_internal.h" #include "tpm_internal.h"
int tpm_open(struct udevice *dev) int tpm_open(struct udevice *dev)

@ -7,7 +7,7 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <tpm.h> #include <tpm-v1.h>
#include <i2c.h> #include <i2c.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>

@ -23,7 +23,7 @@
#include <dm.h> #include <dm.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <i2c.h> #include <i2c.h>
#include <tpm.h> #include <tpm-v1.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>

@ -15,7 +15,7 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <mapmem.h> #include <mapmem.h>
#include <tpm.h> #include <tpm-v1.h>
#include <asm/io.h> #include <asm/io.h>
#define PREFIX "lpc_tpm: " #define PREFIX "lpc_tpm: "

@ -5,7 +5,7 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <tpm.h> #include <tpm-v1.h>
#include <asm/state.h> #include <asm/state.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <linux/crc8.h> #include <linux/crc8.h>

@ -16,7 +16,7 @@
#include <dm.h> #include <dm.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <i2c.h> #include <i2c.h>
#include <tpm.h> #include <tpm-v1.h>
#include <errno.h> #include <errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>

@ -16,7 +16,7 @@
#include <dm.h> #include <dm.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <spi.h> #include <spi.h>
#include <tpm.h> #include <tpm-v1.h>
#include <errno.h> #include <errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>

@ -0,0 +1,210 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2013 The Chromium OS Authors.
* Coypright (c) 2013 Guntermann & Drunck GmbH
*/
#ifndef __TPM_COMMON_H
#define __TPM_COMMON_H
enum tpm_duration {
TPM_SHORT = 0,
TPM_MEDIUM = 1,
TPM_LONG = 2,
TPM_UNDEFINED,
TPM_DURATION_COUNT,
};
/*
* Here is a partial implementation of TPM commands. Please consult TCG Main
* Specification for definitions of TPM commands.
*/
#define TPM_HEADER_SIZE 10
/* Max buffer size supported by our tpm */
#define TPM_DEV_BUFSIZE 1260
/**
* struct tpm_chip_priv - Information about a TPM, stored by the uclass
*
* These values must be set up by the device's probe() method before
* communcation is attempted. If the device has an xfer() method, this is
* not needed. There is no need to set up @buf.
*
* @duration_ms: Length of each duration type in milliseconds
* @retry_time_ms: Time to wait before retrying receive
*/
struct tpm_chip_priv {
uint duration_ms[TPM_DURATION_COUNT];
uint retry_time_ms;
u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */
};
/**
* struct tpm_ops - low-level TPM operations
*
* These are designed to avoid loops and delays in the driver itself. These
* should be handled in the uclass.
*
* In gneral you should implement everything except xfer(). Where you need
* complete control of the transfer, then xfer() can be provided and will
* override the other methods.
*
* This interface is for low-level TPM access. It does not understand the
* concept of localities or the various TPM messages. That interface is
* defined in the functions later on in this file, but they all translate
* to bytes which are sent and received.
*/
struct tpm_ops {
/**
* open() - Request access to locality 0 for the caller
*
* After all commands have been completed the caller should call
* close().
*
* @dev: Device to close
* @return 0 ok OK, -ve on error
*/
int (*open)(struct udevice *dev);
/**
* close() - Close the current session
*
* Releasing the locked locality. Returns 0 on success, -ve 1 on
* failure (in case lock removal did not succeed).
*
* @dev: Device to close
* @return 0 ok OK, -ve on error
*/
int (*close)(struct udevice *dev);
/**
* get_desc() - Get a text description of the TPM
*
* @dev: Device to check
* @buf: Buffer to put the string
* @size: Maximum size of buffer
* @return length of string, or -ENOSPC it no space
*/
int (*get_desc)(struct udevice *dev, char *buf, int size);
/**
* send() - send data to the TPM
*
* @dev: Device to talk to
* @sendbuf: Buffer of the data to send
* @send_size: Size of the data to send
*
* Returns 0 on success or -ve on failure.
*/
int (*send)(struct udevice *dev, const u8 *sendbuf, size_t send_size);
/**
* recv() - receive a response from the TPM
*
* @dev: Device to talk to
* @recvbuf: Buffer to save the response to
* @max_size: Maximum number of bytes to receive
*
* Returns number of bytes received on success, -EAGAIN if the TPM
* response is not ready, -EINTR if cancelled, or other -ve value on
* failure.
*/
int (*recv)(struct udevice *dev, u8 *recvbuf, size_t max_size);
/**
* cleanup() - clean up after an operation in progress
*
* This is called if receiving times out. The TPM may need to abort
* the current transaction if it did not complete, and make itself
* ready for another.
*
* @dev: Device to talk to
*/
int (*cleanup)(struct udevice *dev);
/**
* xfer() - send data to the TPM and get response
*
* This method is optional. If it exists it is used in preference
* to send(), recv() and cleanup(). It should handle all aspects of
* TPM communication for a single transfer.
*
* @dev: Device to talk to
* @sendbuf: Buffer of the data to send
* @send_size: Size of the data to send
* @recvbuf: Buffer to save the response to
* @recv_size: Pointer to the size of the response buffer
*
* Returns 0 on success (and places the number of response bytes at
* recv_size) or -ve on failure.
*/
int (*xfer)(struct udevice *dev, const u8 *sendbuf, size_t send_size,
u8 *recvbuf, size_t *recv_size);
};
#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev))
#define MAKE_TPM_CMD_ENTRY(cmd) \
U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "")
#define TPM_COMMAND_NO_ARG(cmd) \
int do_##cmd(cmd_tbl_t *cmdtp, int flag, \
int argc, char * const argv[]) \
{ \
if (argc != 1) \
return CMD_RET_USAGE; \
return report_return_code(cmd()); \
}
/**
* tpm_get_desc() - Get a text description of the TPM
*
* @dev: Device to check
* @buf: Buffer to put the string
* @size: Maximum size of buffer
* @return length of string, or -ENOSPC it no space
*/
int tpm_get_desc(struct udevice *dev, char *buf, int size);
/**
* tpm_xfer() - send data to the TPM and get response
*
* This first uses the device's send() method to send the bytes. Then it calls
* recv() to get the reply. If recv() returns -EAGAIN then it will delay a
* short time and then call recv() again.
*
* Regardless of whether recv() completes successfully, it will then call
* cleanup() to finish the transaction.
*
* Note that the outgoing data is inspected to determine command type
* (ordinal) and a timeout is used for that command type.
*
* @sendbuf - buffer of the data to send
* @send_size size of the data to send
* @recvbuf - memory to save the response to
* @recv_len - pointer to the size of the response buffer
*
* Returns 0 on success (and places the number of response bytes at
* recv_len) or -ve on failure.
*/
int tpm_xfer(struct udevice *dev, const u8 *sendbuf, size_t send_size,
u8 *recvbuf, size_t *recv_size);
/**
* Initialize TPM device. It must be called before any TPM commands.
*
* @return 0 on success, non-0 on error.
*/
int tpm_init(void);
/**
* Retrieve the array containing all the commands.
*
* @return a cmd_tbl_t array.
*/
cmd_tbl_t *get_tpm_commands(unsigned int *size);
#endif /* __TPM_COMMON_H */

@ -4,23 +4,22 @@
* Coypright (c) 2013 Guntermann & Drunck GmbH * Coypright (c) 2013 Guntermann & Drunck GmbH
*/ */
#ifndef __TPM_H #ifndef __TPM_V1_H
#define __TPM_H #define __TPM_V1_H
/* #include <tpm-common.h>
* Here is a partial implementation of TPM commands. Please consult TCG Main
* Specification for definitions of TPM commands.
*/
#define TPM_HEADER_SIZE 10
enum tpm_duration { /* Useful constants */
TPM_SHORT = 0, enum {
TPM_MEDIUM = 1, TPM_REQUEST_HEADER_LENGTH = 10,
TPM_LONG = 2, TPM_RESPONSE_HEADER_LENGTH = 10,
TPM_UNDEFINED, PCR_DIGEST_LENGTH = 20,
DIGEST_LENGTH = 20,
TPM_DURATION_COUNT, TPM_REQUEST_AUTH_LENGTH = 45,
TPM_RESPONSE_AUTH_LENGTH = 41,
/* some max lengths, valid for RSA keys <= 2048 bits */
TPM_KEY12_MAX_LENGTH = 618,
TPM_PUBKEY_MAX_LENGTH = 288,
}; };
enum tpm_startup_type { enum tpm_startup_type {
@ -232,189 +231,6 @@ struct tpm_permanent_flags {
u8 disable_full_da_logic_info; u8 disable_full_da_logic_info;
} __packed; } __packed;
/* Max buffer size supported by our tpm */
#define TPM_DEV_BUFSIZE 1260
/**
* struct tpm_chip_priv - Information about a TPM, stored by the uclass
*
* These values must be set up by the device's probe() method before
* communcation is attempted. If the device has an xfer() method, this is
* not needed. There is no need to set up @buf.
*
* @duration_ms: Length of each duration type in milliseconds
* @retry_time_ms: Time to wait before retrying receive
*/
struct tpm_chip_priv {
uint duration_ms[TPM_DURATION_COUNT];
uint retry_time_ms;
u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */
};
/**
* struct tpm_ops - low-level TPM operations
*
* These are designed to avoid loops and delays in the driver itself. These
* should be handled in the uclass.
*
* In gneral you should implement everything except xfer(). Where you need
* complete control of the transfer, then xfer() can be provided and will
* override the other methods.
*
* This interface is for low-level TPM access. It does not understand the
* concept of localities or the various TPM messages. That interface is
* defined in the functions later on in this file, but they all translate
* to bytes which are sent and received.
*/
struct tpm_ops {
/**
* open() - Request access to locality 0 for the caller
*
* After all commands have been completed the caller should call
* close().
*
* @dev: Device to close
* @return 0 ok OK, -ve on error
*/
int (*open)(struct udevice *dev);
/**
* close() - Close the current session
*
* Releasing the locked locality. Returns 0 on success, -ve 1 on
* failure (in case lock removal did not succeed).
*
* @dev: Device to close
* @return 0 ok OK, -ve on error
*/
int (*close)(struct udevice *dev);
/**
* get_desc() - Get a text description of the TPM
*
* @dev: Device to check
* @buf: Buffer to put the string
* @size: Maximum size of buffer
* @return length of string, or -ENOSPC it no space
*/
int (*get_desc)(struct udevice *dev, char *buf, int size);
/**
* send() - send data to the TPM
*
* @dev: Device to talk to
* @sendbuf: Buffer of the data to send
* @send_size: Size of the data to send
*
* Returns 0 on success or -ve on failure.
*/
int (*send)(struct udevice *dev, const u8 *sendbuf, size_t send_size);
/**
* recv() - receive a response from the TPM
*
* @dev: Device to talk to
* @recvbuf: Buffer to save the response to
* @max_size: Maximum number of bytes to receive
*
* Returns number of bytes received on success, -EAGAIN if the TPM
* response is not ready, -EINTR if cancelled, or other -ve value on
* failure.
*/
int (*recv)(struct udevice *dev, u8 *recvbuf, size_t max_size);
/**
* cleanup() - clean up after an operation in progress
*
* This is called if receiving times out. The TPM may need to abort
* the current transaction if it did not complete, and make itself
* ready for another.
*
* @dev: Device to talk to
*/
int (*cleanup)(struct udevice *dev);
/**
* xfer() - send data to the TPM and get response
*
* This method is optional. If it exists it is used in preference
* to send(), recv() and cleanup(). It should handle all aspects of
* TPM communication for a single transfer.
*
* @dev: Device to talk to
* @sendbuf: Buffer of the data to send
* @send_size: Size of the data to send
* @recvbuf: Buffer to save the response to
* @recv_size: Pointer to the size of the response buffer
*
* Returns 0 on success (and places the number of response bytes at
* recv_size) or -ve on failure.
*/
int (*xfer)(struct udevice *dev, const u8 *sendbuf, size_t send_size,
u8 *recvbuf, size_t *recv_size);
};
#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev))
/**
* tpm_open() - Request access to locality 0 for the caller
*
* After all commands have been completed the caller is supposed to
* call tpm_close().
*
* Returns 0 on success, -ve on failure.
*/
int tpm_open(struct udevice *dev);
/**
* tpm_close() - Close the current session
*
* Releasing the locked locality. Returns 0 on success, -ve 1 on
* failure (in case lock removal did not succeed).
*/
int tpm_close(struct udevice *dev);
/**
* tpm_get_desc() - Get a text description of the TPM
*
* @dev: Device to check
* @buf: Buffer to put the string
* @size: Maximum size of buffer
* @return length of string, or -ENOSPC it no space
*/
int tpm_get_desc(struct udevice *dev, char *buf, int size);
/**
* tpm_xfer() - send data to the TPM and get response
*
* This first uses the device's send() method to send the bytes. Then it calls
* recv() to get the reply. If recv() returns -EAGAIN then it will delay a
* short time and then call recv() again.
*
* Regardless of whether recv() completes successfully, it will then call
* cleanup() to finish the transaction.
*
* Note that the outgoing data is inspected to determine command type
* (ordinal) and a timeout is used for that command type.
*
* @sendbuf - buffer of the data to send
* @send_size size of the data to send
* @recvbuf - memory to save the response to
* @recv_len - pointer to the size of the response buffer
*
* Returns 0 on success (and places the number of response bytes at
* recv_len) or -ve on failure.
*/
int tpm_xfer(struct udevice *dev, const u8 *sendbuf, size_t send_size,
u8 *recvbuf, size_t *recv_size);
/**
* Initialize TPM device. It must be called before any TPM commands.
*
* @return 0 on success, non-0 on error.
*/
int tpm_init(void);
/** /**
* Issue a TPM_Startup command. * Issue a TPM_Startup command.
* *
@ -661,4 +477,4 @@ u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20],
*/ */
u32 tpm_get_random(void *data, u32 count); u32 tpm_get_random(void *data, u32 count);
#endif /* __TPM_H */ #endif /* __TPM_V1_H */

@ -39,7 +39,8 @@ obj-$(CONFIG_PHYSMEM) += physmem.o
obj-y += qsort.o obj-y += qsort.o
obj-y += rc4.o obj-y += rc4.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o obj-$(CONFIG_SUPPORT_EMMC_RPMB) += sha256.o
obj-$(CONFIG_TPM_V1) += tpm.o obj-$(CONFIG_TPM) += tpm-common.o
obj-$(CONFIG_TPM_V1) += tpm-v1.o
obj-$(CONFIG_RBTREE) += rbtree.o obj-$(CONFIG_RBTREE) += rbtree.o
obj-$(CONFIG_BITREVERSE) += bitrev.o obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-y += list_sort.o obj-y += list_sort.o

@ -0,0 +1,188 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013 The Chromium OS Authors.
* Coypright (c) 2013 Guntermann & Drunck GmbH
*/
#include <common.h>
#include <dm.h>
#include <asm/unaligned.h>
#include <tpm-common.h>
#include "tpm-utils.h"
int pack_byte_string(u8 *str, size_t size, const char *format, ...)
{
va_list args;
size_t offset = 0, length = 0;
u8 *data = NULL;
u32 value = 0;
va_start(args, format);
for (; *format; format++) {
switch (*format) {
case 'b':
offset = va_arg(args, size_t);
value = va_arg(args, int);
length = 1;
break;
case 'w':
offset = va_arg(args, size_t);
value = va_arg(args, int);
length = 2;
break;
case 'd':
offset = va_arg(args, size_t);
value = va_arg(args, u32);
length = 4;
break;
case 's':
offset = va_arg(args, size_t);
data = va_arg(args, u8 *);
length = va_arg(args, u32);
break;
default:
debug("Couldn't recognize format string\n");
va_end(args);
return -1;
}
if (offset + length > size) {
va_end(args);
return -1;
}
switch (*format) {
case 'b':
str[offset] = value;
break;
case 'w':
put_unaligned_be16(value, str + offset);
break;
case 'd':
put_unaligned_be32(value, str + offset);
break;
case 's':
memcpy(str + offset, data, length);
break;
}
}
va_end(args);
return 0;
}
int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
{
va_list args;
size_t offset = 0, length = 0;
u8 *ptr8 = NULL;
u16 *ptr16 = NULL;
u32 *ptr32 = NULL;
va_start(args, format);
for (; *format; format++) {
switch (*format) {
case 'b':
offset = va_arg(args, size_t);
ptr8 = va_arg(args, u8 *);
length = 1;
break;
case 'w':
offset = va_arg(args, size_t);
ptr16 = va_arg(args, u16 *);
length = 2;
break;
case 'd':
offset = va_arg(args, size_t);
ptr32 = va_arg(args, u32 *);
length = 4;
break;
case 's':
offset = va_arg(args, size_t);
ptr8 = va_arg(args, u8 *);
length = va_arg(args, u32);
break;
default:
va_end(args);
debug("Couldn't recognize format string\n");
return -1;
}
if (offset + length > size) {
va_end(args);
return -1;
}
switch (*format) {
case 'b':
*ptr8 = str[offset];
break;
case 'w':
*ptr16 = get_unaligned_be16(str + offset);
break;
case 'd':
*ptr32 = get_unaligned_be32(str + offset);
break;
case 's':
memcpy(ptr8, str + offset, length);
break;
}
}
va_end(args);
return 0;
}
u32 tpm_command_size(const void *command)
{
const size_t command_size_offset = 2;
return get_unaligned_be32(command + command_size_offset);
}
u32 tpm_return_code(const void *response)
{
const size_t return_code_offset = 6;
return get_unaligned_be32(response + return_code_offset);
}
u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr)
{
struct udevice *dev;
int err, ret;
u8 response_buffer[COMMAND_BUFFER_SIZE];
size_t response_length;
if (response) {
response_length = *size_ptr;
} else {
response = response_buffer;
response_length = sizeof(response_buffer);
}
ret = uclass_first_device_err(UCLASS_TPM, &dev);
if (ret)
return ret;
err = tpm_xfer(dev, command, tpm_command_size(command),
response, &response_length);
if (err < 0)
return TPM_LIB_ERROR;
if (size_ptr)
*size_ptr = response_length;
return tpm_return_code(response);
}
int tpm_init(void)
{
struct udevice *dev;
int err;
err = uclass_first_device_err(UCLASS_TPM, &dev);
if (err)
return err;
return tpm_open(dev);
}

@ -0,0 +1,95 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright (c) 2013 The Chromium OS Authors.
* Coypright (c) 2013 Guntermann & Drunck GmbH
*/
#ifndef __TPM_UTILS_H
#define __TPM_UTILS_H
#define COMMAND_BUFFER_SIZE 256
/* Internal error of TPM command library */
#define TPM_LIB_ERROR ((u32)~0u)
/**
* tpm_open() - Request access to locality 0 for the caller
*
* After all commands have been completed the caller is supposed to
* call tpm_close().
*
* Returns 0 on success, -ve on failure.
*/
int tpm_open(struct udevice *dev);
/**
* tpm_close() - Close the current session
*
* Releasing the locked locality. Returns 0 on success, -ve 1 on
* failure (in case lock removal did not succeed).
*/
int tpm_close(struct udevice *dev);
/**
* Pack data into a byte string. The data types are specified in
* the format string: 'b' means unsigned byte, 'w' unsigned word,
* 'd' unsigned double word, and 's' byte string. The data are a
* series of offsets and values (for type byte string there are also
* lengths). The data values are packed into the byte string
* sequentially, and so a latter value could over-write a former
* value.
*
* @param str output string
* @param size size of output string
* @param format format string
* @param ... data points
* @return 0 on success, non-0 on error
*/
int pack_byte_string(u8 *str, size_t size, const char *format, ...);
/**
* Unpack data from a byte string. The data types are specified in
* the format string: 'b' means unsigned byte, 'w' unsigned word,
* 'd' unsigned double word, and 's' byte string. The data are a
* series of offsets and pointers (for type byte string there are also
* lengths).
*
* @param str output string
* @param size size of output string
* @param format format string
* @param ... data points
* @return 0 on success, non-0 on error
*/
int unpack_byte_string(const u8 *str, size_t size, const char *format, ...);
/**
* Get TPM command size.
*
* @param command byte string of TPM command
* @return command size of the TPM command
*/
u32 tpm_command_size(const void *command);
/**
* Get TPM response return code, which is one of TPM_RESULT values.
*
* @param response byte string of TPM response
* @return return code of the TPM response
*/
u32 tpm_return_code(const void *response);
/**
* Send a TPM command and return response's return code, and optionally
* return response to caller.
*
* @param command byte string of TPM command
* @param response output buffer for TPM response, or NULL if the
* caller does not care about it
* @param size_ptr output buffer size (input parameter) and TPM
* response length (output parameter); this parameter
* is a bidirectional
* @return return code of the TPM response
*/
u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr);
#endif /* __TPM_UTILS_H */

@ -6,26 +6,11 @@
#include <common.h> #include <common.h>
#include <dm.h> #include <dm.h>
#include <tpm.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include <u-boot/sha1.h> #include <u-boot/sha1.h>
#include <tpm-common.h>
/* Internal error of TPM command library */ #include <tpm-v1.h>
#define TPM_LIB_ERROR ((u32)~0u) #include "tpm-utils.h"
/* Useful constants */
enum {
COMMAND_BUFFER_SIZE = 256,
TPM_REQUEST_HEADER_LENGTH = 10,
TPM_RESPONSE_HEADER_LENGTH = 10,
PCR_DIGEST_LENGTH = 20,
DIGEST_LENGTH = 20,
TPM_REQUEST_AUTH_LENGTH = 45,
TPM_RESPONSE_AUTH_LENGTH = 41,
/* some max lengths, valid for RSA keys <= 2048 bits */
TPM_KEY12_MAX_LENGTH = 618,
TPM_PUBKEY_MAX_LENGTH = 288,
};
#ifdef CONFIG_TPM_AUTH_SESSIONS #ifdef CONFIG_TPM_AUTH_SESSIONS
@ -44,235 +29,6 @@ static struct session_data oiap_session = {0, };
#endif /* CONFIG_TPM_AUTH_SESSIONS */ #endif /* CONFIG_TPM_AUTH_SESSIONS */
/**
* Pack data into a byte string. The data types are specified in
* the format string: 'b' means unsigned byte, 'w' unsigned word,
* 'd' unsigned double word, and 's' byte string. The data are a
* series of offsets and values (for type byte string there are also
* lengths). The data values are packed into the byte string
* sequentially, and so a latter value could over-write a former
* value.
*
* @param str output string
* @param size size of output string
* @param format format string
* @param ... data points
* @return 0 on success, non-0 on error
*/
int pack_byte_string(u8 *str, size_t size, const char *format, ...)
{
va_list args;
size_t offset = 0, length = 0;
u8 *data = NULL;
u32 value = 0;
va_start(args, format);
for (; *format; format++) {
switch (*format) {
case 'b':
offset = va_arg(args, size_t);
value = va_arg(args, int);
length = 1;
break;
case 'w':
offset = va_arg(args, size_t);
value = va_arg(args, int);
length = 2;
break;
case 'd':
offset = va_arg(args, size_t);
value = va_arg(args, u32);
length = 4;
break;
case 's':
offset = va_arg(args, size_t);
data = va_arg(args, u8 *);
length = va_arg(args, u32);
break;
default:
debug("Couldn't recognize format string\n");
va_end(args);
return -1;
}
if (offset + length > size) {
va_end(args);
return -1;
}
switch (*format) {
case 'b':
str[offset] = value;
break;
case 'w':
put_unaligned_be16(value, str + offset);
break;
case 'd':
put_unaligned_be32(value, str + offset);
break;
case 's':
memcpy(str + offset, data, length);
break;
}
}
va_end(args);
return 0;
}
/**
* Unpack data from a byte string. The data types are specified in
* the format string: 'b' means unsigned byte, 'w' unsigned word,
* 'd' unsigned double word, and 's' byte string. The data are a
* series of offsets and pointers (for type byte string there are also
* lengths).
*
* @param str output string
* @param size size of output string
* @param format format string
* @param ... data points
* @return 0 on success, non-0 on error
*/
int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
{
va_list args;
size_t offset = 0, length = 0;
u8 *ptr8 = NULL;
u16 *ptr16 = NULL;
u32 *ptr32 = NULL;
va_start(args, format);
for (; *format; format++) {
switch (*format) {
case 'b':
offset = va_arg(args, size_t);
ptr8 = va_arg(args, u8 *);
length = 1;
break;
case 'w':
offset = va_arg(args, size_t);
ptr16 = va_arg(args, u16 *);
length = 2;
break;
case 'd':
offset = va_arg(args, size_t);
ptr32 = va_arg(args, u32 *);
length = 4;
break;
case 's':
offset = va_arg(args, size_t);
ptr8 = va_arg(args, u8 *);
length = va_arg(args, u32);
break;
default:
va_end(args);
debug("Couldn't recognize format string\n");
return -1;
}
if (offset + length > size) {
va_end(args);
return -1;
}
switch (*format) {
case 'b':
*ptr8 = str[offset];
break;
case 'w':
*ptr16 = get_unaligned_be16(str + offset);
break;
case 'd':
*ptr32 = get_unaligned_be32(str + offset);
break;
case 's':
memcpy(ptr8, str + offset, length);
break;
}
}
va_end(args);
return 0;
}
/**
* Get TPM command size.
*
* @param command byte string of TPM command
* @return command size of the TPM command
*/
static u32 tpm_command_size(const void *command)
{
const size_t command_size_offset = 2;
return get_unaligned_be32(command + command_size_offset);
}
/**
* Get TPM response return code, which is one of TPM_RESULT values.
*
* @param response byte string of TPM response
* @return return code of the TPM response
*/
static u32 tpm_return_code(const void *response)
{
const size_t return_code_offset = 6;
return get_unaligned_be32(response + return_code_offset);
}
/**
* Send a TPM command and return response's return code, and optionally
* return response to caller.
*
* @param command byte string of TPM command
* @param response output buffer for TPM response, or NULL if the
* caller does not care about it
* @param size_ptr output buffer size (input parameter) and TPM
* response length (output parameter); this parameter
* is a bidirectional
* @return return code of the TPM response
*/
static u32 tpm_sendrecv_command(const void *command, void *response,
size_t *size_ptr)
{
struct udevice *dev;
int err, ret;
u8 response_buffer[COMMAND_BUFFER_SIZE];
size_t response_length;
if (response) {
response_length = *size_ptr;
} else {
response = response_buffer;
response_length = sizeof(response_buffer);
}
ret = uclass_first_device_err(UCLASS_TPM, &dev);
if (ret)
return ret;
err = tpm_xfer(dev, command, tpm_command_size(command),
response, &response_length);
if (err < 0)
return TPM_LIB_ERROR;
if (size_ptr)
*size_ptr = response_length;
return tpm_return_code(response);
}
int tpm_init(void)
{
int err;
struct udevice *dev;
err = uclass_first_device_err(UCLASS_TPM, &dev);
if (err)
return err;
return tpm_open(dev);
}
u32 tpm_startup(enum tpm_startup_type mode) u32 tpm_startup(enum tpm_startup_type mode)
{ {
const u8 command[12] = { const u8 command[12] = {
Loading…
Cancel
Save