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