Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Jun 2018 22:53:17 +0000 (15:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Jun 2018 22:53:17 +0000 (15:53 -0700)
Pull TPM updates from James Morris:
 "From Jarkko:

    This purely a bug fix release.

    The only major change is to move the event log code to its own
    subdirectory because there starts to be so much of it"

* 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  tpm: fix race condition in tpm_common_write()
  tpm: reduce polling time to usecs for even finer granularity
  tpm: replace kmalloc() + memcpy() with kmemdup()
  tpm: replace kmalloc() + memcpy() with kmemdup()
  tpm: fix use after free in tpm2_load_context()
  tpm: reduce poll sleep time in tpm_transmit()
  tpm_tis: verify locality released before returning from release_locality
  tpm: tpm_crb: relinquish locality on error path.
  tpm/st33zp24: Fix spelling mistake in macro ST33ZP24_TISREGISTER_UKNOWN
  tpm: Move eventlog declarations to its own header
  tpm: Move shared eventlog functions to common.c
  tpm: Move eventlog files to a subdirectory
  tpm: Add explicit endianness cast
  tpm: st33zp24: remove redundant null check on chip
  tpm: move the delay_msec increment after sleep in tpm_transmit()

22 files changed:
drivers/char/tpm/Makefile
drivers/char/tpm/eventlog/acpi.c [new file with mode: 0644]
drivers/char/tpm/eventlog/common.c [new file with mode: 0644]
drivers/char/tpm/eventlog/common.h [new file with mode: 0644]
drivers/char/tpm/eventlog/efi.c [new file with mode: 0644]
drivers/char/tpm/eventlog/of.c [new file with mode: 0644]
drivers/char/tpm/eventlog/tpm1.c [new file with mode: 0644]
drivers/char/tpm/eventlog/tpm2.c [new file with mode: 0644]
drivers/char/tpm/st33zp24/spi.c
drivers/char/tpm/st33zp24/st33zp24.c
drivers/char/tpm/tpm-dev-common.c
drivers/char/tpm/tpm-dev.h
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm1_eventlog.c [deleted file]
drivers/char/tpm/tpm2-space.c
drivers/char/tpm/tpm2_eventlog.c [deleted file]
drivers/char/tpm/tpm_crb.c
drivers/char/tpm/tpm_eventlog_acpi.c [deleted file]
drivers/char/tpm/tpm_eventlog_efi.c [deleted file]
drivers/char/tpm/tpm_eventlog_of.c [deleted file]
drivers/char/tpm/tpm_tis_core.c

index acd758381c58ba37f992b8b0f7fcff48e202092c..4e9c33ca1f8fdfdeab625b2c07fd002f31ec6995 100644 (file)
@@ -4,11 +4,11 @@
 #
 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_eventlog_acpi.o
-tpm-$(CONFIG_EFI) += tpm_eventlog_efi.o
-tpm-$(CONFIG_OF) += tpm_eventlog_of.o
+        tpm-dev-common.o tpmrm-dev.o eventlog/common.o eventlog/tpm1.o \
+        eventlog/tpm2.o tpm2-space.o
+tpm-$(CONFIG_ACPI) += tpm_ppi.o eventlog/acpi.o
+tpm-$(CONFIG_EFI) += eventlog/efi.o
+tpm-$(CONFIG_OF) += 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
diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c
new file mode 100644 (file)
index 0000000..7c53b19
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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"
+#include "common.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/eventlog/common.c b/drivers/char/tpm/eventlog/common.c
new file mode 100644 (file)
index 0000000..5a8720d
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2005, 2012 IBM Corporation
+ *
+ * Authors:
+ *     Kent Yoder <key@linux.vnet.ibm.com>
+ *     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>
+ *
+ * Access to the event log created by a system's firmware / BIOS
+ *
+ * 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/tpm_eventlog.h>
+
+#include "../tpm.h"
+#include "common.h"
+
+static int tpm_bios_measurements_open(struct inode *inode,
+                                           struct file *file)
+{
+       int err;
+       struct seq_file *seq;
+       struct tpm_chip_seqops *chip_seqops;
+       const struct seq_operations *seqops;
+       struct tpm_chip *chip;
+
+       inode_lock(inode);
+       if (!inode->i_private) {
+               inode_unlock(inode);
+               return -ENODEV;
+       }
+       chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
+       seqops = chip_seqops->seqops;
+       chip = chip_seqops->chip;
+       get_device(&chip->dev);
+       inode_unlock(inode);
+
+       /* now register seq file */
+       err = seq_open(file, seqops);
+       if (!err) {
+               seq = file->private_data;
+               seq->private = chip;
+       }
+
+       return err;
+}
+
+static int tpm_bios_measurements_release(struct inode *inode,
+                                        struct file *file)
+{
+       struct seq_file *seq = (struct seq_file *)file->private_data;
+       struct tpm_chip *chip = (struct tpm_chip *)seq->private;
+
+       put_device(&chip->dev);
+
+       return seq_release(inode, file);
+}
+
+static const struct file_operations tpm_bios_measurements_ops = {
+       .owner = THIS_MODULE,
+       .open = tpm_bios_measurements_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = tpm_bios_measurements_release,
+};
+
+static int tpm_read_log(struct tpm_chip *chip)
+{
+       int rc;
+
+       if (chip->log.bios_event_log != NULL) {
+               dev_dbg(&chip->dev,
+                       "%s: ERROR - event log already initialized\n",
+                       __func__);
+               return -EFAULT;
+       }
+
+       rc = tpm_read_log_acpi(chip);
+       if (rc != -ENODEV)
+               return rc;
+
+       rc = tpm_read_log_efi(chip);
+       if (rc != -ENODEV)
+               return rc;
+
+       return tpm_read_log_of(chip);
+}
+
+/*
+ * tpm_bios_log_setup() - Read the event log from the firmware
+ * @chip: TPM chip to use.
+ *
+ * If an event log is found then the securityfs files are setup to
+ * export it to userspace, otherwise nothing is done.
+ *
+ * Returns -ENODEV if the firmware has no event log or securityfs is not
+ * supported.
+ */
+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 < 0)
+               return rc;
+       log_version = rc;
+
+       cnt = 0;
+       chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
+       /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
+        * compiled out. The caller should ignore the ENODEV return code.
+        */
+       if (IS_ERR(chip->bios_dir[cnt]))
+               goto err;
+       cnt++;
+
+       chip->bin_log_seqops.chip = chip;
+       if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+               chip->bin_log_seqops.seqops =
+                       &tpm2_binary_b_measurements_seqops;
+       else
+               chip->bin_log_seqops.seqops =
+                       &tpm1_binary_b_measurements_seqops;
+
+
+       chip->bios_dir[cnt] =
+           securityfs_create_file("binary_bios_measurements",
+                                  0440, chip->bios_dir[0],
+                                  (void *)&chip->bin_log_seqops,
+                                  &tpm_bios_measurements_ops);
+       if (IS_ERR(chip->bios_dir[cnt]))
+               goto err;
+       cnt++;
+
+       if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+
+               chip->ascii_log_seqops.chip = chip;
+               chip->ascii_log_seqops.seqops =
+                       &tpm1_ascii_b_measurements_seqops;
+
+               chip->bios_dir[cnt] =
+                       securityfs_create_file("ascii_bios_measurements",
+                                              0440, chip->bios_dir[0],
+                                              (void *)&chip->ascii_log_seqops,
+                                              &tpm_bios_measurements_ops);
+               if (IS_ERR(chip->bios_dir[cnt]))
+                       goto err;
+               cnt++;
+       }
+
+       return 0;
+
+err:
+       rc = PTR_ERR(chip->bios_dir[cnt]);
+       chip->bios_dir[cnt] = NULL;
+       tpm_bios_log_teardown(chip);
+       return rc;
+}
+
+void tpm_bios_log_teardown(struct tpm_chip *chip)
+{
+       int i;
+       struct inode *inode;
+
+       /* securityfs_remove currently doesn't take care of handling sync
+        * between removal and opening of pseudo files. To handle this, a
+        * workaround is added by making i_private = NULL here during removal
+        * and to check it during open(), both within inode_lock()/unlock().
+        * This design ensures that open() either safely gets kref or fails.
+        */
+       for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
+               if (chip->bios_dir[i]) {
+                       inode = d_inode(chip->bios_dir[i]);
+                       inode_lock(inode);
+                       inode->i_private = NULL;
+                       inode_unlock(inode);
+                       securityfs_remove(chip->bios_dir[i]);
+               }
+       }
+}
diff --git a/drivers/char/tpm/eventlog/common.h b/drivers/char/tpm/eventlog/common.h
new file mode 100644 (file)
index 0000000..47ff813
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __TPM_EVENTLOG_COMMON_H__
+#define __TPM_EVENTLOG_COMMON_H__
+
+#include "../tpm.h"
+
+extern const struct seq_operations tpm1_ascii_b_measurements_seqops;
+extern const struct seq_operations tpm1_binary_b_measurements_seqops;
+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
+
+#endif
diff --git a/drivers/char/tpm/eventlog/efi.c b/drivers/char/tpm/eventlog/efi.c
new file mode 100644 (file)
index 0000000..3e673ab
--- /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"
+#include "common.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 = kmemdup(log_tbl->log, log_size, GFP_KERNEL);
+       if (!log->bios_event_log)
+               goto err_memunmap;
+       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/eventlog/of.c b/drivers/char/tpm/eventlog/of.c
new file mode 100644 (file)
index 0000000..bba5fba
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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"
+#include "common.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((__force __be32 *)sizep);
+               base = be64_to_cpup((__force __be64 *)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 = kmemdup(__va(base), size, GFP_KERNEL);
+       if (!log->bios_event_log)
+               return -ENOMEM;
+
+       log->bios_event_log_end = log->bios_event_log + 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;
+}
diff --git a/drivers/char/tpm/eventlog/tpm1.c b/drivers/char/tpm/eventlog/tpm1.c
new file mode 100644 (file)
index 0000000..58c8478
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2005, 2012 IBM Corporation
+ *
+ * Authors:
+ *     Kent Yoder <key@linux.vnet.ibm.com>
+ *     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 created by a system's firmware / BIOS
+ *
+ * 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/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 "common.h"
+
+
+static const char* tcpa_event_type_strings[] = {
+       "PREBOOT",
+       "POST CODE",
+       "",
+       "NO ACTION",
+       "SEPARATOR",
+       "ACTION",
+       "EVENT TAG",
+       "S-CRTM Contents",
+       "S-CRTM Version",
+       "CPU Microcode",
+       "Platform Config Flags",
+       "Table of Devices",
+       "Compact Hash",
+       "IPL",
+       "IPL Partition Data",
+       "Non-Host Code",
+       "Non-Host Config",
+       "Non-Host Info"
+};
+
+static const char* tcpa_pc_event_id_strings[] = {
+       "",
+       "SMBIOS",
+       "BIS Certificate",
+       "POST BIOS ",
+       "ESCD ",
+       "CMOS",
+       "NVRAM",
+       "Option ROM",
+       "Option ROM config",
+       "",
+       "Option ROM microcode ",
+       "S-CRTM Version",
+       "S-CRTM Contents ",
+       "POST Contents ",
+       "Table of Devices",
+};
+
+/* returns pointer to start of pos. entry of tcg log */
+static void *tpm1_bios_measurements_start(struct seq_file *m, loff_t *pos)
+{
+       loff_t i;
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *addr = log->bios_event_log;
+       void *limit = log->bios_event_log_end;
+       struct tcpa_event *event;
+       u32 converted_event_size;
+       u32 converted_event_type;
+
+
+       /* read over *pos measurements */
+       for (i = 0; i < *pos; i++) {
+               event = addr;
+
+               converted_event_size =
+                   do_endian_conversion(event->event_size);
+               converted_event_type =
+                   do_endian_conversion(event->event_type);
+
+               if ((addr + sizeof(struct tcpa_event)) < limit) {
+                       if ((converted_event_type == 0) &&
+                           (converted_event_size == 0))
+                               return NULL;
+                       addr += (sizeof(struct tcpa_event) +
+                                converted_event_size);
+               }
+       }
+
+       /* now check if current entry is valid */
+       if ((addr + sizeof(struct tcpa_event)) >= limit)
+               return NULL;
+
+       event = addr;
+
+       converted_event_size = do_endian_conversion(event->event_size);
+       converted_event_type = do_endian_conversion(event->event_type);
+
+       if (((converted_event_type == 0) && (converted_event_size == 0))
+           || ((addr + sizeof(struct tcpa_event) + converted_event_size)
+               >= limit))
+               return NULL;
+
+       return addr;
+}
+
+static void *tpm1_bios_measurements_next(struct seq_file *m, void *v,
+                                       loff_t *pos)
+{
+       struct tcpa_event *event = v;
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *limit = log->bios_event_log_end;
+       u32 converted_event_size;
+       u32 converted_event_type;
+
+       converted_event_size = do_endian_conversion(event->event_size);
+
+       v += sizeof(struct tcpa_event) + converted_event_size;
+
+       /* now check if current entry is valid */
+       if ((v + sizeof(struct tcpa_event)) >= limit)
+               return NULL;
+
+       event = v;
+
+       converted_event_size = do_endian_conversion(event->event_size);
+       converted_event_type = do_endian_conversion(event->event_type);
+
+       if (((converted_event_type == 0) && (converted_event_size == 0)) ||
+           ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
+               return NULL;
+
+       (*pos)++;
+       return v;
+}
+
+static void tpm1_bios_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static int get_event_name(char *dest, struct tcpa_event *event,
+                       unsigned char * event_entry)
+{
+       const char *name = "";
+       /* 41 so there is room for 40 data and 1 nul */
+       char data[41] = "";
+       int i, n_len = 0, d_len = 0;
+       struct tcpa_pc_event *pc_event;
+
+       switch (do_endian_conversion(event->event_type)) {
+       case PREBOOT:
+       case POST_CODE:
+       case UNUSED:
+       case NO_ACTION:
+       case SCRTM_CONTENTS:
+       case SCRTM_VERSION:
+       case CPU_MICROCODE:
+       case PLATFORM_CONFIG_FLAGS:
+       case TABLE_OF_DEVICES:
+       case COMPACT_HASH:
+       case IPL:
+       case IPL_PARTITION_DATA:
+       case NONHOST_CODE:
+       case NONHOST_CONFIG:
+       case NONHOST_INFO:
+               name = tcpa_event_type_strings[do_endian_conversion
+                                               (event->event_type)];
+               n_len = strlen(name);
+               break;
+       case SEPARATOR:
+       case ACTION:
+               if (MAX_TEXT_EVENT >
+                   do_endian_conversion(event->event_size)) {
+                       name = event_entry;
+                       n_len = do_endian_conversion(event->event_size);
+               }
+               break;
+       case EVENT_TAG:
+               pc_event = (struct tcpa_pc_event *)event_entry;
+
+               /* ToDo Row data -> Base64 */
+
+               switch (do_endian_conversion(pc_event->event_id)) {
+               case SMBIOS:
+               case BIS_CERT:
+               case CMOS:
+               case NVRAM:
+               case OPTION_ROM_EXEC:
+               case OPTION_ROM_CONFIG:
+               case S_CRTM_VERSION:
+                       name = tcpa_pc_event_id_strings[do_endian_conversion
+                                                       (pc_event->event_id)];
+                       n_len = strlen(name);
+                       break;
+               /* hash data */
+               case POST_BIOS_ROM:
+               case ESCD:
+               case OPTION_ROM_MICROCODE:
+               case S_CRTM_CONTENTS:
+               case POST_CONTENTS:
+                       name = tcpa_pc_event_id_strings[do_endian_conversion
+                                                       (pc_event->event_id)];
+                       n_len = strlen(name);
+                       for (i = 0; i < 20; i++)
+                               d_len += sprintf(&data[2*i], "%02x",
+                                               pc_event->event_data[i]);
+                       break;
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
+
+       return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
+                       n_len, name, d_len, data);
+
+}
+
+static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
+{
+       struct tcpa_event *event = v;
+       struct tcpa_event temp_event;
+       char *temp_ptr;
+       int i;
+
+       memcpy(&temp_event, event, sizeof(struct tcpa_event));
+
+       /* convert raw integers for endianness */
+       temp_event.pcr_index = do_endian_conversion(event->pcr_index);
+       temp_event.event_type = do_endian_conversion(event->event_type);
+       temp_event.event_size = do_endian_conversion(event->event_size);
+
+       temp_ptr = (char *) &temp_event;
+
+       for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
+               seq_putc(m, temp_ptr[i]);
+
+       temp_ptr = (char *) v;
+
+       for (i = (sizeof(struct tcpa_event) - 1);
+            i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
+               seq_putc(m, temp_ptr[i]);
+
+       return 0;
+
+}
+
+static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
+{
+       int len = 0;
+       char *eventname;
+       struct tcpa_event *event = v;
+       unsigned char *event_entry =
+           (unsigned char *)(v + sizeof(struct tcpa_event));
+
+       eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
+       if (!eventname) {
+               printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
+                      __func__);
+               return -EFAULT;
+       }
+
+       /* 1st: PCR */
+       seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
+
+       /* 2nd: SHA1 */
+       seq_printf(m, "%20phN", event->pcr_value);
+
+       /* 3rd: event type identifier */
+       seq_printf(m, " %02x", do_endian_conversion(event->event_type));
+
+       len += get_event_name(eventname, event, event_entry);
+
+       /* 4th: eventname <= max + \'0' delimiter */
+       seq_printf(m, " %s\n", eventname);
+
+       kfree(eventname);
+       return 0;
+}
+
+const struct seq_operations tpm1_ascii_b_measurements_seqops = {
+       .start = tpm1_bios_measurements_start,
+       .next = tpm1_bios_measurements_next,
+       .stop = tpm1_bios_measurements_stop,
+       .show = tpm1_ascii_bios_measurements_show,
+};
+
+const struct seq_operations tpm1_binary_b_measurements_seqops = {
+       .start = tpm1_bios_measurements_start,
+       .next = tpm1_bios_measurements_next,
+       .stop = tpm1_bios_measurements_stop,
+       .show = tpm1_binary_bios_measurements_show,
+};
diff --git a/drivers/char/tpm/eventlog/tpm2.c b/drivers/char/tpm/eventlog/tpm2.c
new file mode 100644 (file)
index 0000000..1b8fa9d
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2016 IBM Corporation
+ *
+ * Authors:
+ *      Nayna Jain <nayna@linux.vnet.ibm.com>
+ *
+ * Access to TPM 2.0 event log as written by Firmware.
+ * It assumes that writer of event log has followed TCG Specification
+ * for Family "2.0" and written the event data in little endian.
+ * With that, it doesn't need any endian conversion for structure
+ * content.
+ *
+ * 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/tpm_eventlog.h>
+
+#include "../tpm.h"
+#include "common.h"
+
+/*
+ * calc_tpm2_event_size() - calculate the event size, where event
+ * is an entry in the TPM 2.0 event log. The event is of type Crypto
+ * Agile Log Entry Format as defined in TCG EFI Protocol Specification
+ * Family "2.0".
+
+ * @event: event whose size is to be calculated.
+ * @event_header: the first event in the event log.
+ *
+ * Returns size of the event. If it is an invalid event, returns 0.
+ */
+static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
+                               struct tcg_pcr_event *event_header)
+{
+       struct tcg_efi_specid_event *efispecid;
+       struct tcg_event_field *event_field;
+       void *marker;
+       void *marker_start;
+       u32 halg_size;
+       size_t size;
+       u16 halg;
+       int i;
+       int j;
+
+       marker = event;
+       marker_start = marker;
+       marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
+               + sizeof(event->count);
+
+       efispecid = (struct tcg_efi_specid_event *)event_header->event;
+
+       /* Check if event is malformed. */
+       if (event->count > efispecid->num_algs)
+               return 0;
+
+       for (i = 0; i < event->count; i++) {
+               halg_size = sizeof(event->digests[i].alg_id);
+               memcpy(&halg, marker, halg_size);
+               marker = marker + halg_size;
+               for (j = 0; j < efispecid->num_algs; j++) {
+                       if (halg == efispecid->digest_sizes[j].alg_id) {
+                               marker +=
+                                       efispecid->digest_sizes[j].digest_size;
+                               break;
+                       }
+               }
+               /* Algorithm without known length. Such event is unparseable. */
+               if (j == efispecid->num_algs)
+                       return 0;
+       }
+
+       event_field = (struct tcg_event_field *)marker;
+       marker = marker + sizeof(event_field->event_size)
+               + event_field->event_size;
+       size = marker - marker_start;
+
+       if ((event->event_type == 0) && (event_field->event_size == 0))
+               return 0;
+
+       return size;
+}
+
+static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
+{
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *addr = log->bios_event_log;
+       void *limit = log->bios_event_log_end;
+       struct tcg_pcr_event *event_header;
+       struct tcg_pcr_event2 *event;
+       size_t size;
+       int i;
+
+       event_header = addr;
+       size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
+               + event_header->event_size;
+
+       if (*pos == 0) {
+               if (addr + size < limit) {
+                       if ((event_header->event_type == 0) &&
+                           (event_header->event_size == 0))
+                               return NULL;
+                       return SEQ_START_TOKEN;
+               }
+       }
+
+       if (*pos > 0) {
+               addr += size;
+               event = addr;
+               size = calc_tpm2_event_size(event, event_header);
+               if ((addr + size >=  limit) || (size == 0))
+                       return NULL;
+       }
+
+       for (i = 0; i < (*pos - 1); i++) {
+               event = addr;
+               size = calc_tpm2_event_size(event, event_header);
+
+               if ((addr + size >= limit) || (size == 0))
+                       return NULL;
+               addr += size;
+       }
+
+       return addr;
+}
+
+static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
+                                        loff_t *pos)
+{
+       struct tcg_pcr_event *event_header;
+       struct tcg_pcr_event2 *event;
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       void *limit = log->bios_event_log_end;
+       size_t event_size;
+       void *marker;
+
+       event_header = log->bios_event_log;
+
+       if (v == SEQ_START_TOKEN) {
+               event_size = sizeof(struct tcg_pcr_event) -
+                       sizeof(event_header->event) + event_header->event_size;
+               marker = event_header;
+       } else {
+               event = v;
+               event_size = calc_tpm2_event_size(event, event_header);
+               if (event_size == 0)
+                       return NULL;
+               marker = event;
+       }
+
+       marker = marker + event_size;
+       if (marker >= limit)
+               return NULL;
+       v = marker;
+       event = v;
+
+       event_size = calc_tpm2_event_size(event, event_header);
+       if (((v + event_size) >= limit) || (event_size == 0))
+               return NULL;
+
+       (*pos)++;
+       return v;
+}
+
+static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
+{
+       struct tpm_chip *chip = m->private;
+       struct tpm_bios_log *log = &chip->log;
+       struct tcg_pcr_event *event_header = log->bios_event_log;
+       struct tcg_pcr_event2 *event = v;
+       void *temp_ptr;
+       size_t size;
+
+       if (v == SEQ_START_TOKEN) {
+               size = sizeof(struct tcg_pcr_event) -
+                       sizeof(event_header->event) + event_header->event_size;
+
+               temp_ptr = event_header;
+
+               if (size > 0)
+                       seq_write(m, temp_ptr, size);
+       } else {
+               size = calc_tpm2_event_size(event, event_header);
+               temp_ptr = event;
+               if (size > 0)
+                       seq_write(m, temp_ptr, size);
+       }
+
+       return 0;
+}
+
+const struct seq_operations tpm2_binary_b_measurements_seqops = {
+       .start = tpm2_bios_measurements_start,
+       .next = tpm2_bios_measurements_next,
+       .stop = tpm2_bios_measurements_stop,
+       .show = tpm2_binary_bios_measurements_show,
+};
index 0fc4f20b5f83160974717bf07d2dd8cf5a9e2623..d7909ab287a85c7b75d2f44e70a443451e84a22f 100644 (file)
@@ -40,7 +40,7 @@
 #define ST33ZP24_OK                                    0x5A
 #define ST33ZP24_UNDEFINED_ERR                         0x80
 #define ST33ZP24_BADLOCALITY                           0x81
-#define ST33ZP24_TISREGISTER_UKNOWN                    0x82
+#define ST33ZP24_TISREGISTER_UNKNOWN                   0x82
 #define ST33ZP24_LOCALITY_NOT_ACTIVATED                        0x83
 #define ST33ZP24_HASH_END_BEFORE_HASH_START            0x84
 #define ST33ZP24_BAD_COMMAND_ORDER                     0x85
@@ -84,7 +84,7 @@ static int st33zp24_status_to_errno(u8 code)
                return 0;
        case ST33ZP24_UNDEFINED_ERR:
        case ST33ZP24_BADLOCALITY:
-       case ST33ZP24_TISREGISTER_UKNOWN:
+       case ST33ZP24_TISREGISTER_UNKNOWN:
        case ST33ZP24_LOCALITY_NOT_ACTIVATED:
        case ST33ZP24_HASH_END_BEFORE_HASH_START:
        case ST33ZP24_BAD_COMMAND_ORDER:
index f95b9c75175bcf27825b16891ca405886e51c379..abd675bec88c8435a6b1277b3fac6336d0339c21 100644 (file)
@@ -373,8 +373,6 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
        int ret;
        u8 data;
 
-       if (!chip)
-               return -EBUSY;
        if (len < TPM_HEADER_SIZE)
                return -EBUSY;
 
index 230b99288024994b800c3e9adb42dfc8c0ea4c05..e4a04b2d3c32d49a2ebf2ce37bb6bcf340d38e52 100644 (file)
@@ -37,7 +37,7 @@ static void timeout_work(struct work_struct *work)
        struct file_priv *priv = container_of(work, struct file_priv, work);
 
        mutex_lock(&priv->buffer_mutex);
-       atomic_set(&priv->data_pending, 0);
+       priv->data_pending = 0;
        memset(priv->data_buffer, 0, sizeof(priv->data_buffer));
        mutex_unlock(&priv->buffer_mutex);
 }
@@ -46,7 +46,6 @@ void tpm_common_open(struct file *file, struct tpm_chip *chip,
                     struct file_priv *priv)
 {
        priv->chip = chip;
-       atomic_set(&priv->data_pending, 0);
        mutex_init(&priv->buffer_mutex);
        timer_setup(&priv->user_read_timer, user_reader_timeout, 0);
        INIT_WORK(&priv->work, timeout_work);
@@ -58,29 +57,24 @@ ssize_t tpm_common_read(struct file *file, char __user *buf,
                        size_t size, loff_t *off)
 {
        struct file_priv *priv = file->private_data;
-       ssize_t ret_size;
-       ssize_t orig_ret_size;
+       ssize_t ret_size = 0;
        int rc;
 
        del_singleshot_timer_sync(&priv->user_read_timer);
        flush_work(&priv->work);
-       ret_size = atomic_read(&priv->data_pending);
-       if (ret_size > 0) {     /* relay data */
-               orig_ret_size = ret_size;
-               if (size < ret_size)
-                       ret_size = size;
+       mutex_lock(&priv->buffer_mutex);
 
-               mutex_lock(&priv->buffer_mutex);
+       if (priv->data_pending) {
+               ret_size = min_t(ssize_t, size, priv->data_pending);
                rc = copy_to_user(buf, priv->data_buffer, ret_size);
-               memset(priv->data_buffer, 0, orig_ret_size);
+               memset(priv->data_buffer, 0, priv->data_pending);
                if (rc)
                        ret_size = -EFAULT;
 
-               mutex_unlock(&priv->buffer_mutex);
+               priv->data_pending = 0;
        }
 
-       atomic_set(&priv->data_pending, 0);
-
+       mutex_unlock(&priv->buffer_mutex);
        return ret_size;
 }
 
@@ -91,17 +85,19 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
        size_t in_size = size;
        ssize_t out_size;
 
+       if (in_size > TPM_BUFSIZE)
+               return -E2BIG;
+
+       mutex_lock(&priv->buffer_mutex);
+
        /* Cannot perform a write until the read has cleared either via
         * tpm_read or a user_read_timer timeout. This also prevents split
         * buffered writes from blocking here.
         */
-       if (atomic_read(&priv->data_pending) != 0)
+       if (priv->data_pending != 0) {
+               mutex_unlock(&priv->buffer_mutex);
                return -EBUSY;
-
-       if (in_size > TPM_BUFSIZE)
-               return -E2BIG;
-
-       mutex_lock(&priv->buffer_mutex);
+       }
 
        if (copy_from_user
            (priv->data_buffer, (void __user *) buf, in_size)) {
@@ -132,7 +128,7 @@ ssize_t tpm_common_write(struct file *file, const char __user *buf,
                return out_size;
        }
 
-       atomic_set(&priv->data_pending, out_size);
+       priv->data_pending = out_size;
        mutex_unlock(&priv->buffer_mutex);
 
        /* Set a timeout by which the reader must come claim the result */
@@ -149,5 +145,5 @@ void tpm_common_release(struct file *file, struct file_priv *priv)
        del_singleshot_timer_sync(&priv->user_read_timer);
        flush_work(&priv->work);
        file->private_data = NULL;
-       atomic_set(&priv->data_pending, 0);
+       priv->data_pending = 0;
 }
index ba3b6f9dacf7c6a0f55bca4de024ea736f3304b9..b24cfb4d3ee1e7c7569580f69b2f8146eaa3bcbc 100644 (file)
@@ -8,7 +8,7 @@ struct file_priv {
        struct tpm_chip *chip;
 
        /* Data passed to and from the tpm via the read/write calls */
-       atomic_t data_pending;
+       size_t data_pending;
        struct mutex buffer_mutex;
 
        struct timer_list user_read_timer;      /* user needs to claim result */
index c43a9e28995eb2f03911504fe125523e86ccd107..e32f6e85dc6d0658b3ad61339c65b0dff9738c75 100644 (file)
@@ -489,7 +489,7 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
                        goto out;
                }
 
-               tpm_msleep(TPM_TIMEOUT);
+               tpm_msleep(TPM_TIMEOUT_POLL);
                rmb();
        } while (time_before(jiffies, stop));
 
@@ -587,7 +587,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
                 */
                if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST)
                        break;
-               delay_msec *= 2;
+
                if (delay_msec > TPM2_DURATION_LONG) {
                        if (rc == TPM2_RC_RETRY)
                                dev_err(&chip->dev, "in retry loop\n");
@@ -597,6 +597,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
                        break;
                }
                tpm_msleep(delay_msec);
+               delay_msec *= 2;
                memcpy(buf, save, save_size);
        }
        return ret;
index 7f2d0f489e9c0a95bc530abfb55306faf716e9db..4426649e431c7a58e21312c464161d4684b31908 100644 (file)
@@ -53,7 +53,10 @@ enum tpm_const {
 enum tpm_timeout {
        TPM_TIMEOUT = 5,        /* msecs */
        TPM_TIMEOUT_RETRY = 100, /* msecs */
-       TPM_TIMEOUT_RANGE_US = 300      /* usecs */
+       TPM_TIMEOUT_RANGE_US = 300,     /* usecs */
+       TPM_TIMEOUT_POLL = 1,   /* msecs */
+       TPM_TIMEOUT_USECS_MIN = 100,      /* usecs */
+       TPM_TIMEOUT_USECS_MAX = 500      /* usecs */
 };
 
 /* TPM addresses */
@@ -590,33 +593,6 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
 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
diff --git a/drivers/char/tpm/tpm1_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c
deleted file mode 100644 (file)
index add798b..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * Copyright (C) 2005, 2012 IBM Corporation
- *
- * Authors:
- *     Kent Yoder <key@linux.vnet.ibm.com>
- *     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 created by a system's firmware / BIOS
- *
- * 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/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"
-
-
-static const char* tcpa_event_type_strings[] = {
-       "PREBOOT",
-       "POST CODE",
-       "",
-       "NO ACTION",
-       "SEPARATOR",
-       "ACTION",
-       "EVENT TAG",
-       "S-CRTM Contents",
-       "S-CRTM Version",
-       "CPU Microcode",
-       "Platform Config Flags",
-       "Table of Devices",
-       "Compact Hash",
-       "IPL",
-       "IPL Partition Data",
-       "Non-Host Code",
-       "Non-Host Config",
-       "Non-Host Info"
-};
-
-static const char* tcpa_pc_event_id_strings[] = {
-       "",
-       "SMBIOS",
-       "BIS Certificate",
-       "POST BIOS ",
-       "ESCD ",
-       "CMOS",
-       "NVRAM",
-       "Option ROM",
-       "Option ROM config",
-       "",
-       "Option ROM microcode ",
-       "S-CRTM Version",
-       "S-CRTM Contents ",
-       "POST Contents ",
-       "Table of Devices",
-};
-
-/* returns pointer to start of pos. entry of tcg log */
-static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos)
-{
-       loff_t i;
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       void *addr = log->bios_event_log;
-       void *limit = log->bios_event_log_end;
-       struct tcpa_event *event;
-       u32 converted_event_size;
-       u32 converted_event_type;
-
-
-       /* read over *pos measurements */
-       for (i = 0; i < *pos; i++) {
-               event = addr;
-
-               converted_event_size =
-                   do_endian_conversion(event->event_size);
-               converted_event_type =
-                   do_endian_conversion(event->event_type);
-
-               if ((addr + sizeof(struct tcpa_event)) < limit) {
-                       if ((converted_event_type == 0) &&
-                           (converted_event_size == 0))
-                               return NULL;
-                       addr += (sizeof(struct tcpa_event) +
-                                converted_event_size);
-               }
-       }
-
-       /* now check if current entry is valid */
-       if ((addr + sizeof(struct tcpa_event)) >= limit)
-               return NULL;
-
-       event = addr;
-
-       converted_event_size = do_endian_conversion(event->event_size);
-       converted_event_type = do_endian_conversion(event->event_type);
-
-       if (((converted_event_type == 0) && (converted_event_size == 0))
-           || ((addr + sizeof(struct tcpa_event) + converted_event_size)
-               >= limit))
-               return NULL;
-
-       return addr;
-}
-
-static void *tpm_bios_measurements_next(struct seq_file *m, void *v,
-                                       loff_t *pos)
-{
-       struct tcpa_event *event = v;
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       void *limit = log->bios_event_log_end;
-       u32 converted_event_size;
-       u32 converted_event_type;
-
-       converted_event_size = do_endian_conversion(event->event_size);
-
-       v += sizeof(struct tcpa_event) + converted_event_size;
-
-       /* now check if current entry is valid */
-       if ((v + sizeof(struct tcpa_event)) >= limit)
-               return NULL;
-
-       event = v;
-
-       converted_event_size = do_endian_conversion(event->event_size);
-       converted_event_type = do_endian_conversion(event->event_type);
-
-       if (((converted_event_type == 0) && (converted_event_size == 0)) ||
-           ((v + sizeof(struct tcpa_event) + converted_event_size) >= limit))
-               return NULL;
-
-       (*pos)++;
-       return v;
-}
-
-static void tpm_bios_measurements_stop(struct seq_file *m, void *v)
-{
-}
-
-static int get_event_name(char *dest, struct tcpa_event *event,
-                       unsigned char * event_entry)
-{
-       const char *name = "";
-       /* 41 so there is room for 40 data and 1 nul */
-       char data[41] = "";
-       int i, n_len = 0, d_len = 0;
-       struct tcpa_pc_event *pc_event;
-
-       switch (do_endian_conversion(event->event_type)) {
-       case PREBOOT:
-       case POST_CODE:
-       case UNUSED:
-       case NO_ACTION:
-       case SCRTM_CONTENTS:
-       case SCRTM_VERSION:
-       case CPU_MICROCODE:
-       case PLATFORM_CONFIG_FLAGS:
-       case TABLE_OF_DEVICES:
-       case COMPACT_HASH:
-       case IPL:
-       case IPL_PARTITION_DATA:
-       case NONHOST_CODE:
-       case NONHOST_CONFIG:
-       case NONHOST_INFO:
-               name = tcpa_event_type_strings[do_endian_conversion
-                                               (event->event_type)];
-               n_len = strlen(name);
-               break;
-       case SEPARATOR:
-       case ACTION:
-               if (MAX_TEXT_EVENT >
-                   do_endian_conversion(event->event_size)) {
-                       name = event_entry;
-                       n_len = do_endian_conversion(event->event_size);
-               }
-               break;
-       case EVENT_TAG:
-               pc_event = (struct tcpa_pc_event *)event_entry;
-
-               /* ToDo Row data -> Base64 */
-
-               switch (do_endian_conversion(pc_event->event_id)) {
-               case SMBIOS:
-               case BIS_CERT:
-               case CMOS:
-               case NVRAM:
-               case OPTION_ROM_EXEC:
-               case OPTION_ROM_CONFIG:
-               case S_CRTM_VERSION:
-                       name = tcpa_pc_event_id_strings[do_endian_conversion
-                                                       (pc_event->event_id)];
-                       n_len = strlen(name);
-                       break;
-               /* hash data */
-               case POST_BIOS_ROM:
-               case ESCD:
-               case OPTION_ROM_MICROCODE:
-               case S_CRTM_CONTENTS:
-               case POST_CONTENTS:
-                       name = tcpa_pc_event_id_strings[do_endian_conversion
-                                                       (pc_event->event_id)];
-                       n_len = strlen(name);
-                       for (i = 0; i < 20; i++)
-                               d_len += sprintf(&data[2*i], "%02x",
-                                               pc_event->event_data[i]);
-                       break;
-               default:
-                       break;
-               }
-       default:
-               break;
-       }
-
-       return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]",
-                       n_len, name, d_len, data);
-
-}
-
-static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v)
-{
-       struct tcpa_event *event = v;
-       struct tcpa_event temp_event;
-       char *temp_ptr;
-       int i;
-
-       memcpy(&temp_event, event, sizeof(struct tcpa_event));
-
-       /* convert raw integers for endianness */
-       temp_event.pcr_index = do_endian_conversion(event->pcr_index);
-       temp_event.event_type = do_endian_conversion(event->event_type);
-       temp_event.event_size = do_endian_conversion(event->event_size);
-
-       temp_ptr = (char *) &temp_event;
-
-       for (i = 0; i < (sizeof(struct tcpa_event) - 1) ; i++)
-               seq_putc(m, temp_ptr[i]);
-
-       temp_ptr = (char *) v;
-
-       for (i = (sizeof(struct tcpa_event) - 1);
-            i < (sizeof(struct tcpa_event) + temp_event.event_size); i++)
-               seq_putc(m, temp_ptr[i]);
-
-       return 0;
-
-}
-
-static int tpm_bios_measurements_release(struct inode *inode,
-                                        struct file *file)
-{
-       struct seq_file *seq = (struct seq_file *)file->private_data;
-       struct tpm_chip *chip = (struct tpm_chip *)seq->private;
-
-       put_device(&chip->dev);
-
-       return seq_release(inode, file);
-}
-
-static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v)
-{
-       int len = 0;
-       char *eventname;
-       struct tcpa_event *event = v;
-       unsigned char *event_entry =
-           (unsigned char *)(v + sizeof(struct tcpa_event));
-
-       eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL);
-       if (!eventname) {
-               printk(KERN_ERR "%s: ERROR - No Memory for event name\n ",
-                      __func__);
-               return -EFAULT;
-       }
-
-       /* 1st: PCR */
-       seq_printf(m, "%2d ", do_endian_conversion(event->pcr_index));
-
-       /* 2nd: SHA1 */
-       seq_printf(m, "%20phN", event->pcr_value);
-
-       /* 3rd: event type identifier */
-       seq_printf(m, " %02x", do_endian_conversion(event->event_type));
-
-       len += get_event_name(eventname, event, event_entry);
-
-       /* 4th: eventname <= max + \'0' delimiter */
-       seq_printf(m, " %s\n", eventname);
-
-       kfree(eventname);
-       return 0;
-}
-
-static const struct seq_operations tpm_ascii_b_measurements_seqops = {
-       .start = tpm_bios_measurements_start,
-       .next = tpm_bios_measurements_next,
-       .stop = tpm_bios_measurements_stop,
-       .show = tpm_ascii_bios_measurements_show,
-};
-
-static const struct seq_operations tpm_binary_b_measurements_seqops = {
-       .start = tpm_bios_measurements_start,
-       .next = tpm_bios_measurements_next,
-       .stop = tpm_bios_measurements_stop,
-       .show = tpm_binary_bios_measurements_show,
-};
-
-static int tpm_bios_measurements_open(struct inode *inode,
-                                           struct file *file)
-{
-       int err;
-       struct seq_file *seq;
-       struct tpm_chip_seqops *chip_seqops;
-       const struct seq_operations *seqops;
-       struct tpm_chip *chip;
-
-       inode_lock(inode);
-       if (!inode->i_private) {
-               inode_unlock(inode);
-               return -ENODEV;
-       }
-       chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
-       seqops = chip_seqops->seqops;
-       chip = chip_seqops->chip;
-       get_device(&chip->dev);
-       inode_unlock(inode);
-
-       /* now register seq file */
-       err = seq_open(file, seqops);
-       if (!err) {
-               seq = file->private_data;
-               seq->private = chip;
-       }
-
-       return err;
-}
-
-static const struct file_operations tpm_bios_measurements_ops = {
-       .owner = THIS_MODULE,
-       .open = tpm_bios_measurements_open,
-       .read = seq_read,
-       .llseek = seq_lseek,
-       .release = tpm_bios_measurements_release,
-};
-
-static int tpm_read_log(struct tpm_chip *chip)
-{
-       int rc;
-
-       if (chip->log.bios_event_log != NULL) {
-               dev_dbg(&chip->dev,
-                       "%s: ERROR - event log already initialized\n",
-                       __func__);
-               return -EFAULT;
-       }
-
-       rc = tpm_read_log_acpi(chip);
-       if (rc != -ENODEV)
-               return rc;
-
-       rc = tpm_read_log_efi(chip);
-       if (rc != -ENODEV)
-               return rc;
-
-       return tpm_read_log_of(chip);
-}
-
-/*
- * tpm_bios_log_setup() - Read the event log from the firmware
- * @chip: TPM chip to use.
- *
- * If an event log is found then the securityfs files are setup to
- * export it to userspace, otherwise nothing is done.
- *
- * Returns -ENODEV if the firmware has no event log or securityfs is not
- * supported.
- */
-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 < 0)
-               return rc;
-       log_version = rc;
-
-       cnt = 0;
-       chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
-       /* NOTE: securityfs_create_dir can return ENODEV if securityfs is
-        * compiled out. The caller should ignore the ENODEV return code.
-        */
-       if (IS_ERR(chip->bios_dir[cnt]))
-               goto err;
-       cnt++;
-
-       chip->bin_log_seqops.chip = chip;
-       if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
-               chip->bin_log_seqops.seqops =
-                       &tpm2_binary_b_measurements_seqops;
-       else
-               chip->bin_log_seqops.seqops =
-                       &tpm_binary_b_measurements_seqops;
-
-
-       chip->bios_dir[cnt] =
-           securityfs_create_file("binary_bios_measurements",
-                                  0440, chip->bios_dir[0],
-                                  (void *)&chip->bin_log_seqops,
-                                  &tpm_bios_measurements_ops);
-       if (IS_ERR(chip->bios_dir[cnt]))
-               goto err;
-       cnt++;
-
-       if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
-
-               chip->ascii_log_seqops.chip = chip;
-               chip->ascii_log_seqops.seqops =
-                       &tpm_ascii_b_measurements_seqops;
-
-               chip->bios_dir[cnt] =
-                       securityfs_create_file("ascii_bios_measurements",
-                                              0440, chip->bios_dir[0],
-                                              (void *)&chip->ascii_log_seqops,
-                                              &tpm_bios_measurements_ops);
-               if (IS_ERR(chip->bios_dir[cnt]))
-                       goto err;
-               cnt++;
-       }
-
-       return 0;
-
-err:
-       rc = PTR_ERR(chip->bios_dir[cnt]);
-       chip->bios_dir[cnt] = NULL;
-       tpm_bios_log_teardown(chip);
-       return rc;
-}
-
-void tpm_bios_log_teardown(struct tpm_chip *chip)
-{
-       int i;
-       struct inode *inode;
-
-       /* securityfs_remove currently doesn't take care of handling sync
-        * between removal and opening of pseudo files. To handle this, a
-        * workaround is added by making i_private = NULL here during removal
-        * and to check it during open(), both within inode_lock()/unlock().
-        * This design ensures that open() either safely gets kref or fails.
-        */
-       for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) {
-               if (chip->bios_dir[i]) {
-                       inode = d_inode(chip->bios_dir[i]);
-                       inode_lock(inode);
-                       inode->i_private = NULL;
-                       inode_unlock(inode);
-                       securityfs_remove(chip->bios_dir[i]);
-               }
-       }
-}
index 4e4014eabdb9c34776d1fbd71c3a8747fcca8c6f..6122d3276f7224a05f30dc9fe8094fc69f1bd695 100644 (file)
@@ -102,8 +102,9 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
                 * TPM_RC_REFERENCE_H0 means the session has been
                 * flushed outside the space
                 */
