tpm_crb.c revision 357526
1/*-
2 * Copyright (c) 2018 Stormshield.
3 * Copyright (c) 2018 Semihalf.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/11/sys/dev/tpm/tpm_crb.c 357526 2020-02-04 20:09:25Z dim $");
30
31#include "tpm20.h"
32
33/*
34 * CRB register space as defined in
35 * TCG_PC_Client_Platform_TPM_Profile_PTP_2.0_r1.03_v22
36 */
37#define	TPM_LOC_STATE			0x0
38#define	TPM_LOC_CTRL			0x8
39#define	TPM_LOC_STS			0xC
40#define	TPM_CRB_INTF_ID			0x30
41#define	TPM_CRB_CTRL_EXT		0x38
42#define	TPM_CRB_CTRL_REQ		0x40
43#define	TPM_CRB_CTRL_STS		0x44
44#define	TPM_CRB_CTRL_CANCEL		0x48
45#define	TPM_CRB_CTRL_START		0x4C
46#define	TPM_CRB_INT_ENABLE		0x50
47#define	TPM_CRB_INT_STS			0x54
48#define	TPM_CRB_CTRL_CMD_SIZE		0x58
49#define	TPM_CRB_CTRL_CMD_LADDR		0x5C
50#define	TPM_CRB_CTRL_CMD_HADDR		0x60
51#define	TPM_CRB_CTRL_RSP_SIZE		0x64
52#define	TPM_CRB_CTRL_RSP_ADDR		0x68
53#define	TPM_CRB_CTRL_RSP_HADDR		0x6c
54#define	TPM_CRB_DATA_BUFFER		0x80
55
56#define	TPM_LOC_STATE_ESTB		BIT(0)
57#define	TPM_LOC_STATE_ASSIGNED		BIT(1)
58#define	TPM_LOC_STATE_ACTIVE_MASK	0x9C
59#define	TPM_LOC_STATE_VALID		BIT(7)
60
61#define	TPM_CRB_INTF_ID_TYPE_CRB	0x1
62#define	TPM_CRB_INTF_ID_TYPE		0x7
63
64#define	TPM_LOC_CTRL_REQUEST		BIT(0)
65#define	TPM_LOC_CTRL_RELINQUISH		BIT(1)
66
67#define	TPM_CRB_CTRL_REQ_GO_READY	BIT(0)
68#define	TPM_CRB_CTRL_REQ_GO_IDLE	BIT(1)
69
70#define	TPM_CRB_CTRL_STS_ERR_BIT	BIT(0)
71#define	TPM_CRB_CTRL_STS_IDLE_BIT	BIT(1)
72
73#define	TPM_CRB_CTRL_CANCEL_CMD		0x1
74#define	TPM_CRB_CTRL_CANCEL_CLEAR	0x0
75
76#define	TPM_CRB_CTRL_START_CMD		BIT(0)
77
78#define	TPM_CRB_INT_ENABLE_BIT		BIT(31)
79
80struct tpmcrb_sc {
81	struct tpm_sc	base;
82	bus_size_t	cmd_off;
83	bus_size_t	rsp_off;
84	size_t		cmd_buf_size;
85	size_t		rsp_buf_size;
86};
87
88
89int tpmcrb_transmit(struct tpm_sc *sc, size_t size);
90
91static int tpmcrb_acpi_probe(device_t dev);
92static int tpmcrb_attach(device_t dev);
93static int tpmcrb_detach(device_t dev);
94
95static ACPI_STATUS tpmcrb_fix_buff_offsets(ACPI_RESOURCE *res, void *arg);
96
97static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off,
98    uint32_t mask, uint32_t val, int32_t timeout);
99static bool tpmcrb_request_locality(struct tpm_sc *sc, int locality);
100static void tpmcrb_relinquish_locality(struct tpm_sc *sc);
101static bool tpmcrb_cancel_cmd(struct tpm_sc *sc);
102
103char *tpmcrb_ids[] = {"MSFT0101", NULL};
104
105static int
106tpmcrb_acpi_probe(device_t dev)
107{
108	int err = 0;
109	ACPI_TABLE_TPM2 *tbl;
110	ACPI_STATUS status;
111
112	if (ACPI_ID_PROBE(device_get_parent(dev), dev, tpmcrb_ids) == NULL)
113		return (ENXIO);
114
115	/*Find TPM2 Header*/
116	status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl);
117	if(ACPI_FAILURE(status) ||
118	   tbl->StartMethod != TPM2_START_METHOD_CRB)
119		err = ENXIO;
120
121	device_set_desc(dev, "Trusted Platform Module 2.0, CRB mode");
122	return (err);
123}
124
125static ACPI_STATUS
126tpmcrb_fix_buff_offsets(ACPI_RESOURCE *res, void *arg)
127{
128	struct tpmcrb_sc *crb_sc;
129	size_t length;
130	uint32_t base_addr;
131
132	crb_sc = (struct tpmcrb_sc *)arg;
133
134	if (res->Type != ACPI_RESOURCE_TYPE_FIXED_MEMORY32)
135		return (AE_OK);
136
137	base_addr = res->Data.FixedMemory32.Address;
138	length = res->Data.FixedMemory32.AddressLength;
139
140	if (crb_sc->cmd_off > base_addr && crb_sc->cmd_off < base_addr + length)
141		crb_sc->cmd_off -= base_addr;
142	if (crb_sc->rsp_off > base_addr && crb_sc->rsp_off < base_addr + length)
143		crb_sc->rsp_off -= base_addr;
144
145	return (AE_OK);
146}
147
148static int
149tpmcrb_attach(device_t dev)
150{
151	struct tpmcrb_sc *crb_sc;
152	struct tpm_sc *sc;
153	ACPI_HANDLE handle;
154	ACPI_STATUS status;
155	int result;
156
157	crb_sc = device_get_softc(dev);
158	sc = &crb_sc->base;
159	handle = acpi_get_handle(dev);
160
161	sc->dev = dev;
162
163	sc->mem_rid = 0;
164	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid,
165					     RF_ACTIVE);
166	if (sc->mem_res == NULL)
167		return (ENXIO);
168
169	if(!tpmcrb_request_locality(sc, 0)) {
170		bus_release_resource(dev, SYS_RES_MEMORY,
171		    sc->mem_rid, sc->mem_res);
172		return (ENXIO);
173	}
174
175	/*
176	 * Disable all interrupts for now, since I don't have a device that
177	 * works in CRB mode and supports them.
178	 */
179	AND4(sc, TPM_CRB_INT_ENABLE, ~TPM_CRB_INT_ENABLE_BIT);
180	sc->interrupts = false;
181
182	/*
183	 * Read addresses of Tx/Rx buffers and their sizes. Note that they
184	 * can be implemented by a single buffer. Also for some reason CMD
185	 * addr is stored in two 4 byte neighboring registers, whereas RSP is
186	 * stored in a single 8 byte one.
187	 */
188#ifdef __amd64__
189	crb_sc->rsp_off = RD8(sc, TPM_CRB_CTRL_RSP_ADDR);
190#else
191	crb_sc->rsp_off = RD4(sc, TPM_CRB_CTRL_RSP_ADDR);
192	crb_sc->rsp_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_RSP_HADDR) << 32);
193#endif
194	crb_sc->cmd_off = RD4(sc, TPM_CRB_CTRL_CMD_LADDR);
195	crb_sc->cmd_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_CMD_HADDR) << 32);
196	crb_sc->cmd_buf_size = RD4(sc, TPM_CRB_CTRL_CMD_SIZE);
197	crb_sc->rsp_buf_size = RD4(sc, TPM_CRB_CTRL_RSP_SIZE);
198
199	tpmcrb_relinquish_locality(sc);
200
201	/* Emulator returns address in acpi space instead of an offset */
202	status = AcpiWalkResources(handle, "_CRS", tpmcrb_fix_buff_offsets,
203		    (void *)crb_sc);
204	if (ACPI_FAILURE(status)) {
205		tpmcrb_detach(dev);
206		return (ENXIO);
207	}
208
209	if (crb_sc->rsp_off == crb_sc->cmd_off) {
210		/*
211		 * If Tx/Rx buffers are implemented as one they have to be of
212		 * same size
213		 */
214		if (crb_sc->cmd_buf_size != crb_sc->rsp_buf_size) {
215			device_printf(sc->dev,
216			    "Overlapping Tx/Rx buffers have different sizes\n");
217			tpmcrb_detach(dev);
218			return (ENXIO);
219		}
220	}
221
222	sc->transmit = tpmcrb_transmit;
223
224	result = tpm20_init(sc);
225	if (result != 0)
226		tpmcrb_detach(dev);
227
228	return (result);
229}
230
231static int
232tpmcrb_detach(device_t dev)
233{
234	struct tpm_sc *sc;
235
236	sc = device_get_softc(dev);
237	tpm20_release(sc);
238
239	if (sc->mem_res != NULL)
240		bus_release_resource(dev, SYS_RES_MEMORY,
241		    sc->mem_rid, sc->mem_res);
242
243	return (0);
244}
245
246static bool
247tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
248    int32_t timeout)
249{
250
251	/* Check for condition */
252	if ((RD4(sc, off) & mask) == val)
253		return (true);
254
255	while (timeout > 0) {
256		if ((RD4(sc, off) & mask) == val)
257			return (true);
258
259		pause("TPM in polling mode", 1);
260		timeout -= tick;
261	}
262	return (false);
263}
264
265static bool
266tpmcrb_request_locality(struct tpm_sc *sc, int locality)
267{
268	uint32_t mask;
269
270	/* Currently we only support Locality 0 */
271	if (locality != 0)
272		return (false);
273
274	mask = TPM_LOC_STATE_VALID | TPM_LOC_STATE_ASSIGNED;
275
276	OR4(sc, TPM_LOC_CTRL, TPM_LOC_CTRL_REQUEST);
277	if (!tpm_wait_for_u32(sc, TPM_LOC_STATE, mask, mask, TPM_TIMEOUT_C))
278		return (false);
279
280	return (true);
281}
282
283static void
284tpmcrb_relinquish_locality(struct tpm_sc *sc)
285{
286
287	OR4(sc, TPM_LOC_CTRL, TPM_LOC_CTRL_RELINQUISH);
288}
289
290static bool
291tpmcrb_cancel_cmd(struct tpm_sc *sc)
292{
293	uint32_t mask = ~0;
294
295	WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CMD);
296	if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START,
297		    mask, ~mask, TPM_TIMEOUT_B)) {
298		device_printf(sc->dev,
299		    "Device failed to cancel command\n");
300		return (false);
301	}
302
303	WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR);
304	return (true);
305}
306
307int
308tpmcrb_transmit(struct tpm_sc *sc, size_t length)
309{
310	struct tpmcrb_sc *crb_sc;
311	uint32_t mask, curr_cmd;
312	int timeout, bytes_available;
313
314	crb_sc = (struct tpmcrb_sc *)sc;
315
316	sx_assert(&sc->dev_lock, SA_XLOCKED);
317
318	if (length > crb_sc->cmd_buf_size) {
319		device_printf(sc->dev,
320		    "Requested transfer is bigger than buffer size\n");
321		return (E2BIG);
322	}
323
324	if (RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_ERR_BIT) {
325		device_printf(sc->dev,
326		    "Device has Error bit set\n");
327		return (EIO);
328	}
329	if (!tpmcrb_request_locality(sc, 0)) {
330		device_printf(sc->dev,
331		    "Failed to obtain locality\n");
332		return (EIO);
333	}
334	/* Clear cancellation bit */
335	WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR);
336
337	/* Switch device to idle state if necessary */
338	if (!(RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_IDLE_BIT)) {
339		OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE);
340
341		mask = TPM_CRB_CTRL_STS_IDLE_BIT;
342		if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS,
343			    mask, mask, TPM_TIMEOUT_C)) {
344			device_printf(sc->dev,
345			    "Failed to transition to idle state\n");
346			return (EIO);
347		}
348	}
349	/* Switch to ready state */
350	OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_READY);
351
352	mask = TPM_CRB_CTRL_REQ_GO_READY;
353	if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS,
354		    mask, !mask, TPM_TIMEOUT_C)) {
355		device_printf(sc->dev,
356		    "Failed to transition to ready state\n");
357		return (EIO);
358	}
359
360	/*
361	 * Calculate timeout for current command.
362	 * Command code is passed in bytes 6-10.
363	 */
364	curr_cmd = be32toh(*(uint32_t *) (&sc->buf[6]));
365	timeout = tpm20_get_timeout(curr_cmd);
366
367	/* Send command and tell device to process it. */
368	bus_write_region_stream_1(sc->mem_res, crb_sc->cmd_off,
369	    sc->buf, length);
370	bus_barrier(sc->mem_res, crb_sc->cmd_off,
371	    length, BUS_SPACE_BARRIER_WRITE);
372
373	WR4(sc, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD);
374	bus_barrier(sc->mem_res, TPM_CRB_CTRL_START,
375	    4, BUS_SPACE_BARRIER_WRITE);
376
377	mask = ~0;
378	if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, timeout)) {
379		device_printf(sc->dev,
380		    "Timeout while waiting for device to process cmd\n");
381		if (!tpmcrb_cancel_cmd(sc))
382			return (EIO);
383	}
384
385	/* Read response header. Length is passed in bytes 2 - 6. */
386	bus_read_region_stream_1(sc->mem_res, crb_sc->rsp_off,
387	    sc->buf, TPM_HEADER_SIZE);
388	bytes_available = be32toh(*(uint32_t *) (&sc->buf[2]));
389
390	if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) {
391		device_printf(sc->dev,
392		    "Incorrect response size: %d\n",
393		    bytes_available);
394		return (EIO);
395	}
396
397	bus_read_region_stream_1(sc->mem_res, crb_sc->rsp_off + TPM_HEADER_SIZE,
398	      &sc->buf[TPM_HEADER_SIZE], bytes_available - TPM_HEADER_SIZE);
399
400	OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE);
401
402	tpmcrb_relinquish_locality(sc);
403	sc->pending_data_length = bytes_available;
404
405	return (0);
406}
407
408/* ACPI Driver */
409static device_method_t	tpmcrb_methods[] = {
410	DEVMETHOD(device_probe,		tpmcrb_acpi_probe),
411	DEVMETHOD(device_attach,	tpmcrb_attach),
412	DEVMETHOD(device_detach,	tpmcrb_detach),
413	DEVMETHOD(device_shutdown,	tpm20_shutdown),
414	DEVMETHOD(device_suspend,	tpm20_suspend),
415	{0, 0}
416};
417static driver_t	tpmcrb_driver = {
418	"tpmcrb", tpmcrb_methods, sizeof(struct tpmcrb_sc),
419};
420
421devclass_t tpmcrb_devclass;
422DRIVER_MODULE(tpmcrb, acpi, tpmcrb_driver, tpmcrb_devclass, 0, 0);
423