Merge branch 'for-james' of git://github.com/srajiv/tpm into next
authorJames Morris <jmorris@namei.org>
Wed, 16 Nov 2011 23:08:37 +0000 (10:08 +1100)
committerJames Morris <jmorris@namei.org>
Wed, 16 Nov 2011 23:08:37 +0000 (10:08 +1100)
1  2 
drivers/char/tpm/Kconfig
drivers/char/tpm/tpm.c

diff --combined drivers/char/tpm/Kconfig
@@@ -27,6 -27,7 +27,7 @@@ if TCG_TP
  
  config TCG_TIS
        tristate "TPM Interface Specification 1.2 Interface"
+       depends on X86
        ---help---
          If you have a TPM security chip that is compliant with the
          TCG TIS 1.2 TPM specification say Yes and it will be accessible
@@@ -35,6 -36,7 +36,7 @@@
  
  config TCG_NSC
        tristate "National Semiconductor TPM Interface"
+       depends on X86
        ---help---
          If you have a TPM security chip from National Semiconductor 
          say Yes and it will be accessible from within Linux.  To 
@@@ -43,7 -45,6 +45,7 @@@
  
  config TCG_ATMEL
        tristate "Atmel TPM Interface"
 +      depends on PPC64 || HAS_IOPORT
        ---help---
          If you have a TPM security chip from Atmel say Yes and it 
          will be accessible from within Linux.  To compile this driver 
diff --combined drivers/char/tpm/tpm.c
@@@ -27,6 -27,7 +27,7 @@@
  #include <linux/slab.h>
  #include <linux/mutex.h>
  #include <linux/spinlock.h>
+ #include <linux/freezer.h>
  
  #include "tpm.h"
  
@@@ -383,9 -384,6 +384,9 @@@ static ssize_t tpm_transmit(struct tpm_
        u32 count, ordinal;
        unsigned long stop;
  
 +      if (bufsiz > TPM_BUFSIZE)
 +              bufsiz = TPM_BUFSIZE;
 +
        count = be32_to_cpu(*((__be32 *) (buf + 2)));
        ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
        if (count == 0)
@@@ -440,7 -438,6 +441,6 @@@ out
  }
  
  #define TPM_DIGEST_SIZE 20
- #define TPM_ERROR_SIZE 10
  #define TPM_RET_CODE_IDX 6
  
  enum tpm_capabilities {
@@@ -469,12 -466,14 +469,14 @@@ static ssize_t transmit_cmd(struct tpm_
        len = tpm_transmit(chip,(u8 *) cmd, len);
        if (len <  0)
                return len;
-       if (len == TPM_ERROR_SIZE) {
-               err = be32_to_cpu(cmd->header.out.return_code);
-               dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
-               return err;
-       }
-       return 0;
+       else if (len < TPM_HEADER_SIZE)
+               return -EFAULT;
+       err = be32_to_cpu(cmd->header.out.return_code);
+       if (err != 0)
+               dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
+       return err;
  }
  
  #define TPM_INTERNAL_RESULT_SIZE 200
@@@ -530,7 -529,7 +532,7 @@@ void tpm_gen_interrupt(struct tpm_chip 
  }
  EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
  
void tpm_get_timeouts(struct tpm_chip *chip)
int tpm_get_timeouts(struct tpm_chip *chip)
  {
        struct tpm_cmd_t tpm_cmd;
        struct timeout_t *timeout_cap;
        if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
            be32_to_cpu(tpm_cmd.header.out.length)
            != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
-               return;
+               return -EINVAL;
  
        timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
        /* Don't overwrite default if value is 0 */
@@@ -583,12 -582,12 +585,12 @@@ duration
        rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
                        "attempting to determine the durations");
        if (rc)
-               return;
+               return rc;
  
        if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
            be32_to_cpu(tpm_cmd.header.out.length)
            != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
-               return;
+               return -EINVAL;
  
        duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
        chip->vendor.duration[TPM_SHORT] =
                chip->vendor.duration_adjusted = true;
                dev_info(chip->dev, "Adjusting TPM timeout parameters.");
        }
+       return 0;
  }
  EXPORT_SYMBOL_GPL(tpm_get_timeouts);
  
