image: Return destination node for add_verify_data() method
[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                   u16 algorithm, void *data, u32 digest_len,
258                   unsigned int *updates)
259 {
260         u8 idx_array_sz = max(idx_min_sz, DIV_ROUND_UP(idx, 8));
261         u8 command_v2[COMMAND_BUFFER_SIZE] = {
262                 tpm_u16(TPM2_ST_NO_SESSIONS),   /* TAG */
263                 tpm_u32(17 + idx_array_sz),     /* Length */
264                 tpm_u32(TPM2_CC_PCR_READ),      /* Command code */
265
266                 /* TPML_PCR_SELECTION */
267                 tpm_u32(1),                     /* Number of selections */
268                 tpm_u16(algorithm),             /* Algorithm of the hash */
269                 idx_array_sz,                   /* Array size for selection */
270                 /* bitmap(idx)                     Selected PCR bitmap */
271         };
272         size_t response_len = COMMAND_BUFFER_SIZE;
273         u8 response[COMMAND_BUFFER_SIZE];
274         unsigned int pcr_sel_idx = idx / 8;
275         u8 pcr_sel_bit = BIT(idx % 8);
276         unsigned int counter = 0;
277         int ret;
278
279         if (pack_byte_string(command_v2, COMMAND_BUFFER_SIZE, "b",
280                              17 + pcr_sel_idx, pcr_sel_bit))
281                 return TPM_LIB_ERROR;
282
283         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
284         if (ret)
285                 return ret;
286
287         if (digest_len > response_len)
288                 return TPM_LIB_ERROR;
289
290         if (unpack_byte_string(response, response_len, "ds",
291                                10, &counter,
292                                response_len - digest_len, data,
293                                digest_len))
294                 return TPM_LIB_ERROR;
295
296         if (updates)
297                 *updates = counter;
298
299         return 0;
300 }
301
302 u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property,
303                         void *buf, size_t prop_count)
304 {
305         u8 command_v2[COMMAND_BUFFER_SIZE] = {
306                 tpm_u16(TPM2_ST_NO_SESSIONS),           /* TAG */
307                 tpm_u32(22),                            /* Length */
308                 tpm_u32(TPM2_CC_GET_CAPABILITY),        /* Command code */
309
310                 tpm_u32(capability),                    /* Capability */
311                 tpm_u32(property),                      /* Property */
312                 tpm_u32(prop_count),                    /* Property count */
313         };
314         u8 response[COMMAND_BUFFER_SIZE];
315         size_t response_len = COMMAND_BUFFER_SIZE;
316         unsigned int properties_off;
317         int ret;
318
319         ret = tpm_sendrecv_command(dev, command_v2, response, &response_len);
320         if (ret)
321                 return ret;
322
323         /*
324          * In the response buffer, the properties are located after the:
325          * tag (u16), response size (u32), response code (u32),
326          * YES/NO flag (u8), TPM_CAP (u32).
327          */
328         properties_off = sizeof(u16) + sizeof(u32) + sizeof(u32) +
329                          sizeof(u8) + sizeof(u32);
330         memcpy(buf, &response[properties_off], response_len - properties_off);
331
332         return 0;
333 }
334
335 u32 tpm2_dam_reset(struct udevice *dev, const char *pw, const ssize_t pw_sz)
336 {
337         u8 command_v2[COMMAND_BUFFER_SIZE] = {
338                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
339                 tpm_u32(27 + pw_sz),            /* Length */
340                 tpm_u32(TPM2_CC_DAM_RESET),     /* Command code */
341
342                 /* HANDLE */
343                 tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
344
345                 /* AUTH_SESSION */
346                 tpm_u32(9 + pw_sz),             /* Authorization size */
347                 tpm_u32(TPM2_RS_PW),            /* Session handle */
348                 tpm_u16(0),                     /* Size of <nonce> */
349                                                 /* <nonce> (if any) */
350                 0,                              /* Attributes: Cont/Excl/Rst */
351                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
352                 /* STRING(pw)                      <hmac/password> (if any) */
353         };
354         unsigned int offset = 27;
355         int ret;
356
357         /*
358          * Fill the command structure starting from the first buffer:
359          *     - the password (if any)
360          */
361         ret = pack_byte_string(command_v2, sizeof(command_v2), "s",
362                                offset, pw, pw_sz);
363         offset += pw_sz;
364         if (ret)
365                 return TPM_LIB_ERROR;
366
367         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
368 }
369
370 u32 tpm2_dam_parameters(struct udevice *dev, const char *pw,
371                         const ssize_t pw_sz, unsigned int max_tries,
372                         unsigned int recovery_time,
373                         unsigned int lockout_recovery)
374 {
375         u8 command_v2[COMMAND_BUFFER_SIZE] = {
376                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
377                 tpm_u32(27 + pw_sz + 12),       /* Length */
378                 tpm_u32(TPM2_CC_DAM_PARAMETERS), /* Command code */
379
380                 /* HANDLE */
381                 tpm_u32(TPM2_RH_LOCKOUT),       /* TPM resource handle */
382
383                 /* AUTH_SESSION */
384                 tpm_u32(9 + pw_sz),             /* Authorization size */
385                 tpm_u32(TPM2_RS_PW),            /* Session handle */
386                 tpm_u16(0),                     /* Size of <nonce> */
387                                                 /* <nonce> (if any) */
388                 0,                              /* Attributes: Cont/Excl/Rst */
389                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
390                 /* STRING(pw)                      <hmac/password> (if any) */
391
392                 /* LOCKOUT PARAMETERS */
393                 /* tpm_u32(max_tries)              Max tries (0, always lock) */
394                 /* tpm_u32(recovery_time)          Recovery time (0, no lock) */
395                 /* tpm_u32(lockout_recovery)       Lockout recovery */
396         };
397         unsigned int offset = 27;
398         int ret;
399
400         /*
401          * Fill the command structure starting from the first buffer:
402          *     - the password (if any)
403          *     - max tries
404          *     - recovery time
405          *     - lockout recovery
406          */
407         ret = pack_byte_string(command_v2, sizeof(command_v2), "sddd",
408                                offset, pw, pw_sz,
409                                offset + pw_sz, max_tries,
410                                offset + pw_sz + 4, recovery_time,
411                                offset + pw_sz + 8, lockout_recovery);
412         offset += pw_sz + 12;
413         if (ret)
414                 return TPM_LIB_ERROR;
415
416         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
417 }
418
419 int tpm2_change_auth(struct udevice *dev, u32 handle, const char *newpw,
420                      const ssize_t newpw_sz, const char *oldpw,
421                      const ssize_t oldpw_sz)
422 {
423         unsigned int offset = 27;
424         u8 command_v2[COMMAND_BUFFER_SIZE] = {
425                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
426                 tpm_u32(offset + oldpw_sz + 2 + newpw_sz), /* Length */
427                 tpm_u32(TPM2_CC_HIERCHANGEAUTH), /* Command code */
428
429                 /* HANDLE */
430                 tpm_u32(handle),                /* TPM resource handle */
431
432                 /* AUTH_SESSION */
433                 tpm_u32(9 + oldpw_sz),          /* Authorization size */
434                 tpm_u32(TPM2_RS_PW),            /* Session handle */
435                 tpm_u16(0),                     /* Size of <nonce> */
436                                                 /* <nonce> (if any) */
437                 0,                              /* Attributes: Cont/Excl/Rst */
438                 tpm_u16(oldpw_sz)               /* Size of <hmac/password> */
439                 /* STRING(oldpw)                   <hmac/password> (if any) */
440
441                 /* TPM2B_AUTH (TPM2B_DIGEST) */
442                 /* tpm_u16(newpw_sz)               Digest size, new pw length */
443                 /* STRING(newpw)                   Digest buffer, new pw */
444         };
445         int ret;
446
447         /*
448          * Fill the command structure starting from the first buffer:
449          *     - the old password (if any)
450          *     - size of the new password
451          *     - new password
452          */
453         ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
454                                offset, oldpw, oldpw_sz,
455                                offset + oldpw_sz, newpw_sz,
456                                offset + oldpw_sz + 2, newpw, newpw_sz);
457         offset += oldpw_sz + 2 + newpw_sz;
458         if (ret)
459                 return TPM_LIB_ERROR;
460
461         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
462 }
463
464 u32 tpm2_pcr_setauthpolicy(struct udevice *dev, const char *pw,
465                            const ssize_t pw_sz, u32 index, const char *key)
466 {
467         u8 command_v2[COMMAND_BUFFER_SIZE] = {
468                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
469                 tpm_u32(35 + pw_sz + TPM2_DIGEST_LEN), /* Length */
470                 tpm_u32(TPM2_CC_PCR_SETAUTHPOL), /* Command code */
471
472                 /* HANDLE */
473                 tpm_u32(TPM2_RH_PLATFORM),      /* TPM resource handle */
474
475                 /* AUTH_SESSION */
476                 tpm_u32(9 + pw_sz),             /* Authorization size */
477                 tpm_u32(TPM2_RS_PW),            /* session handle */
478                 tpm_u16(0),                     /* Size of <nonce> */
479                                                 /* <nonce> (if any) */
480                 0,                              /* Attributes: Cont/Excl/Rst */
481                 tpm_u16(pw_sz)                  /* Size of <hmac/password> */
482                 /* STRING(pw)                      <hmac/password> (if any) */
483
484                 /* TPM2B_AUTH (TPM2B_DIGEST) */
485                 /* tpm_u16(TPM2_DIGEST_LEN)        Digest size length */
486                 /* STRING(key)                     Digest buffer (PCR key) */
487
488                 /* TPMI_ALG_HASH */
489                 /* tpm_u16(TPM2_ALG_SHA256)   Algorithm of the hash */
490
491                 /* TPMI_DH_PCR */
492                 /* tpm_u32(index),                 PCR Index */
493         };
494         unsigned int offset = 27;
495         int ret;
496
497         /*
498          * Fill the command structure starting from the first buffer:
499          *     - the password (if any)
500          *     - the PCR key length
501          *     - the PCR key
502          *     - the hash algorithm
503          *     - the PCR index
504          */
505         ret = pack_byte_string(command_v2, sizeof(command_v2), "swswd",
506                                offset, pw, pw_sz,
507                                offset + pw_sz, TPM2_DIGEST_LEN,
508                                offset + pw_sz + 2, key, TPM2_DIGEST_LEN,
509                                offset + pw_sz + 2 + TPM2_DIGEST_LEN,
510                                TPM2_ALG_SHA256,
511                                offset + pw_sz + 4 + TPM2_DIGEST_LEN, index);
512         offset += pw_sz + 2 + TPM2_DIGEST_LEN + 2 + 4;
513         if (ret)
514                 return TPM_LIB_ERROR;
515
516         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
517 }
518
519 u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
520                           const ssize_t pw_sz, u32 index, const char *key,
521                           const ssize_t key_sz)
522 {
523         u8 command_v2[COMMAND_BUFFER_SIZE] = {
524                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
525                 tpm_u32(33 + pw_sz + TPM2_DIGEST_LEN), /* Length */
526                 tpm_u32(TPM2_CC_PCR_SETAUTHVAL), /* Command code */
527
528                 /* HANDLE */
529                 tpm_u32(index),                 /* Handle (PCR Index) */
530
531                 /* AUTH_SESSION */
532                 tpm_u32(9 + pw_sz),             /* Authorization size */
533                 tpm_u32(TPM2_RS_PW),            /* session handle */
534                 tpm_u16(0),                     /* Size of <nonce> */
535                                                 /* <nonce> (if any) */
536                 0,                              /* Attributes: Cont/Excl/Rst */
537                 tpm_u16(pw_sz),                 /* Size of <hmac/password> */
538                 /* STRING(pw)                      <hmac/password> (if any) */
539
540                 /* TPM2B_DIGEST */
541                 /* tpm_u16(key_sz)                 Key length */
542                 /* STRING(key)                     Key */
543         };
544         unsigned int offset = 27;
545         int ret;
546
547         /*
548          * Fill the command structure starting from the first buffer:
549          *     - the password (if any)
550          *     - the number of digests, 1 in our case
551          *     - the algorithm, sha256 in our case
552          *     - the digest (64 bytes)
553          */
554         ret = pack_byte_string(command_v2, sizeof(command_v2), "sws",
555                                offset, pw, pw_sz,
556                                offset + pw_sz, key_sz,
557                                offset + pw_sz + 2, key, key_sz);
558         offset += pw_sz + 2 + key_sz;
559         if (ret)
560                 return TPM_LIB_ERROR;
561
562         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
563 }
564
565 u32 tpm2_get_random(struct udevice *dev, void *data, u32 count)
566 {
567         const u8 command_v2[10] = {
568                 tpm_u16(TPM2_ST_NO_SESSIONS),
569                 tpm_u32(12),
570                 tpm_u32(TPM2_CC_GET_RANDOM),
571         };
572         u8 buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
573
574         const size_t data_size_offset = 10;
575         const size_t data_offset = 12;
576         size_t response_length = sizeof(response);
577         u32 data_size;
578         u8 *out = data;
579
580         while (count > 0) {
581                 u32 this_bytes = min((size_t)count,
582                                      sizeof(response) - data_offset);
583                 u32 err;
584
585                 if (pack_byte_string(buf, sizeof(buf), "sw",
586                                      0, command_v2, sizeof(command_v2),
587                                      sizeof(command_v2), this_bytes))
588                         return TPM_LIB_ERROR;
589                 err = tpm_sendrecv_command(dev, buf, response,
590                                            &response_length);
591                 if (err)
592                         return err;
593                 if (unpack_byte_string(response, response_length, "w",
594                                        data_size_offset, &data_size))
595                         return TPM_LIB_ERROR;
596                 if (data_size > this_bytes)
597                         return TPM_LIB_ERROR;
598                 if (unpack_byte_string(response, response_length, "s",
599                                        data_offset, out, data_size))
600                         return TPM_LIB_ERROR;
601
602                 count -= data_size;
603                 out += data_size;
604         }
605
606         return 0;
607 }
608
609 u32 tpm2_write_lock(struct udevice *dev, u32 index)
610 {
611         u8 command_v2[COMMAND_BUFFER_SIZE] = {
612                 /* header 10 bytes */
613                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
614                 tpm_u32(10 + 8 + 13), /* Length */
615                 tpm_u32(TPM2_CC_NV_WRITELOCK), /* Command code */
616
617                 /* handles 8 bytes */
618                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
619                 tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
620
621                 /* session header 9 bytes */
622                 tpm_u32(9),                     /* Header size */
623                 tpm_u32(TPM2_RS_PW),            /* Password authorisation */
624                 tpm_u16(0),                     /* nonce_size */
625                 0,                              /* session_attrs */
626                 tpm_u16(0),                     /* auth_size */
627         };
628
629         return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
630 }
631
632 u32 tpm2_disable_platform_hierarchy(struct udevice *dev)
633 {
634         struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
635         u8 command_v2[COMMAND_BUFFER_SIZE] = {
636                 /* header 10 bytes */
637                 tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
638                 tpm_u32(10 + 4 + 13 + 5),       /* Length */
639                 tpm_u32(TPM2_CC_HIER_CONTROL),  /* Command code */
640
641                 /* 4 bytes */
642                 tpm_u32(TPM2_RH_PLATFORM),      /* Primary platform seed */
643
644                 /* session header 9 bytes */
645                 tpm_u32(9),                     /* Header size */
646                 tpm_u32(TPM2_RS_PW),            /* Password authorisation */
647                 tpm_u16(0),                     /* nonce_size */
648                 0,                              /* session_attrs */
649                 tpm_u16(0),                     /* auth_size */
650
651                 /* payload 5 bytes */
652                 tpm_u32(TPM2_RH_PLATFORM),      /* Hierarchy to disable */
653                 0,                              /* 0=disable */
654         };
655         int ret;
656
657         ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
658         log_info("ret=%s, %x\n", dev->name, ret);
659         if (ret)
660                 return ret;
661
662         priv->plat_hier_disabled = true;
663
664         return 0;
665 }
666
667 u32 tpm2_submit_command(struct udevice *dev, const u8 *sendbuf,
668                         u8 *recvbuf, size_t *recv_size)
669 {
670         return tpm_sendrecv_command(dev, sendbuf, recvbuf, recv_size);
671 }