diff options
Diffstat (limited to 'drivers/char')
34 files changed, 1069 insertions, 425 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fde005e..31adbeb 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -46,6 +46,7 @@ config SGI_MBCS say Y or M here, otherwise say N. source "drivers/tty/serial/Kconfig" +source "drivers/tty/serdev/Kconfig" config TTY_PRINTK tristate "TTY driver to output user messages via printk" @@ -571,9 +572,12 @@ config TELCLOCK controlling the behavior of this hardware. config DEVPORT - bool + bool "/dev/port character device" depends on ISA || PCI default y + help + Say Y here if you want to support the /dev/port device. The /dev/port + device is similar to /dev/mem, but for I/O ports. source "drivers/s390/char/Kconfig" diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index dd9dfa1..1dfb9f8 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -31,13 +31,6 @@ #include <linux/kthread.h> #include <linux/delay.h> - -/* - * The apm_bios device is one of the misc char devices. - * This is its minor number. - */ -#define APM_MINOR_DEV 134 - /* * One option can be changed at boot time as follows: * apm=on/off enable/disable APM diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c index 7d34b20..c614a56 100644 --- a/drivers/char/ds1302.c +++ b/drivers/char/ds1302.c @@ -17,7 +17,6 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/module.h> -#include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/bcd.h> #include <linux/mutex.h> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index ceff2fc..0cafe08 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -172,8 +172,8 @@ config HW_RANDOM_OMAP default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number - Generator hardware found on OMAP16xx, OMAP2/3/4/5 and AM33xx/AM43xx - multimedia processors. + Generator hardware found on OMAP16xx, OMAP2/3/4/5, AM33xx/AM43xx + multimedia processors, and Marvell Armada 7k/8k SoCs. To compile this driver as a module, choose M here: the module will be called omap-rng. diff --git a/drivers/char/hw_random/cavium-rng-vf.c b/drivers/char/hw_random/cavium-rng-vf.c index 066ae0e..dd1007a 100644 --- a/drivers/char/hw_random/cavium-rng-vf.c +++ b/drivers/char/hw_random/cavium-rng-vf.c @@ -57,7 +57,11 @@ static int cavium_rng_probe_vf(struct pci_dev *pdev, return -ENOMEM; } - rng->ops.name = "cavium rng"; + rng->ops.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "cavium-rng-%s", dev_name(&pdev->dev)); + if (!rng->ops.name) + return -ENOMEM; + rng->ops.read = cavium_rng_read; rng->ops.quality = 1000; diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 87fba42..5c654b5 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -1,55 +1,30 @@ /* - Added support for the AMD Geode LX RNG - (c) Copyright 2004-2005 Advanced Micro Devices, Inc. - - derived from - - Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) - (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> - - derived from - - Hardware driver for the AMD 768 Random Number Generator (RNG) - (c) Copyright 2001 Red Hat Inc <alan@redhat.com> - - derived from - - Hardware driver for Intel i810 Random Number Generator (RNG) - Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> - Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> - - Added generic RNG API - Copyright 2006 Michael Buesch <m@bues.ch> - Copyright 2005 (c) MontaVista Software, Inc. - - Please read Documentation/hw_random.txt for details on use. - - ---------------------------------------------------------- - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - + * hw_random/core.c: HWRNG core API + * + * Copyright 2006 Michael Buesch <m@bues.ch> + * Copyright 2005 (c) MontaVista Software, Inc. + * + * Please read Documentation/hw_random.txt for details on use. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. */ - +#include <linux/delay.h> #include <linux/device.h> +#include <linux/err.h> +#include <linux/fs.h> #include <linux/hw_random.h> -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/sched.h> -#include <linux/miscdevice.h> #include <linux/kthread.h> -#include <linux/delay.h> -#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/module.h> #include <linux/random.h> -#include <linux/err.h> +#include <linux/sched.h> +#include <linux/slab.h> #include <linux/uaccess.h> - #define RNG_MODULE_NAME "hw_random" -#define PFX RNG_MODULE_NAME ": " -#define RNG_MISCDEV_MINOR 183 /* official */ - static struct hwrng *current_rng; static struct task_struct *hwrng_fill; @@ -296,7 +271,6 @@ out_put: goto out; } - static const struct file_operations rng_chrdev_ops = { .owner = THIS_MODULE, .open = rng_dev_open, @@ -307,14 +281,13 @@ static const struct file_operations rng_chrdev_ops = { static const struct attribute_group *rng_dev_groups[]; static struct miscdevice rng_miscdev = { - .minor = RNG_MISCDEV_MINOR, + .minor = HWRNG_MINOR, .name = RNG_MODULE_NAME, .nodename = "hwrng", .fops = &rng_chrdev_ops, .groups = rng_dev_groups, }; - static ssize_t hwrng_attr_current_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) @@ -444,8 +417,7 @@ int hwrng_register(struct hwrng *rng) int err = -EINVAL; struct hwrng *old_rng, *tmp; - if (rng->name == NULL || - (rng->data_read == NULL && rng->read == NULL)) + if (!rng->name || (!rng->data_read && !rng->read)) goto out; mutex_lock(&rng_mutex); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 3b06c1d6..31cbdbb 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -21,11 +21,11 @@ #define DRV_MODULE_NAME "n2rng" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.2" -#define DRV_MODULE_RELDATE "July 27, 2011" +#define DRV_MODULE_VERSION "0.3" +#define DRV_MODULE_RELDATE "Jan 7, 2017" static char version[] = - DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); MODULE_DESCRIPTION("Niagara2 RNG driver"); @@ -302,26 +302,57 @@ static int n2rng_try_read_ctl(struct n2rng *np) return n2rng_hv_err_trans(hv_err); } -#define CONTROL_DEFAULT_BASE \ - ((2 << RNG_CTL_ASEL_SHIFT) | \ - (N2RNG_ACCUM_CYCLES_DEFAULT << RNG_CTL_WAIT_SHIFT) | \ - RNG_CTL_LFSR) - -#define CONTROL_DEFAULT_0 \ - (CONTROL_DEFAULT_BASE | \ - (1 << RNG_CTL_VCO_SHIFT) | \ - RNG_CTL_ES1) -#define CONTROL_DEFAULT_1 \ - (CONTROL_DEFAULT_BASE | \ - (2 << RNG_CTL_VCO_SHIFT) | \ - RNG_CTL_ES2) -#define CONTROL_DEFAULT_2 \ - (CONTROL_DEFAULT_BASE | \ - (3 << RNG_CTL_VCO_SHIFT) | \ - RNG_CTL_ES3) -#define CONTROL_DEFAULT_3 \ - (CONTROL_DEFAULT_BASE | \ - RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3) +static u64 n2rng_control_default(struct n2rng *np, int ctl) +{ + u64 val = 0; + + if (np->data->chip_version == 1) { + val = ((2 << RNG_v1_CTL_ASEL_SHIFT) | + (N2RNG_ACCUM_CYCLES_DEFAULT << RNG_v1_CTL_WAIT_SHIFT) | + RNG_CTL_LFSR); + + switch (ctl) { + case 0: + val |= (1 << RNG_v1_CTL_VCO_SHIFT) | RNG_CTL_ES1; + break; + case 1: + val |= (2 << RNG_v1_CTL_VCO_SHIFT) | RNG_CTL_ES2; + break; + case 2: + val |= (3 << RNG_v1_CTL_VCO_SHIFT) | RNG_CTL_ES3; + break; + case 3: + val |= RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3; + break; + default: + break; + } + + } else { + val = ((2 << RNG_v2_CTL_ASEL_SHIFT) | + (N2RNG_ACCUM_CYCLES_DEFAULT << RNG_v2_CTL_WAIT_SHIFT) | + RNG_CTL_LFSR); + + switch (ctl) { + case 0: + val |= (1 << RNG_v2_CTL_VCO_SHIFT) | RNG_CTL_ES1; + break; + case 1: + val |= (2 << RNG_v2_CTL_VCO_SHIFT) | RNG_CTL_ES2; + break; + case 2: + val |= (3 << RNG_v2_CTL_VCO_SHIFT) | RNG_CTL_ES3; + break; + case 3: + val |= RNG_CTL_ES1 | RNG_CTL_ES2 | RNG_CTL_ES3; + break; + default: + break; + } + } + + return val; +} static void n2rng_control_swstate_init(struct n2rng *np) { @@ -336,10 +367,10 @@ static void n2rng_control_swstate_init(struct n2rng *np) for (i = 0; i < np->num_units; i++) { struct n2rng_unit *up = &np->units[i]; - up->control[0] = CONTROL_DEFAULT_0; - up->control[1] = CONTROL_DEFAULT_1; - up->control[2] = CONTROL_DEFAULT_2; - up->control[3] = CONTROL_DEFAULT_3; + up->control[0] = n2rng_control_default(np, 0); + up->control[1] = n2rng_control_default(np, 1); + up->control[2] = n2rng_control_default(np, 2); + up->control[3] = n2rng_control_default(np, 3); } np->hv_state = HV_RNG_STATE_UNCONFIGURED; @@ -399,6 +430,7 @@ static int n2rng_data_read(struct hwrng *rng, u32 *data) } else { int err = n2rng_generic_read_data(ra); if (!err) { + np->flags |= N2RNG_FLAG_BUFFER_VALID; np->buffer = np->test_data >> 32; *data = np->test_data & 0xffffffff; len = 4; @@ -487,9 +519,21 @@ static void n2rng_dump_test_buffer(struct n2rng *np) static int n2rng_check_selftest_buffer(struct n2rng *np, unsigned long unit) { - u64 val = SELFTEST_VAL; + u64 val; int err, matches, limit; + switch (np->data->id) { + case N2_n2_rng: + case N2_vf_rng: + case N2_kt_rng: + case N2_m4_rng: /* yes, m4 uses the old value */ + val = RNG_v1_SELFTEST_VAL; + break; + default: + val = RNG_v2_SELFTEST_VAL; + break; + } + matches = 0; for (limit = 0; limit < SELFTEST_LOOPS_MAX; limit++) { matches += n2rng_test_buffer_find(np, val); @@ -512,14 +556,32 @@ static int n2rng_check_selftest_buffer(struct n2rng *np, unsigned long unit) static int n2rng_control_selftest(struct n2rng *np, unsigned long unit) { int err; + u64 base, base3; + + switch (np->data->id) { + case N2_n2_rng: + case N2_vf_rng: + case N2_kt_rng: + base = RNG_v1_CTL_ASEL_NOOUT << RNG_v1_CTL_ASEL_SHIFT; + base3 = base | RNG_CTL_LFSR | + ((RNG_v1_SELFTEST_TICKS - 2) << RNG_v1_CTL_WAIT_SHIFT); + break; + case N2_m4_rng: + base = RNG_v2_CTL_ASEL_NOOUT << RNG_v2_CTL_ASEL_SHIFT; + base3 = base | RNG_CTL_LFSR | + ((RNG_v1_SELFTEST_TICKS - 2) << RNG_v2_CTL_WAIT_SHIFT); + break; + default: + base = RNG_v2_CTL_ASEL_NOOUT << RNG_v2_CTL_ASEL_SHIFT; + base3 = base | RNG_CTL_LFSR | + (RNG_v2_SELFTEST_TICKS << RNG_v2_CTL_WAIT_SHIFT); + break; + } - np->test_control[0] = (0x2 << RNG_CTL_ASEL_SHIFT); - np->test_control[1] = (0x2 << RNG_CTL_ASEL_SHIFT); - np->test_control[2] = (0x2 << RNG_CTL_ASEL_SHIFT); - np->test_control[3] = ((0x2 << RNG_CTL_ASEL_SHIFT) | - RNG_CTL_LFSR | - ((SELFTEST_TICKS - 2) << RNG_CTL_WAIT_SHIFT)); - + np->test_control[0] = base; + np->test_control[1] = base; + np->test_control[2] = base; + np->test_control[3] = base3; err = n2rng_entropy_diag_read(np, unit, np->test_control, HV_RNG_STATE_HEALTHCHECK, @@ -557,11 +619,19 @@ static int n2rng_control_configure_units(struct n2rng *np) struct n2rng_unit *up = &np->units[unit]; unsigned long ctl_ra = __pa(&up->control[0]); int esrc; - u64 base; + u64 base, shift; - base = ((np->accum_cycles << RNG_CTL_WAIT_SHIFT) | - (2 << RNG_CTL_ASEL_SHIFT) | - RNG_CTL_LFSR); + if (np->data->chip_version == 1) { + base = ((np->accum_cycles << RNG_v1_CTL_WAIT_SHIFT) | + (RNG_v1_CTL_ASEL_NOOUT << RNG_v1_CTL_ASEL_SHIFT) | + RNG_CTL_LFSR); + shift = RNG_v1_CTL_VCO_SHIFT; + } else { + base = ((np->accum_cycles << RNG_v2_CTL_WAIT_SHIFT) | + (RNG_v2_CTL_ASEL_NOOUT << RNG_v2_CTL_ASEL_SHIFT) | + RNG_CTL_LFSR); + shift = RNG_v2_CTL_VCO_SHIFT; + } /* XXX This isn't the best. We should fetch a bunch * XXX of words using each entropy source combined XXX @@ -570,7 +640,7 @@ static int n2rng_control_configure_units(struct n2rng *np) */ for (esrc = 0; esrc < 3; esrc++) up->control[esrc] = base | - (esrc << RNG_CTL_VCO_SHIFT) | + (esrc << shift) | (RNG_CTL_ES1 << esrc); up->control[3] = base | @@ -589,6 +659,7 @@ static void n2rng_work(struct work_struct *work) { struct n2rng *np = container_of(work, struct n2rng, work.work); int err = 0; + static int retries = 4; if (!(np->flags & N2RNG_FLAG_CONTROL)) { err = n2rng_guest_check(np); @@ -606,7 +677,9 @@ static void n2rng_work(struct work_struct *work) dev_info(&np->op->dev, "RNG ready\n"); } - if (err && !(np->flags & N2RNG_FLAG_SHUTDOWN)) + if (--retries == 0) + dev_err(&np->op->dev, "Self-test retries failed, RNG not ready\n"); + else if (err && !(np->flags & N2RNG_FLAG_SHUTDOWN)) schedule_delayed_work(&np->work, HZ * 2); } @@ -622,24 +695,23 @@ static const struct of_device_id n2rng_match[]; static int n2rng_probe(struct platform_device *op) { const struct of_device_id *match; - int multi_capable; int err = -ENOMEM; struct n2rng *np; match = of_match_device(n2rng_match, &op->dev); if (!match) return -EINVAL; - multi_capable = (match->data != NULL); n2rng_driver_version(); np = devm_kzalloc(&op->dev, sizeof(*np), GFP_KERNEL); if (!np) goto out; np->op = op; + np->data = (struct n2rng_template *)match->data; INIT_DELAYED_WORK(&np->work, n2rng_work); - if (multi_capable) + if (np->data->multi_capable) np->flags |= N2RNG_FLAG_MULTI; err = -ENODEV; @@ -670,8 +742,9 @@ static int n2rng_probe(struct platform_device *op) dev_err(&op->dev, "VF RNG lacks rng-#units property\n"); goto out_hvapi_unregister; } - } else + } else { np->num_units = 1; + } dev_info(&op->dev, "Registered RNG HVAPI major %lu minor %lu\n", np->hvapi_major, np->hvapi_minor); @@ -692,7 +765,7 @@ static int n2rng_probe(struct platform_device *op) "multi-unit-capable" : "single-unit"), np->num_units); - np->hwrng.name = "n2rng"; + np->hwrng.name = DRV_MODULE_NAME; np->hwrng.data_read = n2rng_data_read; np->hwrng.priv = (unsigned long) np; @@ -728,30 +801,61 @@ static int n2rng_remove(struct platform_device *op) return 0; } +static struct n2rng_template n2_template = { + .id = N2_n2_rng, + .multi_capable = 0, + .chip_version = 1, +}; + +static struct n2rng_template vf_template = { + .id = N2_vf_rng, + .multi_capable = 1, + .chip_version = 1, +}; + +static struct n2rng_template kt_template = { + .id = N2_kt_rng, + .multi_capable = 1, + .chip_version = 1, +}; + +static struct n2rng_template m4_template = { + .id = N2_m4_rng, + .multi_capable = 1, + .chip_version = 2, +}; + +static struct n2rng_template m7_template = { + .id = N2_m7_rng, + .multi_capable = 1, + .chip_version = 2, +}; + static const struct of_device_id n2rng_match[] = { { .name = "random-number-generator", .compatible = "SUNW,n2-rng", + .data = &n2_template, }, { .name = "random-number-generator", .compatible = "SUNW,vf-rng", - .data = (void *) 1, + .data = &vf_template, }, { .name = "random-number-generator", .compatible = "SUNW,kt-rng", - .data = (void *) 1, + .data = &kt_template, }, { .name = "random-number-generator", .compatible = "ORCL,m4-rng", - .data = (void *) 1, + .data = &m4_template, }, { .name = "random-number-generator", .compatible = "ORCL,m7-rng", - .data = (void *) 1, + .data = &m7_template, }, {}, }; diff --git a/drivers/char/hw_random/n2rng.h b/drivers/char/hw_random/n2rng.h index f244ac8..6bad6cc 100644 --- a/drivers/char/hw_random/n2rng.h +++ b/drivers/char/hw_random/n2rng.h @@ -6,18 +6,34 @@ #ifndef _N2RNG_H #define _N2RNG_H -#define RNG_CTL_WAIT 0x0000000001fffe00ULL /* Minimum wait time */ -#define RNG_CTL_WAIT_SHIFT 9 -#define RNG_CTL_BYPASS 0x0000000000000100ULL /* VCO voltage source */ -#define RNG_CTL_VCO 0x00000000000000c0ULL /* VCO rate control */ -#define RNG_CTL_VCO_SHIFT 6 -#define RNG_CTL_ASEL 0x0000000000000030ULL /* Analog MUX select */ -#define RNG_CTL_ASEL_SHIFT 4 +/* ver1 devices - n2-rng, vf-rng, kt-rng */ +#define RNG_v1_CTL_WAIT 0x0000000001fffe00ULL /* Minimum wait time */ +#define RNG_v1_CTL_WAIT_SHIFT 9 +#define RNG_v1_CTL_BYPASS 0x0000000000000100ULL /* VCO voltage source */ +#define RNG_v1_CTL_VCO 0x00000000000000c0ULL /* VCO rate control */ +#define RNG_v1_CTL_VCO_SHIFT 6 +#define RNG_v1_CTL_ASEL 0x0000000000000030ULL /* Analog MUX select */ +#define RNG_v1_CTL_ASEL_SHIFT 4 +#define RNG_v1_CTL_ASEL_NOOUT 2 + +/* these are the same in v2 as in v1 */ #define RNG_CTL_LFSR 0x0000000000000008ULL /* Use LFSR or plain shift */ #define RNG_CTL_ES3 0x0000000000000004ULL /* Enable entropy source 3 */ #define RNG_CTL_ES2 0x0000000000000002ULL /* Enable entropy source 2 */ #define RNG_CTL_ES1 0x0000000000000001ULL /* Enable entropy source 1 */ +/* ver2 devices - m4-rng, m7-rng */ +#define RNG_v2_CTL_WAIT 0x0000000007fff800ULL /* Minimum wait time */ +#define RNG_v2_CTL_WAIT_SHIFT 12 +#define RNG_v2_CTL_BYPASS 0x0000000000000400ULL /* VCO voltage source */ +#define RNG_v2_CTL_VCO 0x0000000000000300ULL /* VCO rate control */ +#define RNG_v2_CTL_VCO_SHIFT 9 +#define RNG_v2_CTL_PERF 0x0000000000000180ULL /* Perf */ +#define RNG_v2_CTL_ASEL 0x0000000000000070ULL /* Analog MUX select */ +#define RNG_v2_CTL_ASEL_SHIFT 4 +#define RNG_v2_CTL_ASEL_NOOUT 7 + + #define HV_FAST_RNG_GET_DIAG_CTL 0x130 #define HV_FAST_RNG_CTL_READ 0x131 #define HV_FAST_RNG_CTL_WRITE 0x132 @@ -60,6 +76,20 @@ extern unsigned long sun4v_rng_data_read_diag_v2(unsigned long data_ra, extern unsigned long sun4v_rng_data_read(unsigned long data_ra, unsigned long *tick_delta); +enum n2rng_compat_id { + N2_n2_rng, + N2_vf_rng, + N2_kt_rng, + N2_m4_rng, + N2_m7_rng, +}; + +struct n2rng_template { + enum n2rng_compat_id id; + int multi_capable; + int chip_version; +}; + struct n2rng_unit { u64 control[HV_RNG_NUM_CONTROL]; }; @@ -74,6 +104,7 @@ struct n2rng { #define N2RNG_FLAG_SHUTDOWN 0x00000010 /* Driver unregistering */ #define N2RNG_FLAG_BUFFER_VALID 0x00000020 /* u32 buffer holds valid data */ + struct n2rng_template *data; int num_units; struct n2rng_unit *units; @@ -97,8 +128,10 @@ struct n2rng { u64 scratch_control[HV_RNG_NUM_CONTROL]; -#define SELFTEST_TICKS 38859 -#define SELFTEST_VAL ((u64)0xB8820C7BD387E32C) +#define RNG_v1_SELFTEST_TICKS 38859 +#define RNG_v1_SELFTEST_VAL ((u64)0xB8820C7BD387E32C) +#define RNG_v2_SELFTEST_TICKS 64 +#define RNG_v2_SELFTEST_VAL ((u64)0xffffffffffffffff) #define SELFTEST_POLY ((u64)0x231DCEE91262B8A3) #define SELFTEST_MATCH_GOAL 6 #define SELFTEST_LOOPS_MAX 40000 diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index f786b18..b708c85 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -463,9 +463,9 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma) } static struct miscdevice mmtimer_miscdev = { - SGI_MMTIMER, - MMTIMER_NAME, - &mmtimer_fops + .minor = SGI_MMTIMER, + .name = MMTIMER_NAME, + .fops = &mmtimer_fops }; static struct timespec sgi_clock_offset; diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 277186d..af985cc 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -6,6 +6,7 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM select SECURITYFS + select CRYPTO_HASH_INFO ---help--- If you have a TPM security chip in your system, which implements the Trusted Computing Group's specification, diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index a05b1eb..3d386a8 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_TCG_TPM) += tpm.o tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ - tpm_eventlog.o + tpm1_eventlog.o tpm2_eventlog.o tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o tpm-$(CONFIG_OF) += tpm_of.o obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 6f060c7..e8e0f7c 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -18,7 +18,6 @@ #include <linux/module.h> #include <linux/fs.h> -#include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/wait.h> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index a77262d..c406343 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -141,7 +141,7 @@ static void tpm_dev_release(struct device *dev) * Allocates a new struct tpm_chip instance and assigns a free * device number for it. Must be paired with put_device(&chip->dev). */ -struct tpm_chip *tpm_chip_alloc(struct device *dev, +struct tpm_chip *tpm_chip_alloc(struct device *pdev, const struct tpm_class_ops *ops) { struct tpm_chip *chip; @@ -160,7 +160,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL); mutex_unlock(&idr_lock); if (rc < 0) { - dev_err(dev, "No available tpm device numbers\n"); + dev_err(pdev, "No available tpm device numbers\n"); kfree(chip); return ERR_PTR(rc); } @@ -170,7 +170,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, chip->dev.class = tpm_class; chip->dev.release = tpm_dev_release; - chip->dev.parent = dev; + chip->dev.parent = pdev; chip->dev.groups = chip->groups; if (chip->dev_num == 0) @@ -182,7 +182,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, if (rc) goto out; - if (!dev) + if (!pdev) chip->flags |= TPM_CHIP_FLAG_VIRTUAL; cdev_init(&chip->cdev, &tpm_fops); diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 912ad30..02a8850 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -38,6 +38,9 @@ static void user_reader_timeout(unsigned long ptr) { struct file_priv *priv = (struct file_priv *)ptr; + pr_warn("TPM user space timeout is deprecated (pid=%d)\n", + task_tgid_nr(current)); + schedule_work(&priv->work); } @@ -157,7 +160,7 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, mutex_unlock(&priv->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ - mod_timer(&priv->user_read_timer, jiffies + (60 * HZ)); + mod_timer(&priv->user_read_timer, jiffies + (120 * HZ)); return in_size; } diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index a2688ac..bd2128e 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -47,7 +47,7 @@ static int tpm_suspend_pcr; 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."); + "PCR to use for dummy writes to facilitate flush on suspend."); /* * Array with one entry per ordinal defining the maximum amount @@ -328,8 +328,17 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); -/* - * Internal kernel interface to transmit TPM commands +/** + * tmp_transmit - Internal kernel interface to transmit TPM commands. + * + * @chip: TPM chip to use + * @buf: TPM command buffer + * @bufsiz: length of the TPM command buffer + * @flags: tpm transmit flags - bitmap + * + * Return: + * 0 when the operation is successful. + * A negative number for system errors (errno). */ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags) @@ -409,31 +418,55 @@ out: return rc; } -#define TPM_DIGEST_SIZE 20 -#define TPM_RET_CODE_IDX 6 - -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, - int len, unsigned int flags, const char *desc) +/** + * tmp_transmit_cmd - send a tpm command to the device + * The function extracts tpm out header return code + * + * @chip: TPM chip to use + * @buf: TPM command buffer + * @bufsiz: length of the buffer + * @min_rsp_body_length: minimum expected length of response body + * @flags: tpm transmit flags - bitmap + * @desc: command description used in the error message + * + * Return: + * 0 when the operation is successful. + * A negative number for system errors (errno). + * A positive number for a TPM error. + */ +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, + size_t bufsiz, size_t min_rsp_body_length, + unsigned int flags, const char *desc) { const struct tpm_output_header *header; int err; + ssize_t len; - len = tpm_transmit(chip, (const u8 *)cmd, len, flags); + len = tpm_transmit(chip, (const u8 *)buf, bufsiz, flags); if (len < 0) return len; else if (len < TPM_HEADER_SIZE) return -EFAULT; - header = cmd; + header = buf; + if (len != be32_to_cpu(header->length)) + return -EFAULT; err = be32_to_cpu(header->return_code); if (err != 0 && desc) dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err, desc); + if (err) + return err; + + if (len < min_rsp_body_length + TPM_HEADER_SIZE) + return -EFAULT; - return err; + return 0; } +#define TPM_DIGEST_SIZE 20 +#define TPM_RET_CODE_IDX 6 #define TPM_INTERNAL_RESULT_SIZE 200 #define TPM_ORD_GET_CAP cpu_to_be32(101) #define TPM_ORD_GET_RANDOM cpu_to_be32(70) @@ -445,7 +478,7 @@ static const struct tpm_input_header tpm_getcap_header = { }; ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, - const char *desc) + const char *desc, size_t min_cap_length) { struct tpm_cmd_t tpm_cmd; int rc; @@ -468,8 +501,8 @@ ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); } - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - desc); + rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, + min_cap_length, 0, desc); if (!rc) *cap = tpm_cmd.params.getcap_out.cap; return rc; @@ -493,14 +526,13 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) start_cmd.params.startup_in.startup_type = startup_type; return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - "attempting to start the TPM"); + 0, "attempting to start the TPM"); } int tpm_get_timeouts(struct tpm_chip *chip) { cap_t cap; - unsigned long new_timeout[4]; - unsigned long old_timeout[4]; + unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4]; ssize_t rc; if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) @@ -523,8 +555,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) return 0; } - rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, - "attempting to determine the timeouts"); + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL, + sizeof(cap.timeout)); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ @@ -533,16 +565,26 @@ int tpm_get_timeouts(struct tpm_chip *chip) return rc; rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, - "attempting to determine the timeouts"); + "attempting to determine the timeouts", + sizeof(cap.timeout)); } - if (rc) + + if (rc) { + dev_err(&chip->dev, + "A TPM error (%zd) occurred attempting to determine the timeouts\n", + rc); return rc; + } - old_timeout[0] = be32_to_cpu(cap.timeout.a); - old_timeout[1] = be32_to_cpu(cap.timeout.b); - old_timeout[2] = be32_to_cpu(cap.timeout.c); - old_timeout[3] = be32_to_cpu(cap.timeout.d); - memcpy(new_timeout, old_timeout, sizeof(new_timeout)); + timeout_old[0] = jiffies_to_usecs(chip->timeout_a); + timeout_old[1] = jiffies_to_usecs(chip->timeout_b); + timeout_old[2] = jiffies_to_usecs(chip->timeout_c); + timeout_old[3] = jiffies_to_usecs(chip->timeout_d); + timeout_chip[0] = be32_to_cpu(cap.timeout.a); + timeout_chip[1] = be32_to_cpu(cap.timeout.b); + timeout_chip[2] = be32_to_cpu(cap.timeout.c); + timeout_chip[3] = be32_to_cpu(cap.timeout.d); + memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff)); /* * Provide ability for vendor overrides of timeout values in case @@ -550,16 +592,24 @@ int tpm_get_timeouts(struct tpm_chip *chip) */ if (chip->ops->update_timeouts != NULL) chip->timeout_adjusted = - chip->ops->update_timeouts(chip, new_timeout); + chip->ops->update_timeouts(chip, timeout_eff); if (!chip->timeout_adjusted) { - /* Don't overwrite default if value is 0 */ - if (new_timeout[0] != 0 && new_timeout[0] < 1000) { - int i; + /* Restore default if chip reported 0 */ + int i; + for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) { + if (timeout_eff[i]) + continue; + + timeout_eff[i] = timeout_old[i]; + chip->timeout_adjusted = true; + } + + if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) { /* timeouts in msec rather usec */ - for (i = 0; i != ARRAY_SIZE(new_timeout); i++) - new_timeout[i] *= 1000; + for (i = 0; i != ARRAY_SIZE(timeout_eff); i++) + timeout_eff[i] *= 1000; chip->timeout_adjusted = true; } } @@ -568,19 +618,20 @@ int tpm_get_timeouts(struct tpm_chip *chip) if (chip->timeout_adjusted) { dev_info(&chip->dev, 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], - old_timeout[2], new_timeout[2], - old_timeout[3], new_timeout[3]); + timeout_chip[0], timeout_eff[0], + timeout_chip[1], timeout_eff[1], + timeout_chip[2], timeout_eff[2], + timeout_chip[3], timeout_eff[3]); } - chip->timeout_a = usecs_to_jiffies(new_timeout[0]); - chip->timeout_b = usecs_to_jiffies(new_timeout[1]); - chip->timeout_c = usecs_to_jiffies(new_timeout[2]); - chip->timeout_d = usecs_to_jiffies(new_timeout[3]); + chip->timeout_a = usecs_to_jiffies(timeout_eff[0]); + chip->timeout_b = usecs_to_jiffies(timeout_eff[1]); + chip->timeout_c = usecs_to_jiffies(timeout_eff[2]); + chip->timeout_d = usecs_to_jiffies(timeout_eff[3]); rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, - "attempting to determine the durations"); + "attempting to determine the durations", + sizeof(cap.duration)); if (rc) return rc; @@ -631,13 +682,14 @@ static int tpm_continue_selftest(struct tpm_chip *chip) struct tpm_cmd_t cmd; cmd.header.in = continue_selftest_header; - rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, 0, 0, "continue selftest"); return rc; } #define TPM_ORDINAL_PCRREAD cpu_to_be32(21) #define READ_PCR_RESULT_SIZE 30 +#define READ_PCR_RESULT_BODY_SIZE 20 static const struct tpm_input_header pcrread_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(14), @@ -651,7 +703,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 = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE, + READ_PCR_RESULT_BODY_SIZE, 0, "attempting to read a pcr value"); if (rc == 0) @@ -714,6 +767,7 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); #define TPM_ORD_PCR_EXTEND cpu_to_be32(20) #define EXTEND_PCR_RESULT_SIZE 34 +#define EXTEND_PCR_RESULT_BODY_SIZE 20 static const struct tpm_input_header pcrextend_header = { .tag = TPM_TAG_RQU_COMMAND, .length = cpu_to_be32(34), @@ -735,13 +789,25 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) struct tpm_cmd_t cmd; int rc; struct tpm_chip *chip; + struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)]; + u32 count = 0; + int i; chip = tpm_chip_find_get(chip_num); if (chip == NULL) return -ENODEV; if (chip->flags & TPM_CHIP_FLAG_TPM2) { - rc = tpm2_pcr_extend(chip, pcr_idx, hash); + memset(digest_list, 0, sizeof(digest_list)); + + for (i = 0; i < ARRAY_SIZE(chip->active_banks) && + chip->active_banks[i] != TPM2_ALG_ERROR; i++) { + digest_list[i].alg_id = chip->active_banks[i]; + memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE); + count++; + } + + rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list); tpm_put_ops(chip); return rc; } @@ -749,7 +815,8 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) 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 = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + EXTEND_PCR_RESULT_BODY_SIZE, 0, "attempting extend a PCR value"); tpm_put_ops(chip); @@ -853,7 +920,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen) if (chip == NULL) return -ENODEV; - rc = tpm_transmit_cmd(chip, cmd, buflen, 0, "attempting tpm_cmd"); + rc = tpm_transmit_cmd(chip, cmd, buflen, 0, 0, "attempting tpm_cmd"); tpm_put_ops(chip); return rc; @@ -955,7 +1022,8 @@ int tpm_pm_suspend(struct device *dev) cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr); memcpy(cmd.params.pcrextend_in.hash, dummy_hash, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE, + EXTEND_PCR_RESULT_BODY_SIZE, 0, "extending dummy pcr before suspend"); } @@ -963,7 +1031,7 @@ int tpm_pm_suspend(struct device *dev) for (try = 0; try < TPM_RETRY; try++) { cmd.header.in = savestate_header; rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, 0, - NULL); + 0, NULL); /* * If the TPM indicates that it is too busy to respond to @@ -1025,7 +1093,7 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) { struct tpm_chip *chip; struct tpm_cmd_t tpm_cmd; - u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); + u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength; int err, total = 0, retries = 5; u8 *dest = out; @@ -1048,11 +1116,20 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) err = tpm_transmit_cmd(chip, &tpm_cmd, TPM_GETRANDOM_RESULT_SIZE + num_bytes, + offsetof(struct tpm_getrandom_out, + rng_data), 0, "attempting get random"); if (err) break; recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); + + rlength = be32_to_cpu(tpm_cmd.header.out.length); + if (rlength < offsetof(struct tpm_getrandom_out, rng_data) + + recd) { + total = -EFAULT; + break; + } memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); dest += recd; diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 848ad65..2f596d7 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -21,6 +21,7 @@ #include "tpm.h" #define READ_PUBEK_RESULT_SIZE 314 +#define READ_PUBEK_RESULT_MIN_BODY_SIZE (28 + 256) #define TPM_ORD_READPUBEK cpu_to_be32(124) static const struct tpm_input_header tpm_readpubek_header = { .tag = TPM_TAG_RQU_COMMAND, @@ -39,7 +40,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = to_tpm_chip(dev); tpm_cmd.header.in = tpm_readpubek_header; - err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, 0, + err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE, + READ_PUBEK_RESULT_MIN_BODY_SIZE, 0, "attempting to read the PUBEK"); if (err) goto out; @@ -95,7 +97,8 @@ static ssize_t pcrs_show(struct device *dev, struct device_attribute *attr, struct tpm_chip *chip = to_tpm_chip(dev); rc = tpm_getcap(chip, TPM_CAP_PROP_PCR, &cap, - "attempting to determine the number of PCRS"); + "attempting to determine the number of PCRS", + sizeof(cap.num_pcrs)); if (rc) return 0; @@ -120,7 +123,8 @@ static ssize_t enabled_show(struct device *dev, struct device_attribute *attr, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, - "attempting to determine the permanent enabled state"); + "attempting to determine the permanent enabled state", + sizeof(cap.perm_flags)); if (rc) return 0; @@ -136,7 +140,8 @@ static ssize_t active_show(struct device *dev, struct device_attribute *attr, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_PERM, &cap, - "attempting to determine the permanent active state"); + "attempting to determine the permanent active state", + sizeof(cap.perm_flags)); if (rc) return 0; @@ -152,7 +157,8 @@ static ssize_t owned_show(struct device *dev, struct device_attribute *attr, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_PROP_OWNER, &cap, - "attempting to determine the owner state"); + "attempting to determine the owner state", + sizeof(cap.owned)); if (rc) return 0; @@ -168,7 +174,8 @@ static ssize_t temp_deactivated_show(struct device *dev, ssize_t rc; rc = tpm_getcap(to_tpm_chip(dev), TPM_CAP_FLAG_VOL, &cap, - "attempting to determine the temporary state"); + "attempting to determine the temporary state", + sizeof(cap.stclear_flags)); if (rc) return 0; @@ -186,7 +193,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, char *str = buf; rc = tpm_getcap(chip, TPM_CAP_PROP_MANUFACTURER, &cap, - "attempting to determine the manufacturer"); + "attempting to determine the manufacturer", + sizeof(cap.manufacturer_id)); if (rc) return 0; str += sprintf(str, "Manufacturer: 0x%x\n", @@ -194,7 +202,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap, - "attempting to determine the 1.2 version"); + "attempting to determine the 1.2 version", + sizeof(cap.tpm_version_1_2)); if (!rc) { str += sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", @@ -205,7 +214,8 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, } else { /* Otherwise just use TPM_STRUCT_VER */ rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap, - "attempting to determine the 1.1 version"); + "attempting to determine the 1.1 version", + sizeof(cap.tpm_version)); if (rc) return 0; str += sprintf(str, diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 1ae9768..4937b56 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -34,8 +34,7 @@ #include <linux/acpi.h> #include <linux/cdev.h> #include <linux/highmem.h> - -#include "tpm_eventlog.h" +#include <crypto/hash_info.h> enum tpm_const { TPM_MINOR = 224, /* officially assigned */ @@ -97,6 +96,7 @@ enum tpm2_return_codes { }; enum tpm2_algorithms { + TPM2_ALG_ERROR = 0x0000, TPM2_ALG_SHA1 = 0x0004, TPM2_ALG_KEYEDHASH = 0x0008, TPM2_ALG_SHA256 = 0x000B, @@ -127,6 +127,7 @@ enum tpm2_permanent_handles { }; enum tpm2_capabilities { + TPM2_CAP_PCRS = 5, TPM2_CAP_TPM_PROPERTIES = 6, }; @@ -148,6 +149,11 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), }; +struct tpm_bios_log { + void *bios_event_log; + void *bios_event_log_end; +}; + struct tpm_chip_seqops { struct tpm_chip *chip; const struct seq_operations *seqops; @@ -187,6 +193,8 @@ struct tpm_chip { const struct attribute_group *groups[3]; unsigned int groups_cnt; + + u16 active_banks[7]; #ifdef CONFIG_ACPI acpi_handle acpi_dev_handle; char ppi_version[TPM_PPI_VERSION_LEN + 1]; @@ -195,17 +203,6 @@ struct tpm_chip { #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) -static inline int tpm_read_index(int base, int index) -{ - outb(index, base); - return inb(base+1) & 0xFF; -} - -static inline void tpm_write_index(int base, int index, int value) -{ - outb(index, base); - outb(value & 0xFF, base+1); -} struct tpm_input_header { __be16 tag; __be32 length; @@ -284,7 +281,7 @@ struct permanent_flags_t { typedef union { struct permanent_flags_t perm_flags; struct stclear_flags_t stclear_flags; - bool owned; + __u8 owned; __be32 num_pcrs; struct tpm_version_t tpm_version; struct tpm_version_1_2_t tpm_version_1_2; @@ -387,6 +384,11 @@ struct tpm_cmd_t { tpm_cmd_params params; } __packed; +struct tpm2_digest { + u16 alg_id; + u8 digest[SHA512_DIGEST_SIZE]; +} __packed; + /* A string buffer type for constructing TPM commands. This is based on the * ideas of string buffer code in security/keys/trusted.h but is heap based * in order to keep the stack usage minimal. @@ -493,10 +495,11 @@ enum tpm_transmit_flags { ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags); -ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, - unsigned int flags, const char *desc); +ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *buf, size_t bufsiz, + size_t min_rsp_body_len, unsigned int flags, + const char *desc); ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, - const char *desc); + const char *desc, size_t min_cap_length); int tpm_get_timeouts(struct tpm_chip *); int tpm1_auto_startup(struct tpm_chip *chip); int tpm_do_selftest(struct tpm_chip *chip); @@ -529,8 +532,14 @@ static inline void tpm_add_ppi(struct tpm_chip *chip) } #endif +static inline inline u32 tpm2_rc_value(u32 rc) +{ + return (rc & BIT(7)) ? rc & 0xff : rc; +} + int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); -int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, + struct tpm2_digest *digests); int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm1_eventlog.c index 11bb113..9a8605e 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm1_eventlog.c @@ -390,9 +390,6 @@ int tpm_bios_log_setup(struct tpm_chip *chip) unsigned int cnt; int rc = 0; - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return 0; - rc = tpm_read_log(chip); if (rc) return rc; @@ -407,7 +404,13 @@ int tpm_bios_log_setup(struct tpm_chip *chip) cnt++; chip->bin_log_seqops.chip = chip; - chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + 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", @@ -418,17 +421,21 @@ int tpm_bios_log_setup(struct tpm_chip *chip) goto err; cnt++; - chip->ascii_log_seqops.chip = chip; - chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops; + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { - 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++; + 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; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index da5b782..881aea9 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -53,22 +53,6 @@ struct tpm2_pcr_read_out { u8 digest[TPM_DIGEST_SIZE]; } __packed; -struct tpm2_null_auth_area { - __be32 handle; - __be16 nonce_size; - u8 attributes; - __be16 auth_size; -} __packed; - -struct tpm2_pcr_extend_in { - __be32 pcr_idx; - __be32 auth_area_size; - struct tpm2_null_auth_area auth_area; - __be32 digest_cnt; - __be16 hash_alg; - u8 digest[TPM_DIGEST_SIZE]; -} __packed; - struct tpm2_get_tpm_pt_in { __be32 cap_id; __be32 property_id; @@ -97,7 +81,6 @@ union tpm2_cmd_params { struct tpm2_self_test_in selftest_in; struct tpm2_pcr_read_in pcrread_in; struct tpm2_pcr_read_out pcrread_out; - struct tpm2_pcr_extend_in pcrextend_in; struct tpm2_get_tpm_pt_in get_tpm_pt_in; struct tpm2_get_tpm_pt_out get_tpm_pt_out; struct tpm2_get_random_in getrandom_in; @@ -248,6 +231,9 @@ static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = { (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_pcr_read_in)) +#define TPM2_PCR_READ_RESP_BODY_SIZE \ + sizeof(struct tpm2_pcr_read_out) + static const struct tpm_input_header tpm2_pcrread_header = { .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE), @@ -258,11 +244,9 @@ static const struct tpm_input_header tpm2_pcrread_header = { * tpm2_pcr_read() - read a PCR value * @chip: TPM chip to use. * @pcr_idx: index of the PCR to read. - * @ref_buf: buffer to store the resulting hash, + * @res_buf: buffer to store the resulting hash. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { @@ -282,8 +266,9 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) sizeof(cmd.params.pcrread_in.pcr_select)); cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, - "attempting to read a pcr value"); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + TPM2_PCR_READ_RESP_BODY_SIZE, + 0, "attempting to read a pcr value"); if (rc == 0) { buf = cmd.params.pcrread_out.digest; memcpy(res_buf, buf, TPM_DIGEST_SIZE); @@ -292,50 +277,71 @@ int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) return rc; } -#define TPM2_GET_PCREXTEND_IN_SIZE \ - (sizeof(struct tpm_input_header) + \ - sizeof(struct tpm2_pcr_extend_in)) - -static const struct tpm_input_header tpm2_pcrextend_header = { - .tag = cpu_to_be16(TPM2_ST_SESSIONS), - .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE), - .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND) -}; +struct tpm2_null_auth_area { + __be32 handle; + __be16 nonce_size; + u8 attributes; + __be16 auth_size; +} __packed; /** * tpm2_pcr_extend() - extend a PCR value + * * @chip: TPM chip to use. * @pcr_idx: index of the PCR. - * @hash: hash value to use for the extend operation. + * @count: number of digests passed. + * @digests: list of pcr banks and corresponding digest values to extend. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ -int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash) +int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, u32 count, + struct tpm2_digest *digests) { - struct tpm2_cmd cmd; + struct tpm_buf buf; + struct tpm2_null_auth_area auth_area; int rc; + int i; + int j; + + if (count > ARRAY_SIZE(chip->active_banks)) + return -EINVAL; + + rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND); + if (rc) + return rc; + + tpm_buf_append_u32(&buf, pcr_idx); + + auth_area.handle = cpu_to_be32(TPM2_RS_PW); + auth_area.nonce_size = 0; + auth_area.attributes = 0; + auth_area.auth_size = 0; + + tpm_buf_append_u32(&buf, sizeof(struct tpm2_null_auth_area)); + tpm_buf_append(&buf, (const unsigned char *)&auth_area, + sizeof(auth_area)); + tpm_buf_append_u32(&buf, count); + + for (i = 0; i < count; i++) { + for (j = 0; j < ARRAY_SIZE(tpm2_hash_map); j++) { + if (digests[i].alg_id != tpm2_hash_map[j].tpm_id) + continue; + tpm_buf_append_u16(&buf, digests[i].alg_id); + tpm_buf_append(&buf, (const unsigned char + *)&digests[i].digest, + hash_digest_size[tpm2_hash_map[j].crypto_id]); + } + } - cmd.header.in = tpm2_pcrextend_header; - cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); - cmd.params.pcrextend_in.auth_area_size = - cpu_to_be32(sizeof(struct tpm2_null_auth_area)); - cmd.params.pcrextend_in.auth_area.handle = - cpu_to_be32(TPM2_RS_PW); - cmd.params.pcrextend_in.auth_area.nonce_size = 0; - cmd.params.pcrextend_in.auth_area.attributes = 0; - cmd.params.pcrextend_in.auth_area.auth_size = 0; - cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1); - cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1); - memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE); - - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, 0, "attempting extend a PCR value"); + tpm_buf_destroy(&buf); + return rc; } + #define TPM2_GETRANDOM_IN_SIZE \ (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_get_random_in)) @@ -348,18 +354,18 @@ static const struct tpm_input_header tpm2_getrandom_header = { /** * tpm2_get_random() - get random bytes from the TPM RNG + * * @chip: TPM chip to use * @out: destination buffer for the random bytes * @max: the max number of bytes to write to @out * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: + * Size of the output buffer, or -EIO on error. */ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) { struct tpm2_cmd cmd; - u32 recd; + u32 recd, rlength; u32 num_bytes; int err; int total = 0; @@ -376,13 +382,19 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) cmd.header.in = tpm2_getrandom_header; cmd.params.getrandom_in.size = cpu_to_be16(num_bytes); - err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, - "attempting get random"); + err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + offsetof(struct tpm2_get_random_out, + buffer), + 0, "attempting get random"); if (err) break; recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size), num_bytes); + rlength = be32_to_cpu(cmd.header.out.length); + if (rlength < offsetof(struct tpm2_get_random_out, buffer) + + recd) + return -EFAULT; memcpy(dest, cmd.params.getrandom_out.buffer, recd); dest += recd; @@ -397,6 +409,9 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max) (sizeof(struct tpm_input_header) + \ sizeof(struct tpm2_get_tpm_pt_in)) +#define TPM2_GET_TPM_PT_OUT_BODY_SIZE \ + sizeof(struct tpm2_get_tpm_pt_out) + static const struct tpm_input_header tpm2_get_tpm_pt_header = { .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE), @@ -404,15 +419,15 @@ static const struct tpm_input_header tpm2_get_tpm_pt_header = { }; /** - * Append TPMS_AUTH_COMMAND to the buffer. The buffer must be allocated with - * tpm_buf_alloc(). - * - * @param buf: an allocated tpm_buf instance - * @param nonce: the session nonce, may be NULL if not used - * @param nonce_len: the session nonce length, may be 0 if not used - * @param attributes: the session attributes - * @param hmac: the session HMAC or password, may be NULL if not used - * @param hmac_len: the session HMAC or password length, maybe 0 if not used + * tpm_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. + * + * @buf: an allocated tpm_buf instance + * @session_handle: session handle + * @nonce: the session nonce, may be NULL if not used + * @nonce_len: the session nonce length, may be 0 if not used + * @attributes: the session attributes + * @hmac: the session HMAC or password, may be NULL if not used + * @hmac_len: the session HMAC or password length, maybe 0 if not used */ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle, const u8 *nonce, u16 nonce_len, @@ -435,7 +450,8 @@ static void tpm2_buf_append_auth(struct tpm_buf *buf, u32 session_handle, /** * tpm2_seal_trusted() - seal the payload of a trusted key - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options * @@ -447,7 +463,7 @@ int tpm2_seal_trusted(struct tpm_chip *chip, { unsigned int blob_len; struct tpm_buf buf; - u32 hash; + u32 hash, rlength; int i; int rc; @@ -512,7 +528,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, "sealing data"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, 0, + "sealing data"); if (rc) goto out; @@ -521,6 +538,11 @@ int tpm2_seal_trusted(struct tpm_chip *chip, rc = -E2BIG; goto out; } + rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)->header.out.length); + if (rlength < TPM_HEADER_SIZE + 4 + blob_len) { + rc = -EFAULT; + goto out; + } memcpy(payload->blob, &buf.data[TPM_HEADER_SIZE + 4], blob_len); payload->blob_len = blob_len; @@ -529,7 +551,7 @@ out: tpm_buf_destroy(&buf); if (rc > 0) { - if ((rc & TPM2_RC_HASH) == TPM2_RC_HASH) + if (tpm2_rc_value(rc) == TPM2_RC_HASH) rc = -EINVAL; else rc = -EPERM; @@ -540,11 +562,17 @@ out: /** * tpm2_load_cmd() - execute a TPM2_Load command - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options + * @blob_handle: returned blob handle + * @flags: tpm transmit flags * - * Return: same as with tpm_transmit_cmd + * Return: 0 on success. + * -E2BIG on wrong payload size. + * -EPERM on tpm error status. + * < 0 error from tpm_transmit_cmd. */ static int tpm2_load_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -584,7 +612,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip, goto out; } - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "loading blob"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 4, flags, + "loading blob"); if (!rc) *blob_handle = be32_to_cpup( (__be32 *) &buf.data[TPM_HEADER_SIZE]); @@ -600,11 +629,12 @@ out: /** * tpm2_flush_context_cmd() - execute a TPM2_FlushContext command - * @chip_num: TPM chip to use - * @payload: the key data in clear and encrypted form - * @options: authentication values and other options * - * Return: same as with tpm_transmit_cmd + * @chip: TPM chip to use + * @handle: the key data in clear and encrypted form + * @flags: tpm transmit flags + * + * Return: Same as with tpm_transmit_cmd. */ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, unsigned int flags) @@ -621,7 +651,7 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, tpm_buf_append_u32(&buf, handle); - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 0, flags, "flushing context"); if (rc) dev_warn(&chip->dev, "0x%08x was not flushed, rc=%d\n", handle, @@ -632,11 +662,16 @@ static void tpm2_flush_context_cmd(struct tpm_chip *chip, u32 handle, /** * tpm2_unseal_cmd() - execute a TPM2_Unload command - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options + * @blob_handle: blob handle + * @flags: tpm_transmit_cmd flags * - * Return: same as with tpm_transmit_cmd + * Return: 0 on success + * -EPERM on tpm error status + * < 0 error from tpm_transmit_cmd */ static int tpm2_unseal_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -647,6 +682,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, u16 data_len; u8 *data; int rc; + u32 rlength; rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL); if (rc) @@ -661,13 +697,21 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, options->blobauth /* hmac */, TPM_DIGEST_SIZE); - rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, flags, "unsealing"); + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 6, flags, + "unsealing"); if (rc > 0) rc = -EPERM; if (!rc) { data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + + rlength = be32_to_cpu(((struct tpm2_cmd *)&buf) + ->header.out.length); + if (rlength < TPM_HEADER_SIZE + 6 + data_len) { + rc = -EFAULT; + goto out; + } data = &buf.data[TPM_HEADER_SIZE + 6]; memcpy(payload->key, data, data_len - 1); @@ -675,17 +719,19 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, payload->migratable = data[data_len - 1]; } +out: tpm_buf_destroy(&buf); return rc; } /** * tpm2_unseal_trusted() - unseal the payload of a trusted key - * @chip_num: TPM chip to use + * + * @chip: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options * - * Return: < 0 on error and 0 on success. + * Return: Same as with tpm_transmit_cmd. */ int tpm2_unseal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, @@ -715,9 +761,7 @@ out: * @value: output variable. * @desc: passed to tpm_transmit_cmd() * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, const char *desc) @@ -730,7 +774,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value, cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, desc); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), + TPM2_GET_TPM_PT_OUT_BODY_SIZE, 0, desc); if (!rc) *value = be32_to_cpu(cmd.params.get_tpm_pt_out.value); @@ -750,13 +795,12 @@ static const struct tpm_input_header tpm2_startup_header = { /** * tpm2_startup() - send startup command to the TPM chip + * * @chip: TPM chip to use. - * @startup_type startup type. The value is either + * @startup_type: startup type. The value is either * TPM_SU_CLEAR or TPM_SU_STATE. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd. */ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) { @@ -765,7 +809,7 @@ static int tpm2_startup(struct tpm_chip *chip, u16 startup_type) cmd.header.in = tpm2_startup_header; cmd.params.startup_in.startup_type = cpu_to_be16(startup_type); - return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, + return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, "attempting to start the TPM"); } @@ -781,8 +825,9 @@ static const struct tpm_input_header tpm2_shutdown_header = { /** * tpm2_shutdown() - send shutdown command to the TPM chip + * * @chip: TPM chip to use. - * @shutdown_type shutdown type. The value is either + * @shutdown_type: shutdown type. The value is either * TPM_SU_CLEAR or TPM_SU_STATE. */ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) @@ -793,7 +838,8 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) cmd.header.in = tpm2_shutdown_header; cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, "stopping the TPM"); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, + "stopping the TPM"); /* In places where shutdown command is sent there's no much we can do * except print the error code on a system failure. @@ -805,12 +851,11 @@ void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) /* * tpm2_calc_ordinal_duration() - maximum duration for a command + * * @chip: TPM chip to use. * @ordinal: command code number. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: maximum duration for a command */ unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) { @@ -842,13 +887,12 @@ static const struct tpm_input_header tpm2_selftest_header = { /** * tpm2_continue_selftest() - start a self test + * * @chip: TPM chip to use * @full: test all commands instead of testing only those that were not * previously tested. * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. + * Return: Same as with tpm_transmit_cmd with exception of RC_TESTING. */ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) { @@ -858,7 +902,7 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) cmd.header.in = tpm2_selftest_header; cmd.params.selftest_in.full_test = full; - rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, + rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE, 0, 0, "continue selftest"); /* At least some prototype chips seem to give RC_TESTING error @@ -874,14 +918,13 @@ static int tpm2_start_selftest(struct tpm_chip *chip, bool full) /** * tpm2_do_selftest() - run a full self test + * * @chip: TPM chip to use * + * Return: Same as with tpm_transmit_cmd. + * * During the self test TPM2 commands return with the error code RC_TESTING. * Waiting is done by issuing PCR read until it executes successfully. - * - * 0 is returned when the operation is successful. If a negative number is - * returned it remarks a POSIX error code. If a positive number is returned - * it remarks a TPM error. */ static int tpm2_do_selftest(struct tpm_chip *chip) { @@ -910,7 +953,7 @@ static int tpm2_do_selftest(struct tpm_chip *chip) cmd.params.pcrread_in.pcr_select[1] = 0x00; cmd.params.pcrread_in.pcr_select[2] = 0x00; - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL); if (rc < 0) break; @@ -928,6 +971,8 @@ static int tpm2_do_selftest(struct tpm_chip *chip) * tpm2_probe() - probe TPM 2.0 * @chip: TPM chip to use * + * Return: < 0 error and 0 on success. + * * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on * the reply tag. */ @@ -941,7 +986,7 @@ int tpm2_probe(struct tpm_chip *chip) cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100); cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1); - rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, NULL); + rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 0, 0, NULL); if (rc < 0) return rc; @@ -952,12 +997,85 @@ int tpm2_probe(struct tpm_chip *chip) } EXPORT_SYMBOL_GPL(tpm2_probe); +struct tpm2_pcr_selection { + __be16 hash_alg; + u8 size_of_select; + u8 pcr_select[3]; +} __packed; + +static ssize_t tpm2_get_pcr_allocation(struct tpm_chip *chip) +{ + struct tpm2_pcr_selection pcr_selection; + struct tpm_buf buf; + void *marker; + void *end; + void *pcr_select_offset; + unsigned int count; + u32 sizeof_pcr_selection; + u32 rsp_len; + int rc; + int i = 0; + + rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_GET_CAPABILITY); + if (rc) + return rc; + + tpm_buf_append_u32(&buf, TPM2_CAP_PCRS); + tpm_buf_append_u32(&buf, 0); + tpm_buf_append_u32(&buf, 1); + + rc = tpm_transmit_cmd(chip, buf.data, PAGE_SIZE, 9, 0, + "get tpm pcr allocation"); + if (rc) + goto out; + + count = be32_to_cpup( + (__be32 *)&buf.data[TPM_HEADER_SIZE + 5]); + + if (count > ARRAY_SIZE(chip->active_banks)) { + rc = -ENODEV; + goto out; + } + + marker = &buf.data[TPM_HEADER_SIZE + 9]; + + rsp_len = be32_to_cpup((__be32 *)&buf.data[2]); + end = &buf.data[rsp_len]; + + for (i = 0; i < count; i++) { + pcr_select_offset = marker + + offsetof(struct tpm2_pcr_selection, size_of_select); + if (pcr_select_offset >= end) { + rc = -EFAULT; + break; + } + + memcpy(&pcr_selection, marker, sizeof(pcr_selection)); + chip->active_banks[i] = be16_to_cpu(pcr_selection.hash_alg); + sizeof_pcr_selection = sizeof(pcr_selection.hash_alg) + + sizeof(pcr_selection.size_of_select) + + pcr_selection.size_of_select; + marker = marker + sizeof_pcr_selection; + } + +out: + if (i < ARRAY_SIZE(chip->active_banks)) + chip->active_banks[i] = TPM2_ALG_ERROR; + + tpm_buf_destroy(&buf); + + return rc; +} + /** * tpm2_auto_startup - Perform the standard automatic TPM initialization * sequence * @chip: TPM chip to use * - * Returns 0 on success, < 0 in case of fatal error. + * Initializes timeout values for operation and command durations, conducts + * a self-test and reads the list of active PCR banks. + * + * Return: 0 on success. Otherwise, a system error code is returned. */ int tpm2_auto_startup(struct tpm_chip *chip) { @@ -985,6 +1103,8 @@ int tpm2_auto_startup(struct tpm_chip *chip) } } + rc = tpm2_get_pcr_allocation(chip); + out: if (rc > 0) rc = -ENODEV; diff --git a/drivers/char/tpm/tpm2_eventlog.c b/drivers/char/tpm/tpm2_eventlog.c new file mode 100644 index 0000000..513897c --- /dev/null +++ b/drivers/char/tpm/tpm2_eventlog.c @@ -0,0 +1,203 @@ +/* + * 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 "tpm.h" +#include "tpm_eventlog.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; + + for (i = 0; (i < event->count) && (i < TPM2_ACTIVE_PCR_BANKS); + 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 = marker + + efispecid->digest_sizes[j].digest_size; + break; + } + } + } + + 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, +}; diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index b7718c9..169edf3 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -54,6 +54,9 @@ int tpm_read_log_acpi(struct tpm_chip *chip) 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 diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h index 4f96d80..5c82eb4 100644 --- a/drivers/char/tpm/tpm_atmel.h +++ b/drivers/char/tpm/tpm_atmel.h @@ -96,6 +96,12 @@ enum tpm_atmel_addr { TPM_ATMEL_BASE_ADDR_HI = 0x09 }; +static inline int tpm_read_index(int base, int index) +{ + outb(index, base); + return inb(base+1) & 0xFF; +} + /* Verify this is a 1.1 Atmel TPM */ static int atmel_verify_tpm11(void) { diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 717b6b4..86f355b 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -264,10 +264,12 @@ static const struct tpm_class_ops tpm_crb = { static int crb_check_resource(struct acpi_resource *ares, void *data) { struct resource *io_res = data; - struct resource res; + struct resource_win win; + struct resource *res = &(win.res); - if (acpi_dev_resource_memory(ares, &res)) { - *io_res = res; + if (acpi_dev_resource_memory(ares, res) || + acpi_dev_resource_address_space(ares, &win)) { + *io_res = *res; io_res->name = NULL; } diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h index 1660d74..b4b5495 100644 --- a/drivers/char/tpm/tpm_eventlog.h +++ b/drivers/char/tpm/tpm_eventlog.h @@ -2,9 +2,12 @@ #ifndef __TPM_EVENTLOG_H__ #define __TPM_EVENTLOG_H__ +#include <crypto/hash_info.h> + #define TCG_EVENT_NAME_LEN_MAX 255 #define MAX_TEXT_EVENT 1000 /* Max event string length */ #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ +#define TPM2_ACTIVE_PCR_BANKS 3 #ifdef CONFIG_PPC64 #define do_endian_conversion(x) be32_to_cpu(x) @@ -17,11 +20,6 @@ enum bios_platform_class { BIOS_SERVER = 0x01, }; -struct tpm_bios_log { - void *bios_event_log; - void *bios_event_log_end; -}; - struct tcpa_event { u32 pcr_index; u32 event_type; @@ -73,6 +71,49 @@ enum tcpa_pc_event_ids { HOST_TABLE_OF_DEVICES, }; +/* http://www.trustedcomputinggroup.org/tcg-efi-protocol-specification/ */ + +struct tcg_efi_specid_event_algs { + u16 alg_id; + u16 digest_size; +} __packed; + +struct tcg_efi_specid_event { + u8 signature[16]; + u32 platform_class; + u8 spec_version_minor; + u8 spec_version_major; + u8 spec_errata; + u8 uintnsize; + u32 num_algs; + struct tcg_efi_specid_event_algs digest_sizes[TPM2_ACTIVE_PCR_BANKS]; + u8 vendor_info_size; + u8 vendor_info[0]; +} __packed; + +struct tcg_pcr_event { + u32 pcr_idx; + u32 event_type; + u8 digest[20]; + u32 event_size; + u8 event[0]; +} __packed; + +struct tcg_event_field { + u32 event_size; + u8 event[0]; +} __packed; + +struct tcg_pcr_event2 { + u32 pcr_idx; + u32 event_type; + u32 count; + struct tpm2_digest digests[TPM2_ACTIVE_PCR_BANKS]; + struct tcg_event_field event; +} __packed; + +extern const struct seq_operations tpm2_binary_b_measurements_seqops; + #if defined(CONFIG_ACPI) int tpm_read_log_acpi(struct tpm_chip *chip); #else diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 946025a..1b9d61f 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -40,11 +40,12 @@ MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); /** * ibmvtpm_send_crq - Send a CRQ request + * * @vdev: vio device struct * @w1: first word * @w2: second word * - * Return value: + * Return: * 0 -Sucess * Non-zero - Failure */ @@ -55,11 +56,12 @@ static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2) /** * tpm_ibmvtpm_recv - Receive data after send + * * @chip: tpm chip struct * @buf: buffer to read - * count: size of buffer + * @count: size of buffer * - * Return value: + * Return: * Number of bytes read */ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) @@ -96,12 +98,13 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) /** * tpm_ibmvtpm_send - Send tpm request + * * @chip: tpm chip struct * @buf: buffer contains data to send - * count: size of buffer + * @count: size of buffer * - * Return value: - * Number of bytes sent + * Return: + * Number of bytes sent or < 0 on error. */ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) { @@ -170,11 +173,12 @@ static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) /** * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size + * * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) { @@ -197,11 +201,12 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) /** * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version * - Note that this is vtpm version and not tpm version + * * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) { @@ -225,9 +230,9 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) { @@ -245,9 +250,9 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) * ibmvtpm_crq_send_init - Send a CRQ initialize message * @ibmvtpm: vtpm device struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) { @@ -265,8 +270,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) * tpm_ibmvtpm_remove - ibm vtpm remove entry point * @vdev: vio device struct * - * Return value: - * 0 + * Return: Always 0. */ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) { @@ -303,18 +307,19 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev) * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver * @vdev: vio device struct * - * Return value: - * Number of bytes the driver needs to DMA map + * Return: + * Number of bytes the driver needs to DMA map. */ static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) { struct tpm_chip *chip = dev_get_drvdata(&vdev->dev); struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); - /* ibmvtpm initializes at probe time, so the data we are - * asking for may not be set yet. Estimate that 4K required - * for TCE-mapped buffer in addition to CRQ. - */ + /* + * ibmvtpm initializes at probe time, so the data we are + * asking for may not be set yet. Estimate that 4K required + * for TCE-mapped buffer in addition to CRQ. + */ if (!ibmvtpm) return CRQ_RES_BUF_SIZE + PAGE_SIZE; @@ -325,8 +330,7 @@ static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) * tpm_ibmvtpm_suspend - Suspend * @dev: device struct * - * Return value: - * 0 + * Return: Always 0. */ static int tpm_ibmvtpm_suspend(struct device *dev) { @@ -350,11 +354,12 @@ static int tpm_ibmvtpm_suspend(struct device *dev) /** * ibmvtpm_reset_crq - Reset CRQ + * * @ibmvtpm: ibm vtpm struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) { @@ -376,10 +381,10 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) /** * tpm_ibmvtpm_resume - Resume from suspend + * * @dev: device struct * - * Return value: - * 0 + * Return: Always 0. */ static int tpm_ibmvtpm_resume(struct device *dev) { @@ -434,10 +439,10 @@ static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { /** * ibmvtpm_crq_get_next - Get next responded crq - * @ibmvtpm vtpm device struct * - * Return value: - * vtpm crq pointer + * @ibmvtpm: vtpm device struct + * + * Return: vtpm crq pointer or NULL. */ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) { @@ -455,11 +460,10 @@ static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) /** * ibmvtpm_crq_process - Process responded crq - * @crq crq to be processed - * @ibmvtpm vtpm device struct * - * Return value: - * Nothing + * @crq: crq to be processed + * @ibmvtpm: vtpm device struct + * */ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, struct ibmvtpm_dev *ibmvtpm) @@ -528,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, /** * ibmvtpm_interrupt - Interrupt handler + * * @irq: irq number to handle * @vtpm_instance: vtpm that received interrupt * @@ -554,12 +559,13 @@ static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) /** * tpm_ibmvtpm_probe - ibm vtpm initialize entry point + * * @vio_dev: vio device struct * @id: vio device id struct * - * Return value: - * 0 - Success - * Non-zero - Failure + * Return: + * 0 on success. + * Non-zero on failure. */ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, const struct vio_device_id *id) @@ -671,11 +677,12 @@ static struct vio_driver ibmvtpm_driver = { }; /** - * ibmvtpm_module_init - Initialize ibm vtpm module + * ibmvtpm_module_init - Initialize ibm vtpm module. * - * Return value: - * 0 -Success - * Non-zero - Failure + * + * Return: + * 0 on success. + * Non-zero on failure. */ static int __init ibmvtpm_module_init(void) { @@ -683,10 +690,7 @@ static int __init ibmvtpm_module_init(void) } /** - * ibmvtpm_module_exit - Teardown ibm vtpm module - * - * Return value: - * Nothing + * ibmvtpm_module_exit - Tear down ibm vtpm module. */ static void __exit ibmvtpm_module_exit(void) { diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 9ff0e07..5d6cce7 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -278,6 +278,18 @@ static struct platform_driver nsc_drv = { }, }; +static inline int tpm_read_index(int base, int index) +{ + outb(index, base); + return inb(base+1) & 0xFF; +} + +static inline void tpm_write_index(int base, int index, int value) +{ + outb(index, base); + outb(value & 0xFF, base+1); +} + static int __init init_nsc(void) { int rc = 0; diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 7dee42d7..de57d4a 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -27,6 +27,8 @@ int tpm_read_log_of(struct tpm_chip *chip) 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) @@ -41,18 +43,35 @@ int tpm_read_log_of(struct tpm_chip *chip) if (sizep == NULL || basep == NULL) return -EIO; - if (*sizep == 0) { + /* + * 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(*sizep, GFP_KERNEL); + log->bios_event_log = kmalloc(size, GFP_KERNEL); if (!log->bios_event_log) return -ENOMEM; - log->bios_event_log_end = log->bios_event_log + *sizep; + log->bios_event_log_end = log->bios_event_log + size; - memcpy(log->bios_event_log, __va(*basep), *sizep); + memcpy(log->bios_event_log, __va(base), size); return 0; } diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 0127af1..c7e1384 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -159,7 +159,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info, irq = tpm_info->irq; if (itpm) - phy->priv.flags |= TPM_TIS_ITPM_POSSIBLE; + phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND; return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg, acpi_dev_handle); @@ -432,7 +432,7 @@ err_pnp: acpi_bus_unregister_driver(&tis_acpi_driver); err_acpi: #endif - platform_device_unregister(force_pdev); + platform_driver_unregister(&tis_drv); err_platform: if (force_pdev) platform_device_unregister(force_pdev); diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 7993678..c0f296b 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -264,7 +264,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int rc, status, burstcnt; size_t count = 0; - bool itpm = priv->flags & TPM_TIS_ITPM_POSSIBLE; + bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND; if (request_locality(chip, 0) < 0) return -EBUSY; @@ -464,6 +464,9 @@ static int probe_itpm(struct tpm_chip *chip) size_t len = sizeof(cmd_getticks); u16 vendor; + if (priv->flags & TPM_TIS_ITPM_WORKAROUND) + return 0; + rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor); if (rc < 0) return rc; @@ -479,12 +482,15 @@ static int probe_itpm(struct tpm_chip *chip) tpm_tis_ready(chip); release_locality(chip, priv->locality, 0); + priv->flags |= TPM_TIS_ITPM_WORKAROUND; + rc = tpm_tis_send_data(chip, cmd_getticks, len); - if (rc == 0) { + if (rc == 0) dev_info(&chip->dev, "Detected an iTPM.\n"); - rc = 1; - } else + else { + priv->flags &= ~TPM_TIS_ITPM_WORKAROUND; rc = -EFAULT; + } out: tpm_tis_ready(chip); @@ -552,7 +558,8 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip) if (chip->flags & TPM_CHIP_FLAG_TPM2) return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); else - return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc); + return tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, + 0); } /* Register the IRQ and issue a command that will cause an interrupt. If an @@ -740,15 +747,10 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2", vendor >> 16, rid); - if (!(priv->flags & TPM_TIS_ITPM_POSSIBLE)) { - probe = probe_itpm(chip); - if (probe < 0) { - rc = -ENODEV; - goto out_err; - } - - if (!!probe) - priv->flags |= TPM_TIS_ITPM_POSSIBLE; + probe = probe_itpm(chip); + if (probe < 0) { + rc = -ENODEV; + goto out_err; } /* Figure out the capabilities */ diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 9191aab..e2212f0 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -80,7 +80,7 @@ enum tis_defaults { #define TPM_RID(l) (0x0F04 | ((l) << 12)) enum tpm_tis_flags { - TPM_TIS_ITPM_POSSIBLE = BIT(0), + TPM_TIS_ITPM_WORKAROUND = BIT(0), }; struct tpm_tis_data { diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index dbaad9c..5292e57 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -33,7 +33,6 @@ #include <linux/acpi.h> #include <linux/freezer.h> -#include <linux/module.h> #include <linux/spi/spi.h> #include <linux/gpio.h> #include <linux/of_irq.h> diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 5463b58..751059d 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -65,7 +65,12 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev); /** * vtpm_proxy_fops_read - Read TPM commands on 'server side' * - * Return value: + * @filp: file pointer + * @buf: read buffer + * @count: number of bytes to read + * @off: offset + * + * Return: * Number of bytes read or negative error code */ static ssize_t vtpm_proxy_fops_read(struct file *filp, char __user *buf, @@ -115,7 +120,12 @@ static ssize_t vtpm_proxy_fops_read(struct file *filp, char __user *buf, /** * vtpm_proxy_fops_write - Write TPM responses on 'server side' * - * Return value: + * @filp: file pointer + * @buf: write buffer + * @count: number of bytes to write + * @off: offset + * + * Return: * Number of bytes read or negative error value */ static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf, @@ -155,10 +165,12 @@ static ssize_t vtpm_proxy_fops_write(struct file *filp, const char __user *buf, } /* - * vtpm_proxy_fops_poll: Poll status on 'server side' + * vtpm_proxy_fops_poll - Poll status on 'server side' + * + * @filp: file pointer + * @wait: poll table * - * Return value: - * Poll flags + * Return: Poll flags */ static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait) { @@ -185,6 +197,8 @@ static unsigned int vtpm_proxy_fops_poll(struct file *filp, poll_table *wait) /* * vtpm_proxy_fops_open - Open vTPM device on 'server side' * + * @filp: file pointer + * * Called when setting up the anonymous file descriptor */ static void vtpm_proxy_fops_open(struct file *filp) @@ -196,8 +210,9 @@ static void vtpm_proxy_fops_open(struct file *filp) /** * vtpm_proxy_fops_undo_open - counter-part to vtpm_fops_open + * Call to undo vtpm_proxy_fops_open * - * Call to undo vtpm_proxy_fops_open + *@proxy_dev: tpm proxy device */ static void vtpm_proxy_fops_undo_open(struct proxy_dev *proxy_dev) { @@ -212,9 +227,11 @@ static void vtpm_proxy_fops_undo_open(struct proxy_dev *proxy_dev) } /* - * vtpm_proxy_fops_release: Close 'server side' + * vtpm_proxy_fops_release - Close 'server side' * - * Return value: + * @inode: inode + * @filp: file pointer + * Return: * Always returns 0. */ static int vtpm_proxy_fops_release(struct inode *inode, struct file *filp) @@ -245,7 +262,10 @@ static const struct file_operations vtpm_proxy_fops = { /* * Called when core TPM driver reads TPM responses from 'server side' * - * Return value: + * @chip: tpm chip to use + * @buf: receive buffer + * @count: bytes to read + * Return: * Number of TPM response bytes read, negative error value otherwise */ static int vtpm_proxy_tpm_op_recv(struct tpm_chip *chip, u8 *buf, size_t count) @@ -282,7 +302,11 @@ out: /* * Called when core TPM driver forwards TPM requests to 'server side'. * - * Return value: + * @chip: tpm chip to use + * @buf: send buffer + * @count: bytes to send + * + * Return: * 0 in case of success, negative error value otherwise. */ static int vtpm_proxy_tpm_op_send(struct tpm_chip *chip, u8 *buf, size_t count) @@ -442,7 +466,7 @@ static inline void vtpm_proxy_delete_proxy_dev(struct proxy_dev *proxy_dev) /* * Create a /dev/tpm%d and 'server side' file descriptor pair * - * Return value: + * Return: * Returns file pointer on success, an error value otherwise */ static struct file *vtpm_proxy_create_device( @@ -571,7 +595,7 @@ static long vtpmx_ioc_new_dev(struct file *file, unsigned int ioctl, /* * vtpmx_fops_ioctl: ioctl on /dev/vtpmx * - * Return value: + * Return: * Returns 0 on success, a negative error code otherwise. */ static long vtpmx_fops_ioctl(struct file *f, unsigned int ioctl, diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 5aaa268..656e8af 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -289,7 +289,6 @@ static int tpmfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct tpm_private *priv; - struct tpm_chip *chip; int rv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); @@ -306,7 +305,6 @@ static int tpmfront_probe(struct xenbus_device *dev, rv = setup_ring(dev, priv); if (rv) { - chip = dev_get_drvdata(&dev->dev); ring_free(priv); return rv; } diff --git a/drivers/char/xilinx_hwicap/buffer_icap.c b/drivers/char/xilinx_hwicap/buffer_icap.c index 53c3882..35981ca 100644 --- a/drivers/char/xilinx_hwicap/buffer_icap.c +++ b/drivers/char/xilinx_hwicap/buffer_icap.c @@ -269,7 +269,6 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, { int status; s32 buffer_count = 0; - s32 num_writes = 0; bool dirty = false; u32 i; void __iomem *base_address = drvdata->base_address; @@ -298,7 +297,6 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, } buffer_count = 0; - num_writes++; dirty = false; } @@ -328,7 +326,6 @@ int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, { int status; s32 buffer_count = 0; - s32 read_count = 0; u32 i; void __iomem *base_address = drvdata->base_address; @@ -353,7 +350,6 @@ int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data, } buffer_count = 0; - read_count++; } /* Copy data from bram */ |