Module Name:    src
Committed By:   maxv
Date:           Wed Oct  9 07:30:58 UTC 2019

Modified Files:
        src/sys/dev/acpi: tpm_acpi.c
        src/sys/dev/ic: tpm.c tpmreg.h tpmvar.h
        src/sys/dev/isa: tpm_isa.c

Log Message:
Add suspend support for TPM 2.0 chips. Check the TPM response also for 1.2
chips. Unfortunately I cannot really test this change since ACPI suspend
does not work on any of my laptops.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/acpi/tpm_acpi.c
cvs rdiff -u -r1.14 -r1.15 src/sys/dev/ic/tpm.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/ic/tpmreg.h src/sys/dev/ic/tpmvar.h
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/isa/tpm_isa.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/acpi/tpm_acpi.c
diff -u src/sys/dev/acpi/tpm_acpi.c:1.9 src/sys/dev/acpi/tpm_acpi.c:1.10
--- src/sys/dev/acpi/tpm_acpi.c:1.9	Tue Oct  8 18:43:02 2019
+++ src/sys/dev/acpi/tpm_acpi.c	Wed Oct  9 07:30:58 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: tpm_acpi.c,v 1.9 2019/10/08 18:43:02 maxv Exp $ */
+/* $NetBSD: tpm_acpi.c,v 1.10 2019/10/09 07:30:58 maxv Exp $ */
 
 /*
  * Copyright (c) 2012, 2019 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.9 2019/10/08 18:43:02 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.10 2019/10/09 07:30:58 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -148,6 +148,8 @@ tpm_acpi_attach(device_t parent, device_
 		goto out1;
 	}
 
+	if (!pmf_device_register(self, tpm_suspend, tpm_resume))
+		aprint_error_dev(self, "couldn't establish power handler\n");
 	acpi_resource_cleanup(&res);
 	return;
 

Index: src/sys/dev/ic/tpm.c
diff -u src/sys/dev/ic/tpm.c:1.14 src/sys/dev/ic/tpm.c:1.15
--- src/sys/dev/ic/tpm.c:1.14	Tue Oct  8 18:43:02 2019
+++ src/sys/dev/ic/tpm.c	Wed Oct  9 07:30:58 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: tpm.c,v 1.14 2019/10/08 18:43:02 maxv Exp $	*/
+/*	$NetBSD: tpm.c,v 1.15 2019/10/09 07:30:58 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.14 2019/10/08 18:43:02 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.15 2019/10/09 07:30:58 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -65,8 +65,9 @@ __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.14
 
 #include "ioconf.h"
 
+CTASSERT(sizeof(struct tpm_header) == 10);
+
 #define TPM_BUFSIZ	1024
-#define TPM_HDRSIZE	10
 
 #define TPM_PARAM_SIZE	0x0001	/* that's a flag */
 
@@ -163,31 +164,69 @@ tpm_status(struct tpm_softc *sc)
 
 /* -------------------------------------------------------------------------- */
 
