Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Jan 2018 21:12:31 +0000 (13:12 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 31 Jan 2018 21:12:31 +0000 (13:12 -0800)
Pull tpm updates from James Morris:

 - reduce polling delays in tpm_tis

 - support retrieving TPM 2.0 Event Log through EFI before
   ExitBootServices

 - replace tpm-rng.c with a hwrng device managed by the driver for each
   TPM device

 - TPM resource manager synthesizes TPM_RC_COMMAND_CODE response instead
   of returning -EINVAL for unknown TPM commands. This makes user space
   more sound.

 - CLKRUN fixes:

    * Keep #CLKRUN disable through the entier TPM command/response flow

    * Check whether #CLKRUN is enabled before disabling and enabling it
      again because enabling it breaks PS/2 devices on a system where it
      is disabled

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  tpm: remove unused variables
  tpm: remove unused data fields from I2C and OF device ID tables
  tpm: only attempt to disable the LPC CLKRUN if is already enabled
  tpm: follow coding style for variable declaration in tpm_tis_core_init()
  tpm: delete the TPM_TIS_CLK_ENABLE flag
  tpm: Update MAINTAINERS for Jason Gunthorpe
  tpm: Keep CLKRUN enabled throughout the duration of transmit_cmd()
  tpm_tis: Move ilb_base_addr to tpm_tis_data
  tpm2-cmd: allow more attempts for selftest execution
  tpm: return a TPM_RC_COMMAND_CODE response if command is not implemented
  tpm: Move Linux RNG connection to hwrng
  tpm: use struct tpm_chip for tpm_chip_find_get()
  tpm: parse TPM event logs based on EFI table
  efi: call get_event_log before ExitBootServices
  tpm: add event log format version
  tpm: rename event log provider files
  tpm: move tpm_eventlog.h outside of drivers folder
  tpm: use tpm_msleep() value as max delay
  tpm: reduce tpm polling delay in tpm_tis_core
  tpm: move wait_for_tpm_stat() to respective driver files

36 files changed:
MAINTAINERS
arch/x86/boot/compressed/eboot.c
drivers/char/hw_random/Kconfig
drivers/char/hw_random/Makefile
drivers/char/hw_random/tpm-rng.c [deleted file]
drivers/char/tpm/Kconfig
drivers/char/tpm/Makefile
drivers/char/tpm/tpm-chip.c
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm1_eventlog.c
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm2_eventlog.c
drivers/char/tpm/tpm_acpi.c [deleted file]
drivers/char/tpm/tpm_eventlog.h [deleted file]
drivers/char/tpm/tpm_eventlog_acpi.c [new file with mode: 0644]
drivers/char/tpm/tpm_eventlog_efi.c [new file with mode: 0644]
drivers/char/tpm/tpm_eventlog_of.c [new file with mode: 0644]
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_of.c [deleted file]
drivers/char/tpm/tpm_tis.c
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h
drivers/char/tpm/xen-tpmfront.c
drivers/firmware/efi/Makefile
drivers/firmware/efi/efi.c
drivers/firmware/efi/libstub/Makefile
drivers/firmware/efi/libstub/tpm.c
drivers/firmware/efi/tpm.c [new file with mode: 0644]
include/linux/efi.h
include/linux/tpm.h
include/linux/tpm_eventlog.h [new file with mode: 0644]
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_init.c
security/integrity/ima/ima_queue.c
security/keys/trusted.c

index bc29978d263c5e9e702a27ee655b8d95dd35a29e..7872d430e7b18546f28b8b643d37571a685ed118 100644 (file)
@@ -13869,9 +13869,10 @@ F:     drivers/platform/x86/toshiba-wmi.c
 TPM DEVICE DRIVER
 M:     Peter Huewe <peterhuewe@gmx.de>
 M:     Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
-R:     Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+R:     Jason Gunthorpe <jgg@ziepe.ca>
 L:     linux-integrity@vger.kernel.org
 Q:     https://patchwork.kernel.org/project/linux-integrity/list/
+W:     https://kernsec.org/wiki/index.php/Linux_Kernel_Integrity
 T:     git git://git.infradead.org/users/jjs/linux-tpmdd.git
 S:     Maintained
 F:     drivers/char/tpm/
index e56dbc67e8378e891fa8aa64192d0875237f4aba..353e20c3f114f3132ef18dbc03e7a8110f4e22df 100644 (file)
@@ -999,6 +999,7 @@ struct boot_params *efi_main(struct efi_config *c,
 
        /* Ask the firmware to clear memory on unclean shutdown */
        efi_enable_reset_attack_mitigation(sys_table);
+       efi_retrieve_tpm2_eventlog(sys_table);
 
        setup_graphics(boot_params);
 
index f6e3e5abc117fa4be755d91c47d0acd1d026bc8d..88044eda0ac6ae140cd4b710f7851d87d5d432c2 100644 (file)
@@ -306,19 +306,6 @@ config HW_RANDOM_POWERNV
 
          If unsure, say Y.
 
-config HW_RANDOM_TPM
-       tristate "TPM HW Random Number Generator support"
-       depends on TCG_TPM
-       default HW_RANDOM
-       ---help---
-         This driver provides kernel-side support for the Random Number
-         Generator in the Trusted Platform Module
-
-         To compile this driver as a module, choose M here: the
-         module will be called tpm-rng.
-
-         If unsure, say Y.
-
 config HW_RANDOM_HISI
        tristate "Hisilicon Random Number Generator support"
        depends on HW_RANDOM && ARCH_HISI
index f3728d008fff9f1aa3a7fee446a3ece5f2727894..0ef05c61d9c8c4064b7603c78104dd3735efd780 100644 (file)
@@ -27,7 +27,6 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
 obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
 obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
 obj-$(CONFIG_HW_RANDOM_HISI)   += hisi-rng.o
-obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
 obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
 obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
 obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
diff --git a/drivers/char/hw_random/tpm-rng.c b/drivers/char/hw_random/tpm-rng.c
deleted file mode 100644 (file)
index d6d4482..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2012 Kent Yoder IBM Corporation
- *
- * HWRNG interfaces to pull RNG data from a TPM
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/hw_random.h>
-#include <linux/tpm.h>
-
-#define MODULE_NAME "tpm-rng"
-
-static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
-{
-       return tpm_get_random(TPM_ANY_NUM, data, max);
-}
-
-static struct hwrng tpm_rng = {
-       .name = MODULE_NAME,
-       .read = tpm_rng_read,
-};
-
-static int __init rng_init(void)
-{
-       return hwrng_register(&tpm_rng);
-}
-module_init(rng_init);
-
-static void __exit rng_exit(void)
-{
-       hwrng_unregister(&tpm_rng);
-}
-module_exit(rng_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("RNG driver for TPM devices");
index a30352202f1fdc53f411d1bd6a31ef6386612570..18c81cbe4704ca83ca1919e81a14160bb7353981 100644 (file)
@@ -26,6 +26,17 @@ menuconfig TCG_TPM
 
 if TCG_TPM
 
+config HW_RANDOM_TPM
+       bool "TPM HW Random Number Generator support"
+       depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m)
+       default y
+       ---help---
+         This setting exposes the TPM's Random Number Generator as a hwrng
+         device. This allows the kernel to collect randomness from the TPM at
+         boot, and provides the TPM randomines in /dev/hwrng.
+
+         If unsure, say Y.
+
 config TCG_TIS_CORE
        tristate
        ---help---
index 34b4bcf46f43bc33d77bbf7e8c702d13f9a1616d..acd758381c58ba37f992b8b0f7fcff48e202092c 100644 (file)
@@ -6,8 +6,9 @@ obj-$(CONFIG_TCG_TPM) += tpm.o
 tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
         tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \
          tpm2-space.o
-tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
-tpm-$(CONFIG_OF) += tpm_of.o
+tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_eventlog_acpi.o
+tpm-$(CONFIG_EFI) += tpm_eventlog_efi.o
+tpm-$(CONFIG_OF) += tpm_eventlog_of.o
 obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
 obj-$(CONFIG_TCG_TIS) += tpm_tis.o
 obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
index 0eca20c5a80cf21f95864f93102f10116151aacf..0a62c19937b6177c7f155fa26aa7bbe33183c73d 100644 (file)
@@ -26,8 +26,9 @@
 #include <linux/spinlock.h>
 #include <linux/freezer.h>
 #include <linux/major.h>
+#include <linux/tpm_eventlog.h>
+#include <linux/hw_random.h>
 #include "tpm.h"
-#include "tpm_eventlog.h"
 
 DEFINE_IDR(dev_nums_idr);
 static DEFINE_MUTEX(idr_lock);
@@ -80,21 +81,26 @@ void tpm_put_ops(struct tpm_chip *chip)
 EXPORT_SYMBOL_GPL(tpm_put_ops);
 
 /**
- * tpm_chip_find_get() - return tpm_chip for a given chip number
- * @chip_num: id to find
+ * tpm_chip_find_get() - find and reserve a TPM chip
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
  *
- * The return'd chip has been tpm_try_get_ops'd and must be released via
- * tpm_put_ops
+ * Finds a TPM chip and reserves its class device and operations. The chip must
+ * be released with tpm_chip_put_ops() after use.
+ *
+ * Return:
+ * A reserved &struct tpm_chip instance.
+ * %NULL if a chip is not found.
+ * %NULL if the chip is not available.
  */
-struct tpm_chip *tpm_chip_find_get(int chip_num)
+struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip)
 {
-       struct tpm_chip *chip, *res = NULL;
+       struct tpm_chip *res = NULL;
+       int chip_num = 0;
        int chip_prev;
 
        mutex_lock(&idr_lock);
 
-       if (chip_num == TPM_ANY_NUM) {
-               chip_num = 0;
+       if (!chip) {
                do {
                        chip_prev = chip_num;
                        chip = idr_get_next(&dev_nums_idr, &chip_num);
@@ -104,8 +110,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num)
                        }
                } while (chip_prev != chip_num);
        } else {
-               chip = idr_find(&dev_nums_idr, chip_num);
-               if (chip && !tpm_try_get_ops(chip))
+               if (!tpm_try_get_ops(chip))
                        res = chip;
        }
 
@@ -387,6 +392,26 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
 
        return 0;
 }
