Skip to contentSkip to conversation

TPM: Issue TPM_STARTUP at driver load if the TPM has not been started

PATCH Superseded Jason Gunthorpe 4 participants 18 messages Sep 30, 2012 – Nov 26, 2012 TPM device driver

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 TPM: Issue TPM_STARTUP at driver load if the TPM has not been started

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

---
 drivers/char/tpm/tpm.c |   41 ++++++++++++++++++++++++++++++++++++-----
 drivers/char/tpm/tpm.h |    6 ++++++
 2 files changed, 42 insertions(+), 5 deletions(-)
drivers/char/tpm/tpm.c +35 -4
index 817f0ee..60e8442 100644
@@ -473,7 +473,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 		return -EFAULT;
 
 	err = be32_to_cpu(cmd->header.out.return_code);
-	if (err != 0)
+	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
 	return err;
@@ -489,6 +489,15 @@ static const struct tpm_input_header tpm_getcap_header = {
 	.ordinal = TPM_ORD_GET_CAP
 };
 
+
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be32(1)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
 ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
 		   const char *desc)
 {
@@ -545,11 +554,33 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		struct tpm_cmd_t start_cmd;
+		/* The TPM is not started, we are the first to talk to it.
+		   Execute a startup command. */
+		start_cmd.header.in = tpm_startup_header;
+		start_cmd.params.startup_in.startup_type = TPM_ST_CLEAR;
+
+		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		rc = transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+			"attempting to start the TPM");
+		if (rc)
+			return -EINVAL;
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
-	if (rc)
+		tpm_cmd.header.in = tpm_getcap_header;
+		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+	}
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%d) occurred attempting to determine the timeouts\n",
+			rc);
 		goto duration;
+	}
 
 	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
 	    be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h +6 -0
