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