xref: /openbmc/u-boot/lib/tpm-common.c (revision 407b5b956a2e0facf6668fc8b295f4be9205c83e)
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