Improvements in tpm(4):

- Remove interrupt support, do polling only, avoids unnecessary trouble.
 - Simplify a few things.
 - Fix the suspend function, the SaveState command is 0x98, not 0x9C.
 - Make the driver MP-safe.
 - Sync the man page with reality.
This commit is contained in:
maxv 2019-10-08 18:43:02 +00:00
parent f3a317a980
commit 066833e6eb
6 changed files with 177 additions and 412 deletions

View File

@ -1,20 +1,33 @@
.\" $NetBSD: tpm.4,v 1.4 2018/02/22 01:40:49 pgoyette Exp $
.\" $NetBSD: tpm.4,v 1.5 2019/10/08 18:43:03 maxv Exp $
.\"
.\" Copyright (c) 2010 Hans-Jörg Höxer, <Hans-Joerg.Hoexer@genua.de>
.\" Copyright (c) 2019 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Maxime Villard.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.Dd February 22, 2018
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd October 6, 2019
.Dt TPM 4
.Os
.Sh NAME
@ -22,40 +35,22 @@
.Nd Trusted Platform Module
.Sh SYNOPSIS
.Cd "tpm* at isa? iomem 0xfed40000"
.Cd "tpm* at isa? iomem 0xfed40000 irq 7"
.Cd "tpm* at acpi?"
.Sh DESCRIPTION
The
.Nm
driver provides support for various trusted platform modules (TPM) that can
store cryptographic keys.
driver provides support for various Trusted Platform Module (TPM) chips.
.Pp
Supported modules:
.Pp
.Bl -bullet -compact -offset indent
.It
Atmel 97SC3203
TPM 2.0 chips over ACPI
.It
Broadcom BCM0102
.It
Infineon IFX SLD 9630 TT 1.1 and IFX SLB 9635 TT 1.2
.It
Intel INTC0102
.It
Sinosun SNS SSX35
.It
STM ST19WP18
.It
Winbond WEC WPCT200
TPM 1.2 chips over ISA
.El
.Pp
The driver can be configured to use an IRQ by providing a free ISA
interrupt vector using the keyword
.Em irq
in the kernel configuration file or using
.Xr config 1 .
If not IRQ is specified, the driver uses polling.
This is the default configuration.
Note that the supported interface version is TIS1.2 in each case.
.Sh SEE ALSO
.Xr config 1 ,
.Xr intro 4
@ -64,6 +59,7 @@ This is the default configuration.
The
.Nm
driver was written by
.An Maxime Villard ,
.An Michael Shalayeff
and
.An Hans-Joerg Hoexer .

View File

