aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Hibbits <jhibbits@FreeBSD.org>2024-05-09 19:27:35 +0000
committerJustin Hibbits <jhibbits@FreeBSD.org>2024-05-10 18:35:28 +0000
commit10eea8dc8c4f3d2a3495e7fb08837d91adf465e9 (patch)
treec2d7d54cb816f5b8c51070741a8e9b370e1b231e
parent2e0c027e69de66afc1157c76bd42ecd3737d54e1 (diff)
downloadsrc-10eea8dc8c4f3d2a3495e7fb08837d91adf465e9.tar.gz
src-10eea8dc8c4f3d2a3495e7fb08837d91adf465e9.zip
tpm20: Support partial reads
Summary: In some cases the TPM utilities may read only a partial block, instead of a full block. If a new command starts while in the middle of a read it may cause the TPM to go catatonic and no longer respond to SPI. Reviewed by: kd Obtained from: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D45140
-rw-r--r--sys/dev/tpm/tpm20.c10
-rw-r--r--sys/dev/tpm/tpm20.h1
-rw-r--r--sys/dev/tpm/tpm_crb.c1
-rw-r--r--sys/dev/tpm/tpm_tis_core.c1
4 files changed, 10 insertions, 3 deletions
diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c
index 3399e17f53aa..80f7d9e105a6 100644
--- a/sys/dev/tpm/tpm20.c
+++ b/sys/dev/tpm/tpm20.c
@@ -68,6 +68,7 @@ tpm20_read(struct cdev *dev, struct uio *uio, int flags)
{
struct tpm_sc *sc;
size_t bytes_to_transfer;
+ size_t offset;
int result = 0;
sc = (struct tpm_sc *)dev->si_drv1;
@@ -80,10 +81,10 @@ tpm20_read(struct cdev *dev, struct uio *uio, int flags)
}
bytes_to_transfer = MIN(sc->pending_data_length, uio->uio_resid);
+ offset = sc->total_length - sc->pending_data_length;
if (bytes_to_transfer > 0) {
- result = uiomove((caddr_t) sc->buf, bytes_to_transfer, uio);
- memset(sc->buf, 0, TPM_BUFSIZE);
- sc->pending_data_length = 0;
+ result = uiomove((caddr_t) sc->buf + offset, bytes_to_transfer, uio);
+ sc->pending_data_length -= bytes_to_transfer;
cv_signal(&sc->buf_cv);
} else {
result = ETIMEDOUT;
@@ -152,6 +153,7 @@ tpm20_discard_buffer(void *arg)
memset(sc->buf, 0, TPM_BUFSIZE);
sc->pending_data_length = 0;
+ sc->total_length = 0;
cv_signal(&sc->buf_cv);
sx_xunlock(&sc->dev_lock);
@@ -191,6 +193,7 @@ tpm20_init(struct tpm_sc *sc)
cv_init(&sc->buf_cv, "TPM buffer cv");
callout_init(&sc->discard_buffer_callout, 1);
sc->pending_data_length = 0;
+ sc->total_length = 0;
make_dev_args_init(&args);
args.mda_devsw = &tpm20_cdevsw;
@@ -275,6 +278,7 @@ tpm20_harvest(void *arg, int unused)
/* Ignore response size */
sc->pending_data_length = 0;
+ sc->total_length = 0;
/* The number of random bytes we got is placed right after the header */
entropy_size = (uint16_t) sc->buf[TPM_HEADER_SIZE + 1];
diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h
index 683cd7549bd4..7c2ccd30143a 100644
--- a/sys/dev/tpm/tpm20.h
+++ b/sys/dev/tpm/tpm20.h
@@ -124,6 +124,7 @@ struct tpm_sc {
uint8_t *buf;
size_t pending_data_length;
+ size_t total_length;
lwpid_t owner_tid;
struct callout discard_buffer_callout;
diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c
index b9ddcf0dd3e1..017ebd45c7ea 100644
--- a/sys/dev/tpm/tpm_crb.c
+++ b/sys/dev/tpm/tpm_crb.c
@@ -398,6 +398,7 @@ tpmcrb_transmit(device_t dev, size_t length)
tpmcrb_relinquish_locality(sc);
sc->pending_data_length = bytes_available;
+ sc->total_length = bytes_available;
return (0);
}
diff --git a/sys/dev/tpm/tpm_tis_core.c b/sys/dev/tpm/tpm_tis_core.c
index 230eb12d2acd..d8421f8156c9 100644
--- a/sys/dev/tpm/tpm_tis_core.c
+++ b/sys/dev/tpm/tpm_tis_core.c
@@ -469,6 +469,7 @@ tpmtis_transmit(device_t dev, size_t length)
}
tpmtis_relinquish_locality(sc);
sc->pending_data_length = bytes_available;
+ sc->total_length = bytes_available;
return (0);
}