uboot/drivers/tpm/tpm_tis_sandbox.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 Google, Inc
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <common.h>
   8#include <asm/state.h>
   9#include <asm/unaligned.h>
  10#include <linux/crc8.h>
  11
  12/* TPM NVRAM location indices. */
  13#define FIRMWARE_NV_INDEX               0x1007
  14#define KERNEL_NV_INDEX                 0x1008
  15
  16#define NV_DATA_PUBLIC_PERMISSIONS_OFFSET       60
  17
  18/* Kernel TPM space - KERNEL_NV_INDEX, locked with physical presence */
  19#define ROLLBACK_SPACE_KERNEL_VERSION   2
  20#define ROLLBACK_SPACE_KERNEL_UID       0x4752574C  /* 'GRWL' */
  21
  22struct rollback_space_kernel {
  23        /* Struct version, for backwards compatibility */
  24        uint8_t struct_version;
  25        /* Unique ID to detect space redefinition */
  26        uint32_t uid;
  27        /* Kernel versions */
  28        uint32_t kernel_versions;
  29        /* Reserved for future expansion */
  30        uint8_t reserved[3];
  31        /* Checksum (v2 and later only) */
  32        uint8_t crc8;
  33} __packed rollback_space_kernel;
  34
  35/*
  36 * These numbers derive from adding the sizes of command fields as shown in
  37 * the TPM commands manual.
  38 */
  39#define TPM_REQUEST_HEADER_LENGTH       10
  40#define TPM_RESPONSE_HEADER_LENGTH      10
  41
  42/* These are the different non-volatile spaces that we emulate */
  43enum {
  44        NV_GLOBAL_LOCK,
  45        NV_SEQ_FIRMWARE,
  46        NV_SEQ_KERNEL,
  47        NV_SEQ_COUNT,
  48};
  49
  50/* Size of each non-volatile space */
  51#define NV_DATA_SIZE            0x20
  52
  53/*
  54 * Information about our TPM emulation. This is preserved in the sandbox
  55 * state file if enabled.
  56 */
  57static struct tpm_state {
  58        uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
  59} state;
  60
  61/**
  62 * sandbox_tpm_read_state() - read the sandbox EC state from the state file
  63 *
  64 * If data is available, then blob and node will provide access to it. If
  65 * not this function sets up an empty TPM.
  66 *
  67 * @blob: Pointer to device tree blob, or NULL if no data to read
  68 * @node: Node offset to read from
  69 */
  70static int sandbox_tpm_read_state(const void *blob, int node)
  71{
  72        const char *prop;
  73        int len;
  74        int i;
  75
  76        if (!blob)
  77                return 0;
  78
  79        for (i = 0; i < NV_SEQ_COUNT; i++) {
  80                char prop_name[20];
  81
  82                sprintf(prop_name, "nvdata%d", i);
  83                prop = fdt_getprop(blob, node, prop_name, &len);
  84                if (prop && len == NV_DATA_SIZE)
  85                        memcpy(state.nvdata[i], prop, NV_DATA_SIZE);
  86        }
  87
  88        return 0;
  89}
  90
  91/**
  92 * cros_ec_write_state() - Write out our state to the state file
  93 *
  94 * The caller will ensure that there is a node ready for the state. The node
  95 * may already contain the old state, in which case it is overridden.
  96 *
  97 * @blob: Device tree blob holding state
  98 * @node: Node to write our state into
  99 */
 100static int sandbox_tpm_write_state(void *blob, int node)
 101{
 102        int i;
 103
 104        /*
 105         * We are guaranteed enough space to write basic properties.
 106         * We could use fdt_add_subnode() to put each set of data in its
 107         * own node - perhaps useful if we add access informaiton to each.
 108         */
 109        for (i = 0; i < NV_SEQ_COUNT; i++) {
 110                char prop_name[20];
 111
 112                sprintf(prop_name, "nvdata%d", i);
 113                fdt_setprop(blob, node, prop_name, state.nvdata[i],
 114                            NV_DATA_SIZE);
 115        }
 116
 117        return 0;
 118}
 119
 120SANDBOX_STATE_IO(sandbox_tpm, "google,sandbox-tpm", sandbox_tpm_read_state,
 121                 sandbox_tpm_write_state);
 122
 123static int index_to_seq(uint32_t index)
 124{
 125        switch (index) {
 126        case FIRMWARE_NV_INDEX:
 127                return NV_SEQ_FIRMWARE;
 128        case KERNEL_NV_INDEX:
 129                return NV_SEQ_KERNEL;
 130        case 0:
 131                return NV_GLOBAL_LOCK;
 132        }
 133
 134        printf("Invalid nv index %#x\n", index);
 135        return -1;
 136}
 137
 138int tis_sendrecv(const u8 *sendbuf, size_t send_size,
 139                 u8 *recvbuf, size_t *recv_len)
 140{
 141        struct tpm_state *tpm = &state;
 142        uint32_t code, index, length, type;
 143        uint8_t *data;
 144        int seq;
 145
 146        code = get_unaligned_be32(sendbuf + sizeof(uint16_t) +
 147                                  sizeof(uint32_t));
 148        printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size,
 149               *recv_len, code);
 150        print_buffer(0, sendbuf, 1, send_size, 0);
 151        switch (code) {
 152        case 0x65: /* get flags */
 153                type = get_unaligned_be32(sendbuf + 14);
 154                switch (type) {
 155                case 4:
 156                        index = get_unaligned_be32(sendbuf + 18);
 157                        printf("Get flags index %#02x\n", index);
 158                        *recv_len = 22;
 159                        memset(recvbuf, '\0', *recv_len);
 160                        put_unaligned_be32(22, recvbuf +
 161                                           TPM_RESPONSE_HEADER_LENGTH);
 162                        data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
 163                                        sizeof(uint32_t);
 164                        switch (index) {
 165                        case FIRMWARE_NV_INDEX:
 166                                break;
 167                        case KERNEL_NV_INDEX:
 168                                /* TPM_NV_PER_PPWRITE */
 169                                put_unaligned_be32(1, data +
 170                                        NV_DATA_PUBLIC_PERMISSIONS_OFFSET);
 171                                break;
 172                        }
 173                        break;
 174                case 0x11: /* TPM_CAP_NV_INDEX */
 175                        index = get_unaligned_be32(sendbuf + 18);
 176                        printf("Get cap nv index %#02x\n", index);
 177                        put_unaligned_be32(22, recvbuf +
 178                                           TPM_RESPONSE_HEADER_LENGTH);
 179                        break;
 180                default:
 181                        printf("   ** Unknown 0x65 command type %#02x\n",
 182                               type);
 183                        return -1;
 184                }
 185                break;
 186        case 0xcd: /* nvwrite */
 187                index = get_unaligned_be32(sendbuf + 10);
 188                length = get_unaligned_be32(sendbuf + 18);
 189                seq = index_to_seq(index);
 190                if (seq < 0)
 191                        return -1;
 192                printf("tpm: nvwrite index=%#02x, len=%#02x\n", index, length);
 193                memcpy(&tpm->nvdata[seq], sendbuf + 22, length);
 194                *recv_len = 12;
 195                memset(recvbuf, '\0', *recv_len);
 196                break;
 197        case 0xcf: /* nvread */
 198                index = get_unaligned_be32(sendbuf + 10);
 199                length = get_unaligned_be32(sendbuf + 18);
 200                seq = index_to_seq(index);
 201                if (seq < 0)
 202                        return -1;
 203                printf("tpm: nvread index=%#02x, len=%#02x\n", index, length);
 204                *recv_len = TPM_RESPONSE_HEADER_LENGTH + sizeof(uint32_t) +
 205                                        length;
 206                memset(recvbuf, '\0', *recv_len);
 207                put_unaligned_be32(length, recvbuf +
 208                                   TPM_RESPONSE_HEADER_LENGTH);
 209                if (seq == NV_SEQ_KERNEL) {
 210                        struct rollback_space_kernel rsk;
 211
 212                        data = recvbuf + TPM_RESPONSE_HEADER_LENGTH +
 213                                        sizeof(uint32_t);
 214                        rsk.struct_version = 2;
 215                        rsk.uid = ROLLBACK_SPACE_KERNEL_UID;
 216                        rsk.kernel_versions = 0;
 217                        rsk.crc8 = crc8((unsigned char *)&rsk,
 218                                        offsetof(struct rollback_space_kernel,
 219                                                 crc8));
 220                        memcpy(data, &rsk, sizeof(rsk));
 221                } else {
 222                        memcpy(recvbuf + TPM_RESPONSE_HEADER_LENGTH +
 223                               sizeof(uint32_t), &tpm->nvdata[seq], length);
 224                }
 225                break;
 226        case 0x14: /* tpm extend */
 227        case 0x15: /* pcr read */
 228        case 0x5d: /* force clear */
 229        case 0x6f: /* physical enable */
 230        case 0x72: /* physical set deactivated */
 231        case 0x99: /* startup */
 232        case 0x4000000a:  /* assert physical presence */
 233                *recv_len = 12;
 234                memset(recvbuf, '\0', *recv_len);
 235                break;
 236        default:
 237                printf("Unknown tpm command %02x\n", code);
 238                return -1;
 239        }
 240
 241        return 0;
 242}
 243
 244int tis_open(void)
 245{
 246        printf("%s\n", __func__);
 247        return 0;
 248}
 249
 250int tis_close(void)
 251{
 252        printf("%s\n", __func__);
 253        return 0;
 254}
 255
 256int tis_init(void)
 257{
 258        printf("%s\n", __func__);
 259        return 0;
 260}
 261