mirror of
https://github.com/opnsense/src.git
synced 2026-06-05 06:42:56 -04:00
tpm: Refactor TIS and add a SPI attachment
Summary: Though mostly used in x86 devices, TPM can be used on others, with a direct SPI attachment. Refactor the TPM 2.0 driver set to use an attachment interface, and implement a SPI bus interface. Test Plan: Tested on a Raspberry Pi 4, with a GeeekPi TPM2.0 module (SLB9670 TPM) using security/tpm2-tools tpm2_getcaps for very light testing against the spibus attachment. Reviewed by: kd Obtained from: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D45069
This commit is contained in:
parent
b95e96028e
commit
c2e9c5bbf0
13 changed files with 642 additions and 156 deletions
|
|
@ -3194,6 +3194,13 @@ dev/syscons/warp/warp_saver.c optional warp_saver
|
|||
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
|
||||
|
|
|
|||
|
|
@ -372,9 +372,7 @@ dev/smartpqi/smartpqi_sis.c optional smartpqi
|
|||
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
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ tpm20_write(struct cdev *dev, struct uio *uio, int flags)
|
|||
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 @@ tpm20_harvest(void *arg, int unused)
|
|||
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 @@ tpm20_save_state(device_t dev, bool suspend)
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#ifndef _TPM20_H_
|
||||
#define _TPM20_H_
|
||||
|
||||
#include "opt_acpi.h"
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/param.h>
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#include <sys/bus.h>
|
||||
#include <sys/callout.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/sx.h>
|
||||
|
|
@ -49,12 +51,14 @@
|
|||
#include <machine/md_var.h>
|
||||
#include <machine/resource.h>
|
||||
|
||||
#ifdef DEV_ACPI
|
||||
#include <contrib/dev/acpica/include/acpi.h>
|
||||
#include <contrib/dev/acpica/include/accommon.h>
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include "opt_acpi.h"
|
||||
#endif
|
||||
|
||||
#include "opt_tpm.h"
|
||||
#include "tpm_if.h"
|
||||
|
||||
#define BIT(x) (1 << (x))
|
||||
|
||||
|
|
@ -136,55 +140,36 @@ int32_t tpm20_get_timeout(uint32_t command);
|
|||
int tpm20_init(struct tpm_sc *sc);
|
||||
void tpm20_release(struct tpm_sc *sc);
|
||||
|
||||
/* Mode driver types */
|
||||
DECLARE_CLASS(tpmtis_driver);
|
||||
int tpmtis_attach(device_t dev);
|
||||
|
||||
DECLARE_CLASS(tpmcrb_driver);
|
||||
|
||||
/* Bus driver types */
|
||||
DECLARE_CLASS(tpm_bus_driver);
|
||||
DECLARE_CLASS(tpm_spi_driver);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
|
||||
return (bus_read_8(sc->mem_res, off));
|
||||
}
|
||||
#endif
|
||||
static inline void
|
||||
WR1(struct tpm_sc *sc, bus_size_t off, uint8_t val)
|
||||
{
|
||||
|
||||
bus_write_1(sc->mem_res, off, val);
|
||||
}
|
||||
static inline void
|
||||
WR4(struct tpm_sc *sc, bus_size_t off, uint32_t val)
|
||||
{
|
||||
|
||||
bus_write_4(sc->mem_res, off, val);
|
||||
}
|
||||
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_ */
|
||||
|
|
|
|||
99
sys/dev/tpm/tpm_bus.c
Normal file
99
sys/dev/tpm/tpm_bus.c
Normal file
|
|
@ -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 <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/bus.h>
|
||||
#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));
|
||||
|
|
@ -83,7 +83,7 @@ struct tpmcrb_sc {
|
|||
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 @@ tpmcrb_attach(device_t dev)
|
|||
* 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 @@ tpmcrb_attach(device_t dev)
|
|||
}
|
||||
}
|
||||
|
||||
sc->transmit = tpmcrb_transmit;
|
||||
|
||||
result = tpm20_init(sc);
|
||||
if (result != 0)
|
||||
tpmcrb_detach(dev);
|
||||
|
|
@ -248,11 +246,11 @@ tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
|
|||
{
|
||||
|
||||
/* 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 @@ tpmcrb_cancel_cmd(struct tpm_sc *sc)
|
|||
{
|
||||
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 @@ tpmcrb_cancel_cmd(struct tpm_sc *sc)
|
|||
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 @@ tpmcrb_transmit(struct tpm_sc *sc, size_t length)
|
|||
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 @@ tpmcrb_transmit(struct tpm_sc *sc, size_t length)
|
|||
/* 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 @@ tpmcrb_transmit(struct tpm_sc *sc, size_t length)
|
|||
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 @@ static device_method_t tpmcrb_methods[] = {
|
|||
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);
|
||||
|
|
|
|||
76
sys/dev/tpm/tpm_if.m
Normal file
76
sys/dev/tpm/tpm_if.m
Normal file
|
|
@ -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 <sys/bus.h>
|
||||
#include <dev/tpm/tpm20.h>
|
||||
|
||||
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;
|
||||
}
|
||||
166
sys/dev/tpm/tpm_spibus.c
Normal file
166
sys/dev/tpm/tpm_spibus.c
Normal file
|
|
@ -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 <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/bus.h>
|
||||
|
||||
#include <dev/spibus/spi.h>
|
||||
#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));
|
||||
86
sys/dev/tpm/tpm_tis_acpi.c
Normal file
86
sys/dev/tpm/tpm_tis_acpi.c
Normal file
|
|
@ -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 <sys/cdefs.h>
|
||||
#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);
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#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 bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off,
|
|||
|
||||
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 @@ tpmtis_attach(device_t dev)
|
|||
|
||||
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 @@ tpmtis_test_intr(struct tpm_sc *sc)
|
|||
|
||||
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 @@ tpmtis_setup_intr(struct tpm_sc *sc)
|
|||
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 @@ tpmtis_intr_handler(void *arg)
|
|||
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 @@ tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
|
|||
{
|
||||
|
||||
/* 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 @@ tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
|
|||
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 @@ tpmtis_wait_for_burst(struct tpm_sc *sc)
|
|||
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 @@ tpmtis_read_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf)
|
|||
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 @@ tpmtis_write_bytes(struct tpm_sc *sc, size_t count, uint8_t *buf)
|
|||
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 @@ tpmtis_request_locality(struct tpm_sc *sc, int locality)
|
|||
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 @@ tpmtis_relinquish_locality(struct tpm_sc *sc)
|
|||
* 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 @@ tpmtis_go_ready(struct tpm_sc *sc)
|
|||
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 @@ tpmtis_go_ready(struct tpm_sc *sc)
|
|||
}
|
||||
|
||||
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 @@ tpmtis_transmit(struct tpm_sc *sc, size_t length)
|
|||
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 @@ tpmtis_transmit(struct tpm_sc *sc, size_t length)
|
|||
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 @@ tpmtis_transmit(struct tpm_sc *sc, size_t length)
|
|||
}
|
||||
/* 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 @@ tpmtis_transmit(struct tpm_sc *sc, size_t length)
|
|||
|
||||
/* 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}
|
||||
DEVMETHOD(tpm_transmit, tpmtis_transmit),
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
static driver_t tpmtis_driver = {
|
||||
"tpmtis", tpmtis_methods, sizeof(struct tpm_sc),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(tpmtis, acpi, tpmtis_driver, 0, 0);
|
||||
DEFINE_CLASS_0(tpmtis, tpmtis_driver, tpmtis_methods, sizeof(struct tpm_sc));
|
||||
91
sys/dev/tpm/tpm_tis_spibus.c
Normal file
91
sys/dev/tpm/tpm_tis_spibus.c
Normal file
|
|
@ -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 <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/sx.h>
|
||||
|
||||
#include <dev/spibus/spi.h>
|
||||
#include <dev/tpm/tpm20.h>
|
||||
|
||||
#include "spibus_if.h"
|
||||
#include "tpm_if.h"
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
#include <dev/ofw/ofw_bus_subr.h>
|
||||
|
||||
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);
|
||||
|
|
@ -391,7 +391,7 @@ SUBDIR= \
|
|||
${_ti} \
|
||||
tmpfs \
|
||||
${_toecore} \
|
||||
${_tpm} \
|
||||
tpm \
|
||||
tws \
|
||||
uart \
|
||||
udf \
|
||||
|
|
@ -814,7 +814,6 @@ _pchtherm = pchtherm
|
|||
_s3= s3
|
||||
_sdhci_acpi= sdhci_acpi
|
||||
_superio= superio
|
||||
_tpm= tpm
|
||||
_vesa= vesa
|
||||
_viawd= viawd
|
||||
_vmd= vmd
|
||||
|
|
|
|||
|
|
@ -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 <bsd.kmod.mk>
|
||||
|
|
|
|||
Loading…
Reference in a new issue