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