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