TPM: Issue TPM_STARTUP at driver load if the TPM has not been started
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
@@ -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
@@ -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
Hi Jason,
Quoted 7 lines
The TPM will respond to
TPM_GET_CAPwithTPM_ERR_INVALID_POSTINITifTPM_STARTUPhas not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issueTPM_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
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_CAPwithTPM_ERR_INVALID_POSTINITifTPM_STARTUPhas not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issueTPM_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
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_CAPwithTPM_ERR_INVALID_POSTINITifTPM_STARTUPhas not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issueTPM_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 returnsTPM_FAILEDSELFTESTto 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/
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 returnsTPM_FAILEDSELFTESTto 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_SaveStateon 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
@@ -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
Quoted 3 lines
Curiously the current code does call
TPM_SaveStateon suspend, but relies on the BIOS to doTPM_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@@ -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
-0return 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/
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 calltpm_startupduring 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
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
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
@@ -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
@@ -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
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.cdrivers/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_ttpm_getcap(struct device *dev,__be32subcap_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
-0extern
ssize_ttpm_show_pubek(struct device *, structdevice_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
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).
Tested-by Peter Huewe <[email protected]>
Great, I'll send an updated version, thanks!
Quoted 12 lines
Quoted 12 lines
+++
b/drivers/char/tpm/tpm.cdrivers/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_ttpm_getcap(struct device *dev,__be32subcap_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_getcapand nottpm_startup? All the other definitions are made before they are used - so this should perhaps better be moved directly beforetpm_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
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
__packedto 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
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
@@ -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
@@ -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
Peter Hüwe
maintainerHi 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 getdrivers/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
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
PATCH v5 1/1 TPM: Issue TPM_STARTUP at driver load if the TPM has not been started
In reply to Peter HüweThe 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
@@ -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
@@ -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
Kent Yoder
AppliedQuoted 10 lines · Jason Gunthorpe
The TPM will respond to
TPM_GET_CAPwithTPM_ERR_INVALID_POSTINITifTPM_STARTUPhas not been issued. Detect this and automatically issueTPM_STARTUP.This is for embedded applications where the kernel is the first thing to touch the TPM.
Signed-off-by Jason Gunthorpe <[email protected]>Tested-by Peter Huewe <[email protected]>Reviewed-by Peter Huewe <[email protected]>
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 printingssize_t
Applied!
Thanks,
Kent
Quoted 106 lines
drivers/char/tpm/tpm.c +40
-4@@ -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@@ -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
Hi Jason,
Quoted 45 lines · Jason Gunthorpe
The TPM will respond to
TPM_GET_CAPwithTPM_ERR_INVALID_POSTINITifTPM_STARTUPhas not been issued. This will result in the TPM driver failing to load and no way to recover. Detect this and automatically issueTPM_STARTUP.This is for embedded applications where the kernel is the first thing to touch the TPM.
Signed-off-by Jason Gunthorpe <[email protected]>--- 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@@ -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
-0tpm_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 insidetpm_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@@ -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/