@ -1,4 +1,4 @@
/* $NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $ */
/* $NetBSD: tpm_acpi.c,v 1.9 2019/10/08 18:43:02 maxv Exp $ */
/*
* Copyright (c) 2012, 2019 The NetBSD Foundation, Inc.
@ -30,10 +30,9 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.9 2019/10/08 18:43:02 maxv Exp $");
#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/bus.h>
@ -45,8 +44,6 @@ __KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $");
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#include <dev/isa/isavar.h>
#include "ioconf.h"
#define _COMPONENT ACPI_RESOURCE_COMPONENT
@ -100,41 +97,41 @@ tpm_acpi_attach(device_t parent, device_t self, void *aux)
struct acpi_attach_args *aa = aux;
struct acpi_resources res;
struct acpi_mem *mem;
struct acpi_irq *irq;
bus_addr_t base;
bus_addr_t size;
int rv, inum;
sc->sc_dev = self;
sc->sc_ver = TPM_2_0;
int rv;
rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res,
&acpi_resource_parse_ops_default);
if (ACPI_FAILURE(rv)) {
aprint_error_dev(sc->sc_dev, "cannot parse resources %d\n", rv);
aprint_error_dev(self, "cannot parse resources %d\n", rv);
return;
}
mem = acpi_res_mem(&res, 0);
if (mem == NULL) {
aprint_error_dev(sc->sc_dev, "cannot find mem\n");
aprint_error_dev(self, "cannot find mem\n");
goto out;
}
if (mem->ar_length != TPM_SPACE_SIZE) {
aprint_error_dev(sc->sc_dev,
"wrong size mem %"PRIu64" != %u\n",
aprint_error_dev(self, "wrong size mem %"PRIu64" != %u\n",
(uint64_t)mem->ar_length, TPM_SPACE_SIZE);
goto out;
}
base = mem->ar_base;
size = mem->ar_length;
sc->sc_bt = aa->aa_memt;
sc->sc_dev = self;
sc->sc_ver = TPM_2_0;
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
sc->sc_busy = false;
sc->sc_init = tpm_tis12_init;
sc->sc_start = tpm_tis12_start;
sc->sc_read = tpm_tis12_read;
sc->sc_write = tpm_tis12_write;
sc->sc_end = tpm_tis12_end;
sc->sc_bt = aa->aa_memt;
base = mem->ar_base;
size = mem->ar_length;
if (bus_space_map(sc->sc_bt, base, size, 0, &sc->sc_bh)) {
aprint_error_dev(sc->sc_dev, "cannot map registers\n");
@ -146,24 +143,11 @@ tpm_acpi_attach(device_t parent, device_t self, void *aux)
goto out1;
}
irq = acpi_res_irq(&res, 0);
if (irq == NULL)
inum = -1;
else
inum = irq->ar_irq;
if ((rv = (*sc->sc_init)(sc, inum)) != 0) {
if ((*sc->sc_init)(sc) != 0) {
aprint_error_dev(sc->sc_dev, "cannot init device %d\n", rv);
goto out1;
}
if (inum != -1 &&
(sc->sc_ih = isa_intr_establish(aa->aa_ic, irq->ar_irq,
IST_EDGE, IPL_TTY, tpm_intr, sc)) == NULL) {
aprint_error_dev(sc->sc_dev, "cannot establish interrupt\n");
goto out1;
}
acpi_resource_cleanup(&res);
return;

View File

@ -1,4 +1,4 @@
/* $NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $ */
/* $NetBSD: tpm.c,v 1.14 2019/10/08 18:43:02 maxv Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@ -48,7 +48,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.14 2019/10/08 18:43:02 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -67,6 +67,7 @@ __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $");
#define TPM_BUFSIZ 1024
#define TPM_HDRSIZE 10
#define TPM_PARAM_SIZE 0x0001 /* that's a flag */
/* Timeouts. */
@ -79,23 +80,6 @@ __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $");
(TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT| \
TPM_INTF_INT_LEVEL_LOW)
static const struct {
uint32_t devid;
const char *name;
int flags;
#define TPM_DEV_NOINTS 0x0001
} tpm_devs[] = {
{ 0x000615d1, "IFX SLD 9630 TT 1.1", 0 },
{ 0x000b15d1, "IFX SLB 9635 TT 1.2", 0 },
{ 0x100214e4, "Broadcom BCM0102", TPM_DEV_NOINTS },
{ 0x00fe1050, "WEC WPCT200", 0 },
{ 0x687119fa, "SNS SSX35", 0 },
{ 0x2e4d5453, "STM ST19WP18", 0 },
{ 0x32021114, "ATML 97SC3203", TPM_DEV_NOINTS },
{ 0x10408086, "INTEL INTC0102", 0 },
{ 0, "", TPM_DEV_NOINTS },
};
static inline int
tpm_tmotohz(int tmo)
{
@ -129,7 +113,7 @@ tpm_request_locality(struct tpm_softc *sc, int l)
while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
rv = tsleep(sc->sc_init, PCATCH, "tpm_locality", 1);
if (rv && rv != EWOULDBLOCK) {
return rv;
}
@ -161,7 +145,7 @@ tpm_getburst(struct tpm_softc *sc)
if (burst)
return burst;
rv = tsleep(sc, PRIBIO | PCATCH, "tpm_getburst", 1);
rv = tsleep(sc, PCATCH, "tpm_getburst", 1);
if (rv && rv != EWOULDBLOCK) {
return 0;
}
@ -189,9 +173,9 @@ tpm12_suspend(device_t dev, const pmf_qual_t *qual)
{
struct tpm_softc *sc = device_private(dev);
static const uint8_t command[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0xC1, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 10, /* Length in bytes */
0, 0, 0, 156 /* TPM_ORD_SaveStates */
0, 0, 0, 0x98 /* TPM_ORD_SaveState */
};
uint8_t scratch[sizeof(command)];
@ -209,16 +193,13 @@ tpm12_resume(device_t dev, const pmf_qual_t *qual)
/* -------------------------------------------------------------------------- */
/*
* Wait for given status bits using polling.
*/
static int
tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan)
tpm_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan)
{
int rv;
while (((sc->sc_status = tpm_status(sc)) & mask) != mask && to--) {
rv = tsleep(chan, PRIBIO | PCATCH, "tpm_poll", 1);
rv = tsleep(chan, PCATCH, "tpm_poll", 1);
if (rv && rv != EWOULDBLOCK) {
return rv;
}
@ -227,138 +208,32 @@ tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan)
return 0;
}
/*
* Wait for given status bits using interrupts.
*/
static int
tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, wchan_t chan,
int inttype)
{
int rv, to;
sc->sc_status = tpm_status(sc);
if ((sc->sc_status & mask) == mask)
return 0;
/*
* Enable interrupt on tpm chip. Note that interrupts on our
* level (SPL_TTY) are disabled (see tpm{read,write} et al) and
* will not be delivered to the cpu until we call tsleep(9) below.
*/
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) |
inttype);
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) |
TPM_GLOBAL_INT_ENABLE);
sc->sc_status = tpm_status(sc);
if ((sc->sc_status & mask) == mask) {
rv = 0;
goto out;
}
to = tpm_tmotohz(tmo);
/*
* tsleep(9) enables interrupts on the cpu and returns after
* wake up with interrupts disabled again. Note that interrupts
* generated by the tpm chip while being at SPL_TTY are not lost
* but held and delivered as soon as the cpu goes below SPL_TTY.
*/
rv = tsleep(chan, PRIBIO | PCATCH, "tpm_wait", to);
sc->sc_status = tpm_status(sc);
if ((sc->sc_status & mask) == mask)
rv = 0;
out:
/* Disable interrupts on tpm chip again. */
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) &
~TPM_GLOBAL_INT_ENABLE);
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) &
~inttype);
return rv;
}
/*
* Wait on given status bits, use interrupts where possible, otherwise poll.
*/
static int
tpm_waitfor(struct tpm_softc *sc, uint8_t bits, int tmo, wchan_t chan)
{
int retry, to, rv;
uint8_t todo;
/*
* We use interrupts for TPM_STS_DATA_AVAIL and TPM_STS_VALID (if the
* TPM chip supports them) as waiting for those can take really long.
* The other TPM_STS* are not needed very often so we do not support
* them.
*/
if (sc->sc_vector != -1) {
todo = bits;
/*
* Wait for data ready. This interrupt only occurs when both
* TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted. Thus we
* don't have to bother with TPM_STS_VALID separately and can
* just return.
*
* This only holds for interrupts! When using polling both
* flags have to be waited for, see below.
*/
if ((bits & TPM_STS_DATA_AVAIL) &&
(sc->sc_capabilities & TPM_INTF_DATA_AVAIL_INT))
return tpm_waitfor_int(sc, bits, tmo, chan,
TPM_DATA_AVAIL_INT);
/* Wait for status valid bit. */
if ((bits & TPM_STS_VALID) &&
(sc->sc_capabilities & TPM_INTF_STS_VALID_INT)) {
rv = tpm_waitfor_int(sc, bits, tmo, chan,
TPM_STS_VALID_INT);
if (rv)
return rv;
todo = bits & ~TPM_STS_VALID;
}
/*
* When all flags have been taken care of, return. Otherwise
* use polling for eg TPM_STS_CMD_READY.
*/
if (todo == 0)
return 0;
}
to = tpm_tmotohz(tmo);
retry = 3;
restart:
/*
* If requested, wait for TPM_STS_VALID before dealing with any other
* flag. Eg when both TPM_STS_DATA_AVAIL and TPM_STS_VALID are
* requested, wait for the latter first.
*/
todo = bits;
if (bits & TPM_STS_VALID)
todo = TPM_STS_VALID;
to = tpm_tmotohz(tmo);
again:
if ((rv = tpm_waitfor_poll(sc, todo, to, chan)) != 0)
return rv;
if ((todo & sc->sc_status) == TPM_STS_VALID) {
/* Now wait for other flags. */
todo = bits & ~TPM_STS_VALID;
to++;
goto again;
/*
* TPM_STS_VALID has priority over the others.
*/
if (todo & TPM_STS_VALID) {
if ((rv = tpm_poll(sc, TPM_STS_VALID, to+1, chan)) != 0)
return rv;
todo &= ~TPM_STS_VALID;
}
if ((rv = tpm_poll(sc, todo, to, chan)) != 0)
return rv;
if ((todo & sc->sc_status) != todo) {
if (retry-- && (bits & TPM_STS_VALID)) {
if ((retry-- > 0) && (bits & TPM_STS_VALID)) {
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
TPM_STS_RESP_RETRY);
goto restart;
@ -369,31 +244,6 @@ again:
return 0;
}
int
tpm_intr(void *v)
{
struct tpm_softc *sc = v;
uint32_t reg;
reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
if (!(reg & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
return 0;
if (reg & TPM_STS_VALID_INT)
wakeup(sc);
if (reg & TPM_CMD_READY_INT)
wakeup(sc->sc_write);
if (reg & TPM_DATA_AVAIL_INT)
wakeup(sc->sc_read);
if (reg & TPM_LOCALITY_CHANGE_INT)
wakeup(sc->sc_init);
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, reg);
return 1;
}
/* -------------------------------------------------------------------------- */
/*
@ -412,8 +262,6 @@ tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
return 0;
if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED)
return 0;
if (!(cap & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW)))
return 0;
/* Request locality 0. */
bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
@ -436,70 +284,16 @@ tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
return 1;
}
static int
tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
{
uint32_t reg;
if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
sc->sc_vector = -1;
return 0;
}
/* Ack and disable all interrupts. */
reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE);
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
reg & ~TPM_GLOBAL_INT_ENABLE);
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
/* Program interrupt vector. */
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
sc->sc_vector = irq;
/* Program interrupt type. */
reg &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH|
TPM_INT_LEVEL_LOW);
reg |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT|
TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT;
if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
reg |= TPM_INT_EDGE_RISING;
else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING)
reg |= TPM_INT_EDGE_FALLING;
else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
reg |= TPM_INT_LEVEL_HIGH;
else
reg |= TPM_INT_LEVEL_LOW;
bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, reg);
return 0;
}
int
tpm_tis12_init(struct tpm_softc *sc, int irq)
tpm_tis12_init(struct tpm_softc *sc)
{
int i;
sc->sc_capabilities = bus_space_read_4(sc->sc_bt, sc->sc_bh,
sc->sc_caps = bus_space_read_4(sc->sc_bt, sc->sc_bh,
TPM_INTF_CAPABILITY);
sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
for (i = 0; tpm_devs[i].devid; i++) {
if (tpm_devs[i].devid == sc->sc_devid)
break;
}
if (tpm_devs[i].devid)
aprint_normal_dev(sc->sc_dev, "%s rev 0x%x\n",
tpm_devs[i].name, sc->sc_rev);
else
aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n",
sc->sc_devid, sc->sc_rev);
if (tpm_tis12_irqinit(sc, irq, i))
return 1;
aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n",
sc->sc_devid, sc->sc_rev);
if (tpm_request_locality(sc, 0))
return 1;
@ -511,11 +305,11 @@ tpm_tis12_init(struct tpm_softc *sc, int irq)
}
int
tpm_tis12_start(struct tpm_softc *sc, int flag)
tpm_tis12_start(struct tpm_softc *sc, int rw)
{
int rv;
if (flag == UIO_READ) {
if (rw == UIO_READ) {
rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
TPM_READ_TMO, sc->sc_read);
return rv;
@ -544,7 +338,7 @@ tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count,
{
uint8_t *p = buf;
size_t cnt;
int rv, n, bcnt;
int rv, n;
cnt = 0;
while (len > 0) {
@ -553,12 +347,12 @@ tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count,
if (rv)
return rv;
bcnt = tpm_getburst(sc);
n = MIN(len, bcnt);
for (; n--; len--) {
n = MIN(len, tpm_getburst(sc));
while (n > 0) {
*p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
cnt++;
len--;
n--;
}
if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
@ -612,19 +406,18 @@ tpm_tis12_write(struct tpm_softc *sc, const void *buf, size_t len)
}
int
tpm_tis12_end(struct tpm_softc *sc, int flag, int err)
tpm_tis12_end(struct tpm_softc *sc, int rw, int err)
{
int rv = 0;
if (flag == UIO_READ) {
if (rw == UIO_READ) {
rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read);
if (rv)
return rv;
/* Still more data? */
sc->sc_status = tpm_status(sc);
if (!err && ((sc->sc_status & TPM_STS_DATA_AVAIL) ==
TPM_STS_DATA_AVAIL)) {
if (!err && (sc->sc_status & TPM_STS_DATA_AVAIL)) {
rv = EIO;
}
@ -668,107 +461,111 @@ const struct cdevsw tpm_cdevsw = {
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_discard = nodiscard,
.d_flag = D_OTHER,
.d_flag = D_OTHER | D_MPSAFE,
};
#define TPMUNIT(a) minor(a)
static int
tpmopen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev));
int ret = 0;
if (sc == NULL)
return ENXIO;
if (sc->sc_flags & TPM_OPEN)
return EBUSY;
sc->sc_flags |= TPM_OPEN;
mutex_enter(&sc->sc_lock);
if (sc->sc_busy) {
ret = EBUSY;
} else {
sc->sc_busy = true;
}
mutex_exit(&sc->sc_lock);
return 0;
return ret;
}
static int
tpmclose(dev_t dev, int flag, int mode, struct lwp *l)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev));
int ret = 0;
if (sc == NULL)
return ENXIO;
if (!(sc->sc_flags & TPM_OPEN))
return EINVAL;
sc->sc_flags &= ~TPM_OPEN;
mutex_enter(&sc->sc_lock);
if (!sc->sc_busy) {
ret = EINVAL;
} else {
sc->sc_busy = false;
}
mutex_exit(&sc->sc_lock);
return 0;
return ret;
}
static int
tpmread(dev_t dev, struct uio *uio, int flags)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
uint8_t buf[TPM_BUFSIZ], *p;
struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev));
uint8_t buf[TPM_BUFSIZ];
size_t cnt, len, n;
int rv, s;
int rv;
if (sc == NULL)
return ENXIO;
s = spltty();
if ((rv = (*sc->sc_start)(sc, UIO_READ)))
goto out;
/* Get the header. */
if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
if (len > uio->uio_resid) {
if (len > uio->uio_resid || len < cnt) {
rv = EIO;
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
/* Copy out header. */
/* Copy out the header. */
if ((rv = uiomove(buf, cnt, uio))) {
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
/* Get remaining part of the answer (if anything is left). */
for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n,
n = sizeof(buf)) {
n = MIN(n, len);
if ((rv = (*sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) {
/* Process the rest. */
len -= cnt;
while (len > 0) {
n = MIN(sizeof(buf), len);
if ((rv = (*sc->sc_read)(sc, buf, n, NULL, TPM_PARAM_SIZE))) {
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
p += n;
if ((rv = uiomove(buf, p - buf, uio))) {
if ((rv = uiomove(buf, n, uio))) {
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
len -= n;
}
rv = (*sc->sc_end)(sc, UIO_READ, rv);
out:
splx(s);
return rv;
}
static int
tpmwrite(dev_t dev, struct uio *uio, int flags)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev));
uint8_t buf[TPM_BUFSIZ];
int n, rv, s;
int n, rv;
if (sc == NULL)
return ENXIO;
s = spltty();
n = MIN(sizeof(buf), uio->uio_resid);
if ((rv = uiomove(buf, n, uio))) {
goto out;
@ -782,14 +579,13 @@ tpmwrite(dev_t dev, struct uio *uio, int flags)
rv = (*sc->sc_end)(sc, UIO_WRITE, rv);
out:
splx(s);
return rv;
}
static int
tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev));
struct tpm_ioc_getinfo *info;
if (sc == NULL)
@ -802,7 +598,7 @@ tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
info->tpm_version = sc->sc_ver;
info->device_id = sc->sc_devid;
info->device_rev = sc->sc_rev;
info->device_caps = sc->sc_capabilities;
info->device_caps = sc->sc_caps;
return 0;
default:
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: tpmreg.h,v 1.4 2019/06/22 12:57:41 maxv Exp $ */
/* $NetBSD: tpmreg.h,v 1.5 2019/10/08 18:43:02 maxv Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@ -78,6 +78,7 @@
#define TPM_STS_GO __BIT(5)
#define TPM_STS_DATA_AVAIL __BIT(4)
#define TPM_STS_DATA_EXPECT __BIT(3)
#define TPM_STS_SELFTEST_DONE __BIT(2)
#define TPM_STS_RESP_RETRY __BIT(1)
#define TPM_DATA 0x0024 /* 32bit register */

View File

@ -1,4 +1,4 @@
/* $NetBSD: tpmvar.h,v 1.4 2019/06/22 12:57:41 maxv Exp $ */
/* $NetBSD: tpmvar.h,v 1.5 2019/10/08 18:43:02 maxv Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@ -29,24 +29,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2008, 2009 Michael Shalayeff
* Copyright (c) 2009, 2010 Hans-Joerg Hoexer
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define TPM_API_VERSION 1
enum tpm_version {
@ -56,7 +38,6 @@ enum tpm_version {
struct tpm_ioc_getinfo {
uint32_t api_version;
uint32_t tpm_version;
uint32_t device_id;
uint32_t device_rev;
@ -70,35 +51,29 @@ struct tpm_ioc_getinfo {
struct tpm_softc {
device_t sc_dev;
enum tpm_version sc_ver;
void *sc_ih;
kmutex_t sc_lock;
bool sc_busy;
int (*sc_init)(struct tpm_softc *, int);
int (*sc_init)(struct tpm_softc *);
int (*sc_start)(struct tpm_softc *, int);
int (*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int);
int (*sc_write)(struct tpm_softc *, const void *, size_t);
int (*sc_end)(struct tpm_softc *, int, int);
bus_space_tag_t sc_bt, sc_batm;
bus_space_handle_t sc_bh, sc_bahm;
bus_space_tag_t sc_bt;
bus_space_handle_t sc_bh;
uint32_t sc_devid;
uint32_t sc_rev;
uint32_t sc_status;
uint32_t sc_capabilities;
int sc_flags;
#define TPM_OPEN 0x0001
int sc_vector;
uint32_t sc_caps;
};
int tpm_intr(void *);
bool tpm12_suspend(device_t, const pmf_qual_t *);
bool tpm12_resume(device_t, const pmf_qual_t *);
int tpm_tis12_probe(bus_space_tag_t, bus_space_handle_t);
int tpm_tis12_init(struct tpm_softc *, int);
int tpm_tis12_init(struct tpm_softc *);
int tpm_tis12_start(struct tpm_softc *, int);
int tpm_tis12_read(struct tpm_softc *, void *, size_t, size_t *, int);
int tpm_tis12_write(struct tpm_softc *, const void *, size_t);

View File

@ -1,8 +1,37 @@
/* $NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $ */
/* $NetBSD: tpm_isa.c,v 1.5 2019/10/08 18:43:03 maxv Exp $ */
/*
* Copyright (c) 2019 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 2008, 2009 Michael Shalayeff
* Copyright (c) 2009, 2010 Hans-Jörg Höxer
* Copyright (c) 2009, 2010 Hans-Joerg Hoexer
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
@ -19,13 +48,10 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.5 2019/10/08 18:43:03 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/device.h>
#include <sys/bus.h>
#include <sys/pmf.h>
@ -36,13 +62,13 @@ __KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $");
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include "ioconf.h"
static int tpm_isa_match(device_t, cfdata_t, void *);
static void tpm_isa_attach(device_t, device_t, void *);
CFATTACH_DECL_NEW(tpm_isa, sizeof(struct tpm_softc),
tpm_isa_match, tpm_isa_attach, NULL, NULL);
extern struct cfdriver tpm_cd;
CFATTACH_DECL_NEW(tpm_isa, sizeof(struct tpm_softc), tpm_isa_match,
tpm_isa_attach, NULL, NULL);
static int
tpm_isa_match(device_t parent, cfdata_t match, void *aux)
@ -60,8 +86,8 @@ tpm_isa_match(device_t parent, cfdata_t match, void *aux)
return 0;
/* XXX: integer locator sign extension */
if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SPACE_SIZE,
0, &bh))
if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr,
TPM_SPACE_SIZE, 0, &bh))
return 0;
if ((rv = tpm_tis12_probe(bt, bh))) {
@ -80,46 +106,33 @@ tpm_isa_attach(device_t parent, device_t self, void *aux)
{
struct tpm_softc *sc = device_private(self);
struct isa_attach_args *ia = aux;
bus_addr_t iobase;
bus_addr_t base;
bus_size_t size;
int rv;
sc->sc_dev = self;
sc->sc_ver = TPM_1_2;
sc->sc_bt = ia->ia_memt;
iobase = (unsigned int)ia->ia_iomem[0].ir_addr;
size = TPM_SPACE_SIZE;
mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
sc->sc_busy = false;
sc->sc_init = tpm_tis12_init;
sc->sc_start = tpm_tis12_start;
sc->sc_read = tpm_tis12_read;
sc->sc_write = tpm_tis12_write;
sc->sc_end = tpm_tis12_end;
sc->sc_bt = ia->ia_memt;
if (bus_space_map(sc->sc_bt, iobase, size, 0, &sc->sc_bh)) {
base = (unsigned int)ia->ia_iomem[0].ir_addr;
size = TPM_SPACE_SIZE;
if (bus_space_map(sc->sc_bt, base, size, 0, &sc->sc_bh)) {
aprint_error_dev(sc->sc_dev, "cannot map registers\n");
return;
}
if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq)) != 0) {
if ((*sc->sc_init)(sc) != 0) {
bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
return;
}
/*
* Only setup interrupt handler when we have a vector and the
* chip is TIS 1.2 compliant.
*/
if (sc->sc_init == tpm_tis12_init &&
ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ &&
(sc->sc_ih = isa_intr_establish_xname(ia->ia_ic,
ia->ia_irq[0].ir_irq, IST_EDGE, IPL_TTY, tpm_intr, sc,
device_xname(sc->sc_dev))) == NULL) {
bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SPACE_SIZE);
aprint_error_dev(sc->sc_dev, "cannot establish interrupt\n");
return;
}
if (!pmf_device_register(sc->sc_dev, tpm12_suspend, tpm12_resume))
aprint_error_dev(sc->sc_dev, "cannot set power mgmt handler\n");
aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n");
}