Merge branch 'master' of git://git.denx.de/u-boot-spi
[oweals/u-boot.git] / lib / tpm-common.c
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 <asm/unaligned.h>
12 #include <tpm-common.h>
13 #include "tpm-utils.h"
14
15 int 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
76 int 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);
115                         log_err("Failed to read: size=%d, offset=%x, len=%x\n",
116                                 size, offset, length);
117                         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
140 u32 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
147 u32 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
154 u32 tpm_sendrecv_command(struct udevice *dev, const void *command,
155                          void *response, size_t *size_ptr)
156 {
157         int err, ret;
158         u8 response_buffer[COMMAND_BUFFER_SIZE];
159         size_t response_length;
160         int i;
161
162         if (response) {
163                 response_length = *size_ptr;
164         } else {
165                 response = response_buffer;
166                 response_length = sizeof(response_buffer);
167         }
168
169         err = tpm_xfer(dev, command, tpm_command_size(command),
170                        response, &response_length);
171
172         if (err < 0)
173                 return err;
174
175         if (size_ptr)
176                 *size_ptr = response_length;
177
178         ret = tpm_return_code(response);
179
180         log_debug("TPM response [ret:%d]: ", ret);
181         for (i = 0; i < response_length; i++)
182                 log_debug("%02x ", ((u8 *)response)[i]);
183         log_debug("\n");
184
185         return ret;
186 }
187
188 int tpm_init(struct udevice *dev)
189 {
190         return tpm_open(dev);
191 }