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