index 917f727..2d583ef 100644
@@ -41,6 +41,7 @@ enum tpm_addr {
 #define TPM_WARN_DOING_SELFTEST 0x802
 #define TPM_ERR_DEACTIVATED     0x6
 #define TPM_ERR_DISABLED        0x7
+#define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -269,6 +270,10 @@ struct tpm_pcrextend_in {
 	u8	hash[TPM_DIGEST_SIZE];
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;
+
 typedef union {
 	struct	tpm_getcap_params_out getcap_out;
 	struct	tpm_readpubek_params_out readpubek_out;
@@ -277,6 +282,7 @@ typedef union {
 	struct	tpm_pcrread_in	pcrread_in;
 	struct	tpm_pcrread_out	pcrread_out;
 	struct	tpm_pcrextend_in pcrextend_in;
+	struct tpm_startup_in startup_in;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
Signature · 1 line
1.7.4.1
#1 lore raw

Hi Jason,

Quoted 7 lines

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

Thanks for working on this.
I also thought about this scenario quite often.

Shouldn't we then also add a TpmStartup(ST_STATE) in case of a resume?
rc=GetCapability()
if(rc==INVALID_POSTINIT)
tpm_transmit ("TPM_STARTUP(ST_STATE)")...

Thanks,
Peter

#2 lore raw
Quoted 10 lines · On Mon, Oct 01, 2012 at 09:17:28AM +0000, [email protected] wrote:

Hi Jason,

Quoted 7 lines

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

Quoted 7 lines

Thanks for working on this.
I also thought about this scenario quite often.

Shouldn't we then also add a TpmStartup(ST_STATE) in case of a resume?
rc=GetCapability()
if(rc==INVALID_POSTINIT)
tpm_transmit ("TPM_STARTUP(ST_STATE)")...

I'm not familiar enough with how the power management flow works with the TPM to do this. I don't think that can be the general case because:

3. If stType = TPM_ST_STATE
a. If the TPM has no state to restore, the TPM MUST set the internal
state such that it returns TPM_FAILEDSELFTEST to all subsequent commands.

So you need to know a save state exists in the TPM before attempting the command?

Would you agree that CLEAR is appropriate for an initial driver attach on probe?

Jason

#3 lore raw
Quoted 23 lines · Jason Gunthorpe
Quoted 10 lines · On Mon, Oct 01, 2012 at 09:17:28AM +0000, [email protected] wrote:

Hi Jason,

Quoted 7 lines

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

Quoted 7 lines

Thanks for working on this.
I also thought about this scenario quite often.

Shouldn't we then also add a TpmStartup(ST_STATE) in case of a resume?
rc=GetCapability()
if(rc==INVALID_POSTINIT)
tpm_transmit ("TPM_STARTUP(ST_STATE)")...

I'm not familiar enough with how the power management flow works with the TPM to do this. I don't think that can be the general case because:

Quoted 7 lines

3. If stType = TPM_ST_STATE
a. If the TPM has no state to restore, the TPM MUST set the internal
state such that it returns TPM_FAILEDSELFTEST to all subsequent commands.

So you need to know a save state exists in the TPM before attempting the command?

Presumably we'd have called TPM_SaveState on suspend. It might be
possible to set a flag based on whether we needed to call startup at init time that tells the driver to call save/restore state during suspend/resume.

Kent

Quoted 10 lines

Would you agree that CLEAR is appropriate for an initial driver attach on probe?

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#4 lore raw
Quoted 9 lines · Kent Yoder
Quoted 9 lines

I'm not familiar enough with how the power management flow works with the TPM to do this. I don't think that can be the general case because:

3. If stType = TPM_ST_STATE
a. If the TPM has no state to restore, the TPM MUST set the internal
state such that it returns TPM_FAILEDSELFTEST to all subsequent commands.

Quoted 7 lines
Quoted 2 lines

So you need to know a save state exists in the TPM before attempting the command?

Presumably we'd have called TPM_SaveState on suspend. It might be
possible to set a flag based on whether we needed to call startup at init time that tells the driver to call save/restore state during suspend/resume.

Curiously the current code does call TPM_SaveState on suspend, but relies on the BIOS to do TPM_Startup(ST_STATE) on resume, why the asymmetry?

Anyhow, I think the thing would be something like this. I have no means to test TPM suspend, so I'll just post this as a note here. It will apply over v2 of my patch.

drivers/char/tpm/tpm.c +13 -0
index b13ad77..7a8136a 100644
@@ -1336,10 +1336,23 @@ EXPORT_SYMBOL_GPL(tpm_pm_suspend);
 int tpm_pm_resume(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_cmd_t tpm_cmd;
 
        if (chip == NULL)
                return -ENODEV;
 
+       tpm_cmd.header.in = tpm_getcap_header;
+       tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+       tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+       tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+       rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+       if (rc == TPM_ERR_INVALID_POSTINIT) {
+               /* The BIOS did not restart the TPM, execute a startup
+                  command. */
+               dev_info(chip->dev, "Issuing TPM_STARTUP");
+               tpm_startup(chip, TPM_ST_STATE);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);

Jason

#5 lore raw
Quoted 3 lines

Curiously the current code does call TPM_SaveState on suspend, but relies on the BIOS to do TPM_Startup(ST_STATE) on resume, why the asymmetry?

This is based on the PC Client Implementation for BIOS spec in the
TCG. On suspend, the OS is responsible for the save state and then on resume the BIOS should call startup.

Quoted 19 lines

Anyhow, I think the thing would be something like this. I have no means to test TPM suspend, so I'll just post this as a note here. It will apply over v2 of my patch.

drivers/char/tpm/tpm.c +3 -0
index b13ad77..7a8136a 100644
@@ -1336,10 +1336,23 @@ EXPORT_SYMBOL_GPL(tpm_pm_suspend);
 int tpm_pm_resume(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
+       struct tpm_cmd_t tpm_cmd;
 
        if (chip == NULL)
                return -ENODEV;
 
+       tpm_cmd.header.in = tpm_getcap_header;
+       tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;

drivers/char/tpm/tpm.c EXPORT_SYMBOL_GPL(tpm_pm_suspend); · line 1355

Quoted 10 lines
drivers/char/tpm/tpm.c +10 -0
+       tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+       tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+       rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+       if (rc == TPM_ERR_INVALID_POSTINIT) {
+               /* The BIOS did not restart the TPM, execute a startup
+                  command. */
+               dev_info(chip->dev, "Issuing TPM_STARTUP");
+               tpm_startup(chip, TPM_ST_STATE);
+       }
+

I'd rather see us just track the state and do the right thing here. If
we don't get invalid postinit if we call tpm_startup during tpm_tis_init/tpm_tis_i2c_init, then set a flag we switch on here.

Peter, you mentioned you have some embedded setups, would you be able
to test?

Thanks,
Kent

Quoted 11 lines
drivers/char/tpm/tpm.c +0 -0
        return 0;
 }
 EXPORT_SYMBOL_GPL(tpm_pm_resume);

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#6 lore raw
Quoted 3 lines · Kent Yoder

I'd rather see us just track the state and do the right thing
here. If we don't get invalid postinit if we call tpm_startup during tpm_tis_init/tpm_tis_i2c_init, then set a flag we switch on here.

At least on my platform it is possible for tpm_tis_init to skip the TPM_STARTUP path I added if kexec has been used, so it is not a reliable indicator that the platform does/does not support the TPM.

Directly checking if the TPM has been started on resume seems fool proof to me?

Jasson

#7 lore raw
In reply to Kent Yoder

Hi Kent,

Quoted 2 lines

Peter, you mentioned you have some embedded setups, would you be able
to test?

I could probably test it on the beagleboard c4 with our Infineon SLB9635 TT1.2 I2C TPM, but I'm currently not sure if I have the suspend/resume thing currently running correctly.

Apart from that I also have some 'ancient' x86 systems without TPM bios integration here
(so the BIOS doesn't even know anything about a tpm), there I could test our LPC based tpms (SLB9635 / SLB9655).

Unfortunately it'll take some time, due to other priorities. Please tell me when the patch is ready for testing.

Thanks,
Peter

#8 lore raw

PATCH RESEND 1/1 TPM: Issue TPM_STARTUP at driver load if the TPM has not been started

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

---
 drivers/char/tpm/tpm.c |   43 +++++++++++++++++++++++++++++++++++++++----
 drivers/char/tpm/tpm.h |    6 ++++++
 2 files changed, 45 insertions(+), 4 deletions(-)

Discussion on this got a bit sidetracked talking about suspend/resume.. To be clear, this fixes a real, serious, problem on normal embedded cases where the kernel refuses to attach the TPM driver at all.

Key, are you happy with this as-is for the next merge window?

This version is rebased and retested to 3.7-rc6. Tested on Atmel and Nuvoton LPC TPMs on PPC32.

drivers/char/tpm/tpm.c +39 -4
index 93211df..c576718 100644
@@ -468,7 +468,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 		return -EFAULT;
 
 	err = be32_to_cpu(cmd->header.out.return_code);
-	if (err != 0)
+	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
 	return err;
@@ -485,6 +485,16 @@ static const struct tpm_input_header tpm_getcap_header = {
 	.ordinal = TPM_ORD_GET_CAP
 };
 
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
 ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
 		   const char *desc)
 {
@@ -528,6 +538,15 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
+static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
+{
+	struct tpm_cmd_t start_cmd;
+	start_cmd.header.in = tpm_startup_header;
+	start_cmd.params.startup_in.startup_type = startup_type;
+	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+			    "attempting to start the TPM");
+}
+
 int tpm_get_timeouts(struct tpm_chip *chip)
 {
 	struct tpm_cmd_t tpm_cmd;
@@ -541,11 +560,27 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
-	if (rc)
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		/* The TPM is not started, we are the first to talk to it.
+		   Execute a startup command. */
+		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		if (tpm_startup(chip, TPM_ST_CLEAR))
+			return rc;
+
+		tpm_cmd.header.in = tpm_getcap_header;
+		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+	}
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%d) occurred attempting to determine the timeouts\n",
+			rc);
 		goto duration;
+	}
 
 	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
 	    be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h +6 -0
index 8ef7649..8971b12 100644
@@ -47,6 +47,7 @@ enum tpm_addr {
 #define TPM_WARN_DOING_SELFTEST 0x802
 #define TPM_ERR_DEACTIVATED     0x6
 #define TPM_ERR_DISABLED        0x7
+#define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -291,6 +292,10 @@ struct tpm_getrandom_in {
 	__be32 num_bytes;
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;
+
 typedef union {
 	struct	tpm_getcap_params_out getcap_out;
 	struct	tpm_readpubek_params_out readpubek_out;
@@ -301,6 +306,7 @@ typedef union {
 	struct	tpm_pcrextend_in pcrextend_in;
 	struct	tpm_getrandom_in getrandom_in;
 	struct	tpm_getrandom_out getrandom_out;
+	struct tpm_startup_in startup_in;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
Signature · 1 line
1.7.4.1
Tested-by Reviewed-by on v1 1/1
#9 lore raw

Hi Jason, Hi Kent,

Quoted 10 lines

Discussion on this got a bit sidetracked talking about suspend/resume.. To be clear, this fixes a real, serious, problem on normal embedded cases where the kernel refuses to attach the TPM driver at all.

Key, are you happy with this as-is for the next merge window?

This version is rebased and retested to 3.7-rc6. Tested on Atmel and Nuvoton LPC TPMs on PPC32.

Sorry I was tied up at work with other stuff, so I couldn't try out your initial patch. Thanks for resubmitting!

I just gave the new version a run on my beagleboard with our Infineon SLB9635 TT 1.2 Soft I2C TPM and it seems to work as expected. (Tested with and without previous startup).

I just have some minor comments - please see below.

Quoted 11 lines

+++ b/drivers/char/tpm/tpm.c

drivers/char/tpm/tpm.c +10 -0
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
Quoted 3 lines

ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
const char *desc)
{

Purely cosmetic question, but why did you define this before the tpm_getcap and not tpm_startup?
All the other definitions are made before they are used - so this should perhaps better be moved directly before tpm_startup. (Maybe we should move out these definitions to a common location? Header?)

drivers/char/tpm/tpm.c int tpm_get_timeouts(struct tpm_chip *chip) · line 563

Quoted 5 lines
drivers/char/tpm/tpm.c +1 -0
@@ -541,11 +560,27 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);

Please use NULL instead of 0, otherwise sparse complains - so
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+ rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);

drivers/char/tpm/tpm.c int tpm_get_timeouts(struct tpm_chip *chip) · line 576

Quoted 3 lines
drivers/char/tpm/tpm.c +2 -0
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
...
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);

Same here
please use NULL instead of 0, otherwise sparse complains - so
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+ rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);

