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