Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F170829475
D59195.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D59195.diff
View Options
diff --git a/sys/dev/tpm/tpm20.h b/sys/dev/tpm/tpm20.h
--- a/sys/dev/tpm/tpm20.h
+++ b/sys/dev/tpm/tpm20.h
@@ -74,6 +74,8 @@
*/
#define TPM_TIMEOUT_LONG 40000000
+#define TPM_CC_Shutdown 0x00000145
+
/* List of commands that require TPM_TIMEOUT_LONG time to complete */
#define TPM_CC_CreatePrimary 0x00000131
#define TPM_CC_Create 0x00000153
diff --git a/sys/dev/tpm/tpm20.c b/sys/dev/tpm/tpm20.c
--- a/sys/dev/tpm/tpm20.c
+++ b/sys/dev/tpm/tpm20.c
@@ -31,6 +31,18 @@
#include "tpm20.h"
#define TPM_HARVEST_SIZE 16
+
+#define TPM2_ST_NO_SESSIONS 0x8001
+#define TPM2_RC_SUCCESS 0x0000
+#define TPM2_RC_INITIALIZE 0x0100
+#define TPM2_RC_TESTING 0x090a
+#define TPM2_RC_RETRY 0x0922
+
+#define TPM2_SU_CLEAR 0x0000
+#define TPM2_SU_STATE 0x0001
+
+#define TPM2_RETRY_INITIAL_MS 20
+#define TPM2_RETRY_MAX_MS (TPM_TIMEOUT_B / 1000)
/*
* Perform a harvest every 10 seconds.
* Since discrete TPMs are painfully slow
@@ -44,6 +56,8 @@
#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
static void tpm20_harvest(void *arg, int unused);
#endif
+static int tpm20_command(device_t, uint32_t, uint16_t, uint32_t,
+ const char *);
static int tpm20_restart(device_t dev, bool clear);
static int tpm20_save_state(device_t dev, bool suspend);
@@ -227,8 +241,11 @@
int
tpm20_resume(device_t dev)
{
+ int error;
- tpm20_restart(dev, false);
+ error = tpm20_restart(dev, false);
+ if (error != 0)
+ return (error);
#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
struct tpm_sc *sc;
@@ -243,13 +260,21 @@
int
tpm20_suspend(device_t dev)
{
+ int error;
+
#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
struct tpm_sc *sc;
sc = device_get_softc(dev);
taskqueue_drain_timeout(taskqueue_thread, &sc->harvest_task);
#endif
- return (tpm20_save_state(dev, true));
+ error = tpm20_save_state(dev, true);
+#if defined TPM_HARVEST || defined RANDOM_ENABLE_TPM
+ if (error != 0)
+ taskqueue_enqueue_timeout(taskqueue_thread, &sc->harvest_task,
+ hz * TPM_HARVEST_INTERVAL);
+#endif
+ return (error);
}
int
@@ -308,76 +333,91 @@
}
#endif /* TPM_HARVEST */
+/*
+ * Send a TPM 2.0 command whose successful response contains only a header.
+ */
static int
-tpm20_restart(device_t dev, bool clear)
+tpm20_command(device_t dev, uint32_t command, uint16_t parameter,
+ uint32_t alternate_rc, const char *name)
{
- struct tpm_sc *sc;
struct tpm_priv *priv;
- uint8_t startup_cmd[] = {
- 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/
- 0x00, 0x00, 0x00, 0x0C, /* cmd length */
- 0x00, 0x00, 0x01, 0x44, /* cmd TPM_CC_Startup */
- 0x00, 0x01 /* TPM_SU_STATE */
- };
+ struct tpm_sc *sc;
+ uint32_t response_rc, response_size;
+ uint8_t cmd[12];
+ int delay_ms, error;
sc = device_get_softc(dev);
-
- /*
- * Inform the TPM whether we are resetting or resuming.
- */
- if (clear)
- startup_cmd[11] = 0; /* TPM_SU_CLEAR */
-
if (sc == NULL)
- return (0);
+ return (ENXIO);
- sx_xlock(&sc->dev_lock);
+ be16enc(cmd, TPM2_ST_NO_SESSIONS);
+ be32enc(cmd + 2, sizeof(cmd));
+ be32enc(cmd + 6, command);
+ be16enc(cmd + 10, parameter);
+ sx_xlock(&sc->dev_lock);
priv = sc->internal_priv;
- memcpy(priv->buf, startup_cmd, sizeof(startup_cmd));
-
- /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */
- TPM_TRANSMIT(sc->dev, priv, sizeof(startup_cmd));
-
+ delay_ms = TPM2_RETRY_INITIAL_MS;
+ for (;;) {
+ memcpy(priv->buf, cmd, sizeof(cmd));
+ error = TPM_TRANSMIT(sc->dev, priv, sizeof(cmd));
+ if (error != 0)
+ break;
+ if (priv->len < TPM_HEADER_SIZE) {
+ error = EPROTO;
+ break;
+ }
+
+ response_size = be32dec(priv->buf + 2);
+ response_rc = be32dec(priv->buf + 6);
+ if (be16dec(priv->buf) != TPM2_ST_NO_SESSIONS ||
+ response_size != TPM_HEADER_SIZE ||
+ priv->len != response_size) {
+ error = EPROTO;
+ break;
+ }
+ if (response_rc != TPM2_RC_RETRY &&
+ response_rc != TPM2_RC_TESTING)
+ break;
+ if (delay_ms > TPM2_RETRY_MAX_MS)
+ break;
+ sx_xunlock(&sc->dev_lock);
+ pause("tpm2retry", MAX(hz * delay_ms / 1000, 1));
+ sx_xlock(&sc->dev_lock);
+ delay_ms *= 2;
+ }
sx_xunlock(&sc->dev_lock);
+ if (error != 0) {
+ device_printf(dev, "%s command failed: %d\n", name, error);
+ return (error);
+ }
+ if (response_rc != TPM2_RC_SUCCESS && response_rc != alternate_rc) {
+ device_printf(dev, "%s failed: TPM error 0x%x\n", name,
+ response_rc);
+ return (EIO);
+ }
return (0);
}
static int
-tpm20_save_state(device_t dev, bool suspend)
+tpm20_restart(device_t dev, bool clear)
{
- struct tpm_sc *sc;
- struct tpm_priv *priv;
- uint8_t save_cmd[] = {
- 0x80, 0x01, /* TPM_ST_NO_SESSIONS tag*/
- 0x00, 0x00, 0x00, 0x0C, /* cmd length */
- 0x00, 0x00, 0x01, 0x45, /* cmd TPM_CC_Shutdown */
- 0x00, 0x00 /* TPM_SU_STATE */
- };
-
- sc = device_get_softc(dev);
-
- /*
- * Inform the TPM whether we are going to suspend or reboot/shutdown.
- */
- if (suspend)
- save_cmd[11] = 1; /* TPM_SU_STATE */
+ uint16_t startup_type;
- if (sc == NULL)
- return (0);
-
- sx_xlock(&sc->dev_lock);
-
- priv = sc->internal_priv;
- memcpy(priv->buf, save_cmd, sizeof(save_cmd));
-
- /* XXX Ignoring both TPM_TRANSMIT return and tpm's response */
- TPM_TRANSMIT(sc->dev, priv, sizeof(save_cmd));
+ startup_type = clear ? TPM2_SU_CLEAR : TPM2_SU_STATE;
+ return (tpm20_command(dev, TPM_CC_Startup, startup_type,
+ TPM2_RC_INITIALIZE, "Startup"));
+}
- sx_xunlock(&sc->dev_lock);
+static int
+tpm20_save_state(device_t dev, bool suspend)
+{
+ uint16_t shutdown_type;
- return (0);
+ shutdown_type = suspend ? TPM2_SU_STATE : TPM2_SU_CLEAR;
+ return (tpm20_command(dev, TPM_CC_Shutdown, shutdown_type,
+ TPM2_RC_SUCCESS, "Shutdown"));
}
int32_t
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Sep 7, 9:37 PM (1 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37649941
Default Alt Text
D59195.diff (5 KB)
Attached To
Mode
D59195: tpm20: Validate suspend and resume commands
Attached
Detach File
Event Timeline
Log In to Comment