blob: b592c22bfc132a790c320dc892945e12c44c99c5 [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
Simon Glass70e59cc2018-10-01 12:22:28 -06007#define LOG_CATEGORY UCLASS_TPM
8
Miquel Raynal4c6759e2018-05-15 11:57:06 +02009#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Miquel Raynal4c6759e2018-05-15 11:57:06 +020011#include <asm/unaligned.h>
12#include <tpm-common.h>
13#include "tpm-utils.h"
14
Simon Glasse03dbde2018-11-23 21:29:32 -070015enum tpm_version tpm_get_version(struct udevice *dev)
16{
17 struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
18
19 return priv->version;
20}
21
Miquel Raynal4c6759e2018-05-15 11:57:06 +020022int pack_byte_string(u8 *str, size_t size, const char *format, ...)
23{
24 va_list args;
25 size_t offset = 0, length = 0;
26 u8 *data = NULL;
27 u32 value = 0;
28
29 va_start(args, format);
30 for (; *format; format++) {
31 switch (*format) {
32 case 'b':
33 offset = va_arg(args, size_t);
34 value = va_arg(args, int);
35 length = 1;
36 break;
37 case 'w':
38 offset = va_arg(args, size_t);
39 value = va_arg(args, int);
40 length = 2;
41 break;
42 case 'd':
43 offset = va_arg(args, size_t);
44 value = va_arg(args, u32);
45 length = 4;
46 break;
47 case 's':
48 offset = va_arg(args, size_t);
49 data = va_arg(args, u8 *);
50 length = va_arg(args, u32);
51 break;
52 default:
53 debug("Couldn't recognize format string\n");
54 va_end(args);
55 return -1;
56 }
57
58 if (offset + length > size) {
59 va_end(args);
60 return -1;
61 }
62
63 switch (*format) {
64 case 'b':
65 str[offset] = value;
66 break;
67 case 'w':
68 put_unaligned_be16(value, str + offset);
69 break;
70 case 'd':
71 put_unaligned_be32(value, str + offset);
72 break;
73 case 's':
74 memcpy(str + offset, data, length);
75 break;
76 }
77 }
78 va_end(args);
79
80 return 0;
81}
82
83int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
84{
85 va_list args;
86 size_t offset = 0, length = 0;
87 u8 *ptr8 = NULL;
88 u16 *ptr16 = NULL;
89 u32 *ptr32 = NULL;
90
91 va_start(args, format);
92 for (; *format; format++) {
93 switch (*format) {
94 case 'b':
95 offset = va_arg(args, size_t);
96 ptr8 = va_arg(args, u8 *);
97 length = 1;
98 break;
99 case 'w':
100 offset = va_arg(args, size_t);
101 ptr16 = va_arg(args, u16 *);
102 length = 2;
103 break;
104 case 'd':
105 offset = va_arg(args, size_t);
106 ptr32 = va_arg(args, u32 *);
107 length = 4;
108 break;
109 case 's':
110 offset = va_arg(args, size_t);
111 ptr8 = va_arg(args, u8 *);
112 length = va_arg(args, u32);
113 break;
114 default:
115 va_end(args);
116 debug("Couldn't recognize format string\n");
117 return -1;
118 }
119
120 if (offset + length > size) {
121 va_end(args);
Simon Glasse26b6852018-11-23 21:29:35 -0700122 log_err("Failed to read: size=%zd, offset=%zx, len=%zx\n",
Simon Glass70e59cc2018-10-01 12:22:28 -0600123 size, offset, length);
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200124 return -1;
125 }
126
127 switch (*format) {
128 case 'b':
129 *ptr8 = str[offset];
130 break;
131 case 'w':
132 *ptr16 = get_unaligned_be16(str + offset);
133 break;
134 case 'd':
135 *ptr32 = get_unaligned_be32(str + offset);
136 break;
137 case 's':
138 memcpy(ptr8, str + offset, length);
139 break;
140 }
141 }
142 va_end(args);
143
144 return 0;
145}
146
147u32 tpm_command_size(const void *command)
148{
149 const size_t command_size_offset = 2;
150
151 return get_unaligned_be32(command + command_size_offset);
152}
153
154u32 tpm_return_code(const void *response)
155{
156 const size_t return_code_offset = 6;
157
158 return get_unaligned_be32(response + return_code_offset);
159}
160
Simon Glass8ceca1d2018-11-18 14:22:27 -0700161u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
162 void *response, size_t *size_ptr)
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200163{
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200164 int err, ret;
165 u8 response_buffer[COMMAND_BUFFER_SIZE];
166 size_t response_length;
Miquel Raynal3eec0882018-05-15 11:57:10 +0200167 int i;
Simon Glass94e37a32021-02-06 14:23:34 -0700168 uint size;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200169
170 if (response) {
171 response_length = *size_ptr;
172 } else {
173 response = response_buffer;
174 response_length = sizeof(response_buffer);
175 }
176
Simon Glass94e37a32021-02-06 14:23:34 -0700177 size = tpm_command_size(command);
Simon Glasse463bb32021-05-13 19:39:29 -0600178
179 /* sanity check, which also helps coverity */
180 if (size > COMMAND_BUFFER_SIZE)
181 return log_msg_ret("size", -E2BIG);
182
Simon Glass94e37a32021-02-06 14:23:34 -0700183 log_debug("TPM request [size:%d]: ", size);
184 for (i = 0; i < size; i++)
185 log_debug("%02x ", ((u8 *)command)[i]);
186 log_debug("\n");
187
188 err = tpm_xfer(dev, command, size, response, &response_length);
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200189
190 if (err < 0)
Miquel Raynal68b3f832018-05-15 11:57:11 +0200191 return err;
192
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200193 if (size_ptr)
194 *size_ptr = response_length;
195
Miquel Raynal3eec0882018-05-15 11:57:10 +0200196 ret = tpm_return_code(response);
197
Simon Glass70e59cc2018-10-01 12:22:28 -0600198 log_debug("TPM response [ret:%d]: ", ret);
Miquel Raynal3eec0882018-05-15 11:57:10 +0200199 for (i = 0; i < response_length; i++)
Simon Glass70e59cc2018-10-01 12:22:28 -0600200 log_debug("%02x ", ((u8 *)response)[i]);
201 log_debug("\n");
Miquel Raynal3eec0882018-05-15 11:57:10 +0200202
203 return ret;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200204}
205
Simon Glass8ceca1d2018-11-18 14:22:27 -0700206int tpm_init(struct udevice *dev)
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200207{
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200208 return tpm_open(dev);
209}