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