1d677bfe2SMiquel Raynal // SPDX-License-Identifier: GPL-2.0+ 2d677bfe2SMiquel Raynal /* 3d677bfe2SMiquel Raynal * Copyright (c) 2013 The Chromium OS Authors. 4d677bfe2SMiquel Raynal * Coypright (c) 2013 Guntermann & Drunck GmbH 5d677bfe2SMiquel Raynal */ 6d677bfe2SMiquel Raynal 7d677bfe2SMiquel Raynal #include <common.h> 8d677bfe2SMiquel Raynal #include <dm.h> 9d677bfe2SMiquel Raynal #include <asm/unaligned.h> 10d677bfe2SMiquel Raynal #include <tpm-common.h> 11d677bfe2SMiquel Raynal #include "tpm-utils.h" 12d677bfe2SMiquel Raynal 13d677bfe2SMiquel Raynal int pack_byte_string(u8 *str, size_t size, const char *format, ...) 14d677bfe2SMiquel Raynal { 15d677bfe2SMiquel Raynal va_list args; 16d677bfe2SMiquel Raynal size_t offset = 0, length = 0; 17d677bfe2SMiquel Raynal u8 *data = NULL; 18d677bfe2SMiquel Raynal u32 value = 0; 19d677bfe2SMiquel Raynal 20d677bfe2SMiquel Raynal va_start(args, format); 21d677bfe2SMiquel Raynal for (; *format; format++) { 22d677bfe2SMiquel Raynal switch (*format) { 23d677bfe2SMiquel Raynal case 'b': 24d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 25d677bfe2SMiquel Raynal value = va_arg(args, int); 26d677bfe2SMiquel Raynal length = 1; 27d677bfe2SMiquel Raynal break; 28d677bfe2SMiquel Raynal case 'w': 29d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 30d677bfe2SMiquel Raynal value = va_arg(args, int); 31d677bfe2SMiquel Raynal length = 2; 32d677bfe2SMiquel Raynal break; 33d677bfe2SMiquel Raynal case 'd': 34d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 35d677bfe2SMiquel Raynal value = va_arg(args, u32); 36d677bfe2SMiquel Raynal length = 4; 37d677bfe2SMiquel Raynal break; 38d677bfe2SMiquel Raynal case 's': 39d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 40d677bfe2SMiquel Raynal data = va_arg(args, u8 *); 41d677bfe2SMiquel Raynal length = va_arg(args, u32); 42d677bfe2SMiquel Raynal break; 43d677bfe2SMiquel Raynal default: 44d677bfe2SMiquel Raynal debug("Couldn't recognize format string\n"); 45d677bfe2SMiquel Raynal va_end(args); 46d677bfe2SMiquel Raynal return -1; 47d677bfe2SMiquel Raynal } 48d677bfe2SMiquel Raynal 49d677bfe2SMiquel Raynal if (offset + length > size) { 50d677bfe2SMiquel Raynal va_end(args); 51d677bfe2SMiquel Raynal return -1; 52d677bfe2SMiquel Raynal } 53d677bfe2SMiquel Raynal 54d677bfe2SMiquel Raynal switch (*format) { 55d677bfe2SMiquel Raynal case 'b': 56d677bfe2SMiquel Raynal str[offset] = value; 57d677bfe2SMiquel Raynal break; 58d677bfe2SMiquel Raynal case 'w': 59d677bfe2SMiquel Raynal put_unaligned_be16(value, str + offset); 60d677bfe2SMiquel Raynal break; 61d677bfe2SMiquel Raynal case 'd': 62d677bfe2SMiquel Raynal put_unaligned_be32(value, str + offset); 63d677bfe2SMiquel Raynal break; 64d677bfe2SMiquel Raynal case 's': 65d677bfe2SMiquel Raynal memcpy(str + offset, data, length); 66d677bfe2SMiquel Raynal break; 67d677bfe2SMiquel Raynal } 68d677bfe2SMiquel Raynal } 69d677bfe2SMiquel Raynal va_end(args); 70d677bfe2SMiquel Raynal 71d677bfe2SMiquel Raynal return 0; 72d677bfe2SMiquel Raynal } 73d677bfe2SMiquel Raynal 74d677bfe2SMiquel Raynal int unpack_byte_string(const u8 *str, size_t size, const char *format, ...) 75d677bfe2SMiquel Raynal { 76d677bfe2SMiquel Raynal va_list args; 77d677bfe2SMiquel Raynal size_t offset = 0, length = 0; 78d677bfe2SMiquel Raynal u8 *ptr8 = NULL; 79d677bfe2SMiquel Raynal u16 *ptr16 = NULL; 80d677bfe2SMiquel Raynal u32 *ptr32 = NULL; 81d677bfe2SMiquel Raynal 82d677bfe2SMiquel Raynal va_start(args, format); 83d677bfe2SMiquel Raynal for (; *format; format++) { 84d677bfe2SMiquel Raynal switch (*format) { 85d677bfe2SMiquel Raynal case 'b': 86d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 87d677bfe2SMiquel Raynal ptr8 = va_arg(args, u8 *); 88d677bfe2SMiquel Raynal length = 1; 89d677bfe2SMiquel Raynal break; 90d677bfe2SMiquel Raynal case 'w': 91d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 92d677bfe2SMiquel Raynal ptr16 = va_arg(args, u16 *); 93d677bfe2SMiquel Raynal length = 2; 94d677bfe2SMiquel Raynal break; 95d677bfe2SMiquel Raynal case 'd': 96d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 97d677bfe2SMiquel Raynal ptr32 = va_arg(args, u32 *); 98d677bfe2SMiquel Raynal length = 4; 99d677bfe2SMiquel Raynal break; 100d677bfe2SMiquel Raynal case 's': 101d677bfe2SMiquel Raynal offset = va_arg(args, size_t); 102d677bfe2SMiquel Raynal ptr8 = va_arg(args, u8 *); 103d677bfe2SMiquel Raynal length = va_arg(args, u32); 104d677bfe2SMiquel Raynal break; 105d677bfe2SMiquel Raynal default: 106d677bfe2SMiquel Raynal va_end(args); 107d677bfe2SMiquel Raynal debug("Couldn't recognize format string\n"); 108d677bfe2SMiquel Raynal return -1; 109d677bfe2SMiquel Raynal } 110d677bfe2SMiquel Raynal 111d677bfe2SMiquel Raynal if (offset + length > size) { 112d677bfe2SMiquel Raynal va_end(args); 113d677bfe2SMiquel Raynal return -1; 114d677bfe2SMiquel Raynal } 115d677bfe2SMiquel Raynal 116d677bfe2SMiquel Raynal switch (*format) { 117d677bfe2SMiquel Raynal case 'b': 118d677bfe2SMiquel Raynal *ptr8 = str[offset]; 119d677bfe2SMiquel Raynal break; 120d677bfe2SMiquel Raynal case 'w': 121d677bfe2SMiquel Raynal *ptr16 = get_unaligned_be16(str + offset); 122d677bfe2SMiquel Raynal break; 123d677bfe2SMiquel Raynal case 'd': 124d677bfe2SMiquel Raynal *ptr32 = get_unaligned_be32(str + offset); 125d677bfe2SMiquel Raynal break; 126d677bfe2SMiquel Raynal case 's': 127d677bfe2SMiquel Raynal memcpy(ptr8, str + offset, length); 128d677bfe2SMiquel Raynal break; 129d677bfe2SMiquel Raynal } 130d677bfe2SMiquel Raynal } 131d677bfe2SMiquel Raynal va_end(args); 132d677bfe2SMiquel Raynal 133d677bfe2SMiquel Raynal return 0; 134d677bfe2SMiquel Raynal } 135d677bfe2SMiquel Raynal 136d677bfe2SMiquel Raynal u32 tpm_command_size(const void *command) 137d677bfe2SMiquel Raynal { 138d677bfe2SMiquel Raynal const size_t command_size_offset = 2; 139d677bfe2SMiquel Raynal 140d677bfe2SMiquel Raynal return get_unaligned_be32(command + command_size_offset); 141d677bfe2SMiquel Raynal } 142d677bfe2SMiquel Raynal 143d677bfe2SMiquel Raynal u32 tpm_return_code(const void *response) 144d677bfe2SMiquel Raynal { 145d677bfe2SMiquel Raynal const size_t return_code_offset = 6; 146d677bfe2SMiquel Raynal 147d677bfe2SMiquel Raynal return get_unaligned_be32(response + return_code_offset); 148d677bfe2SMiquel Raynal } 149d677bfe2SMiquel Raynal 150d677bfe2SMiquel Raynal u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr) 151d677bfe2SMiquel Raynal { 152d677bfe2SMiquel Raynal struct udevice *dev; 153d677bfe2SMiquel Raynal int err, ret; 154d677bfe2SMiquel Raynal u8 response_buffer[COMMAND_BUFFER_SIZE]; 155d677bfe2SMiquel Raynal size_t response_length; 156aa643013SMiquel Raynal int i; 157d677bfe2SMiquel Raynal 158d677bfe2SMiquel Raynal if (response) { 159d677bfe2SMiquel Raynal response_length = *size_ptr; 160d677bfe2SMiquel Raynal } else { 161d677bfe2SMiquel Raynal response = response_buffer; 162d677bfe2SMiquel Raynal response_length = sizeof(response_buffer); 163d677bfe2SMiquel Raynal } 164d677bfe2SMiquel Raynal 165d677bfe2SMiquel Raynal ret = uclass_first_device_err(UCLASS_TPM, &dev); 166d677bfe2SMiquel Raynal if (ret) 167d677bfe2SMiquel Raynal return ret; 168d677bfe2SMiquel Raynal err = tpm_xfer(dev, command, tpm_command_size(command), 169d677bfe2SMiquel Raynal response, &response_length); 170d677bfe2SMiquel Raynal 171d677bfe2SMiquel Raynal if (err < 0) 172*bcdf6b9fSMiquel Raynal return err; 173*bcdf6b9fSMiquel Raynal 174d677bfe2SMiquel Raynal if (size_ptr) 175d677bfe2SMiquel Raynal *size_ptr = response_length; 176d677bfe2SMiquel Raynal 177aa643013SMiquel Raynal ret = tpm_return_code(response); 178aa643013SMiquel Raynal 179aa643013SMiquel Raynal log(LOGC_NONE, LOGL_DEBUG, "TPM response [ret:%d]: ", ret); 180aa643013SMiquel Raynal for (i = 0; i < response_length; i++) 181aa643013SMiquel Raynal log(LOGC_NONE, LOGL_DEBUG, "%02x ", ((u8 *)response)[i]); 182aa643013SMiquel Raynal log(LOGC_NONE, LOGL_DEBUG, "\n"); 183aa643013SMiquel Raynal 184aa643013SMiquel Raynal return ret; 185d677bfe2SMiquel Raynal } 186d677bfe2SMiquel Raynal 187d677bfe2SMiquel Raynal int tpm_init(void) 188d677bfe2SMiquel Raynal { 189d677bfe2SMiquel Raynal struct udevice *dev; 190d677bfe2SMiquel Raynal int err; 191d677bfe2SMiquel Raynal 192d677bfe2SMiquel Raynal err = uclass_first_device_err(UCLASS_TPM, &dev); 193d677bfe2SMiquel Raynal if (err) 194d677bfe2SMiquel Raynal return err; 195d677bfe2SMiquel Raynal 196d677bfe2SMiquel Raynal return tpm_open(dev); 197d677bfe2SMiquel Raynal } 198