drivers/char/tpm/tpm.h struct tpm_getrandom_in { · line 297

Quoted 9 lines
drivers/char/tpm/tpm.h +0 -0

extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,

drivers/char/tpm/tpm.h +3 -0
@@ -291,6 +292,10 @@ struct tpm_getrandom_in {
 	__be32 num_bytes;
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;

All the other user
__attribute__((packed));
Care to change to be consistent?

Apart from these three minor topics also a

Thanks,
Peter

#10 lore raw
Quoted 4 lines · On Wed, Nov 21, 2012 at 08:59:24AM +0000, [email protected] wrote:

I just gave the new version a run on my beagleboard with our Infineon SLB9635 TT 1.2 Soft I2C TPM and it seems to work as expected. (Tested with and without previous startup).

Great, I'll send an updated version, thanks!

Quoted 12 lines
Quoted 12 lines

+++ b/drivers/char/tpm/tpm.c

drivers/char/tpm/tpm.c +10 -0
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+

ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,

Quoted 8 lines
Quoted 2 lines

const char *desc)
{

Purely cosmetic question, but why did you define this before the tpm_getcap and not tpm_startup? All the other definitions are made before they are used - so this should perhaps better be moved directly before tpm_startup. (Maybe we should move out these definitions to a common location? Header?)

Hmm, When I first read through this I thought all these definitions were being grouped together, easy to move.

Quoted 8 lines

drivers/char/tpm/tpm.h struct tpm_getrandom_in { · line 297

Quoted 3 lines
drivers/char/tpm/tpm.h +3 -0
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;

All the other user
__attribute__((packed));
Care to change to be consistent?

I used to __packed to avoid a checkpatch warning, they should probably all be changed?

Jason

#11 lore raw

Hi Jason,

Quoted 1 line

Great, I'll send an updated version, thanks!

;) You're welcome.

Quoted 11 lines
Quoted 8 lines

drivers/char/tpm/tpm.h struct tpm_getrandom_in { · line 297

Quoted 3 lines
drivers/char/tpm/tpm.h +3 -0
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;

All the other user
__attribute__((packed));
Care to change to be consistent?

I used to __packed to avoid a checkpatch warning, they should probably all be changed?

Oh you're right - then sorry about my complaint.
Then I'd prefer submitting it as __packed and write another patch which change the remaining ones. Are you creating the patch to change or should I?

Peter

author Tested-by Peter Huewe Reviewed-by Peter Huewe
#12 lore raw

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

---
 drivers/char/tpm/tpm.c |   44 ++++++++++++++++++++++++++++++++++++++++----
 drivers/char/tpm/tpm.h |    6 ++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

v4 changes:
- Use NULL
- Put tpm_startup_header together with tpm_startup
- Add Peter's -by lines.

drivers/char/tpm/tpm.c +40 -4
index 93211df..98d550e 100644
@@ -468,7 +468,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 		return -EFAULT;
 
 	err = be32_to_cpu(cmd->header.out.return_code);
-	if (err != 0)
+	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
 	return err;
@@ -528,6 +528,25 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
+static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
+{
+	struct tpm_cmd_t start_cmd;
+	start_cmd.header.in = tpm_startup_header;
+	start_cmd.params.startup_in.startup_type = startup_type;
+	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+			    "attempting to start the TPM");
+}
+
 int tpm_get_timeouts(struct tpm_chip *chip)
 {
 	struct tpm_cmd_t tpm_cmd;
@@ -541,11 +560,28 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
-	if (rc)
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		/* The TPM is not started, we are the first to talk to it.
+		   Execute a startup command. */
+		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		if (tpm_startup(chip, TPM_ST_CLEAR))
+			return rc;
+
+		tpm_cmd.header.in = tpm_getcap_header;
+		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+				  NULL);
+	}
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%d) occurred attempting to determine the timeouts\n",
+			rc);
 		goto duration;
