xref: /openbmc/u-boot/lib/tpm-common.c (revision cd71b1d5)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2013 The Chromium OS Authors.
4  * Coypright (c) 2013 Guntermann & Drunck GmbH
5  */
6 
7 #define LOG_CATEGORY UCLASS_TPM
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <asm/unaligned.h>
12 #include <tpm-common.h>
13 #include "tpm-utils.h"
14 
15 enum 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 
22 int 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 
83 int 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);
122 			log_err("Failed to read: size=%zd, offset=%zx, len=%zx\n",
123 				size, offset, length);
124 			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 
147 u32 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 
154 u32 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 
161 u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
162 			 void *response, size_t *size_ptr)
163 {
164 	int err, ret;
165 	u8 response_buffer[COMMAND_BUFFER_SIZE];
166 	size_t response_length;
167 	int i;
168 
169 	if (response) {
170 		response_length = *size_ptr;
171 	} else {
172 		response = response_buffer;
173 		response_length = sizeof(response_buffer);
174 	}
175 
176 	err = tpm_xfer(dev, command, tpm_command_size(command),
177 		       response, &response_length);
178 
179 	if (err < 0)
180 		return err;
181 
182 	if (size_ptr)
183 		*size_ptr = response_length;
184 
185 	ret = tpm_return_code(response);
186 
187 	log_debug("TPM response [ret:%d]: ", ret);
188 	for (i = 0; i < response_length; i++)
189 		log_debug("%02x ", ((u8 *)response)[i]);
190 	log_debug("\n");
191 
192 	return ret;
193 }
194 
195 int tpm_init(struct udevice *dev)
196 {
197 	return tpm_open(dev);
198 }
199