The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/tpm/tpm_crb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 1a989d7f01735d8b3beee8c63f3e32a9


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.