blob: a440639cec302fc23d7a0fc31f2f82e2ab9f12ed [file] [log] [blame]
Miquel Raynald677bfe2018-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
Simon Glass34a5e8a2018-10-01 12:22:28 -06007#define LOG_CATEGORY UCLASS_TPM
8
Miquel Raynald677bfe2018-05-15 11:57:06 +02009#include <common.h>
10#include <dm.h>
11#include <asm/unaligned.h>
12#include <tpm-common.h>
13#include "tpm-utils.h"
14
15int 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
76int 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);
Simon Glass34a5e8a2018-10-01 12:22:28 -0600115 log_err("Failed to read: size=%d, offset=%x, len=%x\n",
116 size, offset, length);
Miquel Raynald677bfe2018-05-15 11:57:06 +0200117 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
140u32 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
147u32 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
154u32 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;
Miquel Raynalaa643012018-05-15 11:57:10 +0200160 int i;
Miquel Raynald677bfe2018-05-15 11:57:06 +0200161
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)
Miquel Raynalbcdf6b92018-05-15 11:57:11 +0200176 return err;
177
Miquel Raynald677bfe2018-05-15 11:57:06 +0200178 if (size_ptr)
179 *size_ptr = response_length;
180
Miquel Raynalaa643012018-05-15 11:57:10 +0200181 ret = tpm_return_code(response);
182
Simon Glass34a5e8a2018-10-01 12:22:28 -0600183 log_debug("TPM response [ret:%d]: ", ret);
Miquel Raynalaa643012018-05-15 11:57:10 +0200184 for (i = 0; i < response_length; i++)
Simon Glass34a5e8a2018-10-01 12:22:28 -0600185 log_debug("%02x ", ((u8 *)response)[i]);
186 log_debug("\n");
Miquel Raynalaa643012018-05-15 11:57:10 +0200187
188 return ret;
Miquel Raynald677bfe2018-05-15 11:57:06 +0200189}
190
191int 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}