diff options
author | Jason Gunthorpe <jgunthorpe@obsidianresearch.com> | 2012-11-21 15:54:33 -0500 |
---|---|---|
committer | Kent Yoder <key@linux.vnet.ibm.com> | 2013-02-05 10:38:22 -0500 |
commit | c584af1926b7626ef3bdab3354382cb2bd434d36 (patch) | |
tree | 1d614a9e70d9a5195fa80c89f0027899c5af9531 /drivers/char/tpm | |
parent | 07b133e6060ba9de6cf6265fb23f0de8ec78e51c (diff) |
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.
Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Tested-by: Peter Huewe <peter.huewe@infineon.com>
Reviewed-by: Peter Huewe <peter.huewe@infineon.com>
Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/tpm.c | 44 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 6 |
2 files changed, 46 insertions, 4 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 0a08af031a57..023dfbaffe73 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -451,7 +451,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | |||
451 | return -EFAULT; | 451 | return -EFAULT; |
452 | 452 | ||
453 | err = be32_to_cpu(cmd->header.out.return_code); | 453 | err = be32_to_cpu(cmd->header.out.return_code); |
454 | if (err != 0) | 454 | if (err != 0 && desc) |
455 | dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | 455 | dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); |
456 | 456 | ||
457 | return err; | 457 | return err; |
@@ -511,6 +511,25 @@ void tpm_gen_interrupt(struct tpm_chip *chip) | |||
511 | } | 511 | } |
512 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | 512 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); |
513 | 513 | ||
514 | #define TPM_ORD_STARTUP cpu_to_be32(153) | ||
515 | #define TPM_ST_CLEAR cpu_to_be16(1) | ||
516 | #define TPM_ST_STATE cpu_to_be16(2) | ||
517 | #define TPM_ST_DEACTIVATED cpu_to_be16(3) | ||
518 | static const struct tpm_input_header tpm_startup_header = { | ||
519 | .tag = TPM_TAG_RQU_COMMAND, | ||
520 | .length = cpu_to_be32(12), | ||
521 | .ordinal = TPM_ORD_STARTUP | ||
522 | }; | ||
523 | |||
524 | static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) | ||
525 | { | ||
526 | struct tpm_cmd_t start_cmd; | ||
527 | start_cmd.header.in = tpm_startup_header; | ||
528 | start_cmd.params.startup_in.startup_type = startup_type; | ||
529 | return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, | ||
530 | "attempting to start the TPM"); | ||
531 | } | ||
532 | |||
514 | int tpm_get_timeouts(struct tpm_chip *chip) | 533 | int tpm_get_timeouts(struct tpm_chip *chip) |
515 | { | 534 | { |
516 | struct tpm_cmd_t tpm_cmd; | 535 | struct tpm_cmd_t tpm_cmd; |
@@ -524,11 +543,28 @@ int tpm_get_timeouts(struct tpm_chip *chip) | |||
524 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 543 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
525 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | 544 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); |
526 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | 545 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; |
546 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); | ||
527 | 547 | ||
528 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, | 548 | if (rc == TPM_ERR_INVALID_POSTINIT) { |
529 | "attempting to determine the timeouts"); | 549 | /* The TPM is not started, we are the first to talk to it. |
530 | if (rc) | 550 | Execute a startup command. */ |
551 | dev_info(chip->dev, "Issuing TPM_STARTUP"); | ||
552 | if (tpm_startup(chip, TPM_ST_CLEAR)) | ||
553 | return rc; | ||
554 | |||
555 | tpm_cmd.header.in = tpm_getcap_header; | ||
556 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | ||
557 | tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); | ||
558 | tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; | ||
559 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, | ||
560 | NULL); | ||
561 | } | ||
562 | if (rc) { | ||
563 | dev_err(chip->dev, | ||
564 | "A TPM error (%zd) occurred attempting to determine the timeouts\n", | ||
565 | rc); | ||
531 | goto duration; | 566 | goto duration; |
567 | } | ||
532 | 568 | ||
533 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || | 569 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
534 | be32_to_cpu(tpm_cmd.header.out.length) | 570 | be32_to_cpu(tpm_cmd.header.out.length) |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8ef7649a50aa..8971b128500b 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -47,6 +47,7 @@ enum tpm_addr { | |||
47 | #define TPM_WARN_DOING_SELFTEST 0x802 | 47 | #define TPM_WARN_DOING_SELFTEST 0x802 |
48 | #define TPM_ERR_DEACTIVATED 0x6 | 48 | #define TPM_ERR_DEACTIVATED 0x6 |
49 | #define TPM_ERR_DISABLED 0x7 | 49 | #define TPM_ERR_DISABLED 0x7 |
50 | #define TPM_ERR_INVALID_POSTINIT 38 | ||
50 | 51 | ||
51 | #define TPM_HEADER_SIZE 10 | 52 | #define TPM_HEADER_SIZE 10 |
52 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, | 53 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, |
@@ -291,6 +292,10 @@ struct tpm_getrandom_in { | |||
291 | __be32 num_bytes; | 292 | __be32 num_bytes; |
292 | }__attribute__((packed)); | 293 | }__attribute__((packed)); |
293 | 294 | ||
295 | struct tpm_startup_in { | ||
296 | __be16 startup_type; | ||
297 | } __packed; | ||
298 | |||
294 | typedef union { | 299 | typedef union { |
295 | struct tpm_getcap_params_out getcap_out; | 300 | struct tpm_getcap_params_out getcap_out; |
296 | struct tpm_readpubek_params_out readpubek_out; | 301 | struct tpm_readpubek_params_out readpubek_out; |
@@ -301,6 +306,7 @@ typedef union { | |||
301 | struct tpm_pcrextend_in pcrextend_in; | 306 | struct tpm_pcrextend_in pcrextend_in; |
302 | struct tpm_getrandom_in getrandom_in; | 307 | struct tpm_getrandom_in getrandom_in; |
303 | struct tpm_getrandom_out getrandom_out; | 308 | struct tpm_getrandom_out getrandom_out; |
309 | struct tpm_startup_in startup_in; | ||
304 | } tpm_cmd_params; | 310 | } tpm_cmd_params; |
305 | 311 | ||
306 | struct tpm_cmd_t { | 312 | struct tpm_cmd_t { |