efi_loader: Enable run-time variable support for tee based variables
[platform/kernel/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 <log.h>
12 #include <asm/unaligned.h>
13 #include <tpm-common.h>
14 #include "tpm-utils.h"
15
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
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
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
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
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
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
196 int tpm_init(struct udevice *dev)
197 {
198         return tpm_open(dev);
199 }