blob: 43b530865a0c4e7c01d32d66f5f43fe1702afe83 [file] [log] [blame]
Miquel Raynal4c6759e2018-05-15 11:57:06 +02001// 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
13int 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
74int 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
136u32 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
143u32 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
150u32 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;
Miquel Raynal3eec0882018-05-15 11:57:10 +0200156 int i;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200157
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)
Miquel Raynal68b3f832018-05-15 11:57:11 +0200172 return err;
173
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200174 if (size_ptr)
175 *size_ptr = response_length;
176
Miquel Raynal3eec0882018-05-15 11:57:10 +0200177 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;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200185}
186
187int 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}