+	}
 
 	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
 	    be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h +6 -0
index 8ef7649..8971b12 100644
@@ -47,6 +47,7 @@ enum tpm_addr {
 #define TPM_WARN_DOING_SELFTEST 0x802
 #define TPM_ERR_DEACTIVATED     0x6
 #define TPM_ERR_DISABLED        0x7
+#define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -291,6 +292,10 @@ struct tpm_getrandom_in {
 	__be32 num_bytes;
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;
+
 typedef union {
 	struct	tpm_getcap_params_out getcap_out;
 	struct	tpm_readpubek_params_out readpubek_out;
@@ -301,6 +306,7 @@ typedef union {
 	struct	tpm_pcrextend_in pcrextend_in;
 	struct	tpm_getrandom_in getrandom_in;
 	struct	tpm_getrandom_out getrandom_out;
+	struct tpm_startup_in startup_in;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
Signature · 1 line
1.7.5.4
maintainer
#13 lore raw

Hi Jason,

Thanks for the updated patch!
Sorry, I have one really minor remark left:

drivers/char/tpm/tpm.c int tpm_get_timeouts(struct tpm_chip *chip) · line 581

Quoted 3 lines
drivers/char/tpm/tpm.c +3 -0
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%d) occurred attempting to determine the timeouts\n",

rc is a ssize_t here and when compiling with C=1 I get
drivers/char/tpm/tpm.c:582:4: warning: format '%d' expects argument of type 'int', but argument 3 has type 'ssize_t' [-Wformat]

Care to change to

Review

Quoted 1 line
(quoted diff) +1 -0
+			"A TPM error (%zd) occurred attempting to determine the timeouts\n",

Sorry that I didn't spot it earlier.

Thanks,
Peter

#14 lore raw
Quoted 4 lines · Peter H?we

Care to change to

Review

Quoted 1 line
(quoted diff) +1 -0
+			"A TPM error (%zd) occurred attempting to determine the timeouts\n",

Sorry that I didn't spot it earlier.

Right.. Probably like this in my tree because of:

http://permalink.gmane.org/gmane.linux.kernel/1397887

I should really get sparse setup here... Never enough hours.

Jason

#15 lore raw

PATCH v5 1/1 TPM: Issue TPM_STARTUP at driver load if the TPM has not been started

In reply to Peter Hüwe

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

---
 drivers/char/tpm/tpm.c |   44 ++++++++++++++++++++++++++++++++++++++++----
 drivers/char/tpm/tpm.h |    6 ++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

v5 changes:
- Use %zd for printing ssize_t

drivers/char/tpm/tpm.c +40 -4
index 93211df..433ad6b 100644
@@ -468,7 +468,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 		return -EFAULT;
 
 	err = be32_to_cpu(cmd->header.out.return_code);
-	if (err != 0)
+	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
 	return err;
@@ -528,6 +528,25 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
+static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
+{
+	struct tpm_cmd_t start_cmd;
+	start_cmd.header.in = tpm_startup_header;
+	start_cmd.params.startup_in.startup_type = startup_type;
+	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+			    "attempting to start the TPM");
+}
+
 int tpm_get_timeouts(struct tpm_chip *chip)
 {
 	struct tpm_cmd_t tpm_cmd;
@@ -541,11 +560,28 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
-	if (rc)
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		/* The TPM is not started, we are the first to talk to it.
+		   Execute a startup command. */
+		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		if (tpm_startup(chip, TPM_ST_CLEAR))
+			return rc;
+
+		tpm_cmd.header.in = tpm_getcap_header;
+		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+				  NULL);
+	}
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
+			rc);
 		goto duration;
