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