+
+static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
+{
+       struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
+
+       return tpm_get_random(chip, data, max);
+}
+
+static int tpm_add_hwrng(struct tpm_chip *chip)
+{
+       if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM))
+               return 0;
+
+       snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
+                "tpm-rng-%d", chip->dev_num);
+       chip->hwrng.name = chip->hwrng_name;
+       chip->hwrng.read = tpm_hwrng_read;
+       return hwrng_register(&chip->hwrng);
+}
+
 /*
  * tpm_chip_register() - create a character device for the TPM chip
  * @chip: TPM chip to use.
@@ -419,11 +444,13 @@ int tpm_chip_register(struct tpm_chip *chip)
 
        tpm_add_ppi(chip);
 
+       rc = tpm_add_hwrng(chip);
+       if (rc)
+               goto out_ppi;
+
        rc = tpm_add_char_device(chip);
-       if (rc) {
-               tpm_bios_log_teardown(chip);
-               return rc;
-       }
+       if (rc)
+               goto out_hwrng;
 
        rc = tpm_add_legacy_sysfs(chip);
        if (rc) {
@@ -432,6 +459,14 @@ int tpm_chip_register(struct tpm_chip *chip)
        }
 
        return 0;
+
+out_hwrng:
+       if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
+               hwrng_unregister(&chip->hwrng);
+out_ppi:
+       tpm_bios_log_teardown(chip);
+
+       return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_chip_register);
 
@@ -451,6 +486,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
 void tpm_chip_unregister(struct tpm_chip *chip)
 {
        tpm_del_legacy_sysfs(chip);
+       if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
+               hwrng_unregister(&chip->hwrng);
        tpm_bios_log_teardown(chip);
        if (chip->flags & TPM_CHIP_FLAG_TPM2)
                cdev_device_del(&chip->cdevs, &chip->devs);
index 1d6729be4cd6376727b9b210319bd77f03ccfb02..76df4fbcf089c2371b2ad8b08f31bf446b5c488b 100644 (file)
@@ -30,9 +30,9 @@
 #include <linux/spinlock.h>
 #include <linux/freezer.h>
 #include <linux/pm_runtime.h>
+#include <linux/tpm_eventlog.h>
 
 #include "tpm.h"
-#include "tpm_eventlog.h"
 
 #define TPM_MAX_ORDINAL 243
 #define TSC_MAX_ORDINAL 12
@@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
 }
 EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
 
-static bool tpm_validate_command(struct tpm_chip *chip,
+static int tpm_validate_command(struct tpm_chip *chip,
                                 struct tpm_space *space,
                                 const u8 *cmd,
                                 size_t len)
@@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip,
        unsigned int nr_handles;
 
        if (len < TPM_HEADER_SIZE)
-               return false;
+               return -EINVAL;
 
        if (!space)
-               return true;
+               return 0;
 
        if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
                cc = be32_to_cpu(header->ordinal);
@@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip,
                if (i < 0) {
                        dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
                                cc);
-                       return false;
+                       return -EOPNOTSUPP;
                }
 
                attrs = chip->cc_attrs_tbl[i];
@@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip,
                        goto err_len;
        }
 
-       return true;
+       return 0;
 err_len:
        dev_dbg(&chip->dev,
                "%s: insufficient command length %zu", __func__, len);
-       return false;
+       return -EINVAL;
 }
 
 /**
@@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
        unsigned long stop;
        bool need_locality;
 
-       if (!tpm_validate_command(chip, space, buf, bufsiz))
-               return -EINVAL;
+       rc = tpm_validate_command(chip, space, buf, bufsiz);
+       if (rc == -EINVAL)
+               return rc;
+       /*
+        * If the command is not implemented by the TPM, synthesize a
+        * response with a TPM2_RC_COMMAND_CODE return for user-space.
+        */
+       if (rc == -EOPNOTSUPP) {
+               header->length = cpu_to_be32(sizeof(*header));
+               header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
+               header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
+                                                 TSS2_RESMGR_TPM_RC_LAYER);
+               return bufsiz;
+       }
 
        if (bufsiz > TPM_BUFSIZE)
                bufsiz = TPM_BUFSIZE;
@@ -413,6 +425,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
        if (chip->dev.parent)
                pm_runtime_get_sync(chip->dev.parent);
 
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, true);
+
        /* Store the decision as chip->locality will be changed. */
        need_locality = chip->locality == -1;
 
@@ -489,6 +504,9 @@ out:
                chip->locality = -1;
        }
 out_no_locality:
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, false);
+
        if (chip->dev.parent)
                pm_runtime_put_sync(chip->dev.parent);
 
@@ -809,19 +827,20 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 }
 
 /**
- * tpm_is_tpm2 - is the chip a TPM2 chip?
- * @chip_num:  tpm idx # or ANY
+ * tpm_is_tpm2 - do we a have a TPM2 chip?
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
  *
- * Returns < 0 on error, and 1 or 0 on success depending whether the chip
- * is a TPM2 chip.
+ * Return:
+ * 1 if we have a TPM2 chip.
+ * 0 if we don't have a TPM2 chip.
+ * A negative number for system errors (errno).
  */
-int tpm_is_tpm2(u32 chip_num)
+int tpm_is_tpm2(struct tpm_chip *chip)
 {
-       struct tpm_chip *chip;
        int rc;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL)
+       chip = tpm_chip_find_get(chip);
+       if (!chip)
                return -ENODEV;
 
        rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
@@ -833,23 +852,19 @@ int tpm_is_tpm2(u32 chip_num)
 EXPORT_SYMBOL_GPL(tpm_is_tpm2);
 
 /**
- * tpm_pcr_read - read a pcr value
- * @chip_num:  tpm idx # or ANY
- * @pcr_idx:   pcr idx to retrieve
- * @res_buf:   TPM_PCR value
- *             size of res_buf is 20 bytes (or NULL if you don't care)
+ * tpm_pcr_read - read a PCR value from SHA1 bank
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
+ * @pcr_idx:   the PCR to be retrieved
+ * @res_buf:   the value of the PCR
  *
- * The TPM driver should be built-in, but for whatever reason it
- * isn't, protect against the chip disappearing, by incrementing
- * the module usage count.
+ * Return: same as with tpm_transmit_cmd()
  */
-int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
+int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
 {
-       struct tpm_chip *chip;
        int rc;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL)
+       chip = tpm_chip_find_get(chip);
+       if (!chip)
                return -ENODEV;
        if (chip->flags & TPM_CHIP_FLAG_TPM2)
                rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
@@ -889,25 +904,26 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash,
 }
 
 /**
- * tpm_pcr_extend - extend pcr value with hash
- * @chip_num:  tpm idx # or AN&
- * @pcr_idx:   pcr idx to extend
- * @hash:      hash value used to extend pcr value
+ * tpm_pcr_extend - extend a PCR value in SHA1 bank.
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
+ * @pcr_idx:   the PCR to be retrieved
+ * @hash:      the hash value used to extend the PCR value
  *
- * The TPM driver should be built-in, but for whatever reason it
- * isn't, protect against the chip disappearing, by incrementing
- * the module usage count.
+ * Note: with TPM 2.0 extends also those banks with a known digest size to the
+ * cryto subsystem in order to prevent malicious use of those PCR banks. In the
+ * future we should dynamically determine digest sizes.
+ *
+ * Return: same as with tpm_transmit_cmd()
  */
-int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
+int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
 {
        int rc;
-       struct tpm_chip *chip;
        struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
        u32 count = 0;
        int i;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL)
+       chip = tpm_chip_find_get(chip);
+       if (!chip)
                return -ENODEV;
 
        if (chip->flags & TPM_CHIP_FLAG_TPM2) {
@@ -1019,82 +1035,29 @@ out:
        return rc;
 }
 
-int tpm_send(u32 chip_num, void *cmd, size_t buflen)
+/**
+ * tpm_send - send a TPM command
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
+ * @cmd:       a TPM command buffer
+ * @buflen:    the length of the TPM command buffer
+ *
+ * Return: same as with tpm_transmit_cmd()
+ */
+int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
 {
-       struct tpm_chip *chip;
        int rc;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL)
+       chip = tpm_chip_find_get(chip);
+       if (!chip)
                return -ENODEV;
 
        rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
-                             "attempting tpm_cmd");
+                             "attempting to a send a command");
        tpm_put_ops(chip);
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_send);
 
-static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
-                                       bool check_cancel, bool *canceled)
-{
-       u8 status = chip->ops->status(chip);
-
-       *canceled = false;
-       if ((status & mask) == mask)
-               return true;
-       if (check_cancel && chip->ops->req_canceled(chip, status)) {
-               *canceled = true;
-               return true;
-       }
-       return false;
-}
-
-int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
-                     wait_queue_head_t *queue, bool check_cancel)
-{
-       unsigned long stop;
-       long rc;
-       u8 status;
-       bool canceled = false;
-
-       /* check current status */
-       status = chip->ops->status(chip);
-       if ((status & mask) == mask)
-               return 0;
-
-       stop = jiffies + timeout;
-
-       if (chip->flags & TPM_CHIP_FLAG_IRQ) {
-again:
-               timeout = stop - jiffies;
-               if ((long)timeout <= 0)
-                       return -ETIME;
-               rc = wait_event_interruptible_timeout(*queue,
-                       wait_for_tpm_stat_cond(chip, mask, check_cancel,
-                                              &canceled),
-                       timeout);
-               if (rc > 0) {
-                       if (canceled)
-                               return -ECANCELED;
-                       return 0;
-               }
-               if (rc == -ERESTARTSYS && freezing(current)) {
-                       clear_thread_flag(TIF_SIGPENDING);
-                       goto again;
-               }
-       } else {
-               do {
-                       tpm_msleep(TPM_TIMEOUT);
-                       status = chip->ops->status(chip);
-                       if ((status & mask) == mask)
-                               return 0;
-               } while (time_before(jiffies, stop));
-       }
-       return -ETIME;
-}
-EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
-
 #define TPM_ORD_SAVESTATE 152
 #define SAVESTATE_RESULT_SIZE 10
 
@@ -1187,16 +1150,15 @@ static const struct tpm_input_header tpm_getrandom_header = {
 };
 
 /**
- * tpm_get_random() - Get random bytes from the tpm's RNG
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @out: destination buffer for the random bytes
- * @max: the max number of bytes to write to @out
+ * tpm_get_random() - get random bytes from the TPM's RNG
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
+ * @out:       destination buffer for the random bytes
+ * @max:       the max number of bytes to write to @out
  *
- * Returns < 0 on error and the number of bytes read on success
+ * Return: same as with tpm_transmit_cmd()
  */
-int tpm_get_random(u32 chip_num, u8 *out, size_t max)
+int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
 {
-       struct tpm_chip *chip;
        struct tpm_cmd_t tpm_cmd;
        u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
        int err, total = 0, retries = 5;
@@ -1205,8 +1167,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
        if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
                return -EINVAL;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL)