+	}
 
 	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
 	    be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h +6 -0
index 8ef7649..8971b12 100644
@@ -47,6 +47,7 @@ enum tpm_addr {
 #define TPM_WARN_DOING_SELFTEST 0x802
 #define TPM_ERR_DEACTIVATED     0x6
 #define TPM_ERR_DISABLED        0x7
+#define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -291,6 +292,10 @@ struct tpm_getrandom_in {
 	__be32 num_bytes;
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;
+
 typedef union {
 	struct	tpm_getcap_params_out getcap_out;
 	struct	tpm_readpubek_params_out readpubek_out;
@@ -301,6 +306,7 @@ typedef union {
 	struct	tpm_pcrextend_in pcrextend_in;
 	struct	tpm_getrandom_in getrandom_in;
 	struct	tpm_getrandom_out getrandom_out;
+	struct tpm_startup_in startup_in;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
Signature · 1 line
1.7.5.4
Applied
#16 lore raw
Quoted 10 lines · Jason Gunthorpe

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

Quoted 7 lines
---
 drivers/char/tpm/tpm.c |   44 ++++++++++++++++++++++++++++++++++++++++----
 drivers/char/tpm/tpm.h |    6 ++++++
 2 files changed, 46 insertions(+), 4 deletions(-)

v5 changes:
- Use %zd for printing ssize_t

Applied!

Thanks,
Kent

Quoted 106 lines
drivers/char/tpm/tpm.c +40 -4
index 93211df..433ad6b 100644
@@ -468,7 +468,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 		return -EFAULT;
 
 	err = be32_to_cpu(cmd->header.out.return_code);
-	if (err != 0)
+	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
 	return err;
@@ -528,6 +528,25 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
 }
 EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
 
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be16(1)
+#define TPM_ST_STATE cpu_to_be16(2)
+#define TPM_ST_DEACTIVATED cpu_to_be16(3)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
+static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
+{
+	struct tpm_cmd_t start_cmd;
+	start_cmd.header.in = tpm_startup_header;
+	start_cmd.params.startup_in.startup_type = startup_type;
+	return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+			    "attempting to start the TPM");
+}
+
 int tpm_get_timeouts(struct tpm_chip *chip)
 {
 	struct tpm_cmd_t tpm_cmd;
@@ -541,11 +560,28 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
-	if (rc)
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		/* The TPM is not started, we are the first to talk to it.
+		   Execute a startup command. */
+		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		if (tpm_startup(chip, TPM_ST_CLEAR))
+			return rc;
+
+		tpm_cmd.header.in = tpm_getcap_header;
+		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+				  NULL);
+	}
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
+			rc);
 		goto duration;
