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