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