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