-               rc = -ENOENT;
+               *handle = 0;
                tpm_buf_destroy(&tbuf);
+               return -ENOENT;
        } else if (rc > 0) {
                dev_warn(&chip->dev, "%s: failed with a TPM error 0x%04X\n",
                         __func__, rc);
diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c
deleted file mode 100644 (file)
index 1ce4411..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2016 IBM Corporation
- *
- * Authors:
- *      Nayna Jain <nayna@linux.vnet.ibm.com>
- *
- * Access to TPM 2.0 event log as written by Firmware.
- * It assumes that writer of event log has followed TCG Specification
- * for Family "2.0" and written the event data in little endian.
- * With that, it doesn't need any endian conversion for structure
- * content.
- *
- * 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/tpm_eventlog.h>
-
-#include "tpm.h"
-
-/*
- * calc_tpm2_event_size() - calculate the event size, where event
- * is an entry in the TPM 2.0 event log. The event is of type Crypto
- * Agile Log Entry Format as defined in TCG EFI Protocol Specification
- * Family "2.0".
-
- * @event: event whose size is to be calculated.
- * @event_header: the first event in the event log.
- *
- * Returns size of the event. If it is an invalid event, returns 0.
- */
-static int calc_tpm2_event_size(struct tcg_pcr_event2 *event,
-                               struct tcg_pcr_event *event_header)
-{
-       struct tcg_efi_specid_event *efispecid;
-       struct tcg_event_field *event_field;
-       void *marker;
-       void *marker_start;
-       u32 halg_size;
-       size_t size;
-       u16 halg;
-       int i;
-       int j;
-
-       marker = event;
-       marker_start = marker;
-       marker = marker + sizeof(event->pcr_idx) + sizeof(event->event_type)
-               + sizeof(event->count);
-
-       efispecid = (struct tcg_efi_specid_event *)event_header->event;
-
-       /* Check if event is malformed. */
-       if (event->count > efispecid->num_algs)
-               return 0;
-
-       for (i = 0; i < event->count; i++) {
-               halg_size = sizeof(event->digests[i].alg_id);
-               memcpy(&halg, marker, halg_size);
-               marker = marker + halg_size;
-               for (j = 0; j < efispecid->num_algs; j++) {
-                       if (halg == efispecid->digest_sizes[j].alg_id) {
-                               marker +=
-                                       efispecid->digest_sizes[j].digest_size;
-                               break;
-                       }
-               }
-               /* Algorithm without known length. Such event is unparseable. */
-               if (j == efispecid->num_algs)
-                       return 0;
-       }
-
-       event_field = (struct tcg_event_field *)marker;
-       marker = marker + sizeof(event_field->event_size)
-               + event_field->event_size;
-       size = marker - marker_start;
-
-       if ((event->event_type == 0) && (event_field->event_size == 0))
-               return 0;
-
-       return size;
-}
-
-static void *tpm2_bios_measurements_start(struct seq_file *m, loff_t *pos)
-{
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       void *addr = log->bios_event_log;
-       void *limit = log->bios_event_log_end;
-       struct tcg_pcr_event *event_header;
-       struct tcg_pcr_event2 *event;
-       size_t size;
-       int i;
-
-       event_header = addr;
-       size = sizeof(struct tcg_pcr_event) - sizeof(event_header->event)
-               + event_header->event_size;
-
-       if (*pos == 0) {
-               if (addr + size < limit) {
-                       if ((event_header->event_type == 0) &&
-                           (event_header->event_size == 0))
-                               return NULL;
-                       return SEQ_START_TOKEN;
-               }
-       }
-
-       if (*pos > 0) {
-               addr += size;
-               event = addr;
-               size = calc_tpm2_event_size(event, event_header);
-               if ((addr + size >=  limit) || (size == 0))
-                       return NULL;
-       }
-
-       for (i = 0; i < (*pos - 1); i++) {
-               event = addr;
-               size = calc_tpm2_event_size(event, event_header);
-
-               if ((addr + size >= limit) || (size == 0))
-                       return NULL;
-               addr += size;
-       }
-
-       return addr;
-}
-
-static void *tpm2_bios_measurements_next(struct seq_file *m, void *v,
-                                        loff_t *pos)
-{
-       struct tcg_pcr_event *event_header;
-       struct tcg_pcr_event2 *event;
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       void *limit = log->bios_event_log_end;
-       size_t event_size;
-       void *marker;
-
-       event_header = log->bios_event_log;
-
-       if (v == SEQ_START_TOKEN) {
-               event_size = sizeof(struct tcg_pcr_event) -
-                       sizeof(event_header->event) + event_header->event_size;
-               marker = event_header;
-       } else {
-               event = v;
-               event_size = calc_tpm2_event_size(event, event_header);
-               if (event_size == 0)
-                       return NULL;
-               marker = event;
-       }
-
-       marker = marker + event_size;
-       if (marker >= limit)
-               return NULL;
-       v = marker;
-       event = v;
-
-       event_size = calc_tpm2_event_size(event, event_header);
-       if (((v + event_size) >= limit) || (event_size == 0))
-               return NULL;
-
-       (*pos)++;
-       return v;
-}
-
-static void tpm2_bios_measurements_stop(struct seq_file *m, void *v)
-{
-}
-
-static int tpm2_binary_bios_measurements_show(struct seq_file *m, void *v)
-{
-       struct tpm_chip *chip = m->private;
-       struct tpm_bios_log *log = &chip->log;
-       struct tcg_pcr_event *event_header = log->bios_event_log;
-       struct tcg_pcr_event2 *event = v;
-       void *temp_ptr;
-       size_t size;
-
-       if (v == SEQ_START_TOKEN) {
-               size = sizeof(struct tcg_pcr_event) -
-                       sizeof(event_header->event) + event_header->event_size;
-
-               temp_ptr = event_header;
-
-               if (size > 0)
-                       seq_write(m, temp_ptr, size);
-       } else {
-               size = calc_tpm2_event_size(event, event_header);
-               temp_ptr = event;
-               if (size > 0)
-                       seq_write(m, temp_ptr, size);
-       }
-
-       return 0;
-}
-
-const struct seq_operations tpm2_binary_b_measurements_seqops = {
-       .start = tpm2_bios_measurements_start,
-       .next = tpm2_bios_measurements_next,
-       .stop = tpm2_bios_measurements_stop,
-       .show = tpm2_binary_bios_measurements_show,
-};
index 7f78482cd157b263226261b4ff7166df283c56af..34fbc6cb097bd28134c156e4cf551143b1d3d117 100644 (file)
@@ -511,8 +511,10 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
 
        priv->regs_t = crb_map_res(dev, priv, &io_res, buf->control_address,
                                   sizeof(struct crb_regs_tail));
-       if (IS_ERR(priv->regs_t))
-               return PTR_ERR(priv->regs_t);
+       if (IS_ERR(priv->regs_t)) {
+               ret = PTR_ERR(priv->regs_t);
+               goto out_relinquish_locality;
+       }
 
        /*
         * PTT HW bug w/a: wake up the device to access
@@ -520,7 +522,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
         */
        ret = crb_cmd_ready(dev, priv);
        if (ret)
-               return ret;
+               goto out_relinquish_locality;
 
        pa_high = ioread32(&priv->regs_t->ctrl_cmd_pa_high);
        pa_low  = ioread32(&priv->regs_t->ctrl_cmd_pa_low);
@@ -565,6 +567,8 @@ out:
 
        crb_go_idle(dev, priv);
 
+out_relinquish_locality:
+
        __crb_relinquish_locality(dev, priv, 0);
 
        return ret;
diff --git a/drivers/char/tpm/tpm_eventlog_acpi.c b/drivers/char/tpm/tpm_eventlog_acpi.c
deleted file mode 100644 (file)
index 66f19e9..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 <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
deleted file mode 100644 (file)
index e3f9ffd..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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
deleted file mode 100644 (file)
index 96fd564..0000000
+++ /dev/null
@@ -1,82 +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 <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 5a1f47b43947c80ff3646f6787a4aadb7f224659..8b46aaa9e0492b84eb45b121ed6aabd7e41bef37 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,
@@ -90,7 +84,8 @@ again:
                }
        } else {
                do {
-                       tpm_msleep(TPM_POLL_SLEEP);
+                       usleep_range(TPM_TIMEOUT_USECS_MIN,
+                                    TPM_TIMEOUT_USECS_MAX);
                        status = chip->ops->status(chip);
                        if ((status & mask) == mask)
                                return 0;
@@ -143,13 +138,58 @@ static bool check_locality(struct tpm_chip *chip, int l)
        return false;
 }
 
+static bool locality_inactive(struct tpm_chip *chip, int l)
+{
+       struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+       int rc;
+       u8 access;
+
+       rc = tpm_tis_read8(priv, TPM_ACCESS(l), &access);
+       if (rc < 0)
+               return false;
+
+       if ((access & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
+           == TPM_ACCESS_VALID)
+               return true;
+
+       return false;
+}
+
 static int release_locality(struct tpm_chip *chip, int l)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+       unsigned long stop, timeout;
+       long rc;
 
        tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
 
-       return 0;
+       stop = jiffies + chip->timeout_a;
+
+       if (chip->flags & TPM_CHIP_FLAG_IRQ) {
+again:
+               timeout = stop - jiffies;
+               if ((long)timeout <= 0)
+                       return -1;
+
+               rc = wait_event_interruptible_timeout(priv->int_queue,
+                                                     (locality_inactive(chip, l)),
+                                                     timeout);
+
+               if (rc > 0)
+                       return 0;
+
+               if (rc == -ERESTARTSYS && freezing(current)) {
+                       clear_thread_flag(TIF_SIGPENDING);
+                       goto again;
+               }
+       } else {
+               do {
+                       if (locality_inactive(chip, l))
+                               return 0;
+                       tpm_msleep(TPM_TIMEOUT);
+               } while (time_before(jiffies, stop));
+       }
+       return -1;
 }
 
 static int request_locality(struct tpm_chip *chip, int l)
@@ -234,7 +274,7 @@ static int get_burstcount(struct tpm_chip *chip)
                burstcnt = (value >> 8) & 0xFFFF;
                if (burstcnt)
                        return burstcnt;
-               tpm_msleep(TPM_POLL_SLEEP);
+               usleep_range(TPM_TIMEOUT_USECS_MIN, TPM_TIMEOUT_USECS_MAX);
        } while (time_before(jiffies, stop));
        return -EBUSY;
 }