Merge tag 'u-boot-stm32-20211110' of https://source.denx.de/u-boot/custodians/u-boot-stm
[platform/kernel/u-boot.git] / lib / tpm-v2.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 Bootlin
4  * Author: Miquel Raynal <miquel.raynal@bootlin.com>
5  */
6
7 #include <common.h>
8 #include <dm.h>
9 #include <tpm-common.h>
10 #include <tpm-v2.h>
11 #include <linux/bitops.h>
12 #include "tpm-utils.h"
13
14 u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode)
15 {
16         const u8 command_v2[12] = {
17                 tpm_u16(TPM2_ST_NO_SESSIONS),
18                 tpm_u32(12),
19                 tpm_u32(TPM2_CC_STARTUP),
20                 tpm_u16(mode),
21         };
22         int ret;
23
24         /*
25          * Note TPM2_Startup command will return RC_SUCCESS the first time,
26          * but will return RC_INITIALIZE otherwise.
27          */
28         ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
29         if (ret && ret != TPM2_RC_INITIALIZE)
30                 return ret;
31
32         return 0;
33 }
34
35 u32 tpm2_self_test(struct udevice *dev, enum tpm2_yes_no full_test)
36 {
37         const u8 command_v2[12] = {
38                 tpm_u16(TPM2_ST_NO_SESSIONS),
39                 tpm_u32(11),
40                 tpm_u32(TPM2_CC_SELF_TEST),
41                 full_test,
42         };
43
44         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
45 }
46
47 u32 tpm2_clear(struct udevice *dev, u32 handle, const char *pw,
48                const ssize_t pw_sz)
49 {
50         /* Length of the message header, up to start of password */
51         uint offset = 27;
52         u8 command_v2[COMMAND_BUFFER_SIZE] = {
53                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
54                 tpm_u32(offset + pw_sz),        /* Length */
55                 tpm_u32(TPM2_CC_CLEAR),         /* Command code */
56
57                 /* HANDLE */
58                 tpm_u32(handle),                /* TPM resource handle */
59
60                 /* AUTH_SESSION */
61                 tpm_u32(9 + pw_sz),             /* Authorization size */
62                 tpm_u32(TPM2_RS_PW),            /* Session handle */
63                 tpm_u16(0),                     /* Size of <nonce> */
64                                                 /* <nonce> (if any) */
65                 0,                              /* Attributes: Cont/Excl/Rst */
66                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
67                 /* STRING(pw)                      <hmac/password> (if any) */
68         };
69         int ret;
70
71         /*
72          * Fill the command structure starting from the first buffer:
73          *     - the password (if any)
74          */
75         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
76                                offset, pw, pw_sz);
77         offset += pw_sz;
78         if (ret)
79                 return TPM_LIB_ERROR;
80
81         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
82 }
83
84 u32 tpm2_nv_define_space(struct udevice *dev, u32 space_index,
85                          size_t space_size, u32 nv_attributes,
86                          const u8 *nv_policy, size_t nv_policy_size)
87 {
88         /*
89          * Calculate the offset of the nv_policy piece by adding each of the
90          * chunks below.
91          */
92         uint offset = 10 + 8 + 13 + 14;
93         u8 command_v2[COMMAND_BUFFER_SIZE] = {
94                 /* header 10 bytes */
95                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
96                 tpm_u32(offset + nv_policy_size),/* Length */
97                 tpm_u32(TPM2_CC_NV_DEFINE_SPACE),/* Command code */
98
99                 /* handles 8 bytes */
100                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
101
102                 /* session header 13 bytes */
103                 tpm_u32(9),                     /* Header size */
104                 tpm_u32(TPM2_RS_PW),            /* Password authorisation */
105                 tpm_u16(0),                     /* nonce_size */
106                 0,                              /* session_attrs */
107                 tpm_u16(0),                     /* auth_size */
108
109                 /* message 14 bytes + policy */
110                 tpm_u16(12 + nv_policy_size),   /* size */
111                 tpm_u32(space_index),
112                 tpm_u16(TPM2_ALG_SHA256),
113                 tpm_u32(nv_attributes),
114                 tpm_u16(nv_policy_size),
115                 /* nv_policy */
116         };
117         int ret;
118
119         /*
120          * Fill the command structure starting from the first buffer:
121          *     - the password (if any)
122          */
123         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
124                                offset, nv_policy, nv_policy_size);
125         if (ret)
126                 return TPM_LIB_ERROR;
127
128         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
129 }
130
131 u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
132                     const u8 *digest, u32 digest_len)
133 {
134         /* Length of the message header, up to start of digest */
135         uint offset = 33;
136         u8 command_v2[COMMAND_BUFFER_SIZE] = {
137                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
138                 tpm_u32(offset + digest_len),   /* Length */
139                 tpm_u32(TPM2_CC_PCR_EXTEND),    /* Command code */
140
141                 /* HANDLE */
142                 tpm_u32(index),                 /* Handle (PCR Index) */
143
144                 /* AUTH_SESSION */
145                 tpm_u32(9),                     /* Authorization size */
146                 tpm_u32(TPM2_RS_PW),            /* Session handle */
147                 tpm_u16(0),                     /* Size of <nonce> */
148                                                 /* <nonce> (if any) */
149                 0,                              /* Attributes: Cont/Excl/Rst */
150                 tpm_u16(0),                     /* Size of <hmac/password> */
151                                                 /* <hmac/password> (if any) */
152
153                 /* hashes */
154                 tpm_u32(1),                     /* Count (number of hashes) */
155                 tpm_u16(algorithm),     /* Algorithm of the hash */
156                 /* STRING(digest)                  Digest */
157         };
158         int ret;
159
160         /*
161          * Fill the command structure starting from the first buffer:
162          *     - the digest
163          */
164         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
165                                offset, digest, digest_len);
166         if (ret)
167                 return TPM_LIB_ERROR;
168
169         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
170 }
171
172 u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void *data, u32 count)
173 {
174         u8 command_v2[COMMAND_BUFFER_SIZE] = {
175                 /* header 10 bytes */
176                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
177                 tpm_u32(10 + 8 + 4 + 9 + 4),    /* Length */
178                 tpm_u32(TPM2_CC_NV_READ),       /* Command code */
179
180                 /* handles 8 bytes */
181                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
182                 tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
183
184                 /* AUTH_SESSION */
185                 tpm_u32(9),                     /* Authorization size */
186                 tpm_u32(TPM2_RS_PW),            /* Session handle */
187                 tpm_u16(0),                     /* Size of <nonce> */
188                                                 /* <nonce> (if any) */
189                 0,                              /* Attributes: Cont/Excl/Rst */
190                 tpm_u16(0),                     /* Size of <hmac/password> */
191                                                 /* <hmac/password> (if any) */
192
193                 tpm_u16(count),                 /* Number of bytes */
194                 tpm_u16(0),                     /* Offset */
195         };
196         size_t response_len = COMMAND_BUFFER_SIZE;
197         u8 response[COMMAND_BUFFER_SIZE];
198         int ret;
199         u16 tag;
200         u32 size, code;
201
202         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
203         if (ret)
204                 return log_msg_ret("read", ret);
205         if (unpack_byte_string(response, response_len, "wdds",
206                                0, &tag, 2, &size, 6, &code,
207                                16, data, count))
208                 return TPM_LIB_ERROR;
209
210         return 0;
211 }
212
213 u32 tpm2_nv_write_value(struct udevice *dev, u32 index, const void *data,
214                         u32 count)
215 {
216         struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
217         uint offset = 10 + 8 + 4 + 9 + 2;
218         uint len = offset + count + 2;
219         /* Use empty password auth if platform hierarchy is disabled */
220         u32 auth = priv->plat_hier_disabled ? HR_NV_INDEX + index :
221                 TPM2_RH_PLATFORM;
222         u8 command_v2[COMMAND_BUFFER_SIZE] = {
223                 /* header 10 bytes */
224                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
225                 tpm_u32(len),                   /* Length */
226                 tpm_u32(TPM2_CC_NV_WRITE),      /* Command code */
227
228                 /* handles 8 bytes */
229                 tpm_u32(auth),                  /* Primary platform seed */
230                 tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
231
232                 /* AUTH_SESSION */
233                 tpm_u32(9),                     /* Authorization size */
234                 tpm_u32(TPM2_RS_PW),            /* Session handle */
235                 tpm_u16(0),                     /* Size of <nonce> */
236                                                 /* <nonce> (if any) */
237                 0,                              /* Attributes: Cont/Excl/Rst */
238                 tpm_u16(0),                     /* Size of <hmac/password> */
239                                                 /* <hmac/password> (if any) */
240
241                 tpm_u16(count),
242         };
243         size_t response_len = COMMAND_BUFFER_SIZE;
244         u8 response[COMMAND_BUFFER_SIZE];
245         int ret;
246
247         ret = pack_byte_string(command_v2, sizeof(command_v2), "sw",
248                                offset, data, count,
249                                offset + count, 0);
250         if (ret)
251                 return TPM_LIB_ERROR;
252
253         return tpm_sendrecv_command(dev, command_v2, response, &response_len);
254 }
255
256 u32 tpm2_pcr_read(struct udevice *dev, u32 idx, unsigned int idx_min_sz,
257                   void *data, unsigned int *updates)
258 {
259         u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
260         u8 command_v2[COMMAND_BUFFER_SIZE] = {
261                 tpm_u16(TPM2_ST_NO_SESSIONS),   /* TAG */
262                 tpm_u32(17 + idx_array_sz),     /* Length */
263                 tpm_u32(TPM2_CC_PCR_READ),      /* Command code */
264
265                 /* TPML_PCR_SELECTION */
266                 tpm_u32(1),                     /* Number of selections */
267                 tpm_u16(TPM2_ALG_SHA256),       /* Algorithm of the hash */
268                 idx_array_sz,                   /* Array size for selection */
269                 /* bitmap(idx)                     Selected PCR bitmap */
270         };
271         size_t response_len = COMMAND_BUFFER_SIZE;
272         u8 response[COMMAND_BUFFER_SIZE];
273         unsigned int pcr_sel_idx = idx / 8;
274         u8 pcr_sel_bit = BIT(idx % 8);
275         unsigned int counter = 0;
276         int ret;
277
278         if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
279                              17 + pcr_sel_idx, pcr_sel_bit))
280                 return TPM_LIB_ERROR;
281
282         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
283         if (ret)
284                 return ret;
285
286         if (unpack_byte_string(response, response_len, "ds",
287                                10, &counter,
288                                response_len - TPM2_DIGEST_LEN, data,
289                                TPM2_DIGEST_LEN))
290                 return TPM_LIB_ERROR;
291
292         if (updates)
293                 *updates = counter;
294
295         return 0;
296 }
297
298 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
299                         void *buf, size_t prop_count)
300 {
301         u8 command_v2[COMMAND_BUFFER_SIZE] = {
302                 tpm_u16(TPM2_ST_NO_SESSIONS),           /* TAG */
303                 tpm_u32(22),                            /* Length */
304                 tpm_u32(TPM2_CC_GET_CAPABILITY),        /* Command code */
305
306                 tpm_u32(capability),                    /* Capability */
307                 tpm_u32(property),                      /* Property */
308                 tpm_u32(prop_count),                    /* Property count */
309         };
310         u8 response[COMMAND_BUFFER_SIZE];
311         size_t response_len = COMMAND_BUFFER_SIZE;
312         unsigned int properties_off;
313         int ret;
314
315         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
316         if (ret)
317                 return ret;
318
319         /*
320          * In the response buffer, the properties are located after the:
321          * tag (u16), response size (u32), response code (u32),
322          * YES/NO flag (u8), TPM_CAP (u32).
323          */
324         properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
325                          sizeof(u8) + sizeof(u32);
326         memcpy(buf, &response[properties_off], response_len - properties_off);
327
328         return 0;
329 }
330
331 u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
332 {
333         u8 command_v2[COMMAND_BUFFER_SIZE] = {
334                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
335                 tpm_u32(27 + pw_sz),            /* Length */
336                 tpm_u32(TPM2_CC_DAM_RESET),     /* Command code */
337
338                 /* HANDLE */
339                 tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
340
341                 /* AUTH_SESSION */
342                 tpm_u32(9 + pw_sz),             /* Authorization size */
343                 tpm_u32(TPM2_RS_PW),            /* Session handle */
344                 tpm_u16(0),                     /* Size of <nonce> */
345                                                 /* <nonce> (if any) */
346                 0,                              /* Attributes: Cont/Excl/Rst */
347                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
348                 /* STRING(pw)                      <hmac/password> (if any) */
349         };
350         unsigned int offset = 27;
351         int ret;
352
353         /*
354          * Fill the command structure starting from the first buffer:
355          *     - the password (if any)
356          */
357         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
358                                offset, pw, pw_sz);
359         offset += pw_sz;
360         if (ret)
361                 return TPM_LIB_ERROR;
362
363         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
364 }
365
366 u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
367                         const ssize_t pw_sz, unsigned int max_tries,
368                         unsigned int recovery_time,
369                         unsigned int lockout_recovery)
370 {
371         u8 command_v2[COMMAND_BUFFER_SIZE] = {
372                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
373                 tpm_u32(27 + pw_sz + 12),       /* Length */
374                 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
375
376                 /* HANDLE */
377                 tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
378
379                 /* AUTH_SESSION */
380                 tpm_u32(9 + pw_sz),             /* Authorization size */
381                 tpm_u32(TPM2_RS_PW),            /* Session handle */
382                 tpm_u16(0),                     /* Size of <nonce> */
383                                                 /* <nonce> (if any) */
384                 0,                              /* Attributes: Cont/Excl/Rst */
385                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
386                 /* STRING(pw)                      <hmac/password> (if any) */
387
388                 /* LOCKOUT PARAMETERS */
389                 /* tpm_u32(max_tries)              Max tries (0, always lock) */
390                 /* tpm_u32(recovery_time)          Recovery time (0, no lock) */
391                 /* tpm_u32(lockout_recovery)       Lockout recovery */
392         };
393         unsigned int offset = 27;
394         int ret;
395
396         /*
397          * Fill the command structure starting from the first buffer:
398          *     - the password (if any)
399          *     - max tries
400          *     - recovery time
401          *     - lockout recovery
402          */
403         ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
404                                offset, pw, pw_sz,
405                                offset + pw_sz, max_tries,
406                                offset + pw_sz + 4, recovery_time,
407                                offset + pw_sz + 8, lockout_recovery);
408         offset += pw_sz + 12;
409         if (ret)
410                 return TPM_LIB_ERROR;
411
412         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
413 }
414
415 int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
416                      const ssize_t newpw_sz, const char *oldpw,
417                      const ssize_t oldpw_sz)
418 {
419         unsigned int offset = 27;
420         u8 command_v2[COMMAND_BUFFER_SIZE] = {
421                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
422                 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
423                 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
424
425                 /* HANDLE */
426                 tpm_u32(handle),                /* TPM resource handle */
427
428                 /* AUTH_SESSION */
429                 tpm_u32(9 + oldpw_sz),          /* Authorization size */
430                 tpm_u32(TPM2_RS_PW),            /* Session handle */
431                 tpm_u16(0),                     /* Size of <nonce> */
432                                                 /* <nonce> (if any) */
433                 0,                              /* Attributes: Cont/Excl/Rst */
434                 tpm_u16(oldpw_sz)               /* Size of <hmac/password> */
435                 /* STRING(oldpw)                   <hmac/password> (if any) */
436
437                 /* TPM2B_AUTH (TPM2B_DIGEST) */
438                 /* tpm_u16(newpw_sz)               Digest size, new pw length */
439                 /* STRING(newpw)                   Digest buffer, new pw */
440         };
441         int ret;
442
443         /*
444          * Fill the command structure starting from the first buffer:
445          *     - the old password (if any)
446          *     - size of the new password
447          *     - new password
448          */
449         ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
450                                offset, oldpw, oldpw_sz,
451                                offset + oldpw_sz, newpw_sz,
452                                offset + oldpw_sz + 2, newpw, newpw_sz);
453         offset += oldpw_sz + 2 + newpw_sz;
454         if (ret)
455                 return TPM_LIB_ERROR;
456
457         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
458 }
459
460 u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
461                            const ssize_t pw_sz, u32 index, const char *key)
462 {
463         u8 command_v2[COMMAND_BUFFER_SIZE] = {
464                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
465                 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
466                 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
467
468                 /* HANDLE */
469                 tpm_u32(TPM2_RH_PLATFORM),      /* TPM resource handle */
470
471                 /* AUTH_SESSION */
472                 tpm_u32(9 + pw_sz),             /* Authorization size */
473                 tpm_u32(TPM2_RS_PW),            /* session handle */
474                 tpm_u16(0),                     /* Size of <nonce> */
475                                                 /* <nonce> (if any) */
476                 0,                              /* Attributes: Cont/Excl/Rst */
477                 tpm_u16(pw_sz)                  /* Size of <hmac/password> */
478                 /* STRING(pw)                      <hmac/password> (if any) */
479
480                 /* TPM2B_AUTH (TPM2B_DIGEST) */
481                 /* tpm_u16(TPM2_DIGEST_LEN)        Digest size length */
482                 /* STRING(key)                     Digest buffer (PCR key) */
483
484                 /* TPMI_ALG_HASH */
485                 /* tpm_u16(TPM2_ALG_SHA256)   Algorithm of the hash */
486
487                 /* TPMI_DH_PCR */
488                 /* tpm_u32(index),                 PCR Index */
489         };
490         unsigned int offset = 27;
491         int ret;
492
493         /*
494          * Fill the command structure starting from the first buffer:
495          *     - the password (if any)
496          *     - the PCR key length
497          *     - the PCR key
498          *     - the hash algorithm
499          *     - the PCR index
500          */
501         ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
502                                offset, pw, pw_sz,
503                                offset + pw_sz, TPM2_DIGEST_LEN,
504                                offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
505                                offset + pw_sz + 2 + TPM2_DIGEST_LEN,
506                                TPM2_ALG_SHA256,
507                                offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
508         offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
509         if (ret)
510                 return TPM_LIB_ERROR;
511
512         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
513 }
514
515 u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
516                           const ssize_t pw_sz, u32 index, const char *key,
517                           const ssize_t key_sz)
518 {
519         u8 command_v2[COMMAND_BUFFER_SIZE] = {
520                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
521                 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
522                 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
523
524                 /* HANDLE */
525                 tpm_u32(index),                 /* Handle (PCR Index) */
526
527                 /* AUTH_SESSION */
528                 tpm_u32(9 + pw_sz),             /* Authorization size */
529                 tpm_u32(TPM2_RS_PW),            /* session handle */
530                 tpm_u16(0),                     /* Size of <nonce> */
531                                                 /* <nonce> (if any) */
532                 0,                              /* Attributes: Cont/Excl/Rst */
533                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
534                 /* STRING(pw)                      <hmac/password> (if any) */
535
536                 /* TPM2B_DIGEST */
537                 /* tpm_u16(key_sz)                 Key length */
538                 /* STRING(key)                     Key */
539         };
540         unsigned int offset = 27;
541         int ret;
542
543         /*
544          * Fill the command structure starting from the first buffer:
545          *     - the password (if any)
546          *     - the number of digests, 1 in our case
547          *     - the algorithm, sha256 in our case
548          *     - the digest (64 bytes)
549          */
550         ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
551                                offset, pw, pw_sz,
552                                offset + pw_sz, key_sz,
553                                offset + pw_sz + 2, key, key_sz);
554         offset += pw_sz + 2 + key_sz;
555         if (ret)
556                 return TPM_LIB_ERROR;
557
558         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
559 }
560
561 u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
562 {
563         const u8 command_v2[10] = {
564                 tpm_u16(TPM2_ST_NO_SESSIONS),
565                 tpm_u32(12),
566                 tpm_u32(TPM2_CC_GET_RANDOM),
567         };
568         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
569
570         const size_t data_size_offset = 10;
571         const size_t data_offset = 12;
572         size_t response_length = sizeof(response);
573         u32 data_size;
574         u8 *out = data;
575
576         while (count > 0) {
577                 u32 this_bytes = min((size_t)count,
578                                      sizeof(response) - data_offset);
579                 u32 err;
580
581                 if (pack_byte_string(buf, sizeof(buf), "sw",
582                                      0, command_v2, sizeof(command_v2),
583                                      sizeof(command_v2), this_bytes))
584                         return TPM_LIB_ERROR;
585                 err = tpm_sendrecv_command(dev, buf, response,
586                                            &response_length);
587                 if (err)
588                         return err;
589                 if (unpack_byte_string(response, response_length, "w",
590                                        data_size_offset, &data_size))
591                         return TPM_LIB_ERROR;
592                 if (data_size > this_bytes)
593                         return TPM_LIB_ERROR;
594                 if (unpack_byte_string(response, response_length, "s",
595                                        data_offset, out, data_size))
596                         return TPM_LIB_ERROR;
597
598                 count -= data_size;
599                 out += data_size;
600         }
601
602         return 0;
603 }
604
605 u32 tpm2_write_lock(struct udevice *dev, u32 index)
606 {
607         u8 command_v2[COMMAND_BUFFER_SIZE] = {
608                 /* header 10 bytes */
609                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
610                 tpm_u32(10 + 8 + 13), /* Length */
611                 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
612
613                 /* handles 8 bytes */
614                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
615                 tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
616
617                 /* session header 9 bytes */
618                 tpm_u32(9),                     /* Header size */
619                 tpm_u32(TPM2_RS_PW),            /* Password authorisation */
620                 tpm_u16(0),                     /* nonce_size */
621                 0,                              /* session_attrs */
622                 tpm_u16(0),                     /* auth_size */
623         };
624
625         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
626 }
627
628 u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
629 {
630         struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
631         u8 command_v2[COMMAND_BUFFER_SIZE] = {
632                 /* header 10 bytes */
633                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
634                 tpm_u32(10 + 4 + 13 + 5),       /* Length */
635                 tpm_u32(TPM2_CC_HIER_CONTROL),  /* Command code */
636
637                 /* 4 bytes */
638                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
639
640                 /* session header 9 bytes */
641                 tpm_u32(9),                     /* Header size */
642                 tpm_u32(TPM2_RS_PW),            /* Password authorisation */
643                 tpm_u16(0),                     /* nonce_size */
644                 0,                              /* session_attrs */
645                 tpm_u16(0),                     /* auth_size */
646
647                 /* payload 5 bytes */
648                 tpm_u32(TPM2_RH_PLATFORM),      /* Hierarchy to disable */
649                 0,                              /* 0=disable */
650         };
651         int ret;
652
653         ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
654         log_info("ret=%s, %x\n", dev->name, ret);
655         if (ret)
656                 return ret;
657
658         priv->plat_hier_disabled = true;
659
660         return 0;
661 }
662
663 u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
664                         u8 *recvbuf, size_t *recv_size)
665 {
666         return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
667 }