blob: 6afe59b1fecf28ca603a569a50656c06b59a899b [file] [log] [blame]
Miquel Raynal4c6759e2018-05-15 11:57:06 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2013 The Chromium OS Authors.
4 * Coypright (c) 2013 Guntermann & Drunck GmbH
5 */
6
Simon Glass70e59cc2018-10-01 12:22:28 -06007#define LOG_CATEGORY UCLASS_TPM
8
Miquel Raynal4c6759e2018-05-15 11:57:06 +02009#include <common.h>
10#include <dm.h>
11#include <asm/unaligned.h>
12#include <tpm-common.h>
13#include "tpm-utils.h"
14
15int pack_byte_string(u8 *str, size_t size, const char *format, ...)
16{
17 va_list args;
18 size_t offset = 0, length = 0;
19 u8 *data = NULL;
20 u32 value = 0;
21
22 va_start(args, format);
23 for (; *format; format++) {
24 switch (*format) {
25 case 'b':
26 offset = va_arg(args, size_t);
27 value = va_arg(args, int);
28 length = 1;
29 break;
30 case 'w':
31 offset = va_arg(args, size_t);
32 value = va_arg(args, int);
33 length = 2;
34 break;
35 case 'd':
36 offset = va_arg(args, size_t);
37 value = va_arg(args, u32);
38 length = 4;
39 break;
40 case 's':
41 offset = va_arg(args, size_t);
42 data = va_arg(args, u8 *);
43 length = va_arg(args, u32);
44 break;
45 default:
46 debug("Couldn't recognize format string\n");
47 va_end(args);
48 return -1;
49 }
50
51 if (offset + length > size) {
52 va_end(args);
53 return -1;
54 }
55
56 switch (*format) {
57 case 'b':
58 str[offset] = value;
59 break;
60 case 'w':
61 put_unaligned_be16(value, str + offset);
62 break;
63 case 'd':
64 put_unaligned_be32(value, str + offset);
65 break;
66 case 's':
67 memcpy(str + offset, data, length);
68 break;
69 }
70 }
71 va_end(args);
72
73 return 0;
74}
75
76int unpack_byte_string(const u8 *str, size_t size, const char *format, ...)
77{
78 va_list args;
79 size_t offset = 0, length = 0;
80 u8 *ptr8 = NULL;
81 u16 *ptr16 = NULL;
82 u32 *ptr32 = NULL;
83
84 va_start(args, format);
85 for (; *format; format++) {
86 switch (*format) {
87 case 'b':
88 offset = va_arg(args, size_t);
89 ptr8 = va_arg(args, u8 *);
90 length = 1;
91 break;
92 case 'w':
93 offset = va_arg(args, size_t);
94 ptr16 = va_arg(args, u16 *);
95 length = 2;
96 break;
97 case 'd':
98 offset = va_arg(args, size_t);
99 ptr32 = va_arg(args, u32 *);
100 length = 4;
101 break;
102 case 's':
103 offset = va_arg(args, size_t);
104 ptr8 = va_arg(args, u8 *);
105 length = va_arg(args, u32);
106 break;
107 default:
108 va_end(args);
109 debug("Couldn't recognize format string\n");
110 return -1;
111 }
112
113 if (offset + length > size) {
114 va_end(args);
Simon Glass70e59cc2018-10-01 12:22:28 -0600115 log_err("Failed to read: size=%d, offset=%x, len=%x\n",
116 size, offset, length);
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200117 return -1;
118 }
119
120 switch (*format) {
121 case 'b':
122 *ptr8 = str[offset];
123 break;
124 case 'w':
125 *ptr16 = get_unaligned_be16(str + offset);
126 break;
127 case 'd':
128 *ptr32 = get_unaligned_be32(str + offset);
129 break;
130 case 's':
131 memcpy(ptr8, str + offset, length);
132 break;
133 }
134 }
135 va_end(args);
136
137 return 0;
138}
139
140u32 tpm_command_size(const void *command)
141{
142 const size_t command_size_offset = 2;
143
144 return get_unaligned_be32(command + command_size_offset);
145}
146
147u32 tpm_return_code(const void *response)
148{
149 const size_t return_code_offset = 6;
150
151 return get_unaligned_be32(response + return_code_offset);
152}
153
Simon Glass8ceca1d2018-11-18 14:22:27 -0700154u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
155 void *response, size_t *size_ptr)
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200156{
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200157 int err, ret;
158 u8 response_buffer[COMMAND_BUFFER_SIZE];
159 size_t response_length;
Miquel Raynal3eec0882018-05-15 11:57:10 +0200160 int i;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200161
162 if (response) {
163 response_length = *size_ptr;
164 } else {
165 response = response_buffer;
166 response_length = sizeof(response_buffer);
167 }
168
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200169 err = tpm_xfer(dev, command, tpm_command_size(command),
170 response, &response_length);
171
172 if (err < 0)
Miquel Raynal68b3f832018-05-15 11:57:11 +0200173 return err;
174
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200175 if (size_ptr)
176 *size_ptr = response_length;
177
Miquel Raynal3eec0882018-05-15 11:57:10 +0200178 ret = tpm_return_code(response);
179
Simon Glass70e59cc2018-10-01 12:22:28 -0600180 log_debug("TPM response [ret:%d]: ", ret);
Miquel Raynal3eec0882018-05-15 11:57:10 +0200181 for (i = 0; i < response_length; i++)
Simon Glass70e59cc2018-10-01 12:22:28 -0600182 log_debug("%02x ", ((u8 *)response)[i]);
183 log_debug("\n");
Miquel Raynal3eec0882018-05-15 11:57:10 +0200184
185 return ret;
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200186}
187
Simon Glass8ceca1d2018-11-18 14:22:27 -0700188int tpm_init(struct udevice *dev)
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200189{
Miquel Raynal4c6759e2018-05-15 11:57:06 +0200190 return tpm_open(dev);
191}