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