There are no changes in this commit unless: 1/ a new organization of the code as follow. 2/ some *very* basic checkpatch.pl corrections that polluated my reports like s/uint<x>_t/u<x>/, blank spaces and non-aligned parameters on parenthesis.
* 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.ray...@bootlin.com> --- cmd/Makefile | 3 +- cmd/tpm-common.c | 289 +++++++++++++++++++++++++++++++++++ cmd/tpm-user-utils.h | 25 +++ cmd/{tpm.c => tpm-v1.c} | 305 ++----------------------------------- cmd/tpm_test.c | 2 +- drivers/tpm/tpm-uclass.c | 4 +- drivers/tpm/tpm_atmel_twi.c | 2 +- drivers/tpm/tpm_tis_infineon.c | 2 +- drivers/tpm/tpm_tis_lpc.c | 2 +- drivers/tpm/tpm_tis_sandbox.c | 2 +- drivers/tpm/tpm_tis_st33zp24_i2c.c | 2 +- drivers/tpm/tpm_tis_st33zp24_spi.c | 2 +- include/tpm-common.h | 214 ++++++++++++++++++++++++++ include/{tpm.h => tpm-v1.h} | 274 ++++++--------------------------- lib/Makefile | 3 +- lib/tpm-common.c | 189 +++++++++++++++++++++++ lib/tpm-utils.h | 96 ++++++++++++ lib/{tpm.c => tpm-v1.c} | 248 +----------------------------- 18 files changed, 886 insertions(+), 778 deletions(-) create mode 100644 cmd/tpm-common.c create mode 100644 cmd/tpm-user-utils.h rename cmd/{tpm.c => tpm-v1.c} (76%) create mode 100644 include/tpm-common.h rename include/{tpm.h => tpm-v1.h} (62%) create mode 100644 lib/tpm-common.c create mode 100644 lib/tpm-utils.h rename lib/{tpm.c => tpm-v1.c} (81%) diff --git a/cmd/Makefile b/cmd/Makefile index bbeeb7e7f7..66732085e8 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -117,7 +117,8 @@ obj-$(CONFIG_CMD_TERMINAL) += terminal.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TRACE) += trace.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_CROS_EC) += cros_ec.o obj-$(CONFIG_CMD_TSI148) += tsi148.o diff --git a/cmd/tpm-common.c b/cmd/tpm-common.c new file mode 100644 index 0000000000..235bdf39da --- /dev/null +++ b/cmd/tpm-common.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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); +} diff --git a/cmd/tpm-user-utils.h b/cmd/tpm-user-utils.h new file mode 100644 index 0000000000..6017090971 --- /dev/null +++ b/cmd/tpm-user-utils.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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 */ diff --git a/cmd/tpm.c b/cmd/tpm-v1.c similarity index 76% rename from cmd/tpm.c rename to cmd/tpm-v1.c index d9b433582c..ed0f476be6 100644 --- a/cmd/tpm.c +++ b/cmd/tpm-v1.c @@ -5,238 +5,11 @@ */ #include <common.h> -#include <command.h> -#include <dm.h> #include <malloc.h> -#include <tpm.h> #include <asm/unaligned.h> -#include <linux/string.h> - -/* Useful constants */ -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(uint8_t *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, uint8_t *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] = (uint8_t)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, uint32_t *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[], - uint8_t *data) -{ - size_t offset; - uint32_t 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, uint8_t *data, - char * const vars[]) -{ - size_t offset; - uint32_t 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; -} +#include <tpm-common.h> +#include <tpm-v1.h> +#include "tpm-user-utils.h" static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) @@ -427,55 +200,6 @@ static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag, 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, char * const argv[]) { @@ -814,10 +538,13 @@ static int do_tpm_list(cmd_tbl_t *cmdtp, int flag, int argc, } #endif /* CONFIG_TPM_LIST_RESOURCES */ -#define MAKE_TPM_CMD_ENTRY(cmd) \ - U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "") +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 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(init, 0, 1, do_tpm_init, "", ""), @@ -883,21 +610,15 @@ static cmd_tbl_t tpm_commands[] = { #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, -"Issue a TPM command", +"Issue a TPMv1.x command", "cmd args...\n" " - Issue TPM command <cmd> with arguments <args...>.\n" "Admin Startup and State Commands:\n" diff --git a/cmd/tpm_test.c b/cmd/tpm_test.c index 37ad2ff33d..c9d641f0ce 100644 --- a/cmd/tpm_test.c +++ b/cmd/tpm_test.c @@ -7,7 +7,7 @@ #include <common.h> #include <command.h> #include <environment.h> -#include <tpm.h> +#include <tpm-v1.h> /* Prints error and returns on failure */ #define TPM_CHECK(tpm_command) do { \ diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c index b6e1fc5e62..eb0e511c8f 100644 --- a/drivers/tpm/tpm-uclass.c +++ b/drivers/tpm/tpm-uclass.c @@ -7,8 +7,10 @@ #include <common.h> #include <dm.h> -#include <tpm.h> #include <linux/unaligned/be_byteshift.h> +#if defined(CONFIG_TPM_V1) +#include <tpm-v1.h> +#endif #include "tpm_internal.h" int tpm_open(struct udevice *dev) diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c index 4fd772dc4f..a6f5a333dd 100644 --- a/drivers/tpm/tpm_atmel_twi.c +++ b/drivers/tpm/tpm_atmel_twi.c @@ -8,7 +8,7 @@ #include <common.h> #include <dm.h> -#include <tpm.h> +#include <tpm-v1.h> #include <i2c.h> #include <asm/unaligned.h> diff --git a/drivers/tpm/tpm_tis_infineon.c b/drivers/tpm/tpm_tis_infineon.c index 41b748e7a2..30170afce0 100644 --- a/drivers/tpm/tpm_tis_infineon.c +++ b/drivers/tpm/tpm_tis_infineon.c @@ -24,7 +24,7 @@ #include <dm.h> #include <fdtdec.h> #include <i2c.h> -#include <tpm.h> +#include <tpm-v1.h> #include <linux/errno.h> #include <linux/compiler.h> #include <linux/types.h> diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index c00a2d030b..bf955e73f2 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -16,7 +16,7 @@ #include <common.h> #include <dm.h> #include <mapmem.h> -#include <tpm.h> +#include <tpm-v1.h> #include <asm/io.h> #define PREFIX "lpc_tpm: " diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index e7746dc675..a19c1ba33d 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -6,7 +6,7 @@ #include <common.h> #include <dm.h> -#include <tpm.h> +#include <tpm-v1.h> #include <asm/state.h> #include <asm/unaligned.h> #include <linux/crc8.h> diff --git a/drivers/tpm/tpm_tis_st33zp24_i2c.c b/drivers/tpm/tpm_tis_st33zp24_i2c.c index 245218fc07..21c2b56034 100644 --- a/drivers/tpm/tpm_tis_st33zp24_i2c.c +++ b/drivers/tpm/tpm_tis_st33zp24_i2c.c @@ -17,7 +17,7 @@ #include <dm.h> #include <fdtdec.h> #include <i2c.h> -#include <tpm.h> +#include <tpm-v1.h> #include <errno.h> #include <linux/types.h> #include <asm/unaligned.h> diff --git a/drivers/tpm/tpm_tis_st33zp24_spi.c b/drivers/tpm/tpm_tis_st33zp24_spi.c index c4c5e05286..07daad7beb 100644 --- a/drivers/tpm/tpm_tis_st33zp24_spi.c +++ b/drivers/tpm/tpm_tis_st33zp24_spi.c @@ -17,7 +17,7 @@ #include <dm.h> #include <fdtdec.h> #include <spi.h> -#include <tpm.h> +#include <tpm-v1.h> #include <errno.h> #include <linux/types.h> #include <asm/unaligned.h> diff --git a/include/tpm-common.h b/include/tpm-common.h new file mode 100644 index 0000000000..cf12ea2aac --- /dev/null +++ b/include/tpm-common.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __TPM_COMMON_H +#define __TPM_COMMON_H + +/* Chip private data. Each specification may declare its own structure. */ +struct tpm_chip_priv; + +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 */ diff --git a/include/tpm.h b/include/tpm-v1.h similarity index 62% rename from include/tpm.h rename to include/tpm-v1.h index 760d94865c..a090bf9f50 100644 --- a/include/tpm.h +++ b/include/tpm-v1.h @@ -5,23 +5,22 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#ifndef __TPM_H -#define __TPM_H +#ifndef __TPM_V1_H +#define __TPM_V1_H -/* - * Here is a partial implementation of TPM commands. Please consult TCG Main - * Specification for definitions of TPM commands. - */ +#include <tpm-common.h> -#define TPM_HEADER_SIZE 10 - -enum tpm_duration { - TPM_SHORT = 0, - TPM_MEDIUM = 1, - TPM_LONG = 2, - TPM_UNDEFINED, - - TPM_DURATION_COUNT, +/* Useful constants */ +enum { + 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, }; enum tpm_startup_type { @@ -233,211 +232,27 @@ struct tpm_permanent_flags { u8 disable_full_da_logic_info; } __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 uint8_t *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, uint8_t *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 uint8_t *sendbuf, - size_t send_size, uint8_t *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 uint8_t *sendbuf, size_t send_size, - uint8_t *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. * * @param mode TPM startup mode * @return return code of the operation */ -uint32_t tpm_startup(enum tpm_startup_type mode); +u32 tpm_startup(enum tpm_startup_type mode); /** * Issue a TPM_SelfTestFull command. * * @return return code of the operation */ -uint32_t tpm_self_test_full(void); +u32 tpm_self_test_full(void); /** * Issue a TPM_ContinueSelfTest command. * * @return return code of the operation */ -uint32_t tpm_continue_self_test(void); +u32 tpm_continue_self_test(void); /** * Issue a TPM_NV_DefineSpace command. The implementation is limited @@ -449,7 +264,7 @@ uint32_t tpm_continue_self_test(void); * @param size size of the area * @return return code of the operation */ -uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size); +u32 tpm_nv_define_space(u32 index, u32 perm, u32 size); /** * Issue a TPM_NV_ReadValue command. This implementation is limited @@ -461,7 +276,7 @@ uint32_t tpm_nv_define_space(uint32_t index, uint32_t perm, uint32_t size); * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count); +u32_t tpm_nv_read_value(u32 index, void *data, u32 count); /** * Issue a TPM_NV_WriteValue command. This implementation is limited @@ -473,7 +288,7 @@ uint32_t tpm_nv_read_value(uint32_t index, void *data, uint32_t count); * @param length length of data bytes of input buffer * @return return code of the operation */ -uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length); +u32 tpm_nv_write_value(u32 index, const void *data, u32 length); /** * Issue a TPM_Extend command. @@ -485,7 +300,7 @@ uint32_t tpm_nv_write_value(uint32_t index, const void *data, uint32_t length); * command * @return return code of the operation */ -uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest); +u32 tpm_extend(u32 index, const void *in_digest, void *out_digest); /** * Issue a TPM_PCRRead command. @@ -495,7 +310,7 @@ uint32_t tpm_extend(uint32_t index, const void *in_digest, void *out_digest); * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count); +u32 tpm_pcr_read(u32 index, void *data, size_t count); /** * Issue a TSC_PhysicalPresence command. TPM physical presence flag @@ -504,7 +319,7 @@ uint32_t tpm_pcr_read(uint32_t index, void *data, size_t count); * @param presence TPM physical presence flag * @return return code of the operation */ -uint32_t tpm_tsc_physical_presence(uint16_t presence); +u32 tpm_tsc_physical_presence(u16 presence); /** * Issue a TPM_ReadPubek command. @@ -513,28 +328,28 @@ uint32_t tpm_tsc_physical_presence(uint16_t presence); * @param count size of ouput buffer * @return return code of the operation */ -uint32_t tpm_read_pubek(void *data, size_t count); +u32 tpm_read_pubek(void *data, size_t count); /** * Issue a TPM_ForceClear command. * * @return return code of the operation */ -uint32_t tpm_force_clear(void); +u32 tpm_force_clear(void); /** * Issue a TPM_PhysicalEnable command. * * @return return code of the operation */ -uint32_t tpm_physical_enable(void); +u32 tpm_physical_enable(void); /** * Issue a TPM_PhysicalDisable command. * * @return return code of the operation */ -uint32_t tpm_physical_disable(void); +u32 tpm_physical_disable(void); /** * Issue a TPM_PhysicalSetDeactivated command. @@ -542,7 +357,7 @@ uint32_t tpm_physical_disable(void); * @param state boolean state of the deactivated flag * @return return code of the operation */ -uint32_t tpm_physical_set_deactivated(uint8_t state); +u32 tpm_physical_set_deactivated(u8 state); /** * Issue a TPM_GetCapability command. This implementation is limited @@ -555,8 +370,7 @@ uint32_t tpm_physical_set_deactivated(uint8_t state); * @param count size of ouput buffer * @return return code of the operation */ -uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, - void *cap, size_t count); +u32 tpm_get_capability(u32 cap_area, u32 sub_cap, void *cap, size_t count); /** * Issue a TPM_FlushSpecific command for a AUTH ressource. @@ -564,7 +378,7 @@ uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap, * @param auth_handle handle of the auth session * @return return code of the operation */ -uint32_t tpm_terminate_auth_session(uint32_t auth_handle); +u32 tpm_terminate_auth_session(u32 auth_handle); /** * Issue a TPM_OIAP command to setup an object independant authorization @@ -576,14 +390,14 @@ uint32_t tpm_terminate_auth_session(uint32_t auth_handle); * @param auth_handle pointer to the (new) auth handle or NULL. * @return return code of the operation */ -uint32_t tpm_oiap(uint32_t *auth_handle); +u32 tpm_oiap(u32 *auth_handle); /** * Ends an active OIAP session. * * @return return code of the operation */ -uint32_t tpm_end_oiap(void); +u32 tpm_end_oiap(void); /** * Issue a TPM_LoadKey2 (Auth1) command using an OIAP session for authenticating @@ -596,10 +410,8 @@ uint32_t tpm_end_oiap(void); * @param key_handle pointer to the key handle * @return return code of the operation */ -uint32_t tpm_load_key2_oiap(uint32_t parent_handle, - const void *key, size_t key_length, - const void *parent_key_usage_auth, - uint32_t *key_handle); +u32 tpm_load_key2_oiap(u32 parent_handle, const void *key, size_t key_length, + const void *parent_key_usage_auth, u32 *key_handle); /** * Issue a TPM_GetPubKey (Auth1) command using an OIAP session for @@ -614,8 +426,8 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle, * of the stored TPM_PUBKEY structure (iff pubkey != NULL). * @return return code of the operation */ -uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, - void *pubkey, size_t *pubkey_len); +u32 tpm_get_pub_key_oiap(u32 key_handle, const void *usage_auth, void *pubkey, + size_t *pubkey_len); /** * Get the TPM permanent flags value @@ -623,7 +435,7 @@ uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth, * @param pflags Place to put permanent flags * @return return code of the operation */ -uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); +u32 tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); /** * Get the TPM permissions @@ -631,7 +443,7 @@ uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags); * @param perm Returns permissions value * @return return code of the operation */ -uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm); +u32 tpm_get_permissions(u32 index, u32 *perm); /** * Flush a resource with a given handle and type from the TPM @@ -640,7 +452,7 @@ uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm); * @param resource_type type of the resource * @return return code of the operation */ -uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type); +u32 tpm_flush_specific(u32 key_handle, u32 resource_type); #ifdef CONFIG_TPM_LOAD_KEY_BY_SHA1 /** @@ -651,8 +463,8 @@ uint32_t tpm_flush_specific(uint32_t key_handle, uint32_t resource_type); * @param[out] handle The handle of the key (Non-null iff found) * @return 0 if key was found in TPM; != 0 if not. */ -uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t - pubkey_digest[20], uint32_t *handle); +u32 tpm_find_key_sha1(const u8 auth[20], const u8 pubkey_digest[20], + u32 *handle); #endif /* CONFIG_TPM_LOAD_KEY_BY_SHA1 */ /** @@ -664,6 +476,6 @@ uint32_t tpm_find_key_sha1(const uint8_t auth[20], const uint8_t * @param count size of output buffer * @return return code of the operation */ -uint32_t tpm_get_random(void *data, uint32_t count); +u32 tpm_get_random(void *data, u32 count); -#endif /* __TPM_H */ +#endif /* __TPM_V1_H */ diff --git a/lib/Makefile b/lib/Makefile index 9ec4a93043..2052954841 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -40,7 +40,8 @@ obj-$(CONFIG_PHYSMEM) += physmem.o obj-y += qsort.o obj-y += rc4.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_BITREVERSE) += bitrev.o obj-y += list_sort.o diff --git a/lib/tpm-common.c b/lib/tpm-common.c new file mode 100644 index 0000000000..0812b73220 --- /dev/null +++ b/lib/tpm-common.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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); +} diff --git a/lib/tpm-utils.h b/lib/tpm-utils.h new file mode 100644 index 0000000000..429da46232 --- /dev/null +++ b/lib/tpm-utils.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2013 The Chromium OS Authors. + * Coypright (c) 2013 Guntermann & Drunck GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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 */ diff --git a/lib/tpm.c b/lib/tpm-v1.c similarity index 81% rename from lib/tpm.c rename to lib/tpm-v1.c index c8bf06178f..b7c4418ac1 100644 --- a/lib/tpm.c +++ b/lib/tpm-v1.c @@ -7,26 +7,11 @@ #include <common.h> #include <dm.h> -#include <tpm.h> #include <asm/unaligned.h> #include <u-boot/sha1.h> - -/* Internal error of TPM command library */ -#define TPM_LIB_ERROR ((uint32_t)~0u) - -/* 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, -}; +#include <tpm-common.h> +#include <tpm-v1.h> +#include "tpm-utils.h" #ifdef CONFIG_TPM_AUTH_SESSIONS @@ -45,233 +30,6 @@ static struct session_data oiap_session = {0, }; #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(uint8_t *str, size_t size, const char *format, ...) -{ - va_list args; - size_t offset = 0, length = 0; - uint8_t *data = NULL; - uint32_t 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, uint32_t); - length = 4; - break; - case 's': - offset = va_arg(args, size_t); - data = va_arg(args, uint8_t *); - length = va_arg(args, uint32_t); - 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 uint8_t *str, size_t size, const char *format, ...) -{ - va_list args; - size_t offset = 0, length = 0; - uint8_t *ptr8 = NULL; - uint16_t *ptr16 = NULL; - uint32_t *ptr32 = NULL; - - va_start(args, format); - for (; *format; format++) { - switch (*format) { - case 'b': - offset = va_arg(args, size_t); - ptr8 = va_arg(args, uint8_t *); - length = 1; - break; - case 'w': - offset = va_arg(args, size_t); - ptr16 = va_arg(args, uint16_t *); - length = 2; - break; - case 'd': - offset = va_arg(args, size_t); - ptr32 = va_arg(args, uint32_t *); - length = 4; - break; - case 's': - offset = va_arg(args, size_t); - ptr8 = va_arg(args, uint8_t *); - length = va_arg(args, uint32_t); - 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 uint32_t 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 uint32_t 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 uint32_t tpm_sendrecv_command(const void *command, - void *response, size_t *size_ptr) -{ - struct udevice *dev; - int err, ret; - uint8_t 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); -} - uint32_t tpm_startup(enum tpm_startup_type mode) { const uint8_t command[12] = { -- 2.14.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot