diff --git a/sys/conf/files b/sys/conf/files --- a/sys/conf/files +++ b/sys/conf/files @@ -3194,6 +3194,13 @@ dev/tcp_log/tcp_log_dev.c optional tcp_blackbox inet | tcp_blackbox inet6 dev/tdfx/tdfx_pci.c optional tdfx pci dev/ti/if_ti.c optional ti pci +dev/tpm/tpm20.c optional tpm +dev/tpm/tpm_bus.c optional tpm acpi +dev/tpm/tpm_if.m optional tpm +dev/tpm/tpm_spibus.c optional tpm spibus fdt +dev/tpm/tpm_tis_acpi.c optional tpm acpi +dev/tpm/tpm_tis_core.c optional tpm +dev/tpm/tpm_tis_spibus.c optional tpm spibus fdt dev/tws/tws.c optional tws dev/tws/tws_cam.c optional tws dev/tws/tws_hdm.c optional tws diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 --- a/sys/conf/files.amd64 +++ b/sys/conf/files.amd64 @@ -372,9 +372,7 @@ dev/smartpqi/smartpqi_tag.c optional smartpqi dev/sume/if_sume.c optional sume dev/syscons/apm/apm_saver.c optional apm_saver apm -dev/tpm/tpm20.c optional tpm dev/tpm/tpm_crb.c optional tpm acpi -dev/tpm/tpm_tis.c optional tpm acpi dev/tpm/tpm_acpi.c optional tpm acpi dev/tpm/tpm_isa.c optional tpm isa dev/p2sb/p2sb.c optional p2sb pci diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h --- a/sys/dev/tpm/tpm20.h +++ b/sys/dev/tpm/tpm20.h @@ -28,6 +28,7 @@ #ifndef _TPM20_H_ #define _TPM20_H_ +#include "opt_acpi.h" #include #include #include @@ -39,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -49,12 +51,14 @@ #include #include +#ifdef DEV_ACPI #include #include #include -#include "opt_acpi.h" +#endif #include "opt_tpm.h" +#include "tpm_if.h" #define BIT(x) (1 << (x)) @@ -136,55 +140,36 @@ int tpm20_init(struct tpm_sc *sc); void tpm20_release(struct tpm_sc *sc); -/* Small helper routines for io ops */ -static inline uint8_t -RD1(struct tpm_sc *sc, bus_size_t off) -{ - - return (bus_read_1(sc->mem_res, off)); -} -static inline uint32_t -RD4(struct tpm_sc *sc, bus_size_t off) -{ - - return (bus_read_4(sc->mem_res, off)); -} -#ifdef __amd64__ -static inline uint64_t -RD8(struct tpm_sc *sc, bus_size_t off) -{ +/* Mode driver types */ +DECLARE_CLASS(tpmtis_driver); +int tpmtis_attach(device_t dev); - return (bus_read_8(sc->mem_res, off)); -} -#endif -static inline void -WR1(struct tpm_sc *sc, bus_size_t off, uint8_t val) -{ +DECLARE_CLASS(tpmcrb_driver); - bus_write_1(sc->mem_res, off, val); -} -static inline void -WR4(struct tpm_sc *sc, bus_size_t off, uint32_t val) -{ +/* Bus driver types */ +DECLARE_CLASS(tpm_bus_driver); +DECLARE_CLASS(tpm_spi_driver); - bus_write_4(sc->mem_res, off, val); -} +/* Small helper routines for io ops */ static inline void AND4(struct tpm_sc *sc, bus_size_t off, uint32_t val) { + uint32_t v = TPM_READ_4(sc->dev, off); - WR4(sc, off, RD4(sc, off) & val); + TPM_WRITE_4(sc->dev, off, v & val); } static inline void OR1(struct tpm_sc *sc, bus_size_t off, uint8_t val) { + uint8_t v = TPM_READ_1(sc->dev, off); - WR1(sc, off, RD1(sc, off) | val); + TPM_WRITE_1(sc->dev, off, v | val); } static inline void OR4(struct tpm_sc *sc, bus_size_t off, uint32_t val) { + uint32_t v = TPM_READ_1(sc->dev, off); - WR4(sc, off, RD4(sc, off) | val); + TPM_WRITE_4(sc->dev, off, v | val); } #endif /* _TPM20_H_ */ diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c --- a/sys/dev/tpm/tpm20.c +++ b/sys/dev/tpm/tpm20.c @@ -127,7 +127,7 @@ return (result); } - result = sc->transmit(sc, byte_count); + result = TPM_TRANSMIT(sc->dev, byte_count); if (result == 0) { callout_reset(&sc->discard_buffer_callout, @@ -267,7 +267,7 @@ cv_wait(&sc->buf_cv, &sc->dev_lock); memcpy(sc->buf, cmd, sizeof(cmd)); - result = sc->transmit(sc, sizeof(cmd)); + result = TPM_TRANSMIT(sc->dev, sizeof(cmd)); if (result != 0) { sx_xunlock(&sc->dev_lock); return; @@ -319,7 +319,7 @@ sx_xlock(&sc->dev_lock); memcpy(sc->buf, save_cmd, sizeof(save_cmd)); - sc->transmit(sc, sizeof(save_cmd)); + TPM_TRANSMIT(sc->dev, sizeof(save_cmd)); sx_xunlock(&sc->dev_lock); diff --git a/sys/dev/tpm/tpm_bus.c b/sys/dev/tpm/tpm_bus.c new file mode 100644 --- /dev/null +++ b/sys/dev/tpm/tpm_bus.c @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2023 Juniper Networks, Inc. + * All rights reserved. + * + * 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 AUTHOR ``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 AUTHOR 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. + */ + +#include +#include +#include +#include "tpm_if.h" +#include "tpm20.h" + +/* Override accessors */ +static uint8_t +tpm_read_1(device_t dev, bus_size_t off) +{ + struct tpm_sc *sc = device_get_softc(dev); + + return (bus_read_1(sc->mem_res, off)); +} + +static uint32_t +tpm_read_4(device_t dev, bus_size_t off) +{ + struct tpm_sc *sc = device_get_softc(dev); + + return (bus_read_4(sc->mem_res, off)); +} + +/* + * Only i386 is missing bus_space_read_8. + */ +#ifndef __i386__ +static uint64_t +tpm_read_8(device_t dev, bus_size_t off) +{ + struct tpm_sc *sc = device_get_softc(dev); + + return (bus_read_8(sc->mem_res, off)); +} +#endif + +static void +tpm_write_1(device_t dev, bus_size_t off, uint8_t val) +{ + struct tpm_sc *sc = device_get_softc(dev); + + bus_write_1(sc->mem_res, off, val); +} + +static void +tpm_write_4(device_t dev, bus_size_t off, uint32_t val) +{ + struct tpm_sc *sc = device_get_softc(dev); + + bus_write_4(sc->mem_res, off, val); +} + +static void +tpm_write_barrier(device_t dev, bus_addr_t off, bus_size_t length) +{ + struct tpm_sc *sc = device_get_softc(dev); + + bus_barrier(sc->mem_res, off, length, BUS_SPACE_BARRIER_WRITE); +} + +static device_method_t tpm_bus_methods[] = { + DEVMETHOD(tpm_read_1, tpm_read_1), + DEVMETHOD(tpm_read_4, tpm_read_4), +#ifndef __i386__ + DEVMETHOD(tpm_read_8, tpm_read_8), +#endif + DEVMETHOD(tpm_write_1, tpm_write_1), + DEVMETHOD(tpm_write_4, tpm_write_4), + DEVMETHOD(tpm_write_barrier, tpm_write_barrier), + DEVMETHOD_END +}; + +DEFINE_CLASS_0(tpm_lbc, tpm_bus_driver, tpm_bus_methods, sizeof(struct tpm_sc)); diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c --- a/sys/dev/tpm/tpm_crb.c +++ b/sys/dev/tpm/tpm_crb.c @@ -83,7 +83,7 @@ size_t rsp_buf_size; }; -int tpmcrb_transmit(struct tpm_sc *sc, size_t size); +int tpmcrb_transmit(device_t dev, size_t size); static int tpmcrb_acpi_probe(device_t dev); static int tpmcrb_attach(device_t dev); @@ -185,15 +185,15 @@ * stored in a single 8 byte one. */ #ifdef __amd64__ - crb_sc->rsp_off = RD8(sc, TPM_CRB_CTRL_RSP_ADDR); + crb_sc->rsp_off = TPM_READ_8(sc->dev, TPM_CRB_CTRL_RSP_ADDR); #else - crb_sc->rsp_off = RD4(sc, TPM_CRB_CTRL_RSP_ADDR); - crb_sc->rsp_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_RSP_HADDR) << 32); + crb_sc->rsp_off = TPM_READ_4(sc->dev, TPM_CRB_CTRL_RSP_ADDR); + crb_sc->rsp_off |= ((uint64_t) TPM_READ_4(sc->dev, TPM_CRB_CTRL_RSP_HADDR) << 32); #endif - crb_sc->cmd_off = RD4(sc, TPM_CRB_CTRL_CMD_LADDR); - crb_sc->cmd_off |= ((uint64_t) RD4(sc, TPM_CRB_CTRL_CMD_HADDR) << 32); - crb_sc->cmd_buf_size = RD4(sc, TPM_CRB_CTRL_CMD_SIZE); - crb_sc->rsp_buf_size = RD4(sc, TPM_CRB_CTRL_RSP_SIZE); + crb_sc->cmd_off = TPM_READ_4(sc->dev, TPM_CRB_CTRL_CMD_LADDR); + crb_sc->cmd_off |= ((uint64_t) TPM_READ_4(sc->dev, TPM_CRB_CTRL_CMD_HADDR) << 32); + crb_sc->cmd_buf_size = TPM_READ_4(sc->dev, TPM_CRB_CTRL_CMD_SIZE); + crb_sc->rsp_buf_size = TPM_READ_4(sc->dev, TPM_CRB_CTRL_RSP_SIZE); tpmcrb_relinquish_locality(sc); @@ -218,8 +218,6 @@ } } - sc->transmit = tpmcrb_transmit; - result = tpm20_init(sc); if (result != 0) tpmcrb_detach(dev); @@ -248,11 +246,11 @@ { /* Check for condition */ - if ((RD4(sc, off) & mask) == val) + if ((TPM_READ_4(sc->dev, off) & mask) == val) return (true); while (timeout > 0) { - if ((RD4(sc, off) & mask) == val) + if ((TPM_READ_4(sc->dev, off) & mask) == val) return (true); pause("TPM in polling mode", 1); @@ -291,7 +289,7 @@ { uint32_t mask = ~0; - WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CMD); + TPM_WRITE_4(sc->dev, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CMD); if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, TPM_TIMEOUT_B)) { device_printf(sc->dev, @@ -299,48 +297,50 @@ return (false); } - WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR); + TPM_WRITE_4(sc->dev, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR); return (true); } int -tpmcrb_transmit(struct tpm_sc *sc, size_t length) +tpmcrb_transmit(device_t dev, size_t length) { struct tpmcrb_sc *crb_sc; + struct tpm_sc *sc; uint32_t mask, curr_cmd; int timeout, bytes_available; - crb_sc = (struct tpmcrb_sc *)sc; + crb_sc = device_get_softc(dev); + sc = &crb_sc->base; sx_assert(&sc->dev_lock, SA_XLOCKED); if (length > crb_sc->cmd_buf_size) { - device_printf(sc->dev, + device_printf(dev, "Requested transfer is bigger than buffer size\n"); return (E2BIG); } - if (RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_ERR_BIT) { - device_printf(sc->dev, + if (TPM_READ_4(dev, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_ERR_BIT) { + device_printf(dev, "Device has Error bit set\n"); return (EIO); } if (!tpmcrb_request_locality(sc, 0)) { - device_printf(sc->dev, + device_printf(dev, "Failed to obtain locality\n"); return (EIO); } /* Clear cancellation bit */ - WR4(sc, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR); + TPM_WRITE_4(dev, TPM_CRB_CTRL_CANCEL, TPM_CRB_CTRL_CANCEL_CLEAR); /* Switch device to idle state if necessary */ - if (!(RD4(sc, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_IDLE_BIT)) { + if (!(TPM_READ_4(dev, TPM_CRB_CTRL_STS) & TPM_CRB_CTRL_STS_IDLE_BIT)) { OR4(sc, TPM_CRB_CTRL_REQ, TPM_CRB_CTRL_REQ_GO_IDLE); mask = TPM_CRB_CTRL_STS_IDLE_BIT; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS, mask, mask, TPM_TIMEOUT_C)) { - device_printf(sc->dev, + device_printf(dev, "Failed to transition to idle state\n"); return (EIO); } @@ -351,7 +351,7 @@ mask = TPM_CRB_CTRL_REQ_GO_READY; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_STS, mask, !mask, TPM_TIMEOUT_C)) { - device_printf(sc->dev, + device_printf(dev, "Failed to transition to ready state\n"); return (EIO); } @@ -366,16 +366,14 @@ /* Send command and tell device to process it. */ bus_write_region_stream_1(sc->mem_res, crb_sc->cmd_off, sc->buf, length); - bus_barrier(sc->mem_res, crb_sc->cmd_off, - length, BUS_SPACE_BARRIER_WRITE); + TPM_WRITE_BARRIER(dev, crb_sc->cmd_off, length); - WR4(sc, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD); - bus_barrier(sc->mem_res, TPM_CRB_CTRL_START, - 4, BUS_SPACE_BARRIER_WRITE); + TPM_WRITE_4(dev, TPM_CRB_CTRL_START, TPM_CRB_CTRL_START_CMD); + TPM_WRITE_BARRIER(dev, TPM_CRB_CTRL_START, 4); mask = ~0; if (!tpm_wait_for_u32(sc, TPM_CRB_CTRL_START, mask, ~mask, timeout)) { - device_printf(sc->dev, + device_printf(dev, "Timeout while waiting for device to process cmd\n"); if (!tpmcrb_cancel_cmd(sc)) return (EIO); @@ -387,7 +385,7 @@ bytes_available = be32toh(*(uint32_t *) (&sc->buf[2])); if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) { - device_printf(sc->dev, + device_printf(dev, "Incorrect response size: %d\n", bytes_available); return (EIO); @@ -411,11 +409,11 @@ DEVMETHOD(device_detach, tpmcrb_detach), DEVMETHOD(device_shutdown, tpm20_shutdown), DEVMETHOD(device_suspend, tpm20_suspend), + DEVMETHOD(tpm_transmit, tpmcrb_transmit), {0, 0} }; -static driver_t tpmcrb_driver = { - "tpmcrb", tpmcrb_methods, sizeof(struct tpmcrb_sc), -}; +DEFINE_CLASS_1(tpmcrb, tpmcrb_driver, tpmcrb_methods, sizeof(struct tpmcrb_sc), + tpm_bus_driver); DRIVER_MODULE(tpmcrb, acpi, tpmcrb_driver, 0, 0); diff --git a/sys/dev/tpm/tpm_if.m b/sys/dev/tpm/tpm_if.m new file mode 100644 --- /dev/null +++ b/sys/dev/tpm/tpm_if.m @@ -0,0 +1,76 @@ +#- +# Copyright (c) 2023 Juniper Networks, Inc. +# All Rights Reserved +# +# 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 AUTHOR 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 AUTHOR 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. +# +# + +#include +#include + +INTERFACE tpm; + +# +# Transfer data to the TPM data buffer +# +METHOD int transmit { + device_t dev; + size_t length; +}; + + +METHOD uint64_t read_8 { + device_t dev; + bus_addr_t addr; +} + +# +# Read 4 bytes (host endian) from a TPM register +# +METHOD uint32_t read_4 { + device_t dev; + bus_addr_t addr; +}; + +METHOD uint8_t read_1 { + device_t dev; + bus_addr_t addr; +}; + +METHOD void write_4 { + device_t dev; + bus_addr_t addr; + uint32_t value; +}; + +METHOD void write_1 { + device_t dev; + bus_addr_t addr; + uint8_t value; +}; + +METHOD void write_barrier { + device_t dev; + bus_addr_t off; + bus_size_t length; +} diff --git a/sys/dev/tpm/tpm_spibus.c b/sys/dev/tpm/tpm_spibus.c new file mode 100644 --- /dev/null +++ b/sys/dev/tpm/tpm_spibus.c @@ -0,0 +1,166 @@ +/*- + * Copyright (c) 2023 Juniper Networks, Inc. + * All rights reserved. + * + * 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 AUTHOR ``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 AUTHOR 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. + */ + +#include +#include +#include + +#include +#include "spibus_if.h" +#include "tpm_if.h" +#include "tpm20.h" + +#define TPM_BASE_ADDR 0xD40000 +#define TPM_SPI_HEADER_SIZE 4 +#define TPM_WAIT_STATES 50 + +static void +tpm_insert_wait(device_t dev) +{ + device_t parent = device_get_parent(dev); + int wait = TPM_WAIT_STATES; + struct spi_command spic = SPI_COMMAND_INITIALIZER; + + uint8_t txb = 0; + uint8_t rxb = 0; + + spic.tx_cmd = &txb; + spic.rx_cmd = &rxb; + spic.tx_cmd_sz = 1; + spic.rx_cmd_sz = 1; + spic.flags = SPI_FLAG_KEEP_CS; + do { + SPIBUS_TRANSFER(parent, dev, &spic); + } while (--wait > 0 && (rxb & 0x1) == 0); +} + +static inline int +tpm_spi_read_n(device_t dev, bus_size_t off, void *buf, size_t size) +{ + struct spi_command spic = SPI_COMMAND_INITIALIZER; + uint8_t tx[4] = {0}; + uint8_t rx[4] = {0}; + int err; + + if (size > sizeof(rx)) + return (EINVAL); + off += TPM_BASE_ADDR; + tx[0] = 0x80 | (size - 1); /* Write (size) bytes */ + tx[1] = (off >> 16) & 0xff; + tx[2] = (off >> 8) & 0xff; + tx[3] = off & 0xff; + + spic.tx_cmd = tx; + spic.tx_cmd_sz = sizeof(tx); + spic.rx_cmd = rx; + spic.rx_cmd_sz = sizeof(tx); + spic.flags = SPI_FLAG_KEEP_CS; + + err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic); + + if (!(rx[3] & 0x1)) { + tpm_insert_wait(dev); + } + memset(tx, 0, sizeof(tx)); + spic.tx_cmd_sz = spic.rx_cmd_sz = size; + spic.flags = 0; + err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic); + memcpy(buf, &rx[0], size); + + return (err); +} + +static inline int +tpm_spi_write_n(device_t dev, bus_size_t off, void *buf, size_t size) +{ + struct spi_command spic = SPI_COMMAND_INITIALIZER; + uint8_t tx[8] = {0}; + uint8_t rx[8] = {0}; + int err; + + off += TPM_BASE_ADDR; + tx[0] = 0x00 | (size - 1); /* Write (size) bytes */ + tx[1] = (off >> 16) & 0xff; + tx[2] = (off >> 8) & 0xff; + tx[3] = off & 0xff; + + memcpy(&tx[4], buf, size); + + spic.tx_cmd = tx; + spic.tx_cmd_sz = size + TPM_SPI_HEADER_SIZE; + spic.rx_cmd = rx; + spic.rx_cmd_sz = size + TPM_SPI_HEADER_SIZE; + + err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic); + + return (err); +} + +/* Override accessors */ +static inline uint8_t +spi_read_1(device_t dev, bus_size_t off) +{ + uint8_t rx_byte; + + tpm_spi_read_n(dev, off, &rx_byte, 1); + + return (rx_byte); +} + +static inline uint32_t +spi_read_4(device_t dev, bus_size_t off) +{ + uint32_t rx_word = 0; + + tpm_spi_read_n(dev, off, &rx_word, 4); + rx_word = le32toh(rx_word); + + return (rx_word); +} + +static inline void +spi_write_1(device_t dev, bus_size_t off, uint8_t val) +{ + tpm_spi_write_n(dev, off, &val, 1); +} + +static inline void +spi_write_4(device_t dev, bus_size_t off, uint32_t val) +{ + uint32_t tmp = htole32(val); + tpm_spi_write_n(dev, off, &tmp, 4); +} + +static device_method_t tpm_spibus_methods[] = { + DEVMETHOD(tpm_read_4, spi_read_4), + DEVMETHOD(tpm_read_1, spi_read_1), + DEVMETHOD(tpm_write_4, spi_write_4), + DEVMETHOD(tpm_write_1, spi_write_1), + DEVMETHOD_END +}; + +DEFINE_CLASS_0(tpm_spi, tpm_spi_driver, tpm_spibus_methods, + sizeof(struct tpm_sc)); diff --git a/sys/dev/tpm/tpm_tis_acpi.c b/sys/dev/tpm/tpm_tis_acpi.c new file mode 100644 --- /dev/null +++ b/sys/dev/tpm/tpm_tis_acpi.c @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2018 Stormshield. + * Copyright (c) 2018 Semihalf. + * Copyright (c) 2023 Juniper Networks, Inc. + * All rights reserved. + * + * 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 AUTHOR ``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 AUTHOR 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. + */ + +#include +#include "tpm20.h" +#include "tpm_if.h" + +static int tpmtis_acpi_probe(device_t dev); + +char *tpmtis_ids[] = {"MSFT0101", NULL}; + +static int +tpmtis_acpi_probe(device_t dev) +{ + int err; + ACPI_TABLE_TPM23 *tbl; + ACPI_STATUS status; + + err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmtis_ids, NULL); + if (err > 0) + return (err); + /*Find TPM2 Header*/ + status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl); + if(ACPI_FAILURE(status) || + tbl->StartMethod != TPM2_START_METHOD_TIS) + err = ENXIO; + + device_set_desc(dev, "Trusted Platform Module 2.0, FIFO mode"); + return (err); +} + +static int +tpmtis_acpi_attach(device_t dev) +{ + struct tpm_sc *sc = device_get_softc(dev); + + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, + RF_ACTIVE); + if (sc->mem_res == NULL) { + return (ENXIO); + } + + /* + * If tpmtis_attach() fails, tpmtis_detach() will automatically free + * sc->mem_res (not-NULL). + */ + return (tpmtis_attach(dev)); +} + +/* ACPI Driver */ +static device_method_t tpmtis_methods[] = { + DEVMETHOD(device_attach, tpmtis_acpi_attach), + DEVMETHOD(device_probe, tpmtis_acpi_probe), + DEVMETHOD_END +}; + +DEFINE_CLASS_2(tpmtis, tpmtis_acpi_driver, tpmtis_methods, + sizeof(struct tpm_sc), tpmtis_driver, tpm_bus_driver); + +DRIVER_MODULE(tpmtis, acpi, tpmtis_driver, 0, 0); diff --git a/sys/dev/tpm/tpm_tis.c b/sys/dev/tpm/tpm_tis_core.c rename from sys/dev/tpm/tpm_tis.c rename to sys/dev/tpm/tpm_tis_core.c --- a/sys/dev/tpm/tpm_tis.c +++ b/sys/dev/tpm/tpm_tis_core.c @@ -27,6 +27,7 @@ #include #include "tpm20.h" +#include "tpm_if.h" /* * TIS register space as defined in @@ -72,10 +73,8 @@ #define TPM_STS_BURST_MASK 0xFFFF00 #define TPM_STS_BURST_OFFSET 0x8 -static int tpmtis_transmit(struct tpm_sc *sc, size_t length); +static int tpmtis_transmit(device_t dev, size_t length); -static int tpmtis_acpi_probe(device_t dev); -static int tpmtis_attach(device_t dev); static int tpmtis_detach(device_t dev); static void tpmtis_intr_handler(void *arg); @@ -93,29 +92,7 @@ static uint16_t tpmtis_wait_for_burst(struct tpm_sc *sc); -char *tpmtis_ids[] = {"MSFT0101", NULL}; - -static int -tpmtis_acpi_probe(device_t dev) -{ - int err; - ACPI_TABLE_TPM23 *tbl; - ACPI_STATUS status; - - err = ACPI_ID_PROBE(device_get_parent(dev), dev, tpmtis_ids, NULL); - if (err > 0) - return (err); - /*Find TPM2 Header*/ - status = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **) &tbl); - if(ACPI_FAILURE(status) || - tbl->StartMethod != TPM2_START_METHOD_TIS) - err = ENXIO; - - device_set_desc(dev, "Trusted Platform Module 2.0, FIFO mode"); - return (err); -} - -static int +int tpmtis_attach(device_t dev) { struct tpm_sc *sc; @@ -123,20 +100,11 @@ sc = device_get_softc(dev); sc->dev = dev; - sc->transmit = tpmtis_transmit; sc->intr_type = -1; sx_init(&sc->dev_lock, "TPM driver lock"); sc->buf = malloc(TPM_BUFSIZE, M_TPM20, M_WAITOK); - sc->mem_rid = 0; - sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, - RF_ACTIVE); - if (sc->mem_res == NULL) { - tpmtis_detach(dev); - return (ENXIO); - } - sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE); @@ -198,7 +166,7 @@ sx_xlock(&sc->dev_lock); memcpy(sc->buf, cmd, sizeof(cmd)); - tpmtis_transmit(sc, sizeof(cmd)); + tpmtis_transmit(sc->dev, sizeof(cmd)); sc->pending_data_length = 0; sx_xunlock(&sc->dev_lock); } @@ -222,19 +190,19 @@ if(!tpmtis_request_locality(sc, 0)) sc->interrupts = false; - WR1(sc, TPM_INT_VECTOR, irq); + TPM_WRITE_1(sc->dev, TPM_INT_VECTOR, irq); /* Clear all pending interrupts. */ - reg = RD4(sc, TPM_INT_STS); - WR4(sc, TPM_INT_STS, reg); + reg = TPM_READ_4(sc->dev, TPM_INT_STS); + TPM_WRITE_4(sc->dev, TPM_INT_STS, reg); - reg = RD4(sc, TPM_INT_ENABLE); + reg = TPM_READ_4(sc->dev, TPM_INT_ENABLE); reg |= TPM_INT_ENABLE_GLOBAL_ENABLE | TPM_INT_ENABLE_DATA_AVAIL | TPM_INT_ENABLE_LOC_CHANGE | TPM_INT_ENABLE_CMD_RDY | TPM_INT_ENABLE_STS_VALID; - WR4(sc, TPM_INT_ENABLE, reg); + TPM_WRITE_4(sc->dev, TPM_INT_ENABLE, reg); tpmtis_relinquish_locality(sc); tpmtis_test_intr(sc); @@ -247,9 +215,9 @@ uint32_t status; sc = (struct tpm_sc *)arg; - status = RD4(sc, TPM_INT_STS); + status = TPM_READ_4(sc->dev, TPM_INT_STS); - WR4(sc, TPM_INT_STS, status); + TPM_WRITE_4(sc->dev, TPM_INT_STS, status); /* Check for stray interrupts. */ if (sc->intr_type == -1 || (sc->intr_type & status) == 0) @@ -265,7 +233,7 @@ { /* Check for condition */ - if ((RD4(sc, off) & mask) == val) + if ((TPM_READ_4(sc->dev, off) & mask) == val) return (true); /* If interrupts are enabled sleep for timeout duration */ @@ -273,12 +241,12 @@ tsleep(sc, PWAIT, "TPM WITH INTERRUPTS", timeout / tick); sc->intr_type = -1; - return ((RD4(sc, off) & mask) == val); + return ((TPM_READ_4(sc->dev, off) & mask) == val); } /* If we don't have interrupts poll the device every tick */ while (timeout > 0) { - if ((RD4(sc, off) & mask) == val) + if ((TPM_READ_4(sc->dev, off) & mask) == val) return (true); pause("TPM POLLING", 1); @@ -296,7 +264,7 @@ timeout = TPM_TIMEOUT_A; while (timeout-- > 0) { - burst_count = (RD4(sc, TPM_STS) & TPM_STS_BURST_MASK) >> + burst_count = (TPM_READ_4(sc->dev, TPM_STS) & TPM_STS_BURST_MASK) >> TPM_STS_BURST_OFFSET; if (burst_count > 0) break; @@ -320,7 +288,7 @@ count -= burst_count; while (burst_count-- > 0) - *buf++ = RD1(sc, TPM_DATA_FIFO); + *buf++ = TPM_READ_1(sc->dev, TPM_DATA_FIFO); } return (true); @@ -340,7 +308,7 @@ count -= burst_count; while (burst_count-- > 0) - WR1(sc, TPM_DATA_FIFO, *buf++); + TPM_WRITE_1(sc->dev, TPM_DATA_FIFO, *buf++); } return (true); @@ -360,14 +328,14 @@ timeout = TPM_TIMEOUT_A; sc->intr_type = TPM_INT_STS_LOC_CHANGE; - WR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_REQ); - bus_barrier(sc->mem_res, TPM_ACCESS, 1, BUS_SPACE_BARRIER_WRITE); + TPM_WRITE_1(sc->dev, TPM_ACCESS, TPM_ACCESS_LOC_REQ); + TPM_WRITE_BARRIER(sc->dev, TPM_ACCESS, 1); if(sc->interrupts) { tsleep(sc, PWAIT, "TPMLOCREQUEST with INTR", timeout / tick); - return ((RD1(sc, TPM_ACCESS) & mask) == mask); + return ((TPM_READ_1(sc->dev, TPM_ACCESS) & mask) == mask); } else { while(timeout > 0) { - if ((RD1(sc, TPM_ACCESS) & mask) == mask) + if ((TPM_READ_1(sc->dev, TPM_ACCESS) & mask) == mask) return (true); pause("TPMLOCREQUEST POLLING", 1); @@ -387,7 +355,7 @@ * Clear them now in case interrupt handler didn't make it in time. */ if(sc->interrupts) - AND4(sc, TPM_INT_STS, RD4(sc, TPM_INT_STS)); + AND4(sc, TPM_INT_STS, TPM_READ_4(sc->dev, TPM_INT_STS)); OR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_RELINQUISH); } @@ -400,8 +368,8 @@ mask = TPM_STS_CMD_RDY; sc->intr_type = TPM_INT_STS_CMD_RDY; - WR4(sc, TPM_STS, TPM_STS_CMD_RDY); - bus_barrier(sc->mem_res, TPM_STS, 4, BUS_SPACE_BARRIER_WRITE); + TPM_WRITE_4(sc->dev, TPM_STS, TPM_STS_CMD_RDY); + TPM_WRITE_BARRIER(sc->dev, TPM_STS, 4); if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_B)) return (false); @@ -409,26 +377,28 @@ } static int -tpmtis_transmit(struct tpm_sc *sc, size_t length) +tpmtis_transmit(device_t dev, size_t length) { + struct tpm_sc *sc; size_t bytes_available; uint32_t mask, curr_cmd; int timeout; + sc = device_get_softc(dev); sx_assert(&sc->dev_lock, SA_XLOCKED); if (!tpmtis_request_locality(sc, 0)) { - device_printf(sc->dev, + device_printf(dev, "Failed to obtain locality\n"); return (EIO); } if (!tpmtis_go_ready(sc)) { - device_printf(sc->dev, + device_printf(dev, "Failed to switch to ready state\n"); return (EIO); } if (!tpmtis_write_bytes(sc, length, sc->buf)) { - device_printf(sc->dev, + device_printf(dev, "Failed to write cmd to device\n"); return (EIO); } @@ -436,12 +406,12 @@ mask = TPM_STS_VALID; sc->intr_type = TPM_INT_STS_VALID; if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C)) { - device_printf(sc->dev, + device_printf(dev, "Timeout while waiting for valid bit\n"); return (EIO); } - if (RD4(sc, TPM_STS) & TPM_STS_DATA_EXPECTED) { - device_printf(sc->dev, + if (TPM_READ_4(dev, TPM_STS) & TPM_STS_DATA_EXPECTED) { + device_printf(dev, "Device expects more data even though we already" " sent everything we had\n"); return (EIO); @@ -454,13 +424,13 @@ curr_cmd = be32toh(*(uint32_t *) (&sc->buf[6])); timeout = tpm20_get_timeout(curr_cmd); - WR4(sc, TPM_STS, TPM_STS_CMD_START); - bus_barrier(sc->mem_res, TPM_STS, 4, BUS_SPACE_BARRIER_WRITE); + TPM_WRITE_4(dev, TPM_STS, TPM_STS_CMD_START); + TPM_WRITE_BARRIER(dev, TPM_STS, 4); mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; sc->intr_type = TPM_INT_STS_DATA_AVAIL; if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, timeout)) { - device_printf(sc->dev, + device_printf(dev, "Timeout while waiting for device to process cmd\n"); /* * Switching to ready state also cancels processing @@ -479,21 +449,21 @@ } /* Read response header. Length is passed in bytes 2 - 6. */ if(!tpmtis_read_bytes(sc, TPM_HEADER_SIZE, sc->buf)) { - device_printf(sc->dev, + device_printf(dev, "Failed to read response header\n"); return (EIO); } bytes_available = be32toh(*(uint32_t *) (&sc->buf[2])); if (bytes_available > TPM_BUFSIZE || bytes_available < TPM_HEADER_SIZE) { - device_printf(sc->dev, + device_printf(dev, "Incorrect response size: %zu\n", bytes_available); return (EIO); } if(!tpmtis_read_bytes(sc, bytes_available - TPM_HEADER_SIZE, &sc->buf[TPM_HEADER_SIZE])) { - device_printf(sc->dev, + device_printf(dev, "Failed to read response\n"); return (EIO); } @@ -505,16 +475,12 @@ /* ACPI Driver */ static device_method_t tpmtis_methods[] = { - DEVMETHOD(device_probe, tpmtis_acpi_probe), DEVMETHOD(device_attach, tpmtis_attach), DEVMETHOD(device_detach, tpmtis_detach), DEVMETHOD(device_shutdown, tpm20_shutdown), DEVMETHOD(device_suspend, tpm20_suspend), - {0, 0} -}; - -static driver_t tpmtis_driver = { - "tpmtis", tpmtis_methods, sizeof(struct tpm_sc), + DEVMETHOD(tpm_transmit, tpmtis_transmit), + DEVMETHOD_END }; -DRIVER_MODULE(tpmtis, acpi, tpmtis_driver, 0, 0); +DEFINE_CLASS_0(tpmtis, tpmtis_driver, tpmtis_methods, sizeof(struct tpm_sc)); diff --git a/sys/dev/tpm/tpm_tis_spibus.c b/sys/dev/tpm/tpm_tis_spibus.c new file mode 100644 --- /dev/null +++ b/sys/dev/tpm/tpm_tis_spibus.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 Juniper Networks, Inc. + * All rights reserved. + */ +/*- + * Copyright (c) 2018 Stormshield. + * Copyright (c) 2018 Semihalf. + * All rights reserved. + * + * 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 AUTHOR ``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 AUTHOR 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. + */ + +/* Based *heavily* on the tpm_tis driver. */ + +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "spibus_if.h" +#include "tpm_if.h" + +#include +#include + +static struct ofw_compat_data compatible_data[] = { + {"infineon,slb9670", true}, + {"tcg,tpm_tis-spi", true}, + {NULL, false} +}; + +static int +tpm_spi_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compatible_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "Trusted Platform Module 2.0, SPI Mode"); + + return (BUS_PROBE_DEFAULT); +} + +static device_method_t tpm_methods[] = { + DEVMETHOD(device_probe, tpm_spi_probe), + DEVMETHOD_END +}; + +DEFINE_CLASS_2(tpm, tpm_driver, tpm_methods, sizeof(struct tpm_sc), + tpmtis_driver, tpm_spi_driver); + +#if __FreeBSD_version < 1400067 +static devclass_t tpm_devclass; + +DRIVER_MODULE(tpm, spibus, tpm_driver, tpm_devclass, NULL, NULL); +#else +DRIVER_MODULE(tpm, spibus, tpm_driver, NULL, NULL); +#endif +MODULE_DEPEND(tpm, spibus, 1, 1, 1); +MODULE_VERSION(tpm, 1); diff --git a/sys/modules/Makefile b/sys/modules/Makefile --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -391,7 +391,7 @@ ${_ti} \ tmpfs \ ${_toecore} \ - ${_tpm} \ + tpm \ tws \ uart \ udf \ @@ -814,7 +814,6 @@ _s3= s3 _sdhci_acpi= sdhci_acpi _superio= superio -_tpm= tpm _vesa= vesa _viawd= viawd _vmd= vmd diff --git a/sys/modules/tpm/Makefile b/sys/modules/tpm/Makefile --- a/sys/modules/tpm/Makefile +++ b/sys/modules/tpm/Makefile @@ -3,10 +3,25 @@ KMOD= tpm -SRCS= tpm.c bus_if.h device_if.h +SRCS= bus_if.h device_if.h tpm_if.c tpm_if.h +SRCS+= opt_acpi.h opt_tpm.h + #Bus specific stuff. -SRCS+= tpm_isa.c tpm_acpi.c isa_if.h opt_acpi.h acpi_if.h +.if ${MACHINE_ARCH:Namd64:Ni386} == "" +SRCS+= tpm.c +SRCS+= tpm_acpi.c tpm_isa.c +SRCS+= isa_if.h +.endif + #TPM 2.0 -SRCS+= tpm20.c tpm_crb.c tpm_tis.c opt_tpm.h +SRCS+= tpm20.c tpm_tis_core.c +.if defined(${OPT_FDT}) +SRCS+= tpm_spibus.c tpm_tis_spibus.c spibus_if.h +.endif +.if ${MACHINE_ARCH:Namd64:Ni386:Narm64} == "" +SRCS+= acpi_if.h +SRCS+= tpm_tis_acpi.c +SRCS+= tpm_crb.c +.endif .include