xref: /openbmc/u-boot/lib/tpm-common.c (revision bcdf6b9f26fe9cd452f5f309a6e410ea4513e60b)
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 
7d677bfe2SMiquel Raynal #include <common.h>
8d677bfe2SMiquel Raynal #include <dm.h>
9d677bfe2SMiquel Raynal #include <asm/unaligned.h>
10d677bfe2SMiquel Raynal #include <tpm-common.h>
11d677bfe2SMiquel Raynal #include "tpm-utils.h"
12d677bfe2SMiquel Raynal 
13d677bfe2SMiquel Raynal int pack_byte_string(u8 *str, size_t size, const char *format, ...)
14d677bfe2SMiquel Raynal {
15d677bfe2SMiquel Raynal 	va_list args;
16d677bfe2SMiquel Raynal 	size_t offset = 0, length = 0;
17d677bfe2SMiquel Raynal 	u8 *data = NULL;
18d677bfe2SMiquel Raynal 	u32 value = 0;
19d677bfe2SMiquel Raynal 
20d677bfe2SMiquel Raynal 	va_start(args, format);
21d677bfe2SMiquel Raynal 	for (; *format; format++) {
22d677bfe2SMiquel Raynal 		switch (*format) {
23d677bfe2SMiquel Raynal 		case 'b':
24d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
25d677bfe2SMiquel Raynal 			value = va_arg(args, int);
26d677bfe2SMiquel Raynal 			length = 1;
27d677bfe2SMiquel Raynal 			break;
28d677bfe2SMiquel Raynal 		case 'w':
29d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
30d677bfe2SMiquel Raynal 			value = va_arg(args, int);
31d677bfe2SMiquel Raynal 			length = 2;
32d677bfe2SMiquel Raynal 			break;
33d677bfe2SMiquel Raynal 		case 'd':
34d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
35d677bfe2SMiquel Raynal 			value = va_arg(args, u32);
36d677bfe2SMiquel Raynal 			length = 4;
37d677bfe2SMiquel Raynal 			break;
38d677bfe2SMiquel Raynal 		case 's':
39d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
40d677bfe2SMiquel Raynal 			data = va_arg(args, u8 *);
41d677bfe2SMiquel Raynal 			length = va_arg(args, u32);
42d677bfe2SMiquel Raynal 			break;
43d677bfe2SMiquel Raynal 		default:
44d677bfe2SMiquel Raynal 			debug("Couldn't recognize format string\n");
45d677bfe2SMiquel Raynal 			va_end(args);
46d677bfe2SMiquel Raynal 			return -1;
47d677bfe2SMiquel Raynal 		}
48d677bfe2SMiquel Raynal 
49d677bfe2SMiquel Raynal 		if (offset + length > size) {
50d677bfe2SMiquel Raynal 			va_end(args);
51d677bfe2SMiquel Raynal 			return -1;
52d677bfe2SMiquel Raynal 		}
53d677bfe2SMiquel Raynal 
54d677bfe2SMiquel Raynal 		switch (*format) {
55d677bfe2SMiquel Raynal 		case 'b':
56d677bfe2SMiquel Raynal 			str[offset] = value;
57d677bfe2SMiquel Raynal 			break;
58d677bfe2SMiquel Raynal 		case 'w':
59d677bfe2SMiquel Raynal 			put_unaligned_be16(value, str + offset);
60d677bfe2SMiquel Raynal 			break;
61d677bfe2SMiquel Raynal 		case 'd':
62d677bfe2SMiquel Raynal 			put_unaligned_be32(value, str + offset);
63d677bfe2SMiquel Raynal 			break;
64d677bfe2SMiquel Raynal 		case 's':
65d677bfe2SMiquel Raynal 			memcpy(str + offset, data, length);
66d677bfe2SMiquel Raynal 			break;
67d677bfe2SMiquel Raynal 		}
68d677bfe2SMiquel Raynal 	}
69d677bfe2SMiquel Raynal 	va_end(args);
70d677bfe2SMiquel Raynal 
71d677bfe2SMiquel Raynal 	return 0;
72d677bfe2SMiquel Raynal }
73d677bfe2SMiquel Raynal 
74d677bfe2SMiquel Raynal int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
75d677bfe2SMiquel Raynal {
76d677bfe2SMiquel Raynal 	va_list args;
77d677bfe2SMiquel Raynal 	size_t offset = 0, length = 0;
78d677bfe2SMiquel Raynal 	u8 *ptr8 = NULL;
79d677bfe2SMiquel Raynal 	u16 *ptr16 = NULL;
80d677bfe2SMiquel Raynal 	u32 *ptr32 = NULL;
81d677bfe2SMiquel Raynal 
82d677bfe2SMiquel Raynal 	va_start(args, format);
83d677bfe2SMiquel Raynal 	for (; *format; format++) {
84d677bfe2SMiquel Raynal 		switch (*format) {
85d677bfe2SMiquel Raynal 		case 'b':
86d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
87d677bfe2SMiquel Raynal 			ptr8 = va_arg(args, u8 *);
88d677bfe2SMiquel Raynal 			length = 1;
89d677bfe2SMiquel Raynal 			break;
90d677bfe2SMiquel Raynal 		case 'w':
91d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
92d677bfe2SMiquel Raynal 			ptr16 = va_arg(args, u16 *);
93d677bfe2SMiquel Raynal 			length = 2;
94d677bfe2SMiquel Raynal 			break;
95d677bfe2SMiquel Raynal 		case 'd':
96d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
97d677bfe2SMiquel Raynal 			ptr32 = va_arg(args, u32 *);
98d677bfe2SMiquel Raynal 			length = 4;
99d677bfe2SMiquel Raynal 			break;
100d677bfe2SMiquel Raynal 		case 's':
101d677bfe2SMiquel Raynal 			offset = va_arg(args, size_t);
102d677bfe2SMiquel Raynal 			ptr8 = va_arg(args, u8 *);
103d677bfe2SMiquel Raynal 			length = va_arg(args, u32);
104d677bfe2SMiquel Raynal 			break;
105d677bfe2SMiquel Raynal 		default:
106d677bfe2SMiquel Raynal 			va_end(args);
107d677bfe2SMiquel Raynal 			debug("Couldn't recognize format string\n");
108d677bfe2SMiquel Raynal 			return -1;
109d677bfe2SMiquel Raynal 		}
110d677bfe2SMiquel Raynal 
111d677bfe2SMiquel Raynal 		if (offset + length > size) {
112d677bfe2SMiquel Raynal 			va_end(args);
113d677bfe2SMiquel Raynal 			return -1;
114d677bfe2SMiquel Raynal 		}
115d677bfe2SMiquel Raynal 
116d677bfe2SMiquel Raynal 		switch (*format) {
117d677bfe2SMiquel Raynal 		case 'b':
118d677bfe2SMiquel Raynal 			*ptr8 = str[offset];
119d677bfe2SMiquel Raynal 			break;
120d677bfe2SMiquel Raynal 		case 'w':
121d677bfe2SMiquel Raynal 			*ptr16 = get_unaligned_be16(str + offset);
122d677bfe2SMiquel Raynal 			break;
123d677bfe2SMiquel Raynal 		case 'd':
124d677bfe2SMiquel Raynal 			*ptr32 = get_unaligned_be32(str + offset);
125d677bfe2SMiquel Raynal 			break;
126d677bfe2SMiquel Raynal 		case 's':
127d677bfe2SMiquel Raynal 			memcpy(ptr8, str + offset, length);
128d677bfe2SMiquel Raynal 			break;
129d677bfe2SMiquel Raynal 		}
130d677bfe2SMiquel Raynal 	}
131d677bfe2SMiquel Raynal 	va_end(args);
132d677bfe2SMiquel Raynal 
133d677bfe2SMiquel Raynal 	return 0;
134d677bfe2SMiquel Raynal }
135d677bfe2SMiquel Raynal 
136d677bfe2SMiquel Raynal u32 tpm_command_size(const void *command)
137d677bfe2SMiquel Raynal {
138d677bfe2SMiquel Raynal 	const size_t command_size_offset = 2;
139d677bfe2SMiquel Raynal 
140d677bfe2SMiquel Raynal 	return get_unaligned_be32(command + command_size_offset);
141d677bfe2SMiquel Raynal }
142d677bfe2SMiquel Raynal 
143d677bfe2SMiquel Raynal u32 tpm_return_code(const void *response)
144d677bfe2SMiquel Raynal {
145d677bfe2SMiquel Raynal 	const size_t return_code_offset = 6;
146d677bfe2SMiquel Raynal 
147d677bfe2SMiquel Raynal 	return get_unaligned_be32(response + return_code_offset);
148d677bfe2SMiquel Raynal }
149d677bfe2SMiquel Raynal 
150d677bfe2SMiquel Raynal u32 tpm_sendrecv_command(const void *command, void *response, size_t *size_ptr)
151d677bfe2SMiquel Raynal {
152d677bfe2SMiquel Raynal 	struct udevice *dev;
153d677bfe2SMiquel Raynal 	int err, ret;
154d677bfe2SMiquel Raynal 	u8 response_buffer[COMMAND_BUFFER_SIZE];
155d677bfe2SMiquel Raynal 	size_t response_length;
156aa643013SMiquel Raynal 	int i;
157d677bfe2SMiquel Raynal 
158d677bfe2SMiquel Raynal 	if (response) {
159d677bfe2SMiquel Raynal 		response_length = *size_ptr;
160d677bfe2SMiquel Raynal 	} else {
161d677bfe2SMiquel Raynal 		response = response_buffer;
162d677bfe2SMiquel Raynal 		response_length = sizeof(response_buffer);
163d677bfe2SMiquel Raynal 	}
164d677bfe2SMiquel Raynal 
165d677bfe2SMiquel Raynal 	ret = uclass_first_device_err(UCLASS_TPM, &dev);
166d677bfe2SMiquel Raynal 	if (ret)
167d677bfe2SMiquel Raynal 		return ret;
168d677bfe2SMiquel Raynal 	err = tpm_xfer(dev, command, tpm_command_size(command),
169d677bfe2SMiquel Raynal 		       response, &response_length);
170d677bfe2SMiquel Raynal 
171d677bfe2SMiquel Raynal 	if (err < 0)
172*bcdf6b9fSMiquel Raynal 		return err;
173*bcdf6b9fSMiquel Raynal 
174d677bfe2SMiquel Raynal 	if (size_ptr)
175d677bfe2SMiquel Raynal 		*size_ptr = response_length;
176d677bfe2SMiquel Raynal 
177aa643013SMiquel Raynal 	ret = tpm_return_code(response);
178aa643013SMiquel Raynal 
179aa643013SMiquel Raynal 	log(LOGC_NONE, LOGL_DEBUG, "TPM response [ret:%d]: ", ret);
180aa643013SMiquel Raynal 	for (i = 0; i < response_length; i++)
181aa643013SMiquel Raynal 		log(LOGC_NONE, LOGL_DEBUG, "%02x ", ((u8 *)response)[i]);
182aa643013SMiquel Raynal 	log(LOGC_NONE, LOGL_DEBUG, "\n");
183aa643013SMiquel Raynal 
184aa643013SMiquel Raynal 	return ret;
185d677bfe2SMiquel Raynal }
186d677bfe2SMiquel Raynal 
187d677bfe2SMiquel Raynal int tpm_init(void)
188d677bfe2SMiquel Raynal {
189d677bfe2SMiquel Raynal 	struct udevice *dev;
190d677bfe2SMiquel Raynal 	int err;
191d677bfe2SMiquel Raynal 
192d677bfe2SMiquel Raynal 	err = uclass_first_device_err(UCLASS_TPM, &dev);
193d677bfe2SMiquel Raynal 	if (err)
194d677bfe2SMiquel Raynal 		return err;
195d677bfe2SMiquel Raynal 
196d677bfe2SMiquel Raynal 	return tpm_open(dev);
197d677bfe2SMiquel Raynal }
198