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
pack_byte_string(u8 * str,size_t size,const char * format,...)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
unpack_byte_string(const u8 * str,size_t size,const char * format,...)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
tpm_command_size(const void * command)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
tpm_return_code(const void * response)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
tpm_sendrecv_command(const void * command,void * response,size_t * size_ptr)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
tpm_init(void)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