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