2 * Copyright (c) 2013 Google, Inc
4 * SPDX-License-Identifier: GPL-2.0+
10 #include <asm/state.h>
11 #include <asm/unaligned.h>
12 #include <linux/crc8.h>
14 /* TPM NVRAM location indices. */
15 #define FIRMWARE_NV_INDEX 0x1007
16 #define KERNEL_NV_INDEX 0x1008
18 #define NV_DATA_PUBLIC_PERMISSIONS_OFFSET 60
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' */
24 struct rollback_space_kernel
{
25 /* Struct version, for backwards compatibility */
26 uint8_t struct_version
;
27 /* Unique ID to detect space redefinition */
30 uint32_t kernel_versions
;
31 /* Reserved for future expansion */
33 /* Checksum (v2 and later only) */
35 } __packed rollback_space_kernel
;
38 * These numbers derive from adding the sizes of command fields as shown in
39 * the TPM commands manual.
41 #define TPM_REQUEST_HEADER_LENGTH 10
42 #define TPM_RESPONSE_HEADER_LENGTH 10
44 /* These are the different non-volatile spaces that we emulate */
52 /* Size of each non-volatile space */
53 #define NV_DATA_SIZE 0x20
56 * Information about our TPM emulation. This is preserved in the sandbox
57 * state file if enabled.
59 static struct tpm_state
{
60 uint8_t nvdata
[NV_SEQ_COUNT
][NV_DATA_SIZE
];
64 * sandbox_tpm_read_state() - read the sandbox EC state from the state file
66 * If data is available, then blob and node will provide access to it. If
67 * not this function sets up an empty TPM.
69 * @blob: Pointer to device tree blob, or NULL if no data to read
70 * @node: Node offset to read from
72 static int sandbox_tpm_read_state(const void *blob
, int node
)
81 for (i
= 0; i
< NV_SEQ_COUNT
; i
++) {
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
);
94 * cros_ec_write_state() - Write out our state to the state file
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.
99 * @blob: Device tree blob holding state
100 * @node: Node to write our state into
102 static int sandbox_tpm_write_state(void *blob
, int node
)
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.
111 for (i
= 0; i
< NV_SEQ_COUNT
; i
++) {
114 sprintf(prop_name
, "nvdata%d", i
);
115 fdt_setprop(blob
, node
, prop_name
, g_state
.nvdata
[i
],
122 SANDBOX_STATE_IO(sandbox_tpm
, "google,sandbox-tpm", sandbox_tpm_read_state
,
123 sandbox_tpm_write_state
);
125 static int index_to_seq(uint32_t index
)
128 case FIRMWARE_NV_INDEX
:
129 return NV_SEQ_FIRMWARE
;
130 case KERNEL_NV_INDEX
:
131 return NV_SEQ_KERNEL
;
133 return NV_GLOBAL_LOCK
;
136 printf("Invalid nv index %#x\n", index
);
140 static int sandbox_tpm_xfer(struct udevice
*dev
, const uint8_t *sendbuf
,
141 size_t send_size
, uint8_t *recvbuf
,
144 struct tpm_state
*tpm
= dev_get_priv(dev
);
145 uint32_t code
, index
, length
, type
;
149 code
= get_unaligned_be32(sendbuf
+ sizeof(uint16_t) +
151 printf("tpm: %zd bytes, recv_len %zd, cmd = %x\n", send_size
,
153 print_buffer(0, sendbuf
, 1, send_size
, 0);
155 case 0x65: /* get flags */
156 type
= get_unaligned_be32(sendbuf
+ 14);
159 index
= get_unaligned_be32(sendbuf
+ 18);
160 printf("Get flags index %#02x\n", index
);
162 memset(recvbuf
, '\0', *recv_len
);
163 put_unaligned_be32(22, recvbuf
+
164 TPM_RESPONSE_HEADER_LENGTH
);
165 data
= recvbuf
+ TPM_RESPONSE_HEADER_LENGTH
+
168 case FIRMWARE_NV_INDEX
:
170 case KERNEL_NV_INDEX
:
171 /* TPM_NV_PER_PPWRITE */
172 put_unaligned_be32(1, data
+
173 NV_DATA_PUBLIC_PERMISSIONS_OFFSET
);
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
);
184 printf(" ** Unknown 0x65 command type %#02x\n",
189 case 0xcd: /* nvwrite */
190 index
= get_unaligned_be32(sendbuf
+ 10);
191 length
= get_unaligned_be32(sendbuf
+ 18);
192 seq
= index_to_seq(index
);
195 printf("tpm: nvwrite index=%#02x, len=%#02x\n", index
, length
);
196 memcpy(&tpm
->nvdata
[seq
], sendbuf
+ 22, length
);
198 memset(recvbuf
, '\0', *recv_len
);
200 case 0xcf: /* nvread */
201 index
= get_unaligned_be32(sendbuf
+ 10);
202 length
= get_unaligned_be32(sendbuf
+ 18);
203 seq
= index_to_seq(index
);
206 printf("tpm: nvread index=%#02x, len=%#02x\n", index
, length
);
207 *recv_len
= TPM_RESPONSE_HEADER_LENGTH
+ sizeof(uint32_t) +
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
;
215 data
= recvbuf
+ TPM_RESPONSE_HEADER_LENGTH
+
217 memset(&rsk
, 0, sizeof(struct rollback_space_kernel
));
218 rsk
.struct_version
= 2;
219 rsk
.uid
= ROLLBACK_SPACE_KERNEL_UID
;
220 rsk
.crc8
= crc8(0, (unsigned char *)&rsk
,
221 offsetof(struct rollback_space_kernel
,
223 memcpy(data
, &rsk
, sizeof(rsk
));
225 memcpy(recvbuf
+ TPM_RESPONSE_HEADER_LENGTH
+
226 sizeof(uint32_t), &tpm
->nvdata
[seq
], length
);
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 */
237 memset(recvbuf
, '\0', *recv_len
);
240 printf("Unknown tpm command %02x\n", code
);
247 static int sandbox_tpm_get_desc(struct udevice
*dev
, char *buf
, int size
)
252 return snprintf(buf
, size
, "sandbox TPM");
255 static int sandbox_tpm_probe(struct udevice
*dev
)
257 struct tpm_state
*tpm
= dev_get_priv(dev
);
259 memcpy(tpm
, &g_state
, sizeof(*tpm
));
264 static int sandbox_tpm_open(struct udevice
*dev
)
269 static int sandbox_tpm_close(struct udevice
*dev
)
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
,
281 static const struct udevice_id sandbox_tpm_ids
[] = {
282 { .compatible
= "google,sandbox-tpm" },
286 U_BOOT_DRIVER(sandbox_tpm
) = {
287 .name
= "sandbox_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
),