-/*
- * Save TPM state on suspend. On resume we don't do anything, since the BIOS
- * is supposed to restore the previously saved state.
- */
+static bool
+tpm12_suspend(struct tpm_softc *sc)
+{
+	static const uint8_t command[10] = {
+		0x00, 0xC1,		/* TPM_TAG_RQU_COMMAND */
+		0x00, 0x00, 0x00, 10,	/* Length in bytes */
+		0x00, 0x00, 0x00, 0x98	/* TPM_ORD_SaveState */
+	};
+	struct tpm_header response;
 
-bool
-tpm12_suspend(device_t dev, const pmf_qual_t *qual)
+	if ((*sc->sc_write)(sc, &command, sizeof(command)) != 0)
+		return false;
+	if ((*sc->sc_read)(sc, &response, sizeof(response), NULL, 0) != 0)
+		return false;
+	if (TPM_BE32(response.code) != 0)
+		return false;
+
+	return true;
+}
+
+static bool
+tpm20_suspend(struct tpm_softc *sc)
 {
-	struct tpm_softc *sc = device_private(dev);
-	static const uint8_t command[] = {
-		0, 0xC1,	/* TPM_TAG_RQU_COMMAND */
-		0, 0, 0, 10,	/* Length in bytes */
-		0, 0, 0, 0x98	/* TPM_ORD_SaveState */
+	static const uint8_t command[12] = {
+		0x80, 0x01,		/* TPM_ST_NO_SESSIONS */
+		0x00, 0x00, 0x00, 12,	/* Length in bytes */
+		0x00, 0x00, 0x01, 0x45,	/* TPM_CC_Shutdown */
+		0x00, 0x01		/* TPM_SU_STATE */
 	};
-	uint8_t scratch[sizeof(command)];
+	struct tpm_header response;
 
-	(*sc->sc_write)(sc, &command, sizeof(command));
-	(*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, 0);
+	if ((*sc->sc_write)(sc, &command, sizeof(command)) != 0)
+		return false;
+	if ((*sc->sc_read)(sc, &response, sizeof(response), NULL, 0) != 0)
+		return false;
+	if (TPM_BE32(response.code) != 0)
+		return false;
 
 	return true;
 }
 
 bool
-tpm12_resume(device_t dev, const pmf_qual_t *qual)
+tpm_suspend(device_t dev, const pmf_qual_t *qual)
 {
+	struct tpm_softc *sc = device_private(dev);
+
+	switch (sc->sc_ver) {
+	case TPM_1_2:
+		return tpm12_suspend(sc);
+	case TPM_2_0:
+		return tpm20_suspend(sc);
+	default:
+		panic("%s: impossible", __func__);
+	}
+}
+
+bool
+tpm_resume(device_t dev, const pmf_qual_t *qual)
+{
+	/*
+	 * Don't do anything, the BIOS is supposed to restore the previously
+	 * saved state.
+	 */
 	return true;
 }
 
@@ -508,6 +547,7 @@ static int
 tpmread(dev_t dev, struct uio *uio, int flags)
 {
 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, minor(dev));
+	struct tpm_header hdr;
 	uint8_t buf[TPM_BUFSIZ];
 	size_t cnt, len, n;
 	int rv;
@@ -519,11 +559,11 @@ tpmread(dev_t dev, struct uio *uio, int 
 		goto out;
 
 	/* Get the header. */
-	if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
+	if ((rv = (*sc->sc_read)(sc, &hdr, sizeof(hdr), &cnt, 0))) {
 		(*sc->sc_end)(sc, UIO_READ, rv);
 		goto out;
 	}
-	len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
+	len = TPM_BE32(hdr.length);
 	if (len > uio->uio_resid || len < cnt) {
 		rv = EIO;
 		(*sc->sc_end)(sc, UIO_READ, rv);
@@ -531,7 +571,7 @@ tpmread(dev_t dev, struct uio *uio, int 
 	}
 
 	/* Copy out the header. */
-	if ((rv = uiomove(buf, cnt, uio))) {
+	if ((rv = uiomove(&hdr, cnt, uio))) {
 		(*sc->sc_end)(sc, UIO_READ, rv);
 		goto out;
 	}

Index: src/sys/dev/ic/tpmreg.h
diff -u src/sys/dev/ic/tpmreg.h:1.5 src/sys/dev/ic/tpmreg.h:1.6
--- src/sys/dev/ic/tpmreg.h:1.5	Tue Oct  8 18:43:02 2019
+++ src/sys/dev/ic/tpmreg.h	Wed Oct  9 07:30:58 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: tpmreg.h,v 1.5 2019/10/08 18:43:02 maxv Exp $	*/
+/*	$NetBSD: tpmreg.h,v 1.6 2019/10/09 07:30:58 maxv Exp $	*/
 
 /*
  * Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -29,6 +29,22 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define TPM_BE16(a)	bswap16(a)
+#define TPM_BE32(a)	bswap32(a)
+#else
+#define TPM_BE16(a)	(a)
+#define TPM_BE32(a)	(a)
+#endif
+
+struct tpm_header {
+	uint16_t tag;
+	uint32_t length;
+	uint32_t code;
+} __packed;
+
+/* -------------------------------------------------------------------------- */
+
 /*
  * TPM Interface Specification 1.2 (TIS12).
  */
Index: src/sys/dev/ic/tpmvar.h
diff -u src/sys/dev/ic/tpmvar.h:1.5 src/sys/dev/ic/tpmvar.h:1.6
--- src/sys/dev/ic/tpmvar.h:1.5	Tue Oct  8 18:43:02 2019
+++ src/sys/dev/ic/tpmvar.h	Wed Oct  9 07:30:58 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: tpmvar.h,v 1.5 2019/10/08 18:43:02 maxv Exp $	*/
+/*	$NetBSD: tpmvar.h,v 1.6 2019/10/09 07:30:58 maxv Exp $	*/
 
 /*
  * Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -69,8 +69,8 @@ struct tpm_softc {
 	uint32_t sc_caps;
 };
 
-bool tpm12_suspend(device_t, const pmf_qual_t *);
-bool tpm12_resume(device_t, const pmf_qual_t *);
+bool tpm_suspend(device_t, const pmf_qual_t *);
+bool tpm_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 *);

Index: src/sys/dev/isa/tpm_isa.c
diff -u src/sys/dev/isa/tpm_isa.c:1.5 src/sys/dev/isa/tpm_isa.c:1.6
--- src/sys/dev/isa/tpm_isa.c:1.5	Tue Oct  8 18:43:03 2019
+++ src/sys/dev/isa/tpm_isa.c	Wed Oct  9 07:30:58 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: tpm_isa.c,v 1.5 2019/10/08 18:43:03 maxv Exp $	*/
+/*	$NetBSD: tpm_isa.c,v 1.6 2019/10/09 07:30:58 maxv Exp $	*/
 
 /*
  * Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.5 2019/10/08 18:43:03 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.6 2019/10/09 07:30:58 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -133,6 +133,6 @@ tpm_isa_attach(device_t parent, device_t
 		return;
 	}
 
-	if (!pmf_device_register(sc->sc_dev, tpm12_suspend, tpm12_resume))
-		aprint_error_dev(sc->sc_dev, "couldn't establish power handler\n");
+	if (!pmf_device_register(self, tpm_suspend, tpm_resume))
+		aprint_error_dev(self, "couldn't establish power handler\n");
 }

Reply via email to