1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2013 The Chromium OS Authors.
4 */
5
6#include <common.h>
7#include <command.h>
8#include <dm.h>
9#include <env.h>
10#include <malloc.h>
11#include <asm/unaligned.h>
12#include <linux/string.h>
13#include <tpm-common.h>
14#include <tpm_api.h>
15#include "tpm-user-utils.h"
16
17static struct udevice *tpm_dev;
18
19/**
20 * Print a byte string in hexdecimal format, 16-bytes per line.
21 *
22 * @param data		byte string to be printed
23 * @param count		number of bytes to be printed
24 */
25void print_byte_string(u8 *data, size_t count)
26{
27	int i, print_newline = 0;
28
29	for (i = 0; i < count; i++) {
30		printf(" %02x", data[i]);
31		print_newline = (i % 16 == 15);
32		if (print_newline)
33			putc('\n');
34	}
35	/* Avoid duplicated newline at the end */
36	if (!print_newline)
37		putc('\n');
38}
39
40/**
41 * Convert a text string of hexdecimal values into a byte string.
42 *
43 * @param bytes		text string of hexdecimal values with no space
44 *			between them
45 * @param data		output buffer for byte string.  The caller has to make
46 *			sure it is large enough for storing the output.  If
47 *			NULL is passed, a large enough buffer will be allocated,
48 *			and the caller must free it.
49 * @param count_ptr	output variable for the length of byte string
50 * Return: pointer to output buffer
51 */
52void *parse_byte_string(char *bytes, u8 *data, size_t *count_ptr)
53{
54	char byte[3];
55	size_t count, length;
56	int i;
57
58	if (!bytes)
59		return NULL;
60	length = strlen(bytes);
61	count = length / 2;
62
63	if (!data)
64		data = malloc(count);
65	if (!data)
66		return NULL;
67
68	byte[2] = '\0';
69	for (i = 0; i < length; i += 2) {
70		byte[0] = bytes[i];
71		byte[1] = bytes[i + 1];
72		data[i / 2] = (u8)hextoul(byte, NULL);
73	}
74
75	if (count_ptr)
76		*count_ptr = count;
77
78	return data;
79}
80
81/**
82 * report_return_code() - Report any error and return failure or success
83 *
84 * @param return_code	TPM command return code
85 * Return: value of enum command_ret_t
86 */
87int report_return_code(int return_code)
88{
89	if (return_code) {
90		printf("Error: %d\n", return_code);
91		return CMD_RET_FAILURE;
92	} else {
93		return CMD_RET_SUCCESS;
94	}
95}
96
97/**
98 * Return number of values defined by a type string.
99 *
100 * @param type_str	type string
101 * Return: number of values of type string
102 */
103int type_string_get_num_values(const char *type_str)
104{
105	return strlen(type_str);
106}
107
108/**
109 * Return total size of values defined by a type string.
110 *
111 * @param type_str	type string
112 * Return: total size of values of type string, or 0 if type string
113 *  contains illegal type character.
114 */
115size_t type_string_get_space_size(const char *type_str)
116{
117	size_t size;
118
119	for (size = 0; *type_str; type_str++) {
120		switch (*type_str) {
121		case 'b':
122			size += 1;
123			break;
124		case 'w':
125			size += 2;
126			break;
127		case 'd':
128			size += 4;
129			break;
130		default:
131			return 0;
132		}
133	}
134
135	return size;
136}
137
138/**
139 * Allocate a buffer large enough to hold values defined by a type
140 * string.  The caller has to free the buffer.
141 *
142 * @param type_str	type string
143 * @param count		pointer for storing size of buffer
144 * Return: pointer to buffer or NULL on error
145 */
146void *type_string_alloc(const char *type_str, u32 *count)
147{
148	void *data;
149	size_t size;
150
151	size = type_string_get_space_size(type_str);
152	if (!size)
153		return NULL;
154	data = malloc(size);
155	if (data)
156		*count = size;
157
158	return data;
159}
160
161/**
162 * Pack values defined by a type string into a buffer.  The buffer must have
163 * large enough space.
164 *
165 * @param type_str	type string
166 * @param values	text strings of values to be packed
167 * @param data		output buffer of values
168 * Return: 0 on success, non-0 on error
169 */
170int type_string_pack(const char *type_str, char * const values[],
171		     u8 *data)
172{
173	size_t offset;
174	u32 value;
175
176	for (offset = 0; *type_str; type_str++, values++) {
177		value = simple_strtoul(values[0], NULL, 0);
178		switch (*type_str) {
179		case 'b':
180			data[offset] = value;
181			offset += 1;
182			break;
183		case 'w':
184			put_unaligned_be16(value, data + offset);
185			offset += 2;
186			break;
187		case 'd':
188			put_unaligned_be32(value, data + offset);
189			offset += 4;
190			break;
191		default:
192			return -1;
193		}
194	}
195
196	return 0;
197}
198
199/**
200 * Read values defined by a type string from a buffer, and write these values
201 * to environment variables.
202 *
203 * @param type_str	type string
204 * @param data		input buffer of values
205 * @param vars		names of environment variables
206 * Return: 0 on success, non-0 on error
207 */
208int type_string_write_vars(const char *type_str, u8 *data,
209			   char * const vars[])
210{
211	size_t offset;
212	u32 value;
213
214	for (offset = 0; *type_str; type_str++, vars++) {
215		switch (*type_str) {
216		case 'b':
217			value = data[offset];
218			offset += 1;
219			break;
220		case 'w':
221			value = get_unaligned_be16(data + offset);
222			offset += 2;
223			break;
224		case 'd':
225			value = get_unaligned_be32(data + offset);
226			offset += 4;
227			break;
228		default:
229			return -1;
230		}
231		if (env_set_ulong(*vars, value))
232			return -1;
233	}
234
235	return 0;
236}
237
238static int tpm_show_device(void)
239{
240	struct udevice *dev;
241	char buf[80];
242	int n = 0, rc;
243
244	for_each_tpm_device(dev) {
245		rc = tpm_get_desc(dev, buf, sizeof(buf));
246		if (rc < 0)
247			printf("device %d: can't get info\n", n);
248		else
249			printf("device %d: %s\n", n, buf);
250
251		n++;
252	};
253
254	return 0;
255}
256
257static int tpm_set_device(unsigned long num)
258{
259	struct udevice *dev;
260	unsigned long n = 0;
261	int rc = CMD_RET_FAILURE;
262
263	for_each_tpm_device(dev) {
264		if (n == num) {
265			rc = 0;
266			break;
267		}
268
269		n++;
270	}
271
272	if (!rc)
273		tpm_dev = dev;
274
275	return rc;
276}
277
278int get_tpm(struct udevice **devp)
279{
280	int rc;
281
282	/*
283	 * To keep a backward compatibility with previous code,
284	 * if a tpm device is not explicitly set, we set the first one.
285	 */
286	if (!tpm_dev) {
287		rc = tpm_set_device(0);
288		if (rc) {
289			printf("Couldn't set TPM 0 (rc = %d)\n", rc);
290			return CMD_RET_FAILURE;
291		}
292	}
293
294	if (devp)
295		*devp = tpm_dev;
296
297	return 0;
298}
299
300int do_tpm_device(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
301{
302	unsigned long num;
303	int rc;
304
305	if (argc == 2) {
306		num = dectoul(argv[1], NULL);
307
308		rc = tpm_set_device(num);
309		if (rc)
310			printf("Couldn't set TPM %lu (rc = %d)\n", num, rc);
311	} else {
312		rc = tpm_show_device();
313	}
314
315	return rc;
316}
317
318int do_tpm_info(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
319{
320	struct udevice *dev;
321	char buf[80];
322	int rc;
323
324	rc = get_tpm(&dev);
325	if (rc)
326		return rc;
327	rc = tpm_get_desc(dev, buf, sizeof(buf));
328	if (rc < 0) {
329		printf("Couldn't get TPM info (%d)\n", rc);
330		return CMD_RET_FAILURE;
331	}
332	printf("%s\n", buf);
333
334	return 0;
335}
336
337int do_tpm_report_state(struct cmd_tbl *cmdtp, int flag, int argc,
338			char *const argv[])
339{
340	struct udevice *dev;
341	char buf[80];
342	int rc;
343
344	rc = get_tpm(&dev);
345	if (rc)
346		return rc;
347	rc = tpm_report_state(dev, buf, sizeof(buf));
348	if (rc < 0) {
349		printf("Couldn't get TPM state (%d)\n", rc);
350		return CMD_RET_FAILURE;
351	}
352	printf("%s\n", buf);
353
354	return 0;
355}
356
357int do_tpm_init(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
358{
359	struct udevice *dev;
360	int rc;
361
362	if (argc != 1)
363		return CMD_RET_USAGE;
364	rc = get_tpm(&dev);
365	if (rc)
366		return rc;
367
368	return report_return_code(tpm_init(dev));
369}
370
371int do_tpm_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
372		     char *const argv[])
373{
374	struct udevice *dev;
375	int rc;
376
377	if (argc != 1)
378		return CMD_RET_USAGE;
379	rc = get_tpm(&dev);
380	if (rc)
381		return rc;
382
383	return report_return_code(tpm_auto_start(dev));
384}
385
386int do_tpm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
387{
388	struct cmd_tbl *tpm_commands, *cmd;
389	struct tpm_chip_priv *priv;
390	struct udevice *dev;
391	unsigned int size;
392	int ret;
393
394	if (argc < 2)
395		return CMD_RET_USAGE;
396
397	ret = get_tpm(&dev);
398	if (ret)
399		return ret;
400
401	priv = dev_get_uclass_priv(dev);
402
403	/* Below getters return NULL if the desired stack is not built */
404	switch (priv->version) {
405	case TPM_V1:
406		tpm_commands = get_tpm1_commands(&size);
407		break;
408	case TPM_V2:
409		tpm_commands = get_tpm2_commands(&size);
410		break;
411	default:
412		tpm_commands = NULL;
413	}
414
415	if (!tpm_commands)
416		return CMD_RET_USAGE;
417
418	cmd = find_cmd_tbl(argv[1], tpm_commands, size);
419	if (!cmd)
420		return CMD_RET_USAGE;
421
422	return cmd->cmd(cmdtp, flag, argc - 1, argv + 1);
423}
424