+       chip = tpm_chip_find_get(chip);
+       if (!chip)
                return -ENODEV;
 
        if (chip->flags & TPM_CHIP_FLAG_TPM2) {
@@ -1248,22 +1210,23 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
 /**
- * tpm_seal_trusted() - seal a trusted key
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @options: authentication values and other options
- * @payload: the key data in clear and encrypted form
+ * tpm_seal_trusted() - seal a trusted key payload
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
+ * @options:   authentication values and other options
+ * @payload:   the key data in clear and encrypted form
  *
- * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
- * are supported.
+ * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in
+ * the keyring subsystem.
+ *
+ * Return: same as with tpm_transmit_cmd()
  */
-int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload,
+int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload,
                     struct trusted_key_options *options)
 {
-       struct tpm_chip *chip;
        int rc;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
+       chip = tpm_chip_find_get(chip);
+       if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
                return -ENODEV;
 
        rc = tpm2_seal_trusted(chip, payload, options);
@@ -1275,21 +1238,23 @@ EXPORT_SYMBOL_GPL(tpm_seal_trusted);
 
 /**
  * tpm_unseal_trusted() - unseal a trusted key
- * @chip_num: A specific chip number for the request or TPM_ANY_NUM
- * @options: authentication values and other options
- * @payload: the key data in clear and encrypted form
+ * @chip:      a &struct tpm_chip instance, %NULL for the default chip
+ * @options:   authentication values and other options
+ * @payload:   the key data in clear and encrypted form
+ *
+ * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in
+ * the keyring subsystem.
  *
- * Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
- * are supported.
+ * Return: same as with tpm_transmit_cmd()
  */
-int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload,
+int tpm_unseal_trusted(struct tpm_chip *chip,
+                      struct trusted_key_payload *payload,
                       struct trusted_key_options *options)
 {
-       struct tpm_chip *chip;
        int rc;
 
-       chip = tpm_chip_find_get(chip_num);
-       if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
+       chip = tpm_chip_find_get(chip);
+       if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
                return -ENODEV;
 
        rc = tpm2_unseal_trusted(chip, payload, options);
index 528cffbd49d376603eaf80ccb0a4865f0c742d0b..f895fba4e20d5fd26c82675d3aceb07ab7c0327c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/hw_random.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/platform_device.h>
@@ -34,6 +35,7 @@
 #include <linux/acpi.h>
 #include <linux/cdev.h>
 #include <linux/highmem.h>
+#include <linux/tpm_eventlog.h>
 #include <crypto/hash_info.h>
 
 #ifdef CONFIG_X86
@@ -93,12 +95,17 @@ enum tpm2_structures {
        TPM2_ST_SESSIONS        = 0x8002,
 };
 
+/* Indicates from what layer of the software stack the error comes from */
+#define TSS2_RC_LAYER_SHIFT     16
+#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
+
 enum tpm2_return_codes {
        TPM2_RC_SUCCESS         = 0x0000,
        TPM2_RC_HASH            = 0x0083, /* RC_FMT1 */
        TPM2_RC_HANDLE          = 0x008B,
        TPM2_RC_INITIALIZE      = 0x0100, /* RC_VER1 */
        TPM2_RC_DISABLED        = 0x0120,
+       TPM2_RC_COMMAND_CODE    = 0x0143,
        TPM2_RC_TESTING         = 0x090A, /* RC_WARN */
        TPM2_RC_REFERENCE_H0    = 0x0910,
 };
@@ -210,6 +217,9 @@ struct tpm_chip {
        int dev_num;            /* /dev/tpm# */
        unsigned long is_open;  /* only one allowed */
 
+       char hwrng_name[64];
+       struct hwrng hwrng;
+
        struct mutex tpm_mutex; /* tpm is processing */
 
        unsigned long timeout_a; /* jiffies */
@@ -385,10 +395,6 @@ struct tpm_cmd_t {
        tpm_cmd_params  params;
 } __packed;
 
-struct tpm2_digest {
-       u16 alg_id;
-       u8 digest[SHA512_DIGEST_SIZE];
-} __packed;
 
 /* A string buffer type for constructing TPM commands. This is based on the
  * ideas of string buffer code in security/keys/trusted.h but is heap based
@@ -512,16 +518,14 @@ int tpm_do_selftest(struct tpm_chip *chip);
 unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
 int tpm_pm_suspend(struct device *dev);
 int tpm_pm_resume(struct device *dev);
-int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
-                     wait_queue_head_t *queue, bool check_cancel);
 
 static inline void tpm_msleep(unsigned int delay_msec)
 {
-       usleep_range(delay_msec * 1000,
-                    (delay_msec * 1000) + TPM_TIMEOUT_RANGE_US);
+       usleep_range((delay_msec * 1000) - TPM_TIMEOUT_RANGE_US,
+                    delay_msec * 1000);
 };
 
-struct tpm_chip *tpm_chip_find_get(int chip_num);
+struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip);
 __must_check int tpm_try_get_ops(struct tpm_chip *chip);
 void tpm_put_ops(struct tpm_chip *chip);
 
@@ -575,4 +579,34 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
                       u8 *cmd);
 int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
                      u32 cc, u8 *buf, size_t *bufsiz);
+
+extern const struct seq_operations tpm2_binary_b_measurements_seqops;
+
+#if defined(CONFIG_ACPI)
+int tpm_read_log_acpi(struct tpm_chip *chip);
+#else
+static inline int tpm_read_log_acpi(struct tpm_chip *chip)
+{
+       return -ENODEV;
+}
+#endif
+#if defined(CONFIG_OF)
+int tpm_read_log_of(struct tpm_chip *chip);
+#else
+static inline int tpm_read_log_of(struct tpm_chip *chip)
+{
+       return -ENODEV;
+}
+#endif
+#if defined(CONFIG_EFI)
+int tpm_read_log_efi(struct tpm_chip *chip);
+#else
+static inline int tpm_read_log_efi(struct tpm_chip *chip)
+{
+       return -ENODEV;
+}
+#endif
+
+int tpm_bios_log_setup(struct tpm_chip *chip);
+void tpm_bios_log_teardown(struct tpm_chip *chip);
 #endif
index 9a8605e500b5b3d560eea59a4ed15c75f998c869..add798bd69d0f176cdd175f60268abd3f6a8b1d8 100644 (file)
  */
 
 #include <linux/seq_file.h>
+#include <linux/efi.h>
 #include <linux/fs.h>
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/tpm_eventlog.h>
 
 #include "tpm.h"
-#include "tpm_eventlog.h"
 
 
 static const char* tcpa_event_type_strings[] = {
@@ -371,6 +372,10 @@ static int tpm_read_log(struct tpm_chip *chip)
        if (rc != -ENODEV)
                return rc;
 
+       rc = tpm_read_log_efi(chip);
+       if (rc != -ENODEV)
+               return rc;
+
        return tpm_read_log_of(chip);
 }
 
@@ -388,11 +393,13 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
 {
        const char *name = dev_name(&chip->dev);
        unsigned int cnt;
+       int log_version;
        int rc = 0;
 
        rc = tpm_read_log(chip);
-       if (rc)
+       if (rc < 0)
                return rc;
+       log_version = rc;
 
        cnt = 0;
        chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
@@ -404,7 +411,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
        cnt++;
 
        chip->bin_log_seqops.chip = chip;
-       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+       if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
                chip->bin_log_seqops.seqops =
                        &tpm2_binary_b_measurements_seqops;
        else
index f40d20671a78fd8469c87074f18b5e81b5d3536d..c17e75348a991e355236f2040f931e940541049f 100644 (file)
@@ -849,28 +849,26 @@ static const struct tpm_input_header tpm2_selftest_header = {
 static int tpm2_do_selftest(struct tpm_chip *chip)
 {
        int rc;
-       unsigned int delay_msec = 20;
+       unsigned int delay_msec = 10;
        long duration;
        struct tpm2_cmd cmd;
 
        duration = jiffies_to_msecs(
                tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
 
-       while (duration > 0) {
+       while (1) {
                cmd.header.in = tpm2_selftest_header;
                cmd.params.selftest_in.full_test = 0;
 
                rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
                                      0, 0, "continue selftest");
 
-               if (rc != TPM2_RC_TESTING)
+               if (rc != TPM2_RC_TESTING || delay_msec >= duration)
                        break;
 
-               tpm_msleep(delay_msec);
-               duration -= delay_msec;
-
-               /* wait longer the next round */
+               /* wait longer than before */
                delay_msec *= 2;
+               tpm_msleep(delay_msec);
        }
 
        return rc;
index 34a8afa69138f32fcef5ea3e13cf0ea2545bce2c..1ce4411292ba9f2b37545850a16a97b14a81af4f 100644 (file)
@@ -21,9 +21,9 @@
 #include <linux/security.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/tpm_eventlog.h>
 
 #include "tpm.h"
-#include "tpm_eventlog.h"
 
 /*
  * calc_tpm2_event_size() - calculate the event size, where event
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c
deleted file mode 100644 (file)
index 169edf3..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2005 IBM Corporation
- *
- * Authors:
- *     Seiji Munetoh <munetoh@jp.ibm.com>
- *     Stefan Berger <stefanb@us.ibm.com>
- *     Reiner Sailer <sailer@watson.ibm.com>
- *     Kylene Hall <kjhall@us.ibm.com>
- *     Nayna Jain <nayna@linux.vnet.ibm.com>
- *
- * Maintained by: <tpmdd-devel@lists.sourceforge.net>
- *
- * Access to the event log extended by the TCG BIOS of PC platform
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/seq_file.h>
-#include <linux/fs.h>
-#include <linux/security.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/acpi.h>
-
-#include "tpm.h"
-#include "tpm_eventlog.h"
-
-struct acpi_tcpa {
-       struct acpi_table_header hdr;
-       u16 platform_class;
-       union {
-               struct client_hdr {
-                       u32 log_max_len __packed;
-                       u64 log_start_addr __packed;
-               } client;
-               struct server_hdr {
-                       u16 reserved;
-                       u64 log_max_len __packed;
-                       u64 log_start_addr __packed;
-               } server;
-       };
-};
-
-/* read binary bios log */
-int tpm_read_log_acpi(struct tpm_chip *chip)
-{
-       struct acpi_tcpa *buff;
-       acpi_status status;
-       void __iomem *virt;
-       u64 len, start;
-       struct tpm_bios_log *log;
-
-       if (chip->flags & TPM_CHIP_FLAG_TPM2)
-               return -ENODEV;
-
-       log = &chip->log;
-
-       /* Unfortuntely ACPI does not associate the event log with a specific
-        * TPM, like PPI. Thus all ACPI TPMs will read the same log.
-        */
-       if (!chip->acpi_dev_handle)
-               return -ENODEV;
-
-       /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
-       status = acpi_get_table(ACPI_SIG_TCPA, 1,
-                               (struct acpi_table_header **)&buff);
-
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       switch(buff->platform_class) {
-       case BIOS_SERVER:
-               len = buff->server.log_max_len;
-               start = buff->server.log_start_addr;
-               break;
-       case BIOS_CLIENT:
-       default:
-               len = buff->client.log_max_len;
-               start = buff->client.log_start_addr;
-               break;
-       }
-       if (!len) {
-               dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__);
-               return -EIO;
-       }
-
-       /* malloc EventLog space */
-       log->bios_event_log = kmalloc(len, GFP_KERNEL);
-       if (!log->bios_event_log)
-               return -ENOMEM;
-
-       log->bios_event_log_end = log->bios_event_log + len;
-
-       virt = acpi_os_map_iomem(start, len);
-       if (!virt)
-               goto err;
-
-       memcpy_fromio(log->bios_event_log, virt, len);
-
-       acpi_os_unmap_iomem(virt, len);
-       return 0;
-
-err:
-       kfree(log->bios_event_log);
-       log->bios_event_log = NULL;
-       return -EIO;
-
-}
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h
deleted file mode 100644 (file)
index 204466c..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __TPM_EVENTLOG_H__
-#define __TPM_EVENTLOG_H__
-
-#include <crypto/hash_info.h>
-
-#define TCG_EVENT_NAME_LEN_MAX 255
-#define MAX_TEXT_EVENT         1000    /* Max event string length */
-#define ACPI_TCPA_SIG          "TCPA"  /* 0x41504354 /'TCPA' */
-#define TPM2_ACTIVE_PCR_BANKS  3
-
-#ifdef CONFIG_PPC64
-#define do_endian_conversion(x) be32_to_cpu(x)
-#else
-#define do_endian_conversion(x) x
-#endif
-
-enum bios_platform_class {
-       BIOS_CLIENT = 0x00,
-       BIOS_SERVER = 0x01,
-};
-
-struct tcpa_event {
-       u32 pcr_index;
-       u32 event_type;
-       u8 pcr_value[20];       /* SHA1 */
-       u32 event_size;
-       u8 event_data[0];
-};
-
-enum tcpa_event_types {
-       PREBOOT = 0,
-       POST_CODE,
-       UNUSED,
-       NO_ACTION,
-       SEPARATOR,
-       ACTION,
-       EVENT_TAG,
-       SCRTM_CONTENTS,
-       SCRTM_VERSION,
-       CPU_MICROCODE,
-       PLATFORM_CONFIG_FLAGS,
-       TABLE_OF_DEVICES,
-       COMPACT_HASH,
-       IPL,
-       IPL_PARTITION_DATA,
-       NONHOST_CODE,
-       NONHOST_CONFIG,
-       NONHOST_INFO,
-};
-
-struct tcpa_pc_event {
-       u32 event_id;
-       u32 event_size;
-       u8 event_data[0];
-};
-
-enum tcpa_pc_event_ids {
-       SMBIOS = 1,
-       BIS_CERT,
-       POST_BIOS_ROM,
-       ESCD,
-       CMOS,
-       NVRAM,
-       OPTION_ROM_EXEC,
-       OPTION_ROM_CONFIG,
-       OPTION_ROM_MICROCODE = 10,
-       S_CRTM_VERSION,
-       S_CRTM_CONTENTS,
-       POST_CONTENTS,
-       HOST_TABLE_OF_DEVICES,
-};
-
-/* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */
-
-struct tcg_efi_specid_event_algs {
-       u16 alg_id;
-       u16 digest_size;
-} __packed;
-
-struct tcg_efi_specid_event {
-       u8 signature[16];
-       u32 platform_class;
-       u8 spec_version_minor;
-       u8 spec_version_major;
-       u8 spec_errata;
-       u8 uintnsize;
-       u32 num_algs;
-       struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS];
-       u8 vendor_info_size;
-       u8 vendor_info[0];
-} __packed;
-
-struct tcg_pcr_event {
-       u32 pcr_idx;
-       u32 event_type;
-       u8 digest[20];
-       u32 event_size;
-       u8 event[0];
-} __packed;
-
-struct tcg_event_field {
-       u32 event_size;
-       u8 event[0];
-} __packed;
-
-struct tcg_pcr_event2 {
-       u32 pcr_idx;
-       u32 event_type;
-       u32 count;
-       struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS];
-       struct tcg_event_field event;
-} __packed;
-
-extern const struct seq_operations tpm2_binary_b_measurements_seqops;
-
-#if defined(CONFIG_ACPI)
-int tpm_read_log_acpi(struct tpm_chip *chip);
-#else
-static inline int tpm_read_log_acpi(struct tpm_chip *chip)
-{
-       return -ENODEV;
-}
-#endif
-#if defined(CONFIG_OF)
-int tpm_read_log_of(struct tpm_chip *chip);
-#else
-static inline int tpm_read_log_of(struct tpm_chip *chip)
-{
-       return -ENODEV;
-}
-#endif
-
-int tpm_bios_log_setup(struct tpm_chip *chip);
-void tpm_bios_log_teardown(struct tpm_chip *chip);
-
-#endif
diff --git a/drivers/char/tpm/tpm_eventlog_acpi.c b/drivers/char/tpm/tpm_eventlog_acpi.c
new file mode 100644 (file)
index 0000000..66f19e9
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2005 IBM Corporation
+ *
+ * Authors:
+ *     Seiji Munetoh <munetoh@jp.ibm.com>
+ *     Stefan Berger <stefanb@us.ibm.com>
+ *     Reiner Sailer <sailer@watson.ibm.com>
+ *     Kylene Hall <kjhall@us.ibm.com>
+ *     Nayna Jain <nayna@linux.vnet.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Access to the event log extended by the TCG BIOS of PC platform
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/security.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/tpm_eventlog.h>
+
+#include "tpm.h"
+
+struct acpi_tcpa {
+       struct acpi_table_header hdr;
+       u16 platform_class;
+       union {
+               struct client_hdr {
+                       u32 log_max_len __packed;
+                       u64 log_start_addr __packed;
+               } client;
+               struct server_hdr {
+                       u16 reserved;
+                       u64 log_max_len __packed;
+                       u64 log_start_addr __packed;
+               } server;
+       };
+};
+
+/* read binary bios log */
+int tpm_read_log_acpi(struct tpm_chip *chip)
+{
+       struct acpi_tcpa *buff;
+       acpi_status status;
+       void __iomem *virt;
+       u64 len, start;
+       struct tpm_bios_log *log;
+
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               return -ENODEV;
+
+       log = &chip->log;
+
+       /* Unfortuntely ACPI does not associate the event log with a specific
+        * TPM, like PPI. Thus all ACPI TPMs will read the same log.
+        */
+       if (!chip->acpi_dev_handle)
+               return -ENODEV;
+
+       /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
+       status = acpi_get_table(ACPI_SIG_TCPA, 1,
+                               (struct acpi_table_header **)&buff);
+
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       switch(buff->platform_class) {
+       case BIOS_SERVER:
+               len = buff->server.log_max_len;
+               start = buff->server.log_start_addr;
+               break;
+       case BIOS_CLIENT:
+       default:
+               len = buff->client.log_max_len;
+               start = buff->client.log_start_addr;
+               break;
+       }
+       if (!len) {
+               dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__);
+               return -EIO;
+       }
+
+       /* malloc EventLog space */
+       log->bios_event_log = kmalloc(len, GFP_KERNEL);
+       if (!log->bios_event_log)
+               return -ENOMEM;
+
+       log->bios_event_log_end = log->bios_event_log + len;
+
+       virt = acpi_os_map_iomem(start, len);
+       if (!virt)
+               goto err;
+
+       memcpy_fromio(log->bios_event_log, virt, len);
+
+       acpi_os_unmap_iomem(virt, len);
+       return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+
+err:
+       kfree(log->bios_event_log);
+       log->bios_event_log = NULL;
+       return -EIO;
+
+}
diff --git a/drivers/char/tpm/tpm_eventlog_efi.c b/drivers/char/tpm/tpm_eventlog_efi.c
new file mode 100644 (file)
index 0000000..e3f9ffd
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 Google
+ *
+ * Authors:
+ *      Thiebaud Weksteen <tweek@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/tpm_eventlog.h>
+
+#include "tpm.h"
+
+/* read binary bios log from EFI configuration table */
+int tpm_read_log_efi(struct tpm_chip *chip)
+{
+
+       struct linux_efi_tpm_eventlog *log_tbl;
+       struct tpm_bios_log *log;
+       u32 log_size;
+       u8 tpm_log_version;
+
+       if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+               return -ENODEV;
+
+       if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
+               return -ENODEV;
+
+       log = &chip->log;
+
+       log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB);
+       if (!log_tbl) {
+               pr_err("Could not map UEFI TPM log table !\n");
+               return -ENOMEM;
+       }
+
+       log_size = log_tbl->size;
+       memunmap(log_tbl);
+
+       log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
+                          MEMREMAP_WB);
+       if (!log_tbl) {
+               pr_err("Could not map UEFI TPM log table payload!\n");
+               return -ENOMEM;
+       }
+
+       /* malloc EventLog space */
+       log->bios_event_log = kmalloc(log_size, GFP_KERNEL);
+       if (!log->bios_event_log)
+               goto err_memunmap;
+       memcpy(log->bios_event_log, log_tbl->log, log_size);
+       log->bios_event_log_end = log->bios_event_log + log_size;
+
+       tpm_log_version = log_tbl->version;
+       memunmap(log_tbl);
+       return tpm_log_version;
+
+err_memunmap:
+       memunmap(log_tbl);
+       return -ENOMEM;
+}
diff --git a/drivers/char/tpm/tpm_eventlog_of.c b/drivers/char/tpm/tpm_eventlog_of.c
new file mode 100644 (file)
index 0000000..96fd564
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2012 IBM Corporation
+ *
+ * Author: Ashley Lai <ashleydlai@gmail.com>
+ *         Nayna Jain <nayna@linux.vnet.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * Read the event log created by the firmware on PPC64
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/tpm_eventlog.h>
+
+#include "tpm.h"
+
+int tpm_read_log_of(struct tpm_chip *chip)
+{
+       struct device_node *np;
+       const u32 *sizep;
+       const u64 *basep;
+       struct tpm_bios_log *log;
+       u32 size;
+       u64 base;
+
+       log = &chip->log;
+       if (chip->dev.parent && chip->dev.parent->of_node)
+               np = chip->dev.parent->of_node;
+       else
+               return -ENODEV;
+
+       if (of_property_read_bool(np, "powered-while-suspended"))
+               chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
+
+       sizep = of_get_property(np, "linux,sml-size", NULL);
+       basep = of_get_property(np, "linux,sml-base", NULL);
+       if (sizep == NULL && basep == NULL)
+               return -ENODEV;
+       if (sizep == NULL || basep == NULL)
+               return -EIO;
+
+       /*
+        * For both vtpm/tpm, firmware has log addr and log size in big
+        * endian format. But in case of vtpm, there is a method called
+        * sml-handover which is run during kernel init even before
+        * device tree is setup. This sml-handover function takes care
+        * of endianness and writes to sml-base and sml-size in little
+        * endian format. For this reason, vtpm doesn't need conversion
+        * but physical tpm needs the conversion.
+        */
+       if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) {
+               size = be32_to_cpup(sizep);
+               base = be64_to_cpup(basep);
+       } else {
+               size = *sizep;
+               base = *basep;
+       }
+
+       if (size == 0) {
+               dev_warn(&chip->dev, "%s: Event log area empty\n", __func__);
+               return -EIO;
+       }
+
+       log->bios_event_log = kmalloc(size, GFP_KERNEL);
+       if (!log->bios_event_log)
+               return -ENOMEM;
+
+       log->bios_event_log_end = log->bios_event_log + size;
+
+       memcpy(log->bios_event_log, __va(base), size);
+
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               return EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
+       return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+}
index 79d6bbb58e39b8f35610dfc867bdb5d7aa09fcdf..c1dd39eaaeebb1f474d2d9f8b0d1e98e3559f27f 100644 (file)
@@ -665,9 +665,9 @@ out_err:
 }
 
 static const struct i2c_device_id tpm_tis_i2c_table[] = {
-       {"tpm_i2c_infineon", 0},
-       {"slb9635tt", 0},
-       {"slb9645tt", 1},
+       {"tpm_i2c_infineon"},
+       {"slb9635tt"},
+       {"slb9645tt"},
        {},
 };
 
@@ -675,24 +675,9 @@ MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
 
 #ifdef CONFIG_OF
 static const struct of_device_id tpm_tis_i2c_of_match[] = {
-       {
-               .name = "tpm_i2c_infineon",
-               .type = "tpm",
-               .compatible = "infineon,tpm_i2c_infineon",
-               .data = (void *)0
-       },
-       {
-               .name = "slb9635tt",
-               .type = "tpm",
-               .compatible = "infineon,slb9635tt",
-               .data = (void *)0
-       },
-       {
-               .name = "slb9645tt",
-               .type = "tpm",
-               .compatible = "infineon,slb9645tt",
-               .data = (void *)1
-       },
+       {.compatible = "infineon,tpm_i2c_infineon"},
+       {.compatible = "infineon,slb9635tt"},
+       {.compatible = "infineon,slb9645tt"},
        {},
 };
 MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c
deleted file mode 100644 (file)
index aadb7f4..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2012 IBM Corporation
- *
- * Author: Ashley Lai <ashleydlai@gmail.com>
- *         Nayna Jain <nayna@linux.vnet.ibm.com>
- *
- * Maintained by: <tpmdd-devel@lists.sourceforge.net>
- *
- * Read the event log created by the firmware on PPC64
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/of.h>
-
-#include "tpm.h"
-#include "tpm_eventlog.h"
-
-int tpm_read_log_of(struct tpm_chip *chip)
-{
-       struct device_node *np;
-       const u32 *sizep;
-       const u64 *basep;
-       struct tpm_bios_log *log;
-       u32 size;
-       u64 base;
-
-       log = &chip->log;
-       if (chip->dev.parent && chip->dev.parent->of_node)
-               np = chip->dev.parent->of_node;
-       else
-               return -ENODEV;
-
-       if (of_property_read_bool(np, "powered-while-suspended"))
-               chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
-
-       sizep = of_get_property(np, "linux,sml-size", NULL);
-       basep = of_get_property(np, "linux,sml-base", NULL);
-       if (sizep == NULL && basep == NULL)
-               return -ENODEV;
-       if (sizep == NULL || basep == NULL)
-               return -EIO;
-
-       /*
-        * For both vtpm/tpm, firmware has log addr and log size in big
-        * endian format. But in case of vtpm, there is a method called
-        * sml-handover which is run during kernel init even before
-        * device tree is setup. This sml-handover function takes care
-        * of endianness and writes to sml-base and sml-size in little
-        * endian format. For this reason, vtpm doesn't need conversion
-        * but physical tpm needs the conversion.
-        */
-       if (of_property_match_string(np, "compatible", "IBM,vtpm") < 0) {
-               size = be32_to_cpup(sizep);
-               base = be64_to_cpup(basep);
-       } else {
-               size = *sizep;
-               base = *basep;
-       }
-
-       if (size == 0) {
-               dev_warn(&chip->dev, "%s: Event log area empty\n", __func__);
-               return -EIO;
-       }
-
-       log->bios_event_log = kmalloc(size, GFP_KERNEL);
-       if (!log->bios_event_log)
-               return -ENOMEM;
-
-       log->bios_event_log_end = log->bios_event_log + size;
-
-       memcpy(log->bios_event_log, __va(base), size);
-
-       return 0;
-}
index e2d1055fb814c3e7d2e8b2ed846e6e03d774892c..f08949a5f678508ce864a00df46fe172cb112bba 100644 (file)
@@ -133,93 +133,14 @@ static int check_acpi_tpm2(struct device *dev)
 }
 #endif
 