- void tpm_continue_selftest(struct tpm_chip *chip)
+ #define TPM_ORD_CONTINUE_SELFTEST 83
+ #define CONTINUE_SELFTEST_RESULT_SIZE 10
+ static struct tpm_input_header continue_selftest_header = {
+       .tag = TPM_TAG_RQU_COMMAND,
+       .length = cpu_to_be32(10),
+       .ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
+ };
+ /**
+  * tpm_continue_selftest -- run TPM's selftest
+  * @chip: TPM chip to use
+  *
+  * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
+  * a TPM error code.
+  */
+ static int tpm_continue_selftest(struct tpm_chip *chip)
  {
-       u8 data[] = {
-               0, 193,                 /* TPM_TAG_RQU_COMMAND */
-               0, 0, 0, 10,            /* length */
-               0, 0, 0, 83,            /* TPM_ORD_ContinueSelfTest */
-       };
+       int rc;
+       struct tpm_cmd_t cmd;
  
-       tpm_transmit(chip, data, sizeof(data));
+       cmd.header.in = continue_selftest_header;
+       rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+                         "continue selftest");
+       return rc;
  }
- EXPORT_SYMBOL_GPL(tpm_continue_selftest);
  
  ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
                        char *buf)
@@@ -718,7 -733,7 +736,7 @@@ static struct tpm_input_header pcrread_
        .ordinal = TPM_ORDINAL_PCRREAD
  };
  
- int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
  {
        int rc;
        struct tpm_cmd_t cmd;
@@@ -798,6 -813,45 +816,45 @@@ int tpm_pcr_extend(u32 chip_num, int pc
  }
  EXPORT_SYMBOL_GPL(tpm_pcr_extend);
  
+ /**
+  * tpm_do_selftest - have the TPM continue its selftest and wait until it
+  *                   can receive further commands
+  * @chip: TPM chip to use
+  *
+  * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
+  * a TPM error code.
+  */
+ int tpm_do_selftest(struct tpm_chip *chip)
+ {
+       int rc;
+       u8 digest[TPM_DIGEST_SIZE];
+       unsigned int loops;
+       unsigned int delay_msec = 1000;
+       unsigned long duration;
+       duration = tpm_calc_ordinal_duration(chip,
+                                            TPM_ORD_CONTINUE_SELFTEST);
+       loops = jiffies_to_msecs(duration) / delay_msec;
+       rc = tpm_continue_selftest(chip);
+       /* This may fail if there was no TPM driver during a suspend/resume
+        * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
+        */
+       if (rc)
+               return rc;
+       do {
+               rc = __tpm_pcr_read(chip, 0, digest);
+               if (rc != TPM_WARN_DOING_SELFTEST)
+                       return rc;
+               msleep(delay_msec);
+       } while (--loops > 0);
+       return rc;
+ }
+ EXPORT_SYMBOL_GPL(tpm_do_selftest);
  int tpm_send(u32 chip_num, void *cmd, size_t buflen)
  {
        struct tpm_chip *chip;
@@@ -1005,6 -1059,46 +1062,46 @@@ ssize_t tpm_store_cancel(struct device 
  }
  EXPORT_SYMBOL_GPL(tpm_store_cancel);
  
+ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
+                        wait_queue_head_t *queue)
+ {
+       unsigned long stop;
+       long rc;
+       u8 status;
+       /* check current status */
+       status = chip->vendor.status(chip);
+       if ((status & mask) == mask)
+               return 0;
+       stop = jiffies + timeout;
+       if (chip->vendor.irq) {
+ again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -ETIME;
+               rc = wait_event_interruptible_timeout(*queue,
+                                                     ((chip->vendor.status(chip)
+                                                     & mask) == mask),
+                                                     timeout);
+               if (rc > 0)
+                       return 0;
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
+       } else {
+               do {
+                       msleep(TPM_TIMEOUT);
+                       status = chip->vendor.status(chip);
+                       if ((status & mask) == mask)
+                               return 0;
+               } while (time_before(jiffies, stop));
+       }
+       return -ETIME;
+ }
+ EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
  /*
   * Device file system interface to the TPM
   *
@@@ -1108,7 -1202,6 +1205,7 @@@ ssize_t tpm_read(struct file *file, cha
  {
        struct tpm_chip *chip = file->private_data;
        ssize_t ret_size;
 +      int rc;
  
        del_singleshot_timer_sync(&chip->user_read_timer);
        flush_work_sync(&chip->work);
                        ret_size = size;
  
                mutex_lock(&chip->buffer_mutex);
 -              if (copy_to_user(buf, chip->data_buffer, ret_size))
 +              rc = copy_to_user(buf, chip->data_buffer, ret_size);
 +              memset(chip->data_buffer, 0, ret_size);
 +              if (rc)
                        ret_size = -EFAULT;
 +
                mutex_unlock(&chip->buffer_mutex);
        }