blob: 82ffdc5341bce21aecbd088d1921b73f93f15f2c [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 <common.h>
10#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Miquel Raynal4c6759e2018-05-15 11:57:06 +020012#include <asm/unaligned.h>
13#include <tpm-common.h>
14#include "tpm-utils.h"
15
Simon Glasse03dbde2018-11-23 21:29:32 -070016enum 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
Miquel Raynal4c6759e2018-05-15 11:57:06 +020023int 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
84int 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);
Simon Glasse26b6852018-11-23 21:29:35 -0700123 log_err("Failed to read: size=%zd, offset=%zx, len=%zx\n",
Simon Glass70e59cc2018-10-01 12:22:28 -0600124 size, offset, length);
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200125 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
148u32 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
155u32 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
Simon Glass8ceca1d2018-11-18 14:22:27 -0700162u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
163 void *response, size_t *size_ptr)
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200164{
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200165 int err, ret;
166 u8 response_buffer[COMMAND_BUFFER_SIZE];
167 size_t response_length;
Miquel Raynal3eec0882018-05-15 11:57:10 +0200168 int i;
Simon Glass94e37a32021-02-06 14:23:34 -0700169 uint size;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200170
171 if (response) {
172 response_length = *size_ptr;
173 } else {
174 response = response_buffer;
175 response_length = sizeof(response_buffer);
176 }
177
Simon Glass94e37a32021-02-06 14:23:34 -0700178 size = tpm_command_size(command);
Simon Glasse463bb32021-05-13 19:39:29 -0600179
180 /* sanity check, which also helps coverity */
181 if (size > COMMAND_BUFFER_SIZE)
182 return log_msg_ret("size", -E2BIG);
183
Simon Glass94e37a32021-02-06 14:23:34 -0700184 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);
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200190
191 if (err < 0)
Miquel Raynal68b3f832018-05-15 11:57:11 +0200192 return err;
193
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200194 if (size_ptr)
195 *size_ptr = response_length;
196
Miquel Raynal3eec0882018-05-15 11:57:10 +0200197 ret = tpm_return_code(response);
198
Simon Glass70e59cc2018-10-01 12:22:28 -0600199 log_debug("TPM response [ret:%d]: ", ret);
Miquel Raynal3eec0882018-05-15 11:57:10 +0200200 for (i = 0; i < response_length; i++)
Simon Glass70e59cc2018-10-01 12:22:28 -0600201 log_debug("%02x ", ((u8 *)response)[i]);
202 log_debug("\n");
Miquel Raynal3eec0882018-05-15 11:57:10 +0200203
204 return ret;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200205}
206
Simon Glass8ceca1d2018-11-18 14:22:27 -0700207int tpm_init(struct udevice *dev)
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200208{
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200209 return tpm_open(dev);
210}