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