-#ifdef CONFIG_X86
-#define INTEL_LEGACY_BLK_BASE_ADDR      0xFED08000
-#define ILB_REMAP_SIZE                 0x100
-#define LPC_CNTRL_REG_OFFSET            0x84
-#define LPC_CLKRUN_EN                   (1 << 2)
-
-static void __iomem *ilb_base_addr;
-
-static inline bool is_bsw(void)
-{
-       return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0);
-}
-
-/**
- * tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running
- */
-static void tpm_platform_begin_xfer(void)
-{
-       u32 clkrun_val;
-
-       if (!is_bsw())
-               return;
-
-       clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET);
-
-       /* Disable LPC CLKRUN# */
-       clkrun_val &= ~LPC_CLKRUN_EN;
-       iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET);
-
-       /*
-        * Write any random value on port 0x80 which is on LPC, to make
-        * sure LPC clock is running before sending any TPM command.
-        */
-       outb(0xCC, 0x80);
-
-}
-
-/**
- * tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off
- */
-static void tpm_platform_end_xfer(void)
-{
-       u32 clkrun_val;
-
-       if (!is_bsw())
-               return;
-
-       clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET);
-
-       /* Enable LPC CLKRUN# */
-       clkrun_val |= LPC_CLKRUN_EN;
-       iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET);
-
-       /*
-        * Write any random value on port 0x80 which is on LPC, to make
-        * sure LPC clock is running before sending any TPM command.
-        */
-       outb(0xCC, 0x80);
-
-}
-#else
-static inline bool is_bsw(void)
-{
-       return false;
-}
-
-static void tpm_platform_begin_xfer(void)
-{
-}
-
-static void tpm_platform_end_xfer(void)
-{
-}
-#endif
-
 static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
                              u8 *result)
 {
        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 
-       tpm_platform_begin_xfer();
-
        while (len--)
                *result++ = ioread8(phy->iobase + addr);
 
-       tpm_platform_end_xfer();
-
        return 0;
 }
 
@@ -228,13 +149,9 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
 {
        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 
-       tpm_platform_begin_xfer();
-
        while (len--)
                iowrite8(*value++, phy->iobase + addr);
 
-       tpm_platform_end_xfer();
-
        return 0;
 }
 
@@ -242,12 +159,8 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
 {
        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 
-       tpm_platform_begin_xfer();
-
        *result = ioread16(phy->iobase + addr);
 
-       tpm_platform_end_xfer();
-
        return 0;
 }
 
@@ -255,12 +168,8 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
 {
        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 
-       tpm_platform_begin_xfer();
-
        *result = ioread32(phy->iobase + addr);
 
-       tpm_platform_end_xfer();
-
        return 0;
 }
 
@@ -268,12 +177,8 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value)
 {
        struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
 
-       tpm_platform_begin_xfer();
-
        iowrite32(value, phy->iobase + addr);
 
-       tpm_platform_end_xfer();
-
        return 0;
 }
 
@@ -461,11 +366,6 @@ static int __init init_tis(void)
        if (rc)
                goto err_force;
 
-#ifdef CONFIG_X86
-       if (is_bsw())
-               ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
-                                       ILB_REMAP_SIZE);
-#endif
        rc = platform_driver_register(&tis_drv);
        if (rc)
                goto err_platform;
@@ -484,10 +384,6 @@ err_pnp:
 err_platform:
        if (force_pdev)
                platform_device_unregister(force_pdev);
-#ifdef CONFIG_X86
-       if (is_bsw())
-               iounmap(ilb_base_addr);
-#endif
 err_force:
        return rc;
 }
@@ -497,10 +393,6 @@ static void __exit cleanup_tis(void)
        pnp_unregister_driver(&tis_pnp_driver);
        platform_driver_unregister(&tis_drv);
 
-#ifdef CONFIG_X86
-       if (is_bsw())
-               iounmap(ilb_base_addr);
-#endif
        if (force_pdev)
                platform_device_unregister(force_pdev);
 }
index fdde971bc8108b574eed3a9f1a500904207e3a1c..183a5f54d875d072b98e7aead6563f3dd3d95a62 100644 (file)
 #include "tpm.h"
 #include "tpm_tis_core.h"
 
+/* This is a polling delay to check for status and burstcount.
+ * As per ddwg input, expectation is that status check and burstcount
+ * check should return within few usecs.
+ */
+#define TPM_POLL_SLEEP 1  /* msec */
+
+static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value);
+
+static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
+                                       bool check_cancel, bool *canceled)
+{
+       u8 status = chip->ops->status(chip);
+
+       *canceled = false;
+       if ((status & mask) == mask)
+               return true;
+       if (check_cancel && chip->ops->req_canceled(chip, status)) {
+               *canceled = true;
+               return true;
+       }
+       return false;
+}
+
+static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
+               unsigned long timeout, wait_queue_head_t *queue,
+               bool check_cancel)
+{
+       unsigned long stop;
+       long rc;
+       u8 status;
+       bool canceled = false;
+
+       /* check current status */
+       status = chip->ops->status(chip);
+       if ((status & mask) == mask)
+               return 0;
+
+       stop = jiffies + timeout;
+
+       if (chip->flags & TPM_CHIP_FLAG_IRQ) {
+again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -ETIME;
+               rc = wait_event_interruptible_timeout(*queue,
+                       wait_for_tpm_stat_cond(chip, mask, check_cancel,
+                                              &canceled),
+                       timeout);
+               if (rc > 0) {
+                       if (canceled)
+                               return -ECANCELED;
+                       return 0;
+               }
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
+       } else {
+               do {
+                       tpm_msleep(TPM_POLL_SLEEP);
+                       status = chip->ops->status(chip);
+                       if ((status & mask) == mask)
+                               return 0;
+               } while (time_before(jiffies, stop));
+       }
+       return -ETIME;
+}
+
 /* Before we attempt to access the TPM we must see that the valid bit is set.
  * The specification says that this bit is 0 at reset and remains 0 until the
  * 'TPM has gone through its self test and initialization and has established
@@ -164,7 +232,7 @@ static int get_burstcount(struct tpm_chip *chip)
                burstcnt = (value >> 8) & 0xFFFF;
                if (burstcnt)
                        return burstcnt;
-               tpm_msleep(TPM_TIMEOUT);
+               tpm_msleep(TPM_POLL_SLEEP);
        } while (time_before(jiffies, stop));
        return -EBUSY;
 }
@@ -421,19 +489,28 @@ static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
        int i, rc;
        u32 did_vid;
 
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, true);
+
        rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid);
        if (rc < 0)
-               return rc;
+               goto out;
 
        for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
                if (vendor_timeout_overrides[i].did_vid != did_vid)
                        continue;
                memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
                       sizeof(vendor_timeout_overrides[i].timeout_us));
-               return true;
+               rc = true;
        }
 
-       return false;
+       rc = false;
+
+out:
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, false);
+
+       return rc;
 }
 
 /*
@@ -653,14 +730,73 @@ void tpm_tis_remove(struct tpm_chip *chip)
        u32 interrupt;
        int rc;
 
+       tpm_tis_clkrun_enable(chip, true);
+
        rc = tpm_tis_read32(priv, reg, &interrupt);
        if (rc < 0)
                interrupt = 0;
 
        tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt);
+
+       tpm_tis_clkrun_enable(chip, false);
+
+       if (priv->ilb_base_addr)
+               iounmap(priv->ilb_base_addr);
 }
 EXPORT_SYMBOL_GPL(tpm_tis_remove);
 
+/**
+ * tpm_tis_clkrun_enable() - Keep clkrun protocol disabled for entire duration
+ *                           of a single TPM command
+ * @chip:      TPM chip to use
+ * @value:     1 - Disable CLKRUN protocol, so that clocks are free running
+ *             0 - Enable CLKRUN protocol
+ * Call this function directly in tpm_tis_remove() in error or driver removal
+ * path, since the chip->ops is set to NULL in tpm_chip_unregister().
+ */
+static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value)
+{
+       struct tpm_tis_data *data = dev_get_drvdata(&chip->dev);
+       u32 clkrun_val;
+
+       if (!IS_ENABLED(CONFIG_X86) || !is_bsw() ||
+           !data->ilb_base_addr)
+               return;
+
+       if (value) {
+               data->clkrun_enabled++;
+               if (data->clkrun_enabled > 1)
+                       return;
+               clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET);
+
+               /* Disable LPC CLKRUN# */
+               clkrun_val &= ~LPC_CLKRUN_EN;
+               iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);
+
+               /*
+                * Write any random value on port 0x80 which is on LPC, to make
+                * sure LPC clock is running before sending any TPM command.
+                */
+               outb(0xCC, 0x80);
+       } else {
+               data->clkrun_enabled--;
+               if (data->clkrun_enabled)
+                       return;
+
+               clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET);
+
+               /* Enable LPC CLKRUN# */
+               clkrun_val |= LPC_CLKRUN_EN;
+               iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);
+
+               /*
+                * Write any random value on port 0x80 which is on LPC, to make
+                * sure LPC clock is running before sending any TPM command.
+                */
+               outb(0xCC, 0x80);
+       }
+}
+
 static const struct tpm_class_ops tpm_tis = {
        .flags = TPM_OPS_AUTO_STARTUP,
        .status = tpm_tis_status,
@@ -673,13 +809,17 @@ static const struct tpm_class_ops tpm_tis = {
        .req_canceled = tpm_tis_req_canceled,
        .request_locality = request_locality,
        .relinquish_locality = release_locality,
+       .clk_enable = tpm_tis_clkrun_enable,
 };
 
 int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                      const struct tpm_tis_phy_ops *phy_ops,
                      acpi_handle acpi_dev_handle)
 {
-       u32 vendor, intfcaps, intmask;
+       u32 vendor;
+       u32 intfcaps;
+       u32 intmask;
+       u32 clkrun_val;
        u8 rid;
        int rc, probe;
        struct tpm_chip *chip;
@@ -700,6 +840,23 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
        priv->phy_ops = phy_ops;
        dev_set_drvdata(&chip->dev, priv);
 
+       if (is_bsw()) {
+               priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
+                                       ILB_REMAP_SIZE);
+               if (!priv->ilb_base_addr)
+                       return -ENOMEM;
+
+               clkrun_val = ioread32(priv->ilb_base_addr + LPC_CNTRL_OFFSET);
+               /* Check if CLKRUN# is already not enabled in the LPC bus */
+               if (!(clkrun_val & LPC_CLKRUN_EN)) {
+                       iounmap(priv->ilb_base_addr);
+                       priv->ilb_base_addr = NULL;
+               }
+       }
+
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, true);
+
        if (wait_startup(chip, 0) != 0) {
                rc = -ENODEV;
                goto out_err;
@@ -790,9 +947,20 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                }
        }
 
-       return tpm_chip_register(chip);
+       rc = tpm_chip_register(chip);
+       if (rc)
+               goto out_err;
+
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, false);
+
+       return 0;
 out_err:
+       if ((chip->ops != NULL) && (chip->ops->clk_enable != NULL))
+               chip->ops->clk_enable(chip, false);
+
        tpm_tis_remove(chip);
+
        return rc;
 }
 EXPORT_SYMBOL_GPL(tpm_tis_core_init);
@@ -804,22 +972,31 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
        u32 intmask;
        int rc;
 
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, true);
+
        /* reenable interrupts that device may have lost or
         * BIOS/firmware may have disabled
         */
        rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq);
        if (rc < 0)
-               return;
+               goto out;
 
        rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
        if (rc < 0)
-               return;
+               goto out;
 
        intmask |= TPM_INTF_CMD_READY_INT
            | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
            | TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
 
        tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
+
+out:
+       if (chip->ops->clk_enable != NULL)
+               chip->ops->clk_enable(chip, false);
+
+       return;
 }
 
 int tpm_tis_resume(struct device *dev)
index 6bbac319ff3bfe46169a948775e323e72f172893..d5c6a2e952b3bf38ee77ab600b96f7fd00dc88de 100644 (file)
@@ -79,6 +79,11 @@ enum tis_defaults {
 #define        TPM_DID_VID(l)                  (0x0F00 | ((l) << 12))
 #define        TPM_RID(l)                      (0x0F04 | ((l) << 12))
 
+#define LPC_CNTRL_OFFSET               0x84
+#define LPC_CLKRUN_EN                  (1 << 2)
+#define INTEL_LEGACY_BLK_BASE_ADDR     0xFED08000
+#define ILB_REMAP_SIZE                 0x100
+
 enum tpm_tis_flags {
        TPM_TIS_ITPM_WORKAROUND         = BIT(0),
 };
@@ -89,6 +94,8 @@ struct tpm_tis_data {
        int irq;
        bool irq_tested;
        unsigned int flags;
+       void __iomem *ilb_base_addr;
+       u16 clkrun_enabled;
        wait_queue_head_t int_queue;
        wait_queue_head_t read_queue;
        const struct tpm_tis_phy_ops *phy_ops;
@@ -144,6 +151,15 @@ static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr,
        return data->phy_ops->write32(data, addr, value);
 }
 
+static inline bool is_bsw(void)
+{
+#ifdef CONFIG_X86
+       return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0);
+#else
+       return false;
+#endif
+}
+
 void tpm_tis_remove(struct tpm_chip *chip);
 int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                      const struct tpm_tis_phy_ops *phy_ops,
index 656e8af95d5282f8dbce5e4bd6e277c368092a81..911475d3680028e71ff75cc70411c1da4939494c 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
+#include <linux/freezer.h>
 #include <xen/xen.h>
 #include <xen/events.h>
 #include <xen/interface/io/tpmif.h>
@@ -39,6 +40,66 @@ enum status_bits {
        VTPM_STATUS_CANCELED = 0x8,
 };
 
