Commit c584af1926b7626ef3bdab3354382cb2bd434d36

Authored by Jason Gunthorpe
Committed by Kent Yoder
1 parent 07b133e606

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>

Showing 2 changed files with 46 additions and 4 deletions Side-by-side Diff

drivers/char/tpm/tpm.c
... ... @@ -451,7 +451,7 @@
451 451 return -EFAULT;
452 452  
453 453 err = be32_to_cpu(cmd->header.out.return_code);
454   - if (err != 0)
  454 + if (err != 0 && desc)
455 455 dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
456 456  
457 457 return err;
... ... @@ -511,6 +511,25 @@
511 511 }
512 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 533 int tpm_get_timeouts(struct tpm_chip *chip)
515 534 {
516 535 struct tpm_cmd_t tpm_cmd;
517 536  
518 537  
... ... @@ -524,11 +543,28 @@
524 543 tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
525 544 tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
526 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,
529   - "attempting to determine the timeouts");
530   - if (rc)
  548 + if (rc == TPM_ERR_INVALID_POSTINIT) {
  549 + /* The TPM is not started, we are the first to talk to it.
  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 566 goto duration;
  567 + }
532 568  
533 569 if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
534 570 be32_to_cpu(tpm_cmd.header.out.length)
drivers/char/tpm/tpm.h
... ... @@ -47,6 +47,7 @@
47 47 #define TPM_WARN_DOING_SELFTEST 0x802
48 48 #define TPM_ERR_DEACTIVATED 0x6
49 49 #define TPM_ERR_DISABLED 0x7
  50 +#define TPM_ERR_INVALID_POSTINIT 38
50 51  
51 52 #define TPM_HEADER_SIZE 10
52 53 extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
... ... @@ -291,6 +292,10 @@
291 292 __be32 num_bytes;
292 293 }__attribute__((packed));
293 294  
  295 +struct tpm_startup_in {
  296 + __be16 startup_type;
  297 +} __packed;
  298 +
294 299 typedef union {
295 300 struct tpm_getcap_params_out getcap_out;
296 301 struct tpm_readpubek_params_out readpubek_out;
... ... @@ -301,6 +306,7 @@
301 306 struct tpm_pcrextend_in pcrextend_in;
302 307 struct tpm_getrandom_in getrandom_in;
303 308 struct tpm_getrandom_out getrandom_out;
  309 + struct tpm_startup_in startup_in;
304 310 } tpm_cmd_params;
305 311  
306 312 struct tpm_cmd_t {