diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 20:25:11 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 20:25:11 -0800 |
commit | 8cc748aa76c921d8834ef00f762f31acd2c93aa8 (patch) | |
tree | 764b0ba9b9c16658bbb1077458605dc3faac0411 /drivers | |
parent | 7184487f14eb7c2fcf8337bb16c6a63b6db1252e (diff) | |
parent | 04f81f0154e4bf002be6f4d85668ce1257efa4d9 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
"Highlights:
- Smack adds secmark support for Netfilter
- /proc/keys is now mandatory if CONFIG_KEYS=y
- TPM gets its own device class
- Added TPM 2.0 support
- Smack file hook rework (all Smack users should review this!)"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (64 commits)
cipso: don't use IPCB() to locate the CIPSO IP option
SELinux: fix error code in policydb_init()
selinux: add security in-core xattr support for pstore and debugfs
selinux: quiet the filesystem labeling behavior message
selinux: Remove unused function avc_sidcmp()
ima: /proc/keys is now mandatory
Smack: Repair netfilter dependency
X.509: silence asn1 compiler debug output
X.509: shut up about included cert for silent build
KEYS: Make /proc/keys unconditional if CONFIG_KEYS=y
MAINTAINERS: email update
tpm/tpm_tis: Add missing ifdef CONFIG_ACPI for pnp_acpi_device
smack: fix possible use after frees in task_security() callers
smack: Add missing logging in bidirectional UDS connect check
Smack: secmark support for netfilter
Smack: Rework file hooks
tpm: fix format string error in tpm-chip.c
char/tpm/tpm_crb: fix build error
smack: Fix a bidirectional UDS connect check typo
smack: introduce a special case for tmpfs in smack_d_instantiate()
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/tpm/Kconfig | 15 | ||||
-rw-r--r-- | drivers/char/tpm/Makefile | 5 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 256 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-dev.c | 42 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 263 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-sysfs.c | 29 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 124 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 617 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_atmel.c | 25 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_crb.c | 354 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_atmel.c | 52 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 43 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_nuvoton.c | 69 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_stm_st33.c | 666 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_stm_st33.h | 61 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.c | 27 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.h | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 51 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_nsc.c | 34 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_of.c | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ppi.c | 141 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 276 | ||||
-rw-r--r-- | drivers/char/tpm/xen-tpmfront.c | 14 |
23 files changed, 2231 insertions, 937 deletions
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index c54cac3f8bc8..9d4e37549eb2 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -100,15 +100,15 @@ config TCG_IBMVTPM will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be called tpm_ibmvtpm. -config TCG_ST33_I2C - tristate "STMicroelectronics ST33 I2C TPM" +config TCG_TIS_I2C_ST33 + tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)" depends on I2C depends on GPIOLIB ---help--- If you have a TPM security chip from STMicroelectronics working with an I2C bus say Yes and it will be accessible from within Linux. To compile this driver as a module, choose M here; the module will be - called tpm_stm_st33_i2c. + called tpm_i2c_stm_st33. config TCG_XEN tristate "XEN TPM Interface" @@ -122,4 +122,13 @@ config TCG_XEN To compile this driver as a module, choose M here; the module will be called xen-tpmfront. +config TCG_CRB + tristate "TPM 2.0 CRB Interface" + depends on X86 && ACPI + ---help--- + If you have a TPM security chip that is compliant with the + TCG CRB 2.0 TPM specification say Yes and it will be accessible + from within Linux. To compile this driver as a module, choose + M here; the module will be called tpm_crb. + endif # TCG_TPM diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 4d85dd681b81..990cf183931d 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,7 +2,7 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o tpm-$(CONFIG_ACPI) += tpm_ppi.o ifdef CONFIG_ACPI @@ -20,5 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o -obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o +obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o +obj-$(CONFIG_TCG_CRB) += tpm_crb.o diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c new file mode 100644 index 000000000000..1d278ccd751f --- /dev/null +++ b/drivers/char/tpm/tpm-chip.c @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2004 IBM Corporation + * Copyright (C) 2014 Intel Corporation + * + * Authors: + * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> + * Leendert van Doorn <leendert@watson.ibm.com> + * Dave Safford <safford@watson.ibm.com> + * Reiner Sailer <sailer@watson.ibm.com> + * Kylene Hall <kjhall@us.ibm.com> + * + * Maintained by: <tpmdd-devel@lists.sourceforge.net> + * + * TPM chip management routines. + * + * 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, version 2 of the + * License. + * + */ + +#include <linux/poll.h> +#include <linux/slab.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/freezer.h> +#include <linux/major.h> +#include "tpm.h" +#include "tpm_eventlog.h" + +static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); +static LIST_HEAD(tpm_chip_list); +static DEFINE_SPINLOCK(driver_lock); + +struct class *tpm_class; +dev_t tpm_devt; + +/* + * tpm_chip_find_get - return tpm_chip for a given chip number + * @chip_num the device number for the chip + */ +struct tpm_chip *tpm_chip_find_get(int chip_num) +{ + struct tpm_chip *pos, *chip = NULL; + + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { + if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) + continue; + + if (try_module_get(pos->pdev->driver->owner)) { + chip = pos; + break; + } + } + rcu_read_unlock(); + return chip; +} + +/** + * tpm_dev_release() - free chip memory and the device number + * @dev: the character device for the TPM chip + * + * This is used as the release function for the character device. + */ +static void tpm_dev_release(struct device *dev) +{ + struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); + + spin_lock(&driver_lock); + clear_bit(chip->dev_num, dev_mask); + spin_unlock(&driver_lock); + kfree(chip); +} + +/** + * tpmm_chip_alloc() - allocate a new struct tpm_chip instance + * @dev: device to which the chip is associated + * @ops: struct tpm_class_ops instance + * + * Allocates a new struct tpm_chip instance and assigns a free + * device number for it. Caller does not have to worry about + * freeing the allocated resources. When the devices is removed + * devres calls tpmm_chip_remove() to do the job. + */ +struct tpm_chip *tpmm_chip_alloc(struct device *dev, + const struct tpm_class_ops *ops) +{ + struct tpm_chip *chip; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return ERR_PTR(-ENOMEM); + + mutex_init(&chip->tpm_mutex); + INIT_LIST_HEAD(&chip->list); + + chip->ops = ops; + + spin_lock(&driver_lock); + chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); + spin_unlock(&driver_lock); + + if (chip->dev_num >= TPM_NUM_DEVICES) { + dev_err(dev, "No available tpm device numbers\n"); + kfree(chip); + return ERR_PTR(-ENOMEM); + } + + set_bit(chip->dev_num, dev_mask); + + scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); + + chip->pdev = dev; + + dev_set_drvdata(dev, chip); + + chip->dev.class = tpm_class; + chip->dev.release = tpm_dev_release; + chip->dev.parent = chip->pdev; + + if (chip->dev_num == 0) + chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); + else + chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); + + dev_set_name(&chip->dev, "%s", chip->devname); + + device_initialize(&chip->dev); + + chip->cdev.owner = chip->pdev->driver->owner; + cdev_init(&chip->cdev, &tpm_fops); + + return chip; +} +EXPORT_SYMBOL_GPL(tpmm_chip_alloc); + +static int tpm_dev_add_device(struct tpm_chip *chip) +{ + int rc; + + rc = device_add(&chip->dev); + if (rc) { + dev_err(&chip->dev, + "unable to device_register() %s, major %d, minor %d, err=%d\n", + chip->devname, MAJOR(chip->dev.devt), + MINOR(chip->dev.devt), rc); + + return rc; + } + + rc = cdev_add(&chip->cdev, chip->dev.devt, 1); + if (rc) { + dev_err(&chip->dev, + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", + chip->devname, MAJOR(chip->dev.devt), + MINOR(chip->dev.devt), rc); + + device_unregister(&chip->dev); + return rc; + } + + return rc; +} + +static void tpm_dev_del_device(struct tpm_chip *chip) +{ + cdev_del(&chip->cdev); + device_unregister(&chip->dev); +} + +/* + * tpm_chip_register() - create a character device for the TPM chip + * @chip: TPM chip to use. + * + * Creates a character device for the TPM chip and adds sysfs interfaces for + * the device, PPI and TCPA. As the last step this function adds the + * chip to the list of TPM chips available for use. + * + * NOTE: This function should be only called after the chip initialization + * is complete. + * + * Called from tpm_<specific>.c probe function only for devices + * the driver has determined it should claim. Prior to calling + * this function the specific probe function has called pci_enable_device + * upon errant exit from this function specific probe function should call + * pci_disable_device + */ +int tpm_chip_register(struct tpm_chip *chip) +{ + int rc; + + rc = tpm_dev_add_device(chip); + if (rc) + return rc; + + /* Populate sysfs for TPM1 devices. */ + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + rc = tpm_sysfs_add_device(chip); + if (rc) + goto del_misc; + + rc = tpm_add_ppi(chip); + if (rc) + goto del_sysfs; + + chip->bios_dir = tpm_bios_log_setup(chip->devname); + } + + /* Make the chip available. */ + spin_lock(&driver_lock); + list_add_rcu(&chip->list, &tpm_chip_list); + spin_unlock(&driver_lock); + + chip->flags |= TPM_CHIP_FLAG_REGISTERED; + + return 0; +del_sysfs: + tpm_sysfs_del_device(chip); +del_misc: + tpm_dev_del_device(chip); + return rc; +} +EXPORT_SYMBOL_GPL(tpm_chip_register); + +/* + * tpm_chip_unregister() - release the TPM driver + * @chip: TPM chip to use. + * + * Takes the chip first away from the list of available TPM chips and then + * cleans up all the resources reserved by tpm_chip_register(). + * + * NOTE: This function should be only called before deinitializing chip + * resources. + */ +void tpm_chip_unregister(struct tpm_chip *chip) +{ + if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) + return; + + spin_lock(&driver_lock); + list_del_rcu(&chip->list); + spin_unlock(&driver_lock); + synchronize_rcu(); + + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { + if (chip->bios_dir) + tpm_bios_log_teardown(chip->bios_dir); + tpm_remove_ppi(chip); + tpm_sysfs_del_device(chip); + } + + tpm_dev_del_device(chip); +} +EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index d9b774e02a1f..de0337ebd658 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -17,7 +17,6 @@ * License. * */ -#include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/uaccess.h> #include "tpm.h" @@ -54,16 +53,15 @@ static void timeout_work(struct work_struct *work) static int tpm_open(struct inode *inode, struct file *file) { - struct miscdevice *misc = file->private_data; - struct tpm_chip *chip = container_of(misc, struct tpm_chip, - vendor.miscdev); + struct tpm_chip *chip = + container_of(inode->i_cdev, struct tpm_chip, cdev); struct file_priv *priv; /* It's assured that the chip will be opened just once, * by the check of is_open variable, which is protected * by driver_lock. */ if (test_and_set_bit(0, &chip->is_open)) { - dev_dbg(chip->dev, "Another process owns this TPM\n"); + dev_dbg(chip->pdev, "Another process owns this TPM\n"); return -EBUSY; } @@ -81,7 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file) INIT_WORK(&priv->work, timeout_work); file->private_data = priv; - get_device(chip->dev); + get_device(chip->pdev); return 0; } @@ -168,12 +166,12 @@ static int tpm_release(struct inode *inode, struct file *file) file->private_data = NULL; atomic_set(&priv->data_pending, 0); clear_bit(0, &priv->chip->is_open); - put_device(priv->chip->dev); + put_device(priv->chip->pdev); kfree(priv); return 0; } -static const struct file_operations tpm_fops = { +const struct file_operations tpm_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .open = tpm_open, @@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = { .release = tpm_release, }; -int tpm_dev_add_device(struct tpm_chip *chip) -{ - int rc; - chip->vendor.miscdev.fops = &tpm_fops; - if (chip->dev_num == 0) - chip->vendor.miscdev.minor = TPM_MINOR; - else - chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; - - chip->vendor.miscdev.name = chip->devname; - chip->vendor.miscdev.parent = chip->dev; - - rc = misc_register(&chip->vendor.miscdev); - if (rc) { - chip->vendor.miscdev.name = NULL; - dev_err(chip->dev, - "unable to misc_register %s, minor %d err=%d\n", - chip->vendor.miscdev.name, - chip->vendor.miscdev.minor, rc); - } - return rc; -} - -void tpm_dev_del_device(struct tpm_chip *chip) -{ - if (chip->vendor.miscdev.name) - misc_deregister(&chip->vendor.miscdev); -} diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 6af17002a115..bf53a3771da5 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2004 IBM Corporation + * Copyright (C) 2014 Intel Corporation * * Authors: * Leendert van Doorn <leendert@watson.ibm.com> @@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644); MODULE_PARM_DESC(suspend_pcr, "PCR to use for dummy writes to faciltate flush on suspend."); -static LIST_HEAD(tpm_chip_list); -static DEFINE_SPINLOCK(driver_lock); -static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); - /* * Array with one entry per ordinal defining the maximum amount * of time the chip could take to return the result. The ordinal @@ -346,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (count == 0) return -ENODATA; if (count > bufsiz) { - dev_err(chip->dev, + dev_err(chip->pdev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } @@ -355,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { - dev_err(chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } @@ -363,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, if (chip->vendor.irq) goto out_recv; - stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal); + else + stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->ops->status(chip); if ((status & chip->ops->req_complete_mask) == @@ -371,7 +371,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, goto out_recv; if (chip->ops->req_canceled(chip, status)) { - dev_err(chip->dev, "Operation Canceled\n"); + dev_err(chip->pdev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } @@ -381,14 +381,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, } while (time_before(jiffies, stop)); chip->ops->cancel(chip); - dev_err(chip->dev, "Operation Timed out\n"); + dev_err(chip->pdev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) - dev_err(chip->dev, + dev_err(chip->pdev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: mutex_unlock(&chip->tpm_mutex); @@ -398,9 +398,10 @@ out: #define TPM_DIGEST_SIZE 20 #define TPM_RET_CODE_IDX 6 -static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, - int len, const char *desc) +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, + int len, const char *desc) { + struct tpm_output_header *header; int err; len = tpm_transmit(chip, (u8 *) cmd, len); @@ -409,9 +410,12 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, else if (len < TPM_HEADER_SIZE) return -EFAULT; - err = be32_to_cpu(cmd->header.out.return_code); + header = cmd; + + err = be32_to_cpu(header->return_code); if (err != 0 && desc) - dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err, + desc); return err; } @@ -448,7 +452,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = subcap_id; } - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -464,8 +468,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip) tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the timeouts"); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the timeouts"); } EXPORT_SYMBOL_GPL(tpm_gen_interrupt); @@ -483,9 +487,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) { struct tpm_cmd_t start_cmd; start_cmd.header.in = tpm_startup_header; + start_cmd.params.startup_in.startup_type = startup_type; - return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to start the TPM"); + return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to start the TPM"); } int tpm_get_timeouts(struct tpm_chip *chip) @@ -500,12 +505,12 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ - dev_info(chip->dev, "Issuing TPM_STARTUP"); + dev_info(chip->pdev, "Issuing TPM_STARTUP"); if (tpm_startup(chip, TPM_ST_CLEAR)) return rc; @@ -513,11 +518,11 @@ int tpm_get_timeouts(struct tpm_chip *chip) tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL); } if (rc) { - dev_err(chip->dev, + dev_err(chip->pdev, "A TPM error (%zd) occurred attempting to determine the timeouts\n", rc); goto duration; @@ -556,7 +561,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) /* Report adjusted timeouts */ if (chip->vendor.timeout_adjusted) { - dev_info(chip->dev, + dev_info(chip->pdev, HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n", old_timeout[0], new_timeout[0], old_timeout[1], new_timeout[1], @@ -575,8 +580,8 @@ duration: tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - "attempting to determine the durations"); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + "attempting to determine the durations"); if (rc) return rc; @@ -603,7 +608,7 @@ duration: chip->vendor.duration[TPM_MEDIUM] *= 1000; chip->vendor.duration[TPM_LONG] *= 1000; chip->vendor.duration_adjusted = true; - dev_info(chip->dev, "Adjusting TPM timeout parameters."); + dev_info(chip->pdev, "Adjusting TPM timeout parameters."); } return 0; } @@ -631,32 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip) struct tpm_cmd_t cmd; cmd.header.in = continue_selftest_header; - rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, - "continue selftest"); + rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, + "continue selftest"); return rc; } -/* - * tpm_chip_find_get - return tpm_chip for given chip number - */ -static struct tpm_chip *tpm_chip_find_get(int chip_num) -{ - struct tpm_chip *pos, *chip = NULL; - - rcu_read_lock(); - list_for_each_entry_rcu(pos, &tpm_chip_list, list) { - if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) - continue; - - if (try_module_get(pos->dev->driver->owner)) { - chip = pos; - break; - } - } - rcu_read_unlock(); - return chip; -} - #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 static struct tpm_input_header pcrread_header = { @@ -672,8 +656,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) cmd.header.in = pcrread_header; cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx); - rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, - "attempting to read a pcr value"); + rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + "attempting to read a pcr value"); if (rc == 0) memcpy(res_buf, cmd.params.pcrread_out.pcr_result, @@ -700,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; - rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); + if (chip->flags & TPM_CHIP_FLAG_TPM2) + rc = tpm2_pcr_read(chip, pcr_idx, res_buf); + else + rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); tpm_chip_put(chip); return rc; } @@ -734,11 +721,17 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + rc = tpm2_pcr_extend(chip, pcr_idx, hash); + tpm_chip_put(chip); + return rc; + } + cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "attempting extend a PCR value"); + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "attempting extend a PCR value"); tpm_chip_put(chip); return rc; @@ -781,7 +774,7 @@ int tpm_do_selftest(struct tpm_chip *chip) * around 300ms while the self test is ongoing, keep trying * until the self test duration expires. */ if (rc == -ETIME) { - dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test"); + dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test"); msleep(delay_msec); continue; } @@ -791,7 +784,7 @@ int tpm_do_selftest(struct tpm_chip *chip) rc = be32_to_cpu(cmd.header.out.return_code); if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { - dev_info(chip->dev, + dev_info(chip->pdev, "TPM is disabled/deactivated (0x%X)\n", rc); /* TPM is disabled and/or deactivated; driver can * proceed and TPM does handle commands for @@ -817,7 +810,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) if (chip == NULL) return -ENODEV; - rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); + rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd"); tpm_chip_put(chip); return rc; @@ -884,30 +877,6 @@ again: } EXPORT_SYMBOL_GPL(wait_for_tpm_stat); -void tpm_remove_hardware(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - if (chip == NULL) { - dev_err(dev, "No device data found\n"); - return; - } - - spin_lock(&driver_lock); - list_del_rcu(&chip->list); - spin_unlock(&driver_lock); - synchronize_rcu(); - - tpm_dev_del_device(chip); - tpm_sysfs_del_device(chip); - tpm_remove_ppi(&dev->kobj); - tpm_bios_log_teardown(chip->bios_dir); - - /* write it this way to be explicit (chip->dev == dev) */ - put_device(chip->dev); -} -EXPORT_SYMBOL_GPL(tpm_remove_hardware); - #define TPM_ORD_SAVESTATE cpu_to_be32(152) #define SAVESTATE_RESULT_SIZE 10 @@ -932,20 +901,23 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return tpm2_shutdown(chip, TPM2_SU_CLEAR); + /* for buggy tpm, flush pcrs with extend to selected dummy */ if (tpm_suspend_pcr) { cmd.header.in = pcrextend_header; cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, - "extending dummy pcr before suspend"); + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + "extending dummy pcr before suspend"); } /* now do the actual savestate */ for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; - rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); + rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); /* * If the TPM indicates that it is too busy to respond to @@ -963,10 +935,10 @@ int tpm_pm_suspend(struct device *dev) } if (rc) - dev_err(chip->dev, + dev_err(chip->pdev, "Error (%d) sending savestate before suspend\n", rc); else if (try > 0) - dev_warn(chip->dev, "TPM savestate took %dms\n", + dev_warn(chip->pdev, "TPM savestate took %dms\n", try * TPM_TIMEOUT_RETRY); return rc; @@ -1018,11 +990,17 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { + err = tpm2_get_random(chip, out, max); + tpm_chip_put(chip); + return err; + } + do { tpm_cmd.header.in = tpm_getrandom_header; tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); - err = transmit_cmd(chip, &tpm_cmd, + err = tpm_transmit_cmd(chip, &tpm_cmd, TPM_GETRANDOM_RESULT_SIZE + num_bytes, "attempting get random"); if (err) @@ -1041,103 +1019,34 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) } EXPORT_SYMBOL_GPL(tpm_get_random); -/* In case vendor provided release function, call it too.*/ - -void tpm_dev_vendor_release(struct tpm_chip *chip) +static int __init tpm_init(void) { - if (!chip) - return; - - clear_bit(chip->dev_num, dev_mask); -} -EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); - - -/* - * Once all references to platform device are down to 0, - * release all allocated structures. - */ -static void tpm_dev_release(struct device *dev) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); + int rc; - if (!chip) - return; + tpm_class = class_create(THIS_MODULE, "tpm"); + if (IS_ERR(tpm_class)) { + pr_err("couldn't create tpm class\n"); + return PTR_ERR(tpm_class); + } - tpm_dev_vendor_release(chip); + rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm"); + if (rc < 0) { + pr_err("tpm: failed to allocate char dev region\n"); + class_destroy(tpm_class); + return rc; + } - chip->release(dev); - kfree(chip); + return 0; } -/* - * Called from tpm_<specific>.c probe function only for devices - * the driver has determined it should claim. Prior to calling - * this function the specific probe function has called pci_enable_device - * upon errant exit from this function specific probe function should call - * pci_disable_device - */ -struct tpm_chip *tpm_register_hardware(struct device *dev, - const struct tpm_class_ops *ops) +static void __exit tpm_exit(void) { - struct tpm_chip *chip; - - /* Driver specific per-device data */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - - if (chip == NULL) - return NULL; - - mutex_init(&chip->tpm_mutex); - INIT_LIST_HEAD(&chip->list); - - chip->ops = ops; - chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); - - if (chip->dev_num >= TPM_NUM_DEVICES) { - dev_err(dev, "No available tpm device numbers\n"); - goto out_free; - } - - set_bit(chip->dev_num, dev_mask); - - scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm", - chip->dev_num); - - chip->dev = get_device(dev); - chip->release = dev->release; - dev->release = tpm_dev_release; - dev_set_drvdata(dev, chip); - - if (tpm_dev_add_device(chip)) - goto put_device; - - if (tpm_sysfs_add_device(chip)) - goto del_misc; - - if (tpm_add_ppi(&dev->kobj)) - goto del_sysfs; - - chip->bios_dir = tpm_bios_log_setup(chip->devname); - - /* Make chip available */ - spin_lock(&driver_lock); - list_add_rcu(&chip->list, &tpm_chip_list); |