+static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
+                                       bool check_cancel, bool *canceled)
+{
+       u8 status = chip->ops->status(chip);
+
+       *canceled = false;
+       if ((status & mask) == mask)
+               return true;
+       if (check_cancel && chip->ops->req_canceled(chip, status)) {
+               *canceled = true;
+               return true;
+       }
+       return false;
+}
+
+static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
+               unsigned long timeout, wait_queue_head_t *queue,
+               bool check_cancel)
+{
+       unsigned long stop;
+       long rc;
+       u8 status;
+       bool canceled = false;
+
+       /* check current status */
+       status = chip->ops->status(chip);
+       if ((status & mask) == mask)
+               return 0;
+
+       stop = jiffies + timeout;
+
+       if (chip->flags & TPM_CHIP_FLAG_IRQ) {
+again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -ETIME;
+               rc = wait_event_interruptible_timeout(*queue,
+                       wait_for_tpm_stat_cond(chip, mask, check_cancel,
+                                              &canceled),
+                       timeout);
+               if (rc > 0) {
+                       if (canceled)
+                               return -ECANCELED;
+                       return 0;
+               }
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
+       } else {
+               do {
+                       tpm_msleep(TPM_TIMEOUT);
+                       status = chip->ops->status(chip);
+                       if ((status & mask) == mask)
+                               return 0;
+               } while (time_before(jiffies, stop));
+       }
+       return -ETIME;
+}
+
 static u8 vtpm_status(struct tpm_chip *chip)
 {
        struct tpm_private *priv = dev_get_drvdata(&chip->dev);
index a3e73d6e8a437f2206753aeb0e541f652e07517c..cb805374f4bc8102ecd2edb061cfbeb572233286 100644 (file)
@@ -11,7 +11,7 @@
 KASAN_SANITIZE_runtime-wrappers.o      := n
 
 obj-$(CONFIG_ACPI_BGRT)                += efi-bgrt.o
-obj-$(CONFIG_EFI)                      += efi.o vars.o reboot.o memattr.o
+obj-$(CONFIG_EFI)                      += efi.o vars.o reboot.o memattr.o tpm.o
 obj-$(CONFIG_EFI)                      += capsule.o memmap.o
 obj-$(CONFIG_EFI_VARS)                 += efivars.o
 obj-$(CONFIG_EFI_ESRT)                 += esrt.o
index 8ce70c2e73d53740c879ac7bc204e421ebf855fc..cd42f66a7c85a70801b2322ded2359fc22859ca6 100644 (file)
@@ -52,6 +52,7 @@ struct efi __read_mostly efi = {
        .properties_table       = EFI_INVALID_TABLE_ADDR,
        .mem_attr_table         = EFI_INVALID_TABLE_ADDR,
        .rng_seed               = EFI_INVALID_TABLE_ADDR,
+       .tpm_log                = EFI_INVALID_TABLE_ADDR
 };
 EXPORT_SYMBOL(efi);
 
@@ -464,6 +465,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
        {EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
        {EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
        {LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
+       {LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
        {NULL_GUID, NULL, NULL},
 };
 
@@ -552,6 +554,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
        if (efi_enabled(EFI_MEMMAP))
                efi_memattr_init();
 
+       efi_tpm_eventlog_init();
+
        /* Parse the EFI Properties table if it exists */
        if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
                efi_properties_table_t *tbl;
index adaa4a964f0c548811dedae5f22e846f76fe44a1..7b3ba40f0745bdd310e6507e358b81384867d455 100644 (file)
@@ -30,8 +30,7 @@ OBJECT_FILES_NON_STANDARD     := y
 # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
 KCOV_INSTRUMENT                        := n
 
-lib-y                          := efi-stub-helper.o gop.o secureboot.o
-lib-$(CONFIG_RESET_ATTACK_MITIGATION) += tpm.o
+lib-y                          := efi-stub-helper.o gop.o secureboot.o tpm.o
 
 # include the stub's generic dependencies from lib/ when building for ARM/arm64
 arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
index 6224cdbc96697d71cf040fd2e5b25abe1d93c012..da661bf8cb96e3b683b04574667ec9e7a350376b 100644 (file)
@@ -4,15 +4,18 @@
  * Copyright (C) 2016 CoreOS, Inc
  * Copyright (C) 2017 Google, Inc.
  *     Matthew Garrett <mjg59@google.com>
+ *     Thiebaud Weksteen <tweek@google.com>
  *
  * This file is part of the Linux kernel, and is made available under the
  * terms of the GNU General Public License version 2.
  */
 #include <linux/efi.h>
+#include <linux/tpm_eventlog.h>
 #include <asm/efi.h>
 
 #include "efistub.h"
 
+#ifdef CONFIG_RESET_ATTACK_MITIGATION
 static const efi_char16_t efi_MemoryOverWriteRequest_name[] = {
        'M', 'e', 'm', 'o', 'r', 'y', 'O', 'v', 'e', 'r', 'w', 'r', 'i', 't',
        'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'C', 'o', 'n', 't', 'r', 'o',
@@ -56,3 +59,81 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
                    EFI_VARIABLE_BOOTSERVICE_ACCESS |
                    EFI_VARIABLE_RUNTIME_ACCESS, sizeof(val), &val);
 }
+
+#endif
+
+void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
+{
+       efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
+       efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
+       efi_status_t status;
+       efi_physical_addr_t log_location, log_last_entry;
+       struct linux_efi_tpm_eventlog *log_tbl;
+       unsigned long first_entry_addr, last_entry_addr;
+       size_t log_size, last_entry_size;
+       efi_bool_t truncated;
+       void *tcg2_protocol;
+
+       status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
+                               &tcg2_protocol);
+       if (status != EFI_SUCCESS)
+               return;
+
+       status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
+                               EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
+                               &log_location, &log_last_entry, &truncated);
+       if (status != EFI_SUCCESS)
+               return;
+
+       if (!log_location)
+               return;
+       first_entry_addr = (unsigned long) log_location;
+
+       /*
+        * We populate the EFI table even if the logs are empty.
+        */
+       if (!log_last_entry) {
+               log_size = 0;
+       } else {
+               last_entry_addr = (unsigned long) log_last_entry;
+               /*
+                * get_event_log only returns the address of the last entry.
+                * We need to calculate its size to deduce the full size of
+                * the logs.
+                */
+               last_entry_size = sizeof(struct tcpa_event) +
+                       ((struct tcpa_event *) last_entry_addr)->event_size;
+               log_size = log_last_entry - log_location + last_entry_size;
+       }
+
+       /* Allocate space for the logs and copy them. */
+       status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
+                               sizeof(*log_tbl) + log_size,
+                               (void **) &log_tbl);
+
+       if (status != EFI_SUCCESS) {
+               efi_printk(sys_table_arg,
+                          "Unable to allocate memory for event log\n");
+               return;
+       }
+
+       memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
+       log_tbl->size = log_size;
+       log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+       memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
+
+       status = efi_call_early(install_configuration_table,
+                               &linux_eventlog_guid, log_tbl);
+       if (status != EFI_SUCCESS)
+               goto err_free;
+       return;
+
+err_free:
+       efi_call_early(free_pool, log_tbl);
+}
+
+void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
+{
+       /* Only try to retrieve the logs in 1.2 format. */
+       efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
+}
diff --git a/drivers/firmware/efi/tpm.c b/drivers/firmware/efi/tpm.c
new file mode 100644 (file)
index 0000000..0cbeb3d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 Google, Inc.
+ *     Thiebaud Weksteen <tweek@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/memblock.h>
+
+#include <asm/early_ioremap.h>
+
+/*
+ * Reserve the memory associated with the TPM Event Log configuration table.
+ */
+int __init efi_tpm_eventlog_init(void)
+{
+       struct linux_efi_tpm_eventlog *log_tbl;
+       unsigned int tbl_size;
+
+       if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
+               return 0;
+
+       log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
+       if (!log_tbl) {
+               pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
+                       efi.tpm_log);
+               efi.tpm_log = EFI_INVALID_TABLE_ADDR;
+               return -ENOMEM;
+       }
+
+       tbl_size = sizeof(*log_tbl) + log_tbl->size;
+       memblock_reserve(efi.tpm_log, tbl_size);
+       early_memunmap(log_tbl, sizeof(*log_tbl));
+       return 0;
+}
+
index 29fdf8029cf6fea785631ce65c99eb16c80bf926..f5083aa72eaee51278d9e173525a15039c0f2056 100644 (file)
@@ -475,6 +475,39 @@ typedef struct {
        u64 get_all;
 } apple_properties_protocol_64_t;
 
+typedef struct {
+       u32 get_capability;
+       u32 get_event_log;
+       u32 hash_log_extend_event;
+       u32 submit_command;
+       u32 get_active_pcr_banks;
+       u32 set_active_pcr_banks;
+       u32 get_result_of_set_active_pcr_banks;
+} efi_tcg2_protocol_32_t;
+
+typedef struct {
+       u64 get_capability;
+       u64 get_event_log;
+       u64 hash_log_extend_event;
+       u64 submit_command;
+       u64 get_active_pcr_banks;
+       u64 set_active_pcr_banks;
+       u64 get_result_of_set_active_pcr_banks;
+} efi_tcg2_protocol_64_t;
+
+typedef u32 efi_tcg2_event_log_format;
+
+typedef struct {
+       void *get_capability;
+       efi_status_t (*get_event_log)(efi_handle_t, efi_tcg2_event_log_format,
+               efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *);
+       void *hash_log_extend_event;
+       void *submit_command;
+       void *get_active_pcr_banks;
+       void *set_active_pcr_banks;
+       void *get_result_of_set_active_pcr_banks;
+} efi_tcg2_protocol_t;
+
 /*
  * Types and defines for EFI ResetSystem
  */
@@ -625,6 +658,7 @@ void efi_native_runtime_setup(void);
 #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID       EFI_GUID(0xdcfa911d, 0x26eb, 0x469f,  0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
 #define EFI_CONSOLE_OUT_DEVICE_GUID            EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4,  0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 #define APPLE_PROPERTIES_PROTOCOL_GUID         EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb,  0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
+#define EFI_TCG2_PROTOCOL_GUID                 EFI_GUID(0x607f766c, 0x7455, 0x42be,  0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
 
 #define EFI_IMAGE_SECURITY_DATABASE_GUID       EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596,  0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
 #define EFI_SHIM_LOCK_GUID                     EFI_GUID(0x605dab50, 0xe046, 0x4300,  0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
@@ -637,6 +671,7 @@ void efi_native_runtime_setup(void);
 #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID   EFI_GUID(0xe03fc20a, 0x85dc, 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
 #define LINUX_EFI_LOADER_ENTRY_GUID            EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
 #define LINUX_EFI_RANDOM_SEED_TABLE_GUID       EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
+#define LINUX_EFI_TPM_EVENT_LOG_GUID           EFI_GUID(0xb7799cb0, 0xeca2, 0x4943,  0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
 
 typedef struct {
        efi_guid_t guid;
@@ -911,6 +946,7 @@ extern struct efi {
        unsigned long properties_table; /* properties table */
        unsigned long mem_attr_table;   /* memory attributes table */
        unsigned long rng_seed;         /* UEFI firmware random seed */
+       unsigned long tpm_log;          /* TPM2 Event Log table */
        efi_get_time_t *get_time;
        efi_set_time_t *set_time;
        efi_get_wakeup_time_t *get_wakeup_time;
@@ -1536,6 +1572,8 @@ static inline void
 efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) { }
 #endif
 
+void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table);
+
 /*
  * Arch code can implement the following three template macros, avoiding
  * reptition for the void/non-void return cases of {__,}efi_call_virt():
@@ -1603,4 +1641,12 @@ struct linux_efi_random_seed {
        u8      bits[];
 };
 
+struct linux_efi_tpm_eventlog {
+       u32     size;
+       u8      version;
+       u8      log[];
+};
+
+extern int efi_tpm_eventlog_init(void);
+
 #endif /* _LINUX_EFI_H */
index 5a090f5ab3356f5f26bb21581d9a3df8ea488aa0..bcdd3790e94ddeac42161e55f98dcb284949a2d7 100644 (file)
 
 #define TPM_DIGEST_SIZE 20     /* Max TPM v1.2 PCR size */
 
-/*
- * Chip num is this value or a valid tpm idx
- */
-#define        TPM_ANY_NUM 0xFFFF
-
 struct tpm_chip;
 struct trusted_key_payload;
 struct trusted_key_options;
@@ -50,46 +45,52 @@ struct tpm_class_ops {
                                unsigned long *timeout_cap);
        int (*request_locality)(struct tpm_chip *chip, int loc);
        void (*relinquish_locality)(struct tpm_chip *chip, int loc);
