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