Module Name: src Committed By: maxv Date: Sat Jun 22 12:57:41 UTC 2019
Modified Files: src/sys/dev/acpi: tpm_acpi.c src/sys/dev/ic: tpm.c tpmreg.h tpmvar.h src/sys/dev/isa: tpm_isa.c Log Message: Revamp the TPM driver * Fix several bugs, and clean up. * Drop the "legacy" interface, it relied on an undocumented global variable that was never initialized. It likely had never been tested either, so good riddance. * Add support for TPM 2.0 chips via ACPI. For these we use the TIS1.2 interface, same as TPM 1.2. * Provide an ioctl to fetch TPM information from the driver. Tested on a Lenovo desktop with ACPI-TPM2.0, an HP laptop ACPI-TPM2.0, a Dell laptop with ISA-TPM1.2. To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/sys/dev/acpi/tpm_acpi.c cvs rdiff -u -r1.12 -r1.13 src/sys/dev/ic/tpm.c cvs rdiff -u -r1.3 -r1.4 src/sys/dev/ic/tpmreg.h src/sys/dev/ic/tpmvar.h cvs rdiff -u -r1.3 -r1.4 src/sys/dev/isa/tpm_isa.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/acpi/tpm_acpi.c diff -u src/sys/dev/acpi/tpm_acpi.c:1.7 src/sys/dev/acpi/tpm_acpi.c:1.8 --- src/sys/dev/acpi/tpm_acpi.c:1.7 Sun Dec 9 11:12:58 2018 +++ src/sys/dev/acpi/tpm_acpi.c Sat Jun 22 12:57:40 2019 @@ -1,11 +1,11 @@ -/* $NetBSD: tpm_acpi.c,v 1.7 2018/12/09 11:12:58 jdolecek Exp $ */ +/* $NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $ */ -/*- - * Copyright (c) 2012 The NetBSD Foundation, Inc. +/* + * Copyright (c) 2012, 2019 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. + * by Christos Zoulas and Maxime Villard. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,31 +28,9 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -/* - * Copyright (c) 2008, 2009 Michael Shalayeff - * Copyright (c) 2009, 2010 Hans-Jörg Höxer - * All rights reserved. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -/* - * ACPI attachment for the Infineon SLD 9630 TT 1.1 and SLB 9635 TT 1.2 - * trusted platform module. See www.trustedcomputinggroup.org - */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.7 2018/12/09 11:12:58 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -71,44 +49,48 @@ __KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v #include "ioconf.h" -#define _COMPONENT ACPI_RESOURCE_COMPONENT -ACPI_MODULE_NAME ("tpm_acpi") +#define _COMPONENT ACPI_RESOURCE_COMPONENT +ACPI_MODULE_NAME ("tpm_acpi") static int tpm_acpi_match(device_t, cfdata_t, void *); static void tpm_acpi_attach(device_t, device_t, void *); - CFATTACH_DECL_NEW(tpm_acpi, sizeof(struct tpm_softc), tpm_acpi_match, tpm_acpi_attach, NULL, NULL); /* - * Supported device IDs + * Supported TPM 2.0 devices. */ - -#ifdef notyet -static const char * const tpm_acpi_ids[] = { - "IFX0101", - "IFX0102", +static const char * const tpm2_acpi_ids[] = { + "MSFT0101", NULL }; -#endif static int tpm_acpi_match(device_t parent, cfdata_t match, void *aux) { struct acpi_attach_args *aa = aux; + ACPI_TABLE_TPM2 *tpm2; + ACPI_STATUS rv; if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) return 0; - /* There can be only one. */ + /* We support only one TPM. */ if (tpm_cd.cd_devs && tpm_cd.cd_devs[0]) return 0; -#ifdef notyet - return acpi_match_hid(aa->aa_node->ad_devinfo, tpm_acpi_ids); -#else - return 0; -#endif + + if (!acpi_match_hid(aa->aa_node->ad_devinfo, tpm2_acpi_ids)) + return 0; + + /* Make sure it uses TIS, and not CRB. */ + rv = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **)&tpm2); + if (ACPI_FAILURE(rv)) + return 0; + if (tpm2->StartMethod != ACPI_TPM2_MEMORY_MAPPED) + return 0; + + return 1; } static void @@ -117,7 +99,6 @@ tpm_acpi_attach(device_t parent, device_ struct tpm_softc *sc = device_private(self); struct acpi_attach_args *aa = aux; struct acpi_resources res; - struct acpi_io *io; struct acpi_mem *mem; struct acpi_irq *irq; bus_addr_t base; @@ -125,59 +106,43 @@ tpm_acpi_attach(device_t parent, device_ int rv, inum; sc->sc_dev = self; + sc->sc_ver = TPM_2_0; - /* Parse our resources */ - rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res, - &acpi_resource_parse_ops_default); - - if (ACPI_FAILURE(rv)) { + rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res, + &acpi_resource_parse_ops_default); + if (ACPI_FAILURE(rv)) { aprint_error_dev(sc->sc_dev, "cannot parse resources %d\n", rv); - return; + return; } - io = acpi_res_io(&res, 0); - if (io && tpm_legacy_probe(aa->aa_iot, io->ar_base)) { - sc->sc_bt = aa->aa_iot; - base = io->ar_base; - size = io->ar_length; - sc->sc_batm = aa->aa_iot; - sc->sc_init = tpm_legacy_init; - sc->sc_start = tpm_legacy_start; - sc->sc_read = tpm_legacy_read; - sc->sc_write = tpm_legacy_write; - sc->sc_end = tpm_legacy_end; - mem = NULL; - } else { - mem = acpi_res_mem(&res, 0); - if (mem == NULL) { - aprint_error_dev(sc->sc_dev, "cannot find mem\n"); - goto out; - } - - if (mem->ar_length != TPM_SIZE) { - aprint_error_dev(sc->sc_dev, - "wrong size mem %"PRIu64" != %u\n", - (uint64_t)mem->ar_length, TPM_SIZE); - goto out; - } - - base = mem->ar_base; - size = mem->ar_length; - sc->sc_bt = aa->aa_memt; - sc->sc_init = tpm_tis12_init; - sc->sc_start = tpm_tis12_start; - sc->sc_read = tpm_tis12_read; - sc->sc_write = tpm_tis12_write; - sc->sc_end = tpm_tis12_end; + mem = acpi_res_mem(&res, 0); + if (mem == NULL) { + aprint_error_dev(sc->sc_dev, "cannot find mem\n"); + goto out; + } + if (mem->ar_length != TPM_SPACE_SIZE) { + aprint_error_dev(sc->sc_dev, + "wrong size mem %"PRIu64" != %u\n", + (uint64_t)mem->ar_length, TPM_SPACE_SIZE); + goto out; } + base = mem->ar_base; + size = mem->ar_length; + sc->sc_bt = aa->aa_memt; + sc->sc_init = tpm_tis12_init; + sc->sc_start = tpm_tis12_start; + sc->sc_read = tpm_tis12_read; + sc->sc_write = tpm_tis12_write; + sc->sc_end = tpm_tis12_end; + if (bus_space_map(sc->sc_bt, base, size, 0, &sc->sc_bh)) { aprint_error_dev(sc->sc_dev, "cannot map registers\n"); goto out; } - if (mem && !tpm_tis12_probe(sc->sc_bt, sc->sc_bh)) { - aprint_error_dev(sc->sc_dev, "1.2 probe failed\n"); + if (!tpm_tis12_probe(sc->sc_bt, sc->sc_bh)) { + aprint_error_dev(sc->sc_dev, "TIS1.2 probe failed\n"); goto out1; } @@ -187,7 +152,7 @@ tpm_acpi_attach(device_t parent, device_ else inum = irq->ar_irq; - if ((rv = (*sc->sc_init)(sc, inum, device_xname(sc->sc_dev))) != 0) { + if ((rv = (*sc->sc_init)(sc, inum)) != 0) { aprint_error_dev(sc->sc_dev, "cannot init device %d\n", rv); goto out1; } @@ -199,9 +164,9 @@ tpm_acpi_attach(device_t parent, device_ goto out1; } - if (!pmf_device_register(sc->sc_dev, tpm_suspend, tpm_resume)) - aprint_error_dev(sc->sc_dev, "Cannot set power mgmt handler\n"); + acpi_resource_cleanup(&res); return; + out1: bus_space_unmap(sc->sc_bt, sc->sc_bh, size); out: Index: src/sys/dev/ic/tpm.c diff -u src/sys/dev/ic/tpm.c:1.12 src/sys/dev/ic/tpm.c:1.13 --- src/sys/dev/ic/tpm.c:1.12 Sat Oct 28 04:53:55 2017 +++ src/sys/dev/ic/tpm.c Sat Jun 22 12:57:41 2019 @@ -1,7 +1,37 @@ -/* $NetBSD: tpm.c,v 1.12 2017/10/28 04:53:55 riastradh Exp $ */ +/* $NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $ */ + +/* + * Copyright (c) 2019 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Maxime Villard. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 2008, 2009 Michael Shalayeff - * Copyright (c) 2009, 2010 Hans-Jörg Höxer + * Copyright (c) 2009, 2010 Hans-Joerg Hoexer * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any @@ -18,12 +48,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.12 2017/10/28 04:53:55 riastradh Exp $"); - -#if 0 -#define TPM_DEBUG -#define aprint_debug_dev aprint_error_dev -#endif +__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -40,12 +65,23 @@ __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.12 #include "ioconf.h" -/* Set when enabling legacy interface in host bridge. */ -int tpm_enabled; +#define TPM_BUFSIZ 1024 +#define TPM_HDRSIZE 10 +#define TPM_PARAM_SIZE 0x0001 /* that's a flag */ + +/* Timeouts. */ +#define TPM_ACCESS_TMO 2000 /* 2sec */ +#define TPM_READY_TMO 2000 /* 2sec */ +#define TPM_READ_TMO 2000 /* 2sec */ +#define TPM_BURST_TMO 2000 /* 2sec */ + +#define TPM_CAPS_REQUIRED \ + (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT| \ + TPM_INTF_INT_LEVEL_LOW) -const struct { +static const struct { uint32_t devid; - char name[32]; + const char *name; int flags; #define TPM_DEV_NOINTS 0x0001 } tpm_devs[] = { @@ -60,177 +96,18 @@ const struct { { 0, "", TPM_DEV_NOINTS }, }; -int tpm_tis12_irqinit(struct tpm_softc *, int, int); - -int tpm_waitfor_poll(struct tpm_softc *, uint8_t, int, void *); -int tpm_waitfor_int(struct tpm_softc *, uint8_t, int, void *, int); -int tpm_waitfor(struct tpm_softc *, uint8_t, int, void *); -int tpm_request_locality(struct tpm_softc *, int); -int tpm_getburst(struct tpm_softc *); -uint8_t tpm_status(struct tpm_softc *); -int tpm_tmotohz(int); - -static dev_type_open(tpmopen); -static dev_type_close(tpmclose); -static dev_type_read(tpmread); -static dev_type_read(tpmwrite); -static dev_type_ioctl(tpmioctl); - -#define TPMUNIT(a) minor(a) - -const struct cdevsw tpm_cdevsw = { - .d_open = tpmopen, - .d_close = tpmclose, - .d_read = tpmread, - .d_write = tpmwrite, - .d_ioctl = tpmioctl, - .d_stop = nostop, - .d_tty = notty, - .d_poll = nopoll, - .d_mmap = nommap, - .d_kqfilter = nokqfilter, - .d_discard = nodiscard, - .d_flag = D_OTHER, -}; - -/* Probe TPM using TIS 1.2 interface. */ -int -tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh) -{ - uint32_t r; - uint8_t save, reg; - - r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES); - if (r == 0xffffffff) - return 0; - -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_CAPBITS, r); - printf("%s: caps=%s\n", __func__, buf); -#endif - if ((r & TPM_CAPSREQ) != TPM_CAPSREQ || - !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) { -#ifdef TPM_DEBUG - printf("%s: caps too low (caps=%s)\n", __func__, buf); -#endif - return 0; - } - - save = bus_space_read_1(bt, bh, TPM_ACCESS); - bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE); - reg = bus_space_read_1(bt, bh, TPM_ACCESS); - if ((reg & TPM_ACCESS_VALID) && (reg & TPM_ACCESS_ACTIVE_LOCALITY) && - bus_space_read_4(bt, bh, TPM_ID) != 0xffffffff) - return 1; - - bus_space_write_1(bt, bh, TPM_ACCESS, save); - return 0; -} - -/* - * Setup interrupt vector if one is provided and interrupts are know to - * work on that particular chip. - */ -int -tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx) -{ - uint32_t r; - - if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) { - sc->sc_vector = -1; - return 0; - } - - /* Ack and disable all interrupts. */ - r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE); - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, - r & ~TPM_GLOBAL_INT_ENABLE); - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, - bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS)); -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r); - aprint_debug_dev(sc->sc_dev, "%s: before ien %s\n", __func__, buf); -#endif - - /* Program interrupt vector. */ - bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq); - sc->sc_vector = irq; - - /* Program interrupt type. */ - r &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH| - TPM_INT_LEVEL_LOW); - r |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT| - TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT; - if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING) - r |= TPM_INT_EDGE_RISING; - else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING) - r |= TPM_INT_EDGE_FALLING; - else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH) - r |= TPM_INT_LEVEL_HIGH; - else - r |= TPM_INT_LEVEL_LOW; - - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, r); -#ifdef TPM_DEBUG - snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r); - aprint_debug_dev(sc->sc_dev, "%s: after ien %s\n", __func__, buf); -#endif - - return 0; -} - -/* Setup TPM using TIS 1.2 interface. */ -int -tpm_tis12_init(struct tpm_softc *sc, int irq, const char *name) +static inline int +tpm_tmotohz(int tmo) { - uint32_t r; - int i; - - r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES); -#ifdef TPM_DEBUG - char cbuf[128]; - snprintb(cbuf, sizeof(cbuf), TPM_CAPBITS, r); - aprint_debug_dev(sc->sc_dev, "%s: caps=%s ", __func__, cbuf); -#endif - if ((r & TPM_CAPSREQ) != TPM_CAPSREQ || - !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) { - char buf[128]; - snprintb(buf, sizeof(buf), TPM_CAPBITS, r); - aprint_error_dev(sc->sc_dev, "capabilities too low (caps=%s)\n", - buf); - return 1; - } - sc->sc_capabilities = r; - - sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID); - sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV); - - for (i = 0; tpm_devs[i].devid; i++) - if (tpm_devs[i].devid == sc->sc_devid) - break; - - if (tpm_devs[i].devid) - aprint_normal(": %s rev 0x%x\n", - tpm_devs[i].name, sc->sc_rev); - else - aprint_normal(": device 0x%08x rev 0x%x\n", - sc->sc_devid, sc->sc_rev); - - if (tpm_tis12_irqinit(sc, irq, i)) - return 1; - - if (tpm_request_locality(sc, 0)) - return 1; + struct timeval tv; - /* Abort whatever it thought it was doing. */ - bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); + tv.tv_sec = tmo / 1000; + tv.tv_usec = 1000 * (tmo % 1000); - return 0; + return tvtohz(&tv); } -int +static int tpm_request_locality(struct tpm_softc *sc, int l) { uint32_t r; @@ -253,48 +130,34 @@ tpm_request_locality(struct tpm_softc *s (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) { rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1); - if (rv && rv != EWOULDBLOCK) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: interrupted %d\n", - __func__, rv); -#endif + if (rv && rv != EWOULDBLOCK) { return rv; } } if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_ACCESS_BITS, r); - aprint_debug_dev(sc->sc_dev, "%s: access %s\n", __func__, buf); -#endif return EBUSY; } return 0; } -int +static int tpm_getburst(struct tpm_softc *sc) { int burst, to, rv; to = tpm_tmotohz(TPM_BURST_TMO); - burst = 0; - while (burst == 0 && to--) { + while (to--) { /* - * Burst count has to be read from bits 8 to 23 without - * touching any other bits, eg. the actual status bits 0 - * to 7. + * Burst count is in bits 23:8, so read the two higher bytes. */ burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1); burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2) << 8; -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: read %d\n", __func__, burst); -#endif + if (burst) return burst; @@ -307,77 +170,56 @@ tpm_getburst(struct tpm_softc *sc) return 0; } -uint8_t +static inline uint8_t tpm_status(struct tpm_softc *sc) { - return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK; + return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & + TPM_STS_STATUS_BITS; } -int -tpm_tmotohz(int tmo) -{ - struct timeval tv; - - tv.tv_sec = tmo / 1000; - tv.tv_usec = 1000 * (tmo % 1000); +/* -------------------------------------------------------------------------- */ - return tvtohz(&tv); -} +/* + * Save TPM state on suspend. On resume we don't do anything, since the BIOS + * is supposed to restore the previously saved state. + */ -/* Save TPM state on suspend. */ bool -tpm_suspend(device_t dev, const pmf_qual_t *qual) +tpm12_suspend(device_t dev, const pmf_qual_t *qual) { struct tpm_softc *sc = device_private(dev); static const uint8_t command[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 10, /* Length in bytes */ - 0, 0, 0, 156 /* TPM_ORD_SaveStates */ + 0, 193, /* TPM_TAG_RQU_COMMAND */ + 0, 0, 0, 10, /* Length in bytes */ + 0, 0, 0, 156 /* TPM_ORD_SaveStates */ }; uint8_t scratch[sizeof(command)]; - /* - * Power down: We have to issue the SaveStates command. - */ (*sc->sc_write)(sc, &command, sizeof(command)); - (*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, TPM_HDRSIZE); -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: power down\n", __func__); -#endif + (*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, 0); + return true; } -/* - * Handle resume event. Actually nothing to do as the BIOS is supposed - * to restore the previously saved state. - */ bool -tpm_resume(device_t dev, const pmf_qual_t *qual) +tpm12_resume(device_t dev, const pmf_qual_t *qual) { -#ifdef TPM_DEBUG - struct tpm_softc *sc = device_private(dev); - aprint_debug_dev(sc->sc_dev, "%s: resume\n", __func__); -#endif return true; } -/* Wait for given status bits using polling. */ -int -tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int tmo, void *c) +/* -------------------------------------------------------------------------- */ + +/* + * Wait for given status bits using polling. + */ +static int +tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan) { int rv; - /* - * Poll until either the requested condition or a time out is - * met. - */ - while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) { - rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1); + while (((sc->sc_status = tpm_status(sc)) & mask) != mask && to--) { + rv = tsleep(chan, PRIBIO | PCATCH, "tpm_poll", 1); if (rv && rv != EWOULDBLOCK) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: interrupted %d\n", __func__, rv); -#endif return rv; } } @@ -385,16 +227,17 @@ tpm_waitfor_poll(struct tpm_softc *sc, u return 0; } -/* Wait for given status bits using interrupts. */ -int -tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, void *c, +/* + * Wait for given status bits using interrupts. + */ +static int +tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, wchan_t chan, int inttype) { int rv, to; - /* Poll and return when condition is already met. */ - sc->sc_stat = tpm_status(sc); - if ((sc->sc_stat & mask) == mask) + sc->sc_status = tpm_status(sc); + if ((sc->sc_status & mask) == mask) return 0; /* @@ -402,147 +245,120 @@ tpm_waitfor_int(struct tpm_softc *sc, ui * level (SPL_TTY) are disabled (see tpm{read,write} et al) and * will not be delivered to the cpu until we call tsleep(9) below. */ - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, - bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) | + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, + bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) | inttype); - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, - bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) | + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, + bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) | TPM_GLOBAL_INT_ENABLE); - /* - * Poll once more to remedy the race between previous polling - * and enabling interrupts on the tpm chip. - */ - sc->sc_stat = tpm_status(sc); - if ((sc->sc_stat & mask) == mask) { + sc->sc_status = tpm_status(sc); + if ((sc->sc_status & mask) == mask) { rv = 0; goto out; } to = tpm_tmotohz(tmo); -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: sleeping for %d ticks on %p\n", __func__, to, c); -#endif + /* * tsleep(9) enables interrupts on the cpu and returns after * wake up with interrupts disabled again. Note that interrupts * generated by the tpm chip while being at SPL_TTY are not lost * but held and delivered as soon as the cpu goes below SPL_TTY. */ - rv = tsleep(c, PRIBIO | PCATCH, "tpm_wait", to); + rv = tsleep(chan, PRIBIO | PCATCH, "tpm_wait", to); - sc->sc_stat = tpm_status(sc); -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, - "%s: woke up with rv %d stat %s\n", __func__, rv, buf); -#endif - if ((sc->sc_stat & mask) == mask) + sc->sc_status = tpm_status(sc); + if ((sc->sc_status & mask) == mask) rv = 0; +out: /* Disable interrupts on tpm chip again. */ -out: bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, - bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) & + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, + bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) & ~TPM_GLOBAL_INT_ENABLE); - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, - bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) & + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, + bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) & ~inttype); return rv; } /* - * Wait on given status bits, uses interrupts where possible, otherwise polls. + * Wait on given status bits, use interrupts where possible, otherwise poll. */ -int -tpm_waitfor(struct tpm_softc *sc, uint8_t b0, int tmo, void *c) +static int +tpm_waitfor(struct tpm_softc *sc, uint8_t bits, int tmo, wchan_t chan) { - uint8_t b; - int re, to, rv; - -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, "%s: b0 %s\n", __func__, buf); -#endif + int retry, to, rv; + uint8_t todo; /* - * If possible, use interrupts, otherwise poll. - * - * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if - * the tpm chips supports them) as waiting for those can take - * really long. The other TPM_STS* are not needed very often - * so we do not support them. + * We use interrupts for TPM_STS_DATA_AVAIL and TPM_STS_VALID (if the + * TPM chip supports them) as waiting for those can take really long. + * The other TPM_STS* are not needed very often so we do not support + * them. */ if (sc->sc_vector != -1) { - b = b0; + todo = bits; /* - * Wait for data ready. This interrupt only occures - * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted. - * Thus we don't have to bother with TPM_STS_VALID - * separately and can just return. + * Wait for data ready. This interrupt only occurs when both + * TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted. Thus we + * don't have to bother with TPM_STS_VALID separately and can + * just return. * - * This only holds for interrupts! When using polling - * both flags have to be waited for, see below. + * This only holds for interrupts! When using polling both + * flags have to be waited for, see below. */ - if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities & - TPM_INTF_DATA_AVAIL_INT)) - return tpm_waitfor_int(sc, b, tmo, c, + if ((bits & TPM_STS_DATA_AVAIL) && + (sc->sc_capabilities & TPM_INTF_DATA_AVAIL_INT)) + return tpm_waitfor_int(sc, bits, tmo, chan, TPM_DATA_AVAIL_INT); /* Wait for status valid bit. */ - if ((b & TPM_STS_VALID) && (sc->sc_capabilities & - TPM_INTF_STS_VALID_INT)) { - rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT); - if (rv != 0) + if ((bits & TPM_STS_VALID) && + (sc->sc_capabilities & TPM_INTF_STS_VALID_INT)) { + rv = tpm_waitfor_int(sc, bits, tmo, chan, + TPM_STS_VALID_INT); + if (rv) return rv; - else - b = b0 & ~TPM_STS_VALID; + todo = bits & ~TPM_STS_VALID; } /* - * When all flags are taken care of, return. Otherwise - * use polling for eg. TPM_STS_CMD_READY. + * When all flags have been taken care of, return. Otherwise + * use polling for eg TPM_STS_CMD_READY. */ - if (b == 0) + if (todo == 0) return 0; } - re = 3; + retry = 3; + restart: /* - * If requested wait for TPM_STS_VALID before dealing with - * any other flag. Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID - * are requested, wait for the latter first. + * If requested, wait for TPM_STS_VALID before dealing with any other + * flag. Eg when both TPM_STS_DATA_AVAIL and TPM_STS_VALID are + * requested, wait for the latter first. */ - b = b0; - if (b0 & TPM_STS_VALID) - b = TPM_STS_VALID; - + todo = bits; + if (bits & TPM_STS_VALID) + todo = TPM_STS_VALID; to = tpm_tmotohz(tmo); again: - if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0) + if ((rv = tpm_waitfor_poll(sc, todo, to, chan)) != 0) return rv; - if ((b & sc->sc_stat) == TPM_STS_VALID) { + if ((todo & sc->sc_status) == TPM_STS_VALID) { /* Now wait for other flags. */ - b = b0 & ~TPM_STS_VALID; + todo = bits & ~TPM_STS_VALID; to++; goto again; } - if ((sc->sc_stat & b) != b) { -#ifdef TPM_DEBUG - char bbuf[128], cbuf[128]; - snprintb(bbuf, sizeof(bbuf), TPM_STS_BITS, b); - snprintb(cbuf, sizeof(cbuf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, - "%s: timeout: stat=%s b=%s\n", __func__, cbuf, bbuf); -#endif - if (re-- && (b0 & TPM_STS_VALID)) { + if ((todo & sc->sc_status) != todo) { + if (retry-- && (bits & TPM_STS_VALID)) { bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_RESP_RETRY); goto restart; @@ -553,7 +369,147 @@ again: return 0; } -/* Start transaction. */ +int +tpm_intr(void *v) +{ + struct tpm_softc *sc = v; + uint32_t reg; + + reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS); + if (!(reg & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT | + TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT))) + return 0; + + if (reg & TPM_STS_VALID_INT) + wakeup(sc); + if (reg & TPM_CMD_READY_INT) + wakeup(sc->sc_write); + if (reg & TPM_DATA_AVAIL_INT) + wakeup(sc->sc_read); + if (reg & TPM_LOCALITY_CHANGE_INT) + wakeup(sc->sc_init); + + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, reg); + + return 1; +} + +/* -------------------------------------------------------------------------- */ + +/* + * TPM using TIS 1.2 interface. + */ + +int +tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh) +{ + uint32_t cap; + uint8_t reg; + int tmo; + + cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY); + if (cap == 0xffffffff) + return 0; + if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED) + return 0; + if (!(cap & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) + return 0; + + /* Request locality 0. */ + bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE); + + /* Wait for it to become active. */ + tmo = TPM_ACCESS_TMO; /* Milliseconds. */ + while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) & + (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != + (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) { + DELAY(1000); /* 1 millisecond. */ + } + if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) != + (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { + return 0; + } + + if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff) + return 0; + + return 1; +} + +static int +tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx) +{ + uint32_t reg; + + if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) { + sc->sc_vector = -1; + return 0; + } + + /* Ack and disable all interrupts. */ + reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE); + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, + reg & ~TPM_GLOBAL_INT_ENABLE); + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, + bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS)); + + /* Program interrupt vector. */ + bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq); + sc->sc_vector = irq; + + /* Program interrupt type. */ + reg &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH| + TPM_INT_LEVEL_LOW); + reg |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT| + TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT; + if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING) + reg |= TPM_INT_EDGE_RISING; + else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING) + reg |= TPM_INT_EDGE_FALLING; + else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH) + reg |= TPM_INT_LEVEL_HIGH; + else + reg |= TPM_INT_LEVEL_LOW; + + bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, reg); + + return 0; +} + +int +tpm_tis12_init(struct tpm_softc *sc, int irq) +{ + int i; + + sc->sc_capabilities = bus_space_read_4(sc->sc_bt, sc->sc_bh, + TPM_INTF_CAPABILITY); + sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID); + sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV); + + for (i = 0; tpm_devs[i].devid; i++) { + if (tpm_devs[i].devid == sc->sc_devid) + break; + } + + if (tpm_devs[i].devid) + aprint_normal_dev(sc->sc_dev, "%s rev 0x%x\n", + tpm_devs[i].name, sc->sc_rev); + else + aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n", + sc->sc_devid, sc->sc_rev); + + if (tpm_tis12_irqinit(sc, irq, i)) + return 1; + + if (tpm_request_locality(sc, 0)) + return 1; + + /* Abort whatever it thought it was doing. */ + bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); + + return 0; +} + int tpm_tis12_start(struct tpm_softc *sc, int flag) { @@ -565,41 +521,19 @@ tpm_tis12_start(struct tpm_softc *sc, in return rv; } - /* Own our (0th) locality. */ + /* Request the 0th locality. */ if ((rv = tpm_request_locality(sc, 0)) != 0) return rv; - sc->sc_stat = tpm_status(sc); - if (sc->sc_stat & TPM_STS_CMD_READY) { -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE status %s\n", - __func__, buf); -#endif + sc->sc_status = tpm_status(sc); + if (sc->sc_status & TPM_STS_CMD_READY) return 0; - } - -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: UIO_WRITE readying chip\n", __func__); -#endif /* Abort previous and restart. */ bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); - if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, - sc->sc_write))) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: UIO_WRITE readying failed %d\n", __func__, rv); -#endif + rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write); + if (rv) return rv; - } - -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: UIO_WRITE readying done\n", __func__); -#endif return 0; } @@ -612,21 +546,16 @@ tpm_tis12_read(struct tpm_softc *sc, voi size_t cnt; int rv, n, bcnt; -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: len %zu\n", __func__, len); -#endif cnt = 0; while (len > 0) { - if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, - TPM_READ_TMO, sc->sc_read))) + rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, + TPM_READ_TMO, sc->sc_read); + if (rv) return rv; bcnt = tpm_getburst(sc); n = MIN(len, bcnt); -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: fetching %d, burst is %d\n", __func__, n, bcnt); -#endif + for (; n--; len--) { *p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA); cnt++; @@ -635,10 +564,6 @@ tpm_tis12_read(struct tpm_softc *sc, voi if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6) break; } -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: read %zu bytes, len %zu\n", __func__, cnt, len); -#endif if (count) *count = cnt; @@ -653,13 +578,8 @@ tpm_tis12_write(struct tpm_softc *sc, co size_t cnt; int rv, r; -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: sc %p buf %p len %zu\n", __func__, sc, buf, len); -#endif if (len == 0) return 0; - if ((rv = tpm_request_locality(sc, 0)) != 0) return rv; @@ -670,20 +590,10 @@ tpm_tis12_write(struct tpm_softc *sc, co cnt++; } if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: failed burst rv %d\n", __func__, rv); -#endif return rv; } - sc->sc_stat = tpm_status(sc); - if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) { -#ifdef TPM_DEBUG - char sbuf[128]; - snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, - "%s: failed rv %d stat=%s\n", __func__, rv, sbuf); -#endif + sc->sc_status = tpm_status(sc); + if (!(sc->sc_status & TPM_STS_DATA_EXPECT)) { return EIO; } } @@ -692,69 +602,42 @@ tpm_tis12_write(struct tpm_softc *sc, co cnt++; if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: failed last byte rv %d\n", - __func__, rv); -#endif return rv; } - if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) { -#ifdef TPM_DEBUG - char sbuf[128]; - snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, - "%s: failed rv %d stat=%s\n", __func__, rv, sbuf); -#endif + if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) { return EIO; } -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: wrote %zu byte\n", __func__, cnt); -#endif - return 0; } -/* Finish transaction. */ int tpm_tis12_end(struct tpm_softc *sc, int flag, int err) { int rv = 0; if (flag == UIO_READ) { - if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, - sc->sc_read))) + rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read); + if (rv) return rv; /* Still more data? */ - sc->sc_stat = tpm_status(sc); - if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL) - == TPM_STS_DATA_AVAIL)) { -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, - "%s: read failed stat=%s\n", __func__, buf); -#endif + sc->sc_status = tpm_status(sc); + if (!err && ((sc->sc_status & TPM_STS_DATA_AVAIL) == + TPM_STS_DATA_AVAIL)) { rv = EIO; } bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); - /* Release our (0th) locality. */ - bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS, + /* Release the 0th locality. */ + bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS, TPM_ACCESS_ACTIVE_LOCALITY); } else { /* Hungry for more? */ - sc->sc_stat = tpm_status(sc); - if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) { -#ifdef TPM_DEBUG - char buf[128]; - snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); - aprint_debug_dev(sc->sc_dev, - "%s: write failed stat=%s\n", __func__, buf); -#endif + sc->sc_status = tpm_status(sc); + if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) { rv = EIO; } @@ -765,247 +648,38 @@ tpm_tis12_end(struct tpm_softc *sc, int return rv; } -int -tpm_intr(void *v) -{ - struct tpm_softc *sc = v; - uint32_t r; -#ifdef TPM_DEBUG - static int cnt = 0; -#endif - - r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS); -#ifdef TPM_DEBUG - if (r != 0) { - char buf[128]; - snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r); - aprint_debug_dev(sc->sc_dev, "%s: int=%s (%d)\n", __func__, - buf, cnt); - } else - cnt++; -#endif - if (!(r & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT | - TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT))) -#ifdef __FreeBSD__ - return; -#else - return 0; -#endif - if (r & TPM_STS_VALID_INT) - wakeup(sc); - - if (r & TPM_CMD_READY_INT) - wakeup(sc->sc_write); - - if (r & TPM_DATA_AVAIL_INT) - wakeup(sc->sc_read); - - if (r & TPM_LOCALITY_CHANGE_INT) - wakeup(sc->sc_init); - - bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, r); - - return 1; -} - -/* Read single byte using legacy interface. */ -static inline uint8_t -tpm_legacy_in(bus_space_tag_t iot, bus_space_handle_t ioh, int reg) -{ - bus_space_write_1(iot, ioh, 0, reg); - return bus_space_read_1(iot, ioh, 1); -} - -/* Probe for TPM using legacy interface. */ -int -tpm_legacy_probe(bus_space_tag_t iot, bus_addr_t iobase) -{ - bus_space_handle_t ioh; - uint8_t r, v; - int i, rv = 0; - char id[8]; - - if (!tpm_enabled || iobase == -1) - return 0; - - if (bus_space_map(iot, iobase, 2, 0, &ioh)) - return 0; - - v = bus_space_read_1(iot, ioh, 0); - if (v == 0xff) { - bus_space_unmap(iot, ioh, 2); - return 0; - } - r = bus_space_read_1(iot, ioh, 1); - - for (i = sizeof(id); i--; ) - id[i] = tpm_legacy_in(iot, ioh, TPM_ID + i); - -#ifdef TPM_DEBUG - printf("tpm_legacy_probe %.4s %d.%d.%d.%d\n", - &id[4], id[0], id[1], id[2], id[3]); -#endif - /* - * The only chips using the legacy interface we are aware of are - * by Atmel. For other chips more signature would have to be added. - */ - if (!bcmp(&id[4], "ATML", 4)) - rv = 1; - - if (!rv) { - bus_space_write_1(iot, ioh, r, 1); - bus_space_write_1(iot, ioh, v, 0); - } - bus_space_unmap(iot, ioh, 2); - - return rv; -} - -/* Setup TPM using legacy interface. */ -int -tpm_legacy_init(struct tpm_softc *sc, int irq, const char *name) -{ - char id[8]; - int i; - - if ((i = bus_space_map(sc->sc_batm, tpm_enabled, 2, 0, &sc->sc_bahm))) { - aprint_debug_dev(sc->sc_dev, "cannot map tpm registers (%d)\n", - i); - tpm_enabled = 0; - return 1; - } - - for (i = sizeof(id); i--; ) - id[i] = tpm_legacy_in(sc->sc_bt, sc->sc_bh, TPM_ID + i); - - aprint_debug_dev(sc->sc_dev, "%.4s %d.%d @0x%x\n", &id[4], id[0], - id[1], tpm_enabled); - tpm_enabled = 0; - - return 0; -} - -/* Start transaction. */ -int -tpm_legacy_start(struct tpm_softc *sc, int flag) -{ - struct timeval tv; - uint8_t bits, r; - int to, rv; - - bits = flag == UIO_READ ? TPM_LEGACY_DA : 0; - tv.tv_sec = TPM_LEGACY_TMO; - tv.tv_usec = 0; - to = tvtohz(&tv) / TPM_LEGACY_SLEEP; - while (((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) & - (TPM_LEGACY_BUSY|bits)) != bits && to--) { - rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_start", - TPM_LEGACY_SLEEP); - if (rv && rv != EWOULDBLOCK) - return rv; - } - -#if defined(TPM_DEBUG) && !defined(__FreeBSD__) - char buf[128]; - snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r); - aprint_debug_dev(sc->sc_dev, "%s: bits %s\n", device_xname(sc->sc_dev), - buf); -#endif - if ((r & (TPM_LEGACY_BUSY|bits)) != bits) - return EIO; - - return 0; -} - -int -tpm_legacy_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count, - int flags) -{ - uint8_t *p; - size_t cnt; - int to, rv; - - cnt = rv = 0; - for (p = buf; !rv && len > 0; len--) { - for (to = 1000; - !(bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1) & - TPM_LEGACY_DA); DELAY(1)) - if (!to--) - return EIO; - - DELAY(TPM_LEGACY_DELAY); - *p++ = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 0); - cnt++; - } - - *count = cnt; - return 0; -} - -int -tpm_legacy_write(struct tpm_softc *sc, const void *buf, size_t len) -{ - const uint8_t *p; - size_t n; - - for (p = buf, n = len; n--; DELAY(TPM_LEGACY_DELAY)) { - if (!n && len != TPM_BUFSIZ) { - bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, - TPM_LEGACY_LAST); - DELAY(TPM_LEGACY_DELAY); - } - bus_space_write_1(sc->sc_batm, sc->sc_bahm, 0, *p++); - } - - return 0; -} - -/* Finish transaction. */ -int -tpm_legacy_end(struct tpm_softc *sc, int flag, int rv) -{ - struct timeval tv; - uint8_t r; - int to; - - if (rv || flag == UIO_READ) - bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, TPM_LEGACY_ABRT); - else { - tv.tv_sec = TPM_LEGACY_TMO; - tv.tv_usec = 0; - to = tvtohz(&tv) / TPM_LEGACY_SLEEP; - while(((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) & - TPM_LEGACY_BUSY) && to--) { - rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_end", - TPM_LEGACY_SLEEP); - if (rv && rv != EWOULDBLOCK) - return rv; - } +/* -------------------------------------------------------------------------- */ -#if defined(TPM_DEBUG) && !defined(__FreeBSD__) - char buf[128]; - snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r); - aprint_debug_dev(sc->sc_dev, "%s: bits %s\n", - device_xname(sc->sc_dev), buf); -#endif - if (r & TPM_LEGACY_BUSY) - return EIO; +static dev_type_open(tpmopen); +static dev_type_close(tpmclose); +static dev_type_read(tpmread); +static dev_type_write(tpmwrite); +static dev_type_ioctl(tpmioctl); - if (r & TPM_LEGACY_RE) - return EIO; /* XXX Retry the loop? */ - } +const struct cdevsw tpm_cdevsw = { + .d_open = tpmopen, + .d_close = tpmclose, + .d_read = tpmread, + .d_write = tpmwrite, + .d_ioctl = tpmioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER, +}; - return rv; -} +#define TPMUNIT(a) minor(a) -int +static int tpmopen(dev_t dev, int flag, int mode, struct lwp *l) { struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); - if (!sc) + if (sc == NULL) return ENXIO; - if (sc->sc_flags & TPM_OPEN) return EBUSY; @@ -1014,14 +688,13 @@ tpmopen(dev_t dev, int flag, int mode, s return 0; } -int +static int tpmclose(dev_t dev, int flag, int mode, struct lwp *l) { struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); - if (!sc) + if (sc == NULL) return ENXIO; - if (!(sc->sc_flags & TPM_OPEN)) return EINVAL; @@ -1030,7 +703,7 @@ tpmclose(dev_t dev, int flag, int mode, return 0; } -int +static int tpmread(dev_t dev, struct uio *uio, int flags) { struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); @@ -1038,43 +711,27 @@ tpmread(dev_t dev, struct uio *uio, int size_t cnt, len, n; int rv, s; - if (!sc) + if (sc == NULL) return ENXIO; s = spltty(); if ((rv = (*sc->sc_start)(sc, UIO_READ))) goto out; -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: getting header\n", __func__); -#endif if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) { (*sc->sc_end)(sc, UIO_READ, rv); goto out; } len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5]; -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: len %zu, io count %zu\n", __func__, - len, uio->uio_resid); -#endif if (len > uio->uio_resid) { rv = EIO; (*sc->sc_end)(sc, UIO_READ, rv); -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: bad residual io count 0x%zx\n", __func__, - uio->uio_resid); -#endif goto out; } /* Copy out header. */ if ((rv = uiomove(buf, cnt, uio))) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: uiomove failed %d\n", __func__, rv); -#endif (*sc->sc_end)(sc, UIO_READ, rv); goto out; } @@ -1083,20 +740,12 @@ tpmread(dev_t dev, struct uio *uio, int for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n, n = sizeof(buf)) { n = MIN(n, len); -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: n %zu len %zu\n", __func__, - n, len); -#endif if ((rv = (*sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) { (*sc->sc_end)(sc, UIO_READ, rv); goto out; } p += n; if ((rv = uiomove(buf, p - buf, uio))) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: uiomove failed %d\n", __func__, rv); -#endif (*sc->sc_end)(sc, UIO_READ, rv); goto out; } @@ -1108,50 +757,56 @@ out: return rv; } -int +static int tpmwrite(dev_t dev, struct uio *uio, int flags) { struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); uint8_t buf[TPM_BUFSIZ]; int n, rv, s; - if (!sc) + if (sc == NULL) return ENXIO; s = spltty(); -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, "%s: io count %zu\n", __func__, - uio->uio_resid); -#endif - n = MIN(sizeof(buf), uio->uio_resid); if ((rv = uiomove(buf, n, uio))) { -#ifdef TPM_DEBUG - aprint_debug_dev(sc->sc_dev, - "%s: uiomove failed %d\n", __func__, rv); -#endif - splx(s); - return rv; + goto out; } - if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) { - splx(s); - return rv; + goto out; } - if ((rv = (*sc->sc_write)(sc, buf, n))) { - splx(s); - return rv; + goto out; } rv = (*sc->sc_end)(sc, UIO_WRITE, rv); +out: splx(s); return rv; } -int -tpmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l) +static int +tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) { + struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev)); + struct tpm_ioc_getinfo *info; + + if (sc == NULL) + return ENXIO; + + switch (cmd) { + case TPM_IOC_GETINFO: + info = addr; + info->api_version = TPM_API_VERSION; + info->tpm_version = sc->sc_ver; + info->device_id = sc->sc_devid; + info->device_rev = sc->sc_rev; + info->device_caps = sc->sc_capabilities; + return 0; + default: + break; + } + return ENOTTY; } Index: src/sys/dev/ic/tpmreg.h diff -u src/sys/dev/ic/tpmreg.h:1.3 src/sys/dev/ic/tpmreg.h:1.4 --- src/sys/dev/ic/tpmreg.h:1.3 Mon Jan 23 04:12:26 2012 +++ src/sys/dev/ic/tpmreg.h Sat Jun 22 12:57:41 2019 @@ -1,100 +1,90 @@ -/* $NetBSD: tpmreg.h,v 1.3 2012/01/23 04:12:26 christos Exp $ */ +/* $NetBSD: tpmreg.h,v 1.4 2019/06/22 12:57:41 maxv Exp $ */ /* - * Copyright (c) 2008, 2009 Michael Shalayeff - * Copyright (c) 2009, 2010 Hans-Jörg Höxer + * Copyright (c) 2019 The NetBSD Foundation, Inc. * All rights reserved. * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. + * This code is derived from software contributed to The NetBSD Foundation + * by Maxime Villard. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN - * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT - * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ -#define TPM_BUFSIZ 1024 - -#define TPM_HDRSIZE 10 +/* + * TPM Interface Specification 1.2 (TIS12). + */ -#define TPM_PARAM_SIZE 0x0001 +#define TPM_ACCESS 0x0000 /* 8bit register */ +#define TPM_ACCESS_VALID __BIT(7) +#define TPM_ACCESS_ACTIVE_LOCALITY __BIT(5) +#define TPM_ACCESS_BEEN_SEIZED __BIT(4) +#define TPM_ACCESS_SEIZE __BIT(3) +#define TPM_ACCESS_PENDING_REQUEST __BIT(2) +#define TPM_ACCESS_REQUEST_USE __BIT(1) +#define TPM_ACCESS_ESTABLISHMENT __BIT(0) + +#define TPM_INT_ENABLE 0x0008 /* 32bit register */ +#define TPM_GLOBAL_INT_ENABLE __BIT(31) +#define TPM_CMD_READY_INT __BIT(7) +#define TPM_TYPE_POLARITY __BITS(4,3) +#define TPM_INT_LEVEL_HIGH __SHIFTIN(0, TPM_TYPE_POLARITY) +#define TPM_INT_LEVEL_LOW __SHIFTIN(1, TPM_TYPE_POLARITY) +#define TPM_INT_EDGE_RISING __SHIFTIN(2, TPM_TYPE_POLARITY) +#define TPM_INT_EDGE_FALLING __SHIFTIN(3, TPM_TYPE_POLARITY) +#define TPM_LOCALITY_CHANGE_INT __BIT(2) +#define TPM_STS_VALID_INT __BIT(1) +#define TPM_DATA_AVAIL_INT __BIT(0) + +#define TPM_INT_VECTOR 0x000c /* 8bit register */ +#define TPM_INT_STATUS 0x0010 /* 32bit register */ + +#define TPM_INTF_CAPABILITY 0x0014 /* 32bit register */ +#define TPM_INTF_BURST_COUNT_STATIC __BIT(8) +#define TPM_INTF_CMD_READY_INT __BIT(7) +#define TPM_INTF_INT_EDGE_FALLING __BIT(6) +#define TPM_INTF_INT_EDGE_RISING __BIT(5) +#define TPM_INTF_INT_LEVEL_LOW __BIT(4) +#define TPM_INTF_INT_LEVEL_HIGH __BIT(3) +#define TPM_INTF_LOCALITY_CHANGE_INT __BIT(2) +#define TPM_INTF_STS_VALID_INT __BIT(1) +#define TPM_INTF_DATA_AVAIL_INT __BIT(0) +#define TPM_INTF_CAPABILITY_BITS \ + "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IRISE\07IFALL\010IRDY\011BCST" + +#define TPM_STS 0x0018 /* 24bit register */ +#define TPM_STS_BURST_COUNT __BITS(23,8) +#define TPM_STS_STATUS_BITS __BITS(7,0) +#define TPM_STS_VALID __BIT(7) +#define TPM_STS_CMD_READY __BIT(6) +#define TPM_STS_GO __BIT(5) +#define TPM_STS_DATA_AVAIL __BIT(4) +#define TPM_STS_DATA_EXPECT __BIT(3) +#define TPM_STS_RESP_RETRY __BIT(1) + +#define TPM_DATA 0x0024 /* 32bit register */ +#define TPM_ID 0x0f00 /* 32bit register */ +#define TPM_REV 0x0f04 /* 8bit register */ -#define TPM_ACCESS 0x0000 /* access register */ -#define TPM_ACCESS_ESTABLISHMENT 0x01 /* establishment */ -#define TPM_ACCESS_REQUEST_USE 0x02 /* request using locality */ -#define TPM_ACCESS_REQUEST_PENDING 0x04 /* pending request */ -#define TPM_ACCESS_SEIZE 0x08 /* request locality seize */ -#define TPM_ACCESS_SEIZED 0x10 /* locality has been seized */ -#define TPM_ACCESS_ACTIVE_LOCALITY 0x20 /* locality is active */ -#define TPM_ACCESS_VALID 0x80 /* bits are valid */ -#define TPM_ACCESS_BITS \ - "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID" - -#define TPM_INTERRUPT_ENABLE 0x0008 -#define TPM_GLOBAL_INT_ENABLE 0x80000000 /* enable ints */ -#define TPM_CMD_READY_INT 0x00000080 /* cmd ready enable */ -#define TPM_INT_EDGE_FALLING 0x00000018 -#define TPM_INT_EDGE_RISING 0x00000010 -#define TPM_INT_LEVEL_LOW 0x00000008 -#define TPM_INT_LEVEL_HIGH 0x00000000 -#define TPM_LOCALITY_CHANGE_INT 0x00000004 /* locality change enable */ -#define TPM_STS_VALID_INT 0x00000002 /* int on TPM_STS_VALID is set */ -#define TPM_DATA_AVAIL_INT 0x00000001 /* int on TPM_STS_DATA_AVAIL is set */ -#define TPM_INTERRUPT_ENABLE_BITS \ - "\177\020b\0DRDY\0b\1STSVALID\0b\2LOCCHG\0" \ - "F\3\2:\0HIGH\0:\1LOW\0:\2RISE\0:\3FALL\0" \ - "b\7IRDY\0b\x1fGIENABLE\0" - -#define TPM_INT_VECTOR 0x000c /* 8 bit reg for 4 bit irq vector */ -#define TPM_INT_STATUS 0x0010 /* bits are & 0x87 from TPM_INTERRUPT_ENABLE */ - -#define TPM_INTF_CAPABILITIES 0x0014 /* capability register */ -#define TPM_INTF_BURST_COUNT_STATIC 0x0100 /* TPM_STS_BMASK static */ -#define TPM_INTF_CMD_READY_INT 0x0080 /* int on ready supported */ -#define TPM_INTF_INT_EDGE_FALLING 0x0040 /* falling edge ints supported */ -#define TPM_INTF_INT_EDGE_RISING 0x0020 /* rising edge ints supported */ -#define TPM_INTF_INT_LEVEL_LOW 0x0010 /* level-low ints supported */ -#define TPM_INTF_INT_LEVEL_HIGH 0x0008 /* level-high ints supported */ -#define TPM_INTF_LOCALITY_CHANGE_INT 0x0004 /* locality-change int (mb 1) */ -#define TPM_INTF_STS_VALID_INT 0x0002 /* TPM_STS_VALID int supported */ -#define TPM_INTF_DATA_AVAIL_INT 0x0001 /* TPM_STS_DATA_AVAIL int supported (mb 1) */ -#define TPM_CAPSREQ \ - (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW) -#define TPM_CAPBITS \ - "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IRISE\07IFALL\010IRDY\011BCST" - -#define TPM_STS 0x0018 /* status register */ -#define TPM_STS_MASK 0x000000ff /* status bits */ -#define TPM_STS_BMASK 0x00ffff00 /* ro io burst size */ -#define TPM_STS_VALID 0x00000080 /* ro other bits are valid */ -#define TPM_STS_CMD_READY 0x00000040 /* rw chip/signal ready */ -#define TPM_STS_GO 0x00000020 /* wo start the command */ -#define TPM_STS_DATA_AVAIL 0x00000010 /* ro data available */ -#define TPM_STS_DATA_EXPECT 0x00000008 /* ro more data to be written */ -#define TPM_STS_RESP_RETRY 0x00000002 /* wo resend the response */ -#define TPM_STS_BITS "\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY" - -#define TPM_DATA 0x0024 -#define TPM_ID 0x0f00 -#define TPM_REV 0x0f04 -#define TPM_SIZE 0x5000 /* five pages of the above */ - -#define TPM_ACCESS_TMO 2000 /* 2sec */ -#define TPM_READY_TMO 2000 /* 2sec */ -#define TPM_READ_TMO 2000 /* 2sec */ -#define TPM_BURST_TMO 2000 /* 2sec */ - -#define TPM_LEGACY_BUSY 0x01 -#define TPM_LEGACY_ABRT 0x01 -#define TPM_LEGACY_DA 0x02 -#define TPM_LEGACY_RE 0x04 -#define TPM_LEGACY_LAST 0x04 -#define TPM_LEGACY_BITS "\020\01BUSY\2DA\3RE\4LAST" -#define TPM_LEGACY_TMO (2*60) /* sec */ -#define TPM_LEGACY_SLEEP 5 /* ticks */ -#define TPM_LEGACY_DELAY 100 +/* + * Five localities, 4K per locality. + */ +#define TPM_SPACE_SIZE 0x5000 Index: src/sys/dev/ic/tpmvar.h diff -u src/sys/dev/ic/tpmvar.h:1.3 src/sys/dev/ic/tpmvar.h:1.4 --- src/sys/dev/ic/tpmvar.h:1.3 Sat Oct 27 17:18:23 2012 +++ src/sys/dev/ic/tpmvar.h Sat Jun 22 12:57:41 2019 @@ -1,7 +1,37 @@ -/* $NetBSD: tpmvar.h,v 1.3 2012/10/27 17:18:23 chs Exp $ */ +/* $NetBSD: tpmvar.h,v 1.4 2019/06/22 12:57:41 maxv Exp $ */ + +/* + * Copyright (c) 2019 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Maxime Villard. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + /* * Copyright (c) 2008, 2009 Michael Shalayeff - * Copyright (c) 2009, 2010 Hans-Jörg Höxer + * Copyright (c) 2009, 2010 Hans-Joerg Hoexer * All rights reserved. * * Permission to use, copy, modify, and distribute this software for any @@ -17,45 +47,61 @@ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define TPM_API_VERSION 1 + +enum tpm_version { + TPM_1_2, + TPM_2_0 +}; + +struct tpm_ioc_getinfo { + uint32_t api_version; + + uint32_t tpm_version; + uint32_t device_id; + uint32_t device_rev; + uint32_t device_caps; +}; + +#define TPM_IOC_GETINFO _IOR ('N', 0, struct tpm_ioc_getinfo) + +#ifdef _KERNEL + struct tpm_softc { device_t sc_dev; + enum tpm_version sc_ver; void *sc_ih; - int (*sc_init)(struct tpm_softc *, int, const char *); - int (*sc_start)(struct tpm_softc *, int); - int (*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int); - int (*sc_write)(struct tpm_softc *, const void *, size_t); - int (*sc_end)(struct tpm_softc *, int, int); + int (*sc_init)(struct tpm_softc *, int); + int (*sc_start)(struct tpm_softc *, int); + int (*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int); + int (*sc_write)(struct tpm_softc *, const void *, size_t); + int (*sc_end)(struct tpm_softc *, int, int); bus_space_tag_t sc_bt, sc_batm; bus_space_handle_t sc_bh, sc_bahm; - u_int32_t sc_devid; - u_int32_t sc_rev; - u_int32_t sc_stat; - u_int32_t sc_capabilities; + uint32_t sc_devid; + uint32_t sc_rev; + uint32_t sc_status; + uint32_t sc_capabilities; int sc_flags; #define TPM_OPEN 0x0001 - int sc_vector; + int sc_vector; }; int tpm_intr(void *); -bool tpm_suspend(device_t, const pmf_qual_t *); -bool tpm_resume(device_t, const pmf_qual_t *); +bool tpm12_suspend(device_t, const pmf_qual_t *); +bool tpm12_resume(device_t, const pmf_qual_t *); int tpm_tis12_probe(bus_space_tag_t, bus_space_handle_t); -int tpm_tis12_init(struct tpm_softc *, int, const char *); +int tpm_tis12_init(struct tpm_softc *, int); int tpm_tis12_start(struct tpm_softc *, int); int tpm_tis12_read(struct tpm_softc *, void *, size_t, size_t *, int); int tpm_tis12_write(struct tpm_softc *, const void *, size_t); int tpm_tis12_end(struct tpm_softc *, int, int); -int tpm_legacy_probe(bus_space_tag_t, bus_addr_t); -int tpm_legacy_init(struct tpm_softc *, int, const char *); -int tpm_legacy_start(struct tpm_softc *, int); -int tpm_legacy_read(struct tpm_softc *, void *, size_t, size_t *, int); -int tpm_legacy_write(struct tpm_softc *, const void *, size_t); -int tpm_legacy_end(struct tpm_softc *, int, int); +#endif Index: src/sys/dev/isa/tpm_isa.c diff -u src/sys/dev/isa/tpm_isa.c:1.3 src/sys/dev/isa/tpm_isa.c:1.4 --- src/sys/dev/isa/tpm_isa.c:1.3 Thu Apr 27 10:01:53 2017 +++ src/sys/dev/isa/tpm_isa.c Sat Jun 22 12:57:41 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: tpm_isa.c,v 1.3 2017/04/27 10:01:53 msaitoh Exp $ */ +/* $NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $ */ /* * Copyright (c) 2008, 2009 Michael Shalayeff @@ -19,7 +19,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.3 2017/04/27 10:01:53 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -56,27 +56,22 @@ tpm_isa_match(device_t parent, cfdata_t if (tpm_cd.cd_devs && tpm_cd.cd_devs[0]) return 0; - if (tpm_legacy_probe(ia->ia_iot, ia->ia_io[0].ir_addr)) { - ia->ia_io[0].ir_size = 2; - return 1; - } - if (ia->ia_iomem[0].ir_addr == ISA_UNKNOWN_IOMEM) return 0; /* XXX: integer locator sign extension */ - if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SIZE, + if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SPACE_SIZE, 0, &bh)) return 0; if ((rv = tpm_tis12_probe(bt, bh))) { ia->ia_nio = 0; ia->ia_io[0].ir_size = 0; - ia->ia_iomem[0].ir_size = TPM_SIZE; + ia->ia_iomem[0].ir_size = TPM_SPACE_SIZE; } ia->ia_ndrq = 0; - bus_space_unmap(bt, bh, TPM_SIZE); + bus_space_unmap(bt, bh, TPM_SPACE_SIZE); return rv; } @@ -90,35 +85,23 @@ tpm_isa_attach(device_t parent, device_t int rv; sc->sc_dev = self; + sc->sc_ver = TPM_1_2; - if (tpm_legacy_probe(ia->ia_iot, ia->ia_io[0].ir_addr)) { - sc->sc_bt = ia->ia_iot; - iobase = (unsigned int)ia->ia_io[0].ir_addr; - size = ia->ia_io[0].ir_size; - sc->sc_batm = ia->ia_iot; - sc->sc_init = tpm_legacy_init; - sc->sc_start = tpm_legacy_start; - sc->sc_read = tpm_legacy_read; - sc->sc_write = tpm_legacy_write; - sc->sc_end = tpm_legacy_end; - } else { - sc->sc_bt = ia->ia_memt; - iobase = (unsigned int)ia->ia_iomem[0].ir_addr; - size = TPM_SIZE; - sc->sc_init = tpm_tis12_init; - sc->sc_start = tpm_tis12_start; - sc->sc_read = tpm_tis12_read; - sc->sc_write = tpm_tis12_write; - sc->sc_end = tpm_tis12_end; - } + sc->sc_bt = ia->ia_memt; + iobase = (unsigned int)ia->ia_iomem[0].ir_addr; + size = TPM_SPACE_SIZE; + sc->sc_init = tpm_tis12_init; + sc->sc_start = tpm_tis12_start; + sc->sc_read = tpm_tis12_read; + sc->sc_write = tpm_tis12_write; + sc->sc_end = tpm_tis12_end; if (bus_space_map(sc->sc_bt, iobase, size, 0, &sc->sc_bh)) { aprint_error_dev(sc->sc_dev, "cannot map registers\n"); return; } - if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq, - device_xname(sc->sc_dev))) != 0) { + if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq)) != 0) { bus_space_unmap(sc->sc_bt, sc->sc_bh, size); return; } @@ -132,11 +115,11 @@ tpm_isa_attach(device_t parent, device_t (sc->sc_ih = isa_intr_establish_xname(ia->ia_ic, ia->ia_irq[0].ir_irq, IST_EDGE, IPL_TTY, tpm_intr, sc, device_xname(sc->sc_dev))) == NULL) { - bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SIZE); + bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SPACE_SIZE); aprint_error_dev(sc->sc_dev, "cannot establish interrupt\n"); return; } - if (!pmf_device_register(sc->sc_dev, tpm_suspend, tpm_resume)) - aprint_error_dev(sc->sc_dev, "Cannot set power mgmt handler\n"); + if (!pmf_device_register(sc->sc_dev, tpm12_suspend, tpm12_resume)) + aprint_error_dev(sc->sc_dev, "cannot set power mgmt handler\n"); }