+	}
 
 	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
 	    be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h +6 -0
index 8ef7649..8971b12 100644
@@ -47,6 +47,7 @@ enum tpm_addr {
 #define TPM_WARN_DOING_SELFTEST 0x802
 #define TPM_ERR_DEACTIVATED     0x6
 #define TPM_ERR_DISABLED        0x7
+#define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -291,6 +292,10 @@ struct tpm_getrandom_in {
 	__be32 num_bytes;
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;
+
 typedef union {
 	struct	tpm_getcap_params_out getcap_out;
 	struct	tpm_readpubek_params_out readpubek_out;
@@ -301,6 +306,7 @@ typedef union {
 	struct	tpm_pcrextend_in pcrextend_in;
 	struct	tpm_getrandom_in getrandom_in;
 	struct	tpm_getrandom_out getrandom_out;
+	struct tpm_startup_in startup_in;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
Signature · 1 line
1.7.5.4
#17 lore raw
In reply to Jason Gunthorpe

Hi Jason,

Quoted 45 lines · Jason Gunthorpe

The TPM will respond to TPM_GET_CAP with TPM_ERR_INVALID_POSTINIT if TPM_STARTUP has not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issue TPM_STARTUP.

This is for embedded applications where the kernel is the first thing to touch the TPM.

---
 drivers/char/tpm/tpm.c |   41 ++++++++++++++++++++++++++++++++++++-----
 drivers/char/tpm/tpm.h |    6 ++++++
 2 files changed, 42 insertions(+), 5 deletions(-)
drivers/char/tpm/tpm.c +10 -1
index 817f0ee..60e8442 100644
@@ -473,7 +473,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
 		return -EFAULT;
 
 	err = be32_to_cpu(cmd->header.out.return_code);
-	if (err != 0)
+	if (err != 0 && desc)
 		dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
 
 	return err;
@@ -489,6 +489,15 @@ static const struct tpm_input_header tpm_getcap_header = {
 	.ordinal = TPM_ORD_GET_CAP
 };
 
+
+#define TPM_ORD_STARTUP cpu_to_be32(153)
+#define TPM_ST_CLEAR cpu_to_be32(1)
+static const struct tpm_input_header tpm_startup_header = {
+	.tag = TPM_TAG_RQU_COMMAND,
+	.length = cpu_to_be32(12),
+	.ordinal = TPM_ORD_STARTUP
+};
+
 ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
 		   const char *desc)
 {
@@ -545,11 +554,33 @@ int tpm_get_timeouts(struct tpm_chip *chip)
 	tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;

drivers/char/tpm/tpm.c int tpm_get_timeouts(struct tpm_chip *chip) · line 564

Quoted 10 lines
drivers/char/tpm/tpm.c +8 -0
 	tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
 	tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+
+	if (rc == TPM_ERR_INVALID_POSTINIT) {
+		struct tpm_cmd_t start_cmd;
+		/* The TPM is not started, we are the first to talk to it.
+		   Execute a startup command. */
+		start_cmd.header.in = tpm_startup_header;
+		start_cmd.params.startup_in.startup_type = TPM_ST_CLEAR;

Please make this its own function instead of putting it inside
tpm_get_timeouts.

Kent

Quoted 65 lines
drivers/char/tpm/tpm.c +17 -3
+
+		dev_info(chip->dev, "Issuing TPM_STARTUP");
+		rc = transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+			"attempting to start the TPM");
+		if (rc)
+			return -EINVAL;
 
-	rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
-			"attempting to determine the timeouts");
-	if (rc)
+		tpm_cmd.header.in = tpm_getcap_header;
+		tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
+		tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
+		tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
+		rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0);
+	}
+	if (rc) {
+		dev_err(chip->dev,
+			"A TPM error (%d) occurred attempting to determine the timeouts\n",
+			rc);
 		goto duration;
+	}
 
 	if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
 	    be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h +6 -0
index 917f727..2d583ef 100644
@@ -41,6 +41,7 @@ enum tpm_addr {
 #define TPM_WARN_DOING_SELFTEST 0x802
 #define TPM_ERR_DEACTIVATED     0x6
 #define TPM_ERR_DISABLED        0x7
+#define TPM_ERR_INVALID_POSTINIT 38
 
 #define TPM_HEADER_SIZE		10
 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
@@ -269,6 +270,10 @@ struct tpm_pcrextend_in {
 	u8	hash[TPM_DIGEST_SIZE];
 }__attribute__((packed));
 
+struct tpm_startup_in {
+	__be16	startup_type;
+} __packed;
+
 typedef union {
 	struct	tpm_getcap_params_out getcap_out;
 	struct	tpm_readpubek_params_out readpubek_out;
@@ -277,6 +282,7 @@ typedef union {
 	struct	tpm_pcrread_in	pcrread_in;
 	struct	tpm_pcrread_out	pcrread_out;
 	struct	tpm_pcrextend_in pcrextend_in;
+	struct tpm_startup_in startup_in;
 } tpm_cmd_params;
 
 struct tpm_cmd_t {
Signature · 7 lines
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/