1d677bfe2SMiquel Raynal // SPDX-License-Identifier: GPL-2.0+
2d677bfe2SMiquel Raynal /*
3d677bfe2SMiquel Raynal * Copyright (c) 2013 The Chromium OS Authors.
4d677bfe2SMiquel Raynal * Coypright (c) 2013 Guntermann & Drunck GmbH
5d677bfe2SMiquel Raynal */
6d677bfe2SMiquel Raynal
734a5e8a2SSimon Glass #define LOG_CATEGORY UCLASS_TPM
834a5e8a2SSimon Glass
9d677bfe2SMiquel Raynal #include <common.h>
10d677bfe2SMiquel Raynal #include <dm.h>
11d677bfe2SMiquel Raynal #include <asm/unaligned.h>
12d677bfe2SMiquel Raynal #include <tpm-common.h>
13d677bfe2SMiquel Raynal #include "tpm-utils.h"
14d677bfe2SMiquel Raynal
tpm_get_version(struct udevice * dev)150a60a0a6SSimon Glass enum tpm_version tpm_get_version(struct udevice *dev)
160a60a0a6SSimon Glass {
170a60a0a6SSimon Glass struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
180a60a0a6SSimon Glass
190a60a0a6SSimon Glass return priv->version;
200a60a0a6SSimon Glass }
210a60a0a6SSimon Glass
pack_byte_string(u8 * str,size_t size,const char * format,...)22d677bfe2SMiquel Raynal int pack_byte_string(u8 *str, size_t size, const char *format, ...)
23d677bfe2SMiquel Raynal {
24d677bfe2SMiquel Raynal va_list args;
25d677bfe2SMiquel Raynal size_t offset = 0, length = 0;
26d677bfe2SMiquel Raynal u8 *data = NULL;
27d677bfe2SMiquel Raynal u32 value = 0;
28d677bfe2SMiquel Raynal
29d677bfe2SMiquel Raynal va_start(args, format);
30d677bfe2SMiquel Raynal for (; *format; format++) {
31d677bfe2SMiquel Raynal switch (*format) {
32d677bfe2SMiquel Raynal case 'b':
33d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
34d677bfe2SMiquel Raynal value = va_arg(args, int);
35d677bfe2SMiquel Raynal length = 1;
36d677bfe2SMiquel Raynal break;
37d677bfe2SMiquel Raynal case 'w':
38d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
39d677bfe2SMiquel Raynal value = va_arg(args, int);
40d677bfe2SMiquel Raynal length = 2;
41d677bfe2SMiquel Raynal break;
42d677bfe2SMiquel Raynal case 'd':
43d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
44d677bfe2SMiquel Raynal value = va_arg(args, u32);
45d677bfe2SMiquel Raynal length = 4;
46d677bfe2SMiquel Raynal break;
47d677bfe2SMiquel Raynal case 's':
48d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
49d677bfe2SMiquel Raynal data = va_arg(args, u8 *);
50d677bfe2SMiquel Raynal length = va_arg(args, u32);
51d677bfe2SMiquel Raynal break;
52d677bfe2SMiquel Raynal default:
53d677bfe2SMiquel Raynal debug("Couldn't recognize format string\n");
54d677bfe2SMiquel Raynal va_end(args);
55d677bfe2SMiquel Raynal return -1;
56d677bfe2SMiquel Raynal }
57d677bfe2SMiquel Raynal
58d677bfe2SMiquel Raynal if (offset + length > size) {
59d677bfe2SMiquel Raynal va_end(args);
60d677bfe2SMiquel Raynal return -1;
61d677bfe2SMiquel Raynal }
62d677bfe2SMiquel Raynal
63d677bfe2SMiquel Raynal switch (*format) {
64d677bfe2SMiquel Raynal case 'b':
65d677bfe2SMiquel Raynal str[offset] = value;
66d677bfe2SMiquel Raynal break;
67d677bfe2SMiquel Raynal case 'w':
68d677bfe2SMiquel Raynal put_unaligned_be16(value, str + offset);
69d677bfe2SMiquel Raynal break;
70d677bfe2SMiquel Raynal case 'd':
71d677bfe2SMiquel Raynal put_unaligned_be32(value, str + offset);
72d677bfe2SMiquel Raynal break;
73d677bfe2SMiquel Raynal case 's':
74d677bfe2SMiquel Raynal memcpy(str + offset, data, length);
75d677bfe2SMiquel Raynal break;
76d677bfe2SMiquel Raynal }
77d677bfe2SMiquel Raynal }
78d677bfe2SMiquel Raynal va_end(args);
79d677bfe2SMiquel Raynal
80d677bfe2SMiquel Raynal return 0;
81d677bfe2SMiquel Raynal }
82d677bfe2SMiquel Raynal
unpack_byte_string(const u8 * str,size_t size,const char * format,...)83d677bfe2SMiquel Raynal int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
84d677bfe2SMiquel Raynal {
85d677bfe2SMiquel Raynal va_list args;
86d677bfe2SMiquel Raynal size_t offset = 0, length = 0;
87d677bfe2SMiquel Raynal u8 *ptr8 = NULL;
88d677bfe2SMiquel Raynal u16 *ptr16 = NULL;
89d677bfe2SMiquel Raynal u32 *ptr32 = NULL;
90d677bfe2SMiquel Raynal
91d677bfe2SMiquel Raynal va_start(args, format);
92d677bfe2SMiquel Raynal for (; *format; format++) {
93d677bfe2SMiquel Raynal switch (*format) {
94d677bfe2SMiquel Raynal case 'b':
95d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
96d677bfe2SMiquel Raynal ptr8 = va_arg(args, u8 *);
97d677bfe2SMiquel Raynal length = 1;
98d677bfe2SMiquel Raynal break;
99d677bfe2SMiquel Raynal case 'w':
100d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
101d677bfe2SMiquel Raynal ptr16 = va_arg(args, u16 *);
102d677bfe2SMiquel Raynal length = 2;
103d677bfe2SMiquel Raynal break;
104d677bfe2SMiquel Raynal case 'd':
105d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
106d677bfe2SMiquel Raynal ptr32 = va_arg(args, u32 *);
107d677bfe2SMiquel Raynal length = 4;
108d677bfe2SMiquel Raynal break;
109d677bfe2SMiquel Raynal case 's':
110d677bfe2SMiquel Raynal offset = va_arg(args, size_t);
111d677bfe2SMiquel Raynal ptr8 = va_arg(args, u8 *);
112d677bfe2SMiquel Raynal length = va_arg(args, u32);
113d677bfe2SMiquel Raynal break;
114d677bfe2SMiquel Raynal default:
115d677bfe2SMiquel Raynal va_end(args);
116d677bfe2SMiquel Raynal debug("Couldn't recognize format string\n");
117d677bfe2SMiquel Raynal return -1;
118d677bfe2SMiquel Raynal }
119d677bfe2SMiquel Raynal
120d677bfe2SMiquel Raynal if (offset + length > size) {
121d677bfe2SMiquel Raynal va_end(args);
122*5092af6bSSimon Glass log_err("Failed to read: size=%zd, offset=%zx, len=%zx\n",
12334a5e8a2SSimon Glass size, offset, length);
124d677bfe2SMiquel Raynal return -1;
125d677bfe2SMiquel Raynal }
126d677bfe2SMiquel Raynal
127d677bfe2SMiquel Raynal switch (*format) {
128d677bfe2SMiquel Raynal case 'b':
129d677bfe2SMiquel Raynal *ptr8 = str[offset];
130d677bfe2SMiquel Raynal break;
131d677bfe2SMiquel Raynal case 'w':
132d677bfe2SMiquel Raynal *ptr16 = get_unaligned_be16(str + offset);
133d677bfe2SMiquel Raynal break;
134d677bfe2SMiquel Raynal case 'd':
135d677bfe2SMiquel Raynal *ptr32 = get_unaligned_be32(str + offset);
136d677bfe2SMiquel Raynal break;
137d677bfe2SMiquel Raynal case 's':
138d677bfe2SMiquel Raynal memcpy(ptr8, str + offset, length);
139d677bfe2SMiquel Raynal break;
140d677bfe2SMiquel Raynal }
141d677bfe2SMiquel Raynal }
142d677bfe2SMiquel Raynal va_end(args);
143d677bfe2SMiquel Raynal
144d677bfe2SMiquel Raynal return 0;
145d677bfe2SMiquel Raynal }
146d677bfe2SMiquel Raynal
tpm_command_size(const void * command)147d677bfe2SMiquel Raynal u32 tpm_command_size(const void *command)
148d677bfe2SMiquel Raynal {
149d677bfe2SMiquel Raynal const size_t command_size_offset = 2;
150d677bfe2SMiquel Raynal
151d677bfe2SMiquel Raynal return get_unaligned_be32(command + command_size_offset);
152d677bfe2SMiquel Raynal }
153d677bfe2SMiquel Raynal
tpm_return_code(const void * response)154d677bfe2SMiquel Raynal u32 tpm_return_code(const void *response)
155d677bfe2SMiquel Raynal {
156d677bfe2SMiquel Raynal const size_t return_code_offset = 6;
157d677bfe2SMiquel Raynal
158d677bfe2SMiquel Raynal return get_unaligned_be32(response + return_code_offset);
159d677bfe2SMiquel Raynal }
160d677bfe2SMiquel Raynal
tpm_sendrecv_command(struct udevice * dev,const void * command,void * response,size_t * size_ptr)161abdc7b8aSSimon Glass u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
162abdc7b8aSSimon Glass void *response, size_t *size_ptr)
163d677bfe2SMiquel Raynal {
164d677bfe2SMiquel Raynal int err, ret;
165d677bfe2SMiquel Raynal u8 response_buffer[COMMAND_BUFFER_SIZE];
166d677bfe2SMiquel Raynal size_t response_length;
167aa643013SMiquel Raynal int i;
168d677bfe2SMiquel Raynal
169d677bfe2SMiquel Raynal if (response) {
170d677bfe2SMiquel Raynal response_length = *size_ptr;
171d677bfe2SMiquel Raynal } else {
172d677bfe2SMiquel Raynal response = response_buffer;
173d677bfe2SMiquel Raynal response_length = sizeof(response_buffer);
174d677bfe2SMiquel Raynal }
175d677bfe2SMiquel Raynal
176d677bfe2SMiquel Raynal err = tpm_xfer(dev, command, tpm_command_size(command),
177d677bfe2SMiquel Raynal response, &response_length);
178d677bfe2SMiquel Raynal
179d677bfe2SMiquel Raynal if (err < 0)
180bcdf6b9fSMiquel Raynal return err;
181bcdf6b9fSMiquel Raynal
182d677bfe2SMiquel Raynal if (size_ptr)
183d677bfe2SMiquel Raynal *size_ptr = response_length;
184d677bfe2SMiquel Raynal
185aa643013SMiquel Raynal ret = tpm_return_code(response);
186aa643013SMiquel Raynal
18734a5e8a2SSimon Glass log_debug("TPM response [ret:%d]: ", ret);
188aa643013SMiquel Raynal for (i = 0; i < response_length; i++)
18934a5e8a2SSimon Glass log_debug("%02x ", ((u8 *)response)[i]);
19034a5e8a2SSimon Glass log_debug("\n");
191aa643013SMiquel Raynal
192aa643013SMiquel Raynal return ret;
193d677bfe2SMiquel Raynal }
194d677bfe2SMiquel Raynal
tpm_init(struct udevice * dev)195abdc7b8aSSimon Glass int tpm_init(struct udevice *dev)
196d677bfe2SMiquel Raynal {
197d677bfe2SMiquel Raynal return tpm_open(dev);
198d677bfe2SMiquel Raynal }
199