+       void (*clk_enable)(struct tpm_chip *chip, bool value);
 };
 
 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
 
-extern int tpm_is_tpm2(u32 chip_num);
-extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
-extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
-extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
-extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
-extern int tpm_seal_trusted(u32 chip_num,
+extern int tpm_is_tpm2(struct tpm_chip *chip);
+extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
+extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
+extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen);
+extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max);
+extern int tpm_seal_trusted(struct tpm_chip *chip,
                            struct trusted_key_payload *payload,
                            struct trusted_key_options *options);
-extern int tpm_unseal_trusted(u32 chip_num,
+extern int tpm_unseal_trusted(struct tpm_chip *chip,
                              struct trusted_key_payload *payload,
                              struct trusted_key_options *options);
 #else
-static inline int tpm_is_tpm2(u32 chip_num)
+static inline int tpm_is_tpm2(struct tpm_chip *chip)
 {
        return -ENODEV;
 }
-static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
+static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
+{
        return -ENODEV;
 }
-static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
+static inline int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx,
+                                const u8 *hash)
+{
        return -ENODEV;
 }
-static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
+static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
+{
        return -ENODEV;
 }
-static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
+static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max)
+{
        return -ENODEV;
 }
 
-static inline int tpm_seal_trusted(u32 chip_num,
+static inline int tpm_seal_trusted(struct tpm_chip *chip,
                                   struct trusted_key_payload *payload,
                                   struct trusted_key_options *options)
 {
        return -ENODEV;
 }
-static inline int tpm_unseal_trusted(u32 chip_num,
+static inline int tpm_unseal_trusted(struct tpm_chip *chip,
                                     struct trusted_key_payload *payload,
                                     struct trusted_key_options *options)
 {
diff --git a/include/linux/tpm_eventlog.h b/include/linux/tpm_eventlog.h
new file mode 100644 (file)
index 0000000..20d9da7
--- /dev/null
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_TPM_EVENTLOG_H__
+#define __LINUX_TPM_EVENTLOG_H__
+
+#include <crypto/hash_info.h>
+
+#define TCG_EVENT_NAME_LEN_MAX 255
+#define MAX_TEXT_EVENT         1000    /* Max event string length */
+#define ACPI_TCPA_SIG          "TCPA"  /* 0x41504354 /'TCPA' */
+#define TPM2_ACTIVE_PCR_BANKS  3
+
+#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1
+#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2   0x2
+
+#ifdef CONFIG_PPC64
+#define do_endian_conversion(x) be32_to_cpu(x)
+#else
+#define do_endian_conversion(x) x
+#endif
+
+enum bios_platform_class {
+       BIOS_CLIENT = 0x00,
+       BIOS_SERVER = 0x01,
+};
+
+struct tcpa_event {
+       u32 pcr_index;
+       u32 event_type;
+       u8 pcr_value[20];       /* SHA1 */
+       u32 event_size;
+       u8 event_data[0];
+};
+
+enum tcpa_event_types {
+       PREBOOT = 0,
+       POST_CODE,
+       UNUSED,
+       NO_ACTION,
+       SEPARATOR,
+       ACTION,
+       EVENT_TAG,
+       SCRTM_CONTENTS,
+       SCRTM_VERSION,
+       CPU_MICROCODE,
+       PLATFORM_CONFIG_FLAGS,
+       TABLE_OF_DEVICES,
+       COMPACT_HASH,
+       IPL,
+       IPL_PARTITION_DATA,
+       NONHOST_CODE,
+       NONHOST_CONFIG,
+       NONHOST_INFO,
+};
+
+struct tcpa_pc_event {
+       u32 event_id;
+       u32 event_size;
+       u8 event_data[0];
+};
+
+enum tcpa_pc_event_ids {
+       SMBIOS = 1,
+       BIS_CERT,
+       POST_BIOS_ROM,
+       ESCD,
+       CMOS,
+       NVRAM,
+       OPTION_ROM_EXEC,
+       OPTION_ROM_CONFIG,
+       OPTION_ROM_MICROCODE = 10,
+       S_CRTM_VERSION,
+       S_CRTM_CONTENTS,
+       POST_CONTENTS,
+       HOST_TABLE_OF_DEVICES,
+};
+
+/* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */
+
+struct tcg_efi_specid_event_algs {
+       u16 alg_id;
+       u16 digest_size;
+} __packed;
+
+struct tcg_efi_specid_event {
+       u8 signature[16];
+       u32 platform_class;
+       u8 spec_version_minor;
+       u8 spec_version_major;
+       u8 spec_errata;
+       u8 uintnsize;
+       u32 num_algs;
+       struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS];
+       u8 vendor_info_size;
+       u8 vendor_info[0];
+} __packed;
+
+struct tcg_pcr_event {
+       u32 pcr_idx;
+       u32 event_type;
+       u8 digest[20];
+       u32 event_size;
+       u8 event[0];
+} __packed;
+
+struct tcg_event_field {
+       u32 event_size;
+       u8 event[0];
+} __packed;
+
+struct tpm2_digest {
+       u16 alg_id;
+       u8 digest[SHA512_DIGEST_SIZE];
+} __packed;
+
+struct tcg_pcr_event2 {
+       u32 pcr_idx;
+       u32 event_type;
+       u32 count;
+       struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS];
+       struct tcg_event_field event;
+} __packed;
+
+#endif
index 9057b163c37829acee89f61eaab87627f61c21bd..205bc69361ea6667febadb403c6cede9a7827a52 100644 (file)
@@ -632,7 +632,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)
        if (!ima_used_chip)
                return;
 
-       if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
+       if (tpm_pcr_read(NULL, idx, pcr) != 0)
                pr_err("Error Communicating to TPM chip\n");
 }
 
index 2967d497a665c9f627af9ecf77f1554a97f5addc..29b72cd2502ea753893c1f8b49a8b44352139c16 100644 (file)
@@ -110,7 +110,7 @@ int __init ima_init(void)
        int rc;
 
        ima_used_chip = 0;
-       rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i);
+       rc = tpm_pcr_read(NULL, 0, pcr_i);
        if (rc == 0)
                ima_used_chip = 1;
 
index a02a86d5110285c39eeb4f77d5d36aedc576d7fb..418f35e38015a7cc337dbb6a7c9423c4b7ebaf8b 100644 (file)
@@ -145,7 +145,7 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
        if (!ima_used_chip)
                return result;
 
-       result = tpm_pcr_extend(TPM_ANY_NUM, pcr, hash);
+       result = tpm_pcr_extend(NULL, pcr, hash);
        if (result != 0)
                pr_err("Error Communicating to TPM chip, result: %d\n", result);
        return result;
index 98aa89ff7bfd9ed57662116ca455f3a5628ec380..42377668202597527bf5ac660342031ecf4afdd5 100644 (file)
@@ -355,13 +355,12 @@ out:
  * For key specific tpm requests, we will generate and send our
  * own TPM command packets using the drivers send function.
  */
-static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
-                           size_t buflen)
+static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
 {
        int rc;
 
        dump_tpm_buf(cmd);
-       rc = tpm_send(chip_num, cmd, buflen);
+       rc = tpm_send(NULL, cmd, buflen);
        dump_tpm_buf(cmd);
        if (rc > 0)
                /* Can't return positive return codes values to keyctl */
@@ -382,10 +381,10 @@ static int pcrlock(const int pcrnum)
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
-       ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE);
+       ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);
        if (ret != SHA1_DIGEST_SIZE)
                return ret;
-       return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
+       return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;
 }
 
 /*
@@ -398,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
        unsigned char ononce[TPM_NONCE_SIZE];
        int ret;
 
-       ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE);
+       ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE);
        if (ret != TPM_NONCE_SIZE)
                return ret;
 
@@ -410,7 +409,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
        store32(tb, handle);
        storebytes(tb, ononce, TPM_NONCE_SIZE);
 
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
        if (ret < 0)
                return ret;
 
@@ -434,7 +433,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
        store16(tb, TPM_TAG_RQU_COMMAND);
        store32(tb, TPM_OIAP_SIZE);
        store32(tb, TPM_ORD_OIAP);
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
        if (ret < 0)
                return ret;
 
@@ -493,7 +492,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
        if (ret < 0)
                goto out;
 
-       ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE);
+       ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE);
        if (ret != TPM_NONCE_SIZE)
                goto out;
        ordinal = htonl(TPM_ORD_SEAL);
@@ -542,7 +541,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
        store8(tb, cont);
        storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
 
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
        if (ret < 0)
                goto out;
 
@@ -603,7 +602,7 @@ static int tpm_unseal(struct tpm_buf *tb,
 
        ordinal = htonl(TPM_ORD_UNSEAL);
        keyhndl = htonl(SRKHANDLE);
-       ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE);
+       ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);
        if (ret != TPM_NONCE_SIZE) {
                pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
                return ret;
@@ -635,7 +634,7 @@ static int tpm_unseal(struct tpm_buf *tb,
        store8(tb, cont);
        storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
 
-       ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
+       ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
        if (ret < 0) {
                pr_info("trusted_key: authhmac failed (%d)\n", ret);
                return ret;
@@ -748,7 +747,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
        int i;
        int tpm2;
 
-       tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+       tpm2 = tpm_is_tpm2(NULL);
        if (tpm2 < 0)
                return tpm2;
 
@@ -917,7 +916,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
        struct trusted_key_options *options;
        int tpm2;
 
-       tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+       tpm2 = tpm_is_tpm2(NULL);
        if (tpm2 < 0)
                return NULL;
 
@@ -967,7 +966,7 @@ static int trusted_instantiate(struct key *key,
        size_t key_len;
        int tpm2;
 
-       tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+       tpm2 = tpm_is_tpm2(NULL);
        if (tpm2 < 0)
                return tpm2;
 
@@ -1008,7 +1007,7 @@ static int trusted_instantiate(struct key *key,
        switch (key_cmd) {
        case Opt_load:
                if (tpm2)
-                       ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options);
+                       ret = tpm_unseal_trusted(NULL, payload, options);
                else
                        ret = key_unseal(payload, options);
                dump_payload(payload);
@@ -1018,13 +1017,13 @@ static int trusted_instantiate(struct key *key,
                break;
        case Opt_new:
                key_len = payload->key_len;
-               ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len);
+               ret = tpm_get_random(NULL, payload->key, key_len);
                if (ret != key_len) {
                        pr_info("trusted_key: key_create failed (%d)\n", ret);
                        goto out;
                }
                if (tpm2)
-                       ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options);
+                       ret = tpm_seal_trusted(NULL, payload, options);
                else
                        ret = key_seal(payload, options);
                if (ret < 0)