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