Commit ebceb1c8 authored by James Morris's avatar James Morris

Merge tag 'tpmdd-next-20180108' of git://git.infradead.org/users/jjs/linux-tpmdd into next-tpm

tpmdd updates for Linux 4.16
parents d21bd689 68021bf4
......@@ -13809,9 +13809,10 @@ F: drivers/platform/x86/toshiba-wmi.c
TPM DEVICE DRIVER
M: Peter Huewe <peterhuewe@gmx.de>
M: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
R: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
R: Jason Gunthorpe <jgg@ziepe.ca>
L: linux-integrity@vger.kernel.org
Q: https://patchwork.kernel.org/project/linux-integrity/list/
W: https://kernsec.org/wiki/index.php/Linux_Kernel_Integrity
T: git git://git.infradead.org/users/jjs/linux-tpmdd.git
S: Maintained
F: drivers/char/tpm/
......
......@@ -999,6 +999,7 @@ struct boot_params *efi_main(struct efi_config *c,
/* Ask the firmware to clear memory on unclean shutdown */
efi_enable_reset_attack_mitigation(sys_table);
efi_retrieve_tpm2_eventlog(sys_table);
setup_graphics(boot_params);
......
......@@ -306,19 +306,6 @@ config HW_RANDOM_POWERNV
If unsure, say Y.
config HW_RANDOM_TPM
tristate "TPM HW Random Number Generator support"
depends on TCG_TPM
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
Generator in the Trusted Platform Module
To compile this driver as a module, choose M here: the
module will be called tpm-rng.
If unsure, say Y.
config HW_RANDOM_HISI
tristate "Hisilicon Random Number Generator support"
depends on HW_RANDOM && ARCH_HISI
......
......@@ -27,7 +27,6 @@ obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o
obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
......
/*
* Copyright (C) 2012 Kent Yoder IBM Corporation
*
* HWRNG interfaces to pull RNG data from a TPM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/hw_random.h>
#include <linux/tpm.h>
#define MODULE_NAME "tpm-rng"
static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
return tpm_get_random(TPM_ANY_NUM, data, max);
}
static struct hwrng tpm_rng = {
.name = MODULE_NAME,
.read = tpm_rng_read,
};
static int __init rng_init(void)
{
return hwrng_register(&tpm_rng);
}
module_init(rng_init);
static void __exit rng_exit(void)
{
hwrng_unregister(&tpm_rng);
}
module_exit(rng_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("RNG driver for TPM devices");
......@@ -26,6 +26,17 @@ menuconfig TCG_TPM
if TCG_TPM
config HW_RANDOM_TPM
bool "TPM HW Random Number Generator support"
depends on TCG_TPM && HW_RANDOM && !(TCG_TPM=y && HW_RANDOM=m)
default y
---help---
This setting exposes the TPM's Random Number Generator as a hwrng
device. This allows the kernel to collect randomness from the TPM at
boot, and provides the TPM randomines in /dev/hwrng.
If unsure, say Y.
config TCG_TIS_CORE
tristate
---help---
......
......@@ -6,8 +6,9 @@ obj-$(CONFIG_TCG_TPM) += tpm.o
tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \
tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \
tpm2-space.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
tpm-$(CONFIG_OF) += tpm_of.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_eventlog_acpi.o
tpm-$(CONFIG_EFI) += tpm_eventlog_efi.o
tpm-$(CONFIG_OF) += tpm_eventlog_of.o
obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
......
......@@ -26,8 +26,9 @@
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include <linux/major.h>
#include <linux/tpm_eventlog.h>
#include <linux/hw_random.h>
#include "tpm.h"
#include "tpm_eventlog.h"
DEFINE_IDR(dev_nums_idr);
static DEFINE_MUTEX(idr_lock);
......@@ -80,21 +81,26 @@ void tpm_put_ops(struct tpm_chip *chip)
EXPORT_SYMBOL_GPL(tpm_put_ops);
/**
* tpm_chip_find_get() - return tpm_chip for a given chip number
* @chip_num: id to find
* tpm_chip_find_get() - find and reserve a TPM chip
* @chip: a &struct tpm_chip instance, %NULL for the default chip
*
* The return'd chip has been tpm_try_get_ops'd and must be released via
* tpm_put_ops
* Finds a TPM chip and reserves its class device and operations. The chip must
* be released with tpm_chip_put_ops() after use.
*
* Return:
* A reserved &struct tpm_chip instance.
* %NULL if a chip is not found.
* %NULL if the chip is not available.
*/
struct tpm_chip *tpm_chip_find_get(int chip_num)
struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip)
{
struct tpm_chip *chip, *res = NULL;
struct tpm_chip *res = NULL;
int chip_num = 0;
int chip_prev;
mutex_lock(&idr_lock);
if (chip_num == TPM_ANY_NUM) {
chip_num = 0;
if (!chip) {
do {
chip_prev = chip_num;
chip = idr_get_next(&dev_nums_idr, &chip_num);
......@@ -104,8 +110,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num)
}
} while (chip_prev != chip_num);
} else {
chip = idr_find(&dev_nums_idr, chip_num);
if (chip && !tpm_try_get_ops(chip))
if (!tpm_try_get_ops(chip))
res = chip;
}
......@@ -387,6 +392,26 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
return 0;
}
static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{
struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
return tpm_get_random(chip, data, max);
}
static int tpm_add_hwrng(struct tpm_chip *chip)
{
if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM))
return 0;
snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
"tpm-rng-%d", chip->dev_num);
chip->hwrng.name = chip->hwrng_name;
chip->hwrng.read = tpm_hwrng_read;
return hwrng_register(&chip->hwrng);
}
/*
* tpm_chip_register() - create a character device for the TPM chip
* @chip: TPM chip to use.
......@@ -419,11 +444,13 @@ int tpm_chip_register(struct tpm_chip *chip)
tpm_add_ppi(chip);
rc = tpm_add_hwrng(chip);
if (rc)
goto out_ppi;
rc = tpm_add_char_device(chip);
if (rc) {
tpm_bios_log_teardown(chip);
return rc;
}
if (rc)
goto out_hwrng;
rc = tpm_add_legacy_sysfs(chip);
if (rc) {
......@@ -432,6 +459,14 @@ int tpm_chip_register(struct tpm_chip *chip)
}
return 0;
out_hwrng:
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
hwrng_unregister(&chip->hwrng);
out_ppi:
tpm_bios_log_teardown(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_chip_register);
......@@ -451,6 +486,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
void tpm_chip_unregister(struct tpm_chip *chip)
{
tpm_del_legacy_sysfs(chip);
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
hwrng_unregister(&chip->hwrng);
tpm_bios_log_teardown(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
cdev_device_del(&chip->cdevs, &chip->devs);
......
This diff is collapsed.
......@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/hw_random.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
......@@ -34,6 +35,7 @@
#include <linux/acpi.h>
#include <linux/cdev.h>
#include <linux/highmem.h>
#include <linux/tpm_eventlog.h>
#include <crypto/hash_info.h>
#ifdef CONFIG_X86
......@@ -93,12 +95,17 @@ enum tpm2_structures {
TPM2_ST_SESSIONS = 0x8002,
};
/* Indicates from what layer of the software stack the error comes from */
#define TSS2_RC_LAYER_SHIFT 16
#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
enum tpm2_return_codes {
TPM2_RC_SUCCESS = 0x0000,
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
TPM2_RC_HANDLE = 0x008B,
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
TPM2_RC_DISABLED = 0x0120,
TPM2_RC_COMMAND_CODE = 0x0143,
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
TPM2_RC_REFERENCE_H0 = 0x0910,
};
......@@ -210,6 +217,9 @@ struct tpm_chip {
int dev_num; /* /dev/tpm# */
unsigned long is_open; /* only one allowed */
char hwrng_name[64];
struct hwrng hwrng;
struct mutex tpm_mutex; /* tpm is processing */
unsigned long timeout_a; /* jiffies */
......@@ -385,10 +395,6 @@ struct tpm_cmd_t {
tpm_cmd_params params;
} __packed;
struct tpm2_digest {
u16 alg_id;
u8 digest[SHA512_DIGEST_SIZE];
} __packed;
/* A string buffer type for constructing TPM commands. This is based on the
* ideas of string buffer code in security/keys/trusted.h but is heap based
......@@ -512,16 +518,14 @@ int tpm_do_selftest(struct tpm_chip *chip);
unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
int tpm_pm_suspend(struct device *dev);
int tpm_pm_resume(struct device *dev);
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
wait_queue_head_t *queue, bool check_cancel);
static inline void tpm_msleep(unsigned int delay_msec)
{
usleep_range(delay_msec * 1000,
(delay_msec * 1000) + TPM_TIMEOUT_RANGE_US);
usleep_range((delay_msec * 1000) - TPM_TIMEOUT_RANGE_US,
delay_msec * 1000);
};
struct tpm_chip *tpm_chip_find_get(int chip_num);
struct tpm_chip *tpm_chip_find_get(struct tpm_chip *chip);
__must_check int tpm_try_get_ops(struct tpm_chip *chip);
void tpm_put_ops(struct tpm_chip *chip);
......@@ -575,4 +579,34 @@ int tpm2_prepare_space(struct tpm_chip *chip, struct tpm_space *space, u32 cc,
u8 *cmd);
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
u32 cc, u8 *buf, size_t *bufsiz);
extern const struct seq_operations tpm2_binary_b_measurements_seqops;
#if defined(CONFIG_ACPI)
int tpm_read_log_acpi(struct tpm_chip *chip);
#else
static inline int tpm_read_log_acpi(struct tpm_chip *chip)
{
return -ENODEV;
}
#endif
#if defined(CONFIG_OF)
int tpm_read_log_of(struct tpm_chip *chip);
#else
static inline int tpm_read_log_of(struct tpm_chip *chip)
{
return -ENODEV;
}
#endif
#if defined(CONFIG_EFI)
int tpm_read_log_efi(struct tpm_chip *chip);
#else
static inline int tpm_read_log_efi(struct tpm_chip *chip)
{
return -ENODEV;
}
#endif
int tpm_bios_log_setup(struct tpm_chip *chip);
void tpm_bios_log_teardown(struct tpm_chip *chip);
#endif
......@@ -21,13 +21,14 @@
*/
#include <linux/seq_file.h>
#include <linux/efi.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
#include "tpm_eventlog.h"
static const char* tcpa_event_type_strings[] = {
......@@ -371,6 +372,10 @@ static int tpm_read_log(struct tpm_chip *chip)
if (rc != -ENODEV)
return rc;
rc = tpm_read_log_efi(chip);
if (rc != -ENODEV)
return rc;
return tpm_read_log_of(chip);
}
......@@ -388,11 +393,13 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
{
const char *name = dev_name(&chip->dev);
unsigned int cnt;
int log_version;
int rc = 0;
rc = tpm_read_log(chip);
if (rc)
if (rc < 0)
return rc;
log_version = rc;
cnt = 0;
chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
......@@ -404,7 +411,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
cnt++;
chip->bin_log_seqops.chip = chip;
if (chip->flags & TPM_CHIP_FLAG_TPM2)
if (log_version == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
chip->bin_log_seqops.seqops =
&tpm2_binary_b_measurements_seqops;
else
......
......@@ -849,28 +849,26 @@ static const struct tpm_input_header tpm2_selftest_header = {
static int tpm2_do_selftest(struct tpm_chip *chip)
{
int rc;
unsigned int delay_msec = 20;
unsigned int delay_msec = 10;
long duration;
struct tpm2_cmd cmd;
duration = jiffies_to_msecs(
tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
while (duration > 0) {
while (1) {
cmd.header.in = tpm2_selftest_header;
cmd.params.selftest_in.full_test = 0;
rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
0, 0, "continue selftest");
if (rc != TPM2_RC_TESTING)
if (rc != TPM2_RC_TESTING || delay_msec >= duration)
break;
tpm_msleep(delay_msec);
duration -= delay_msec;
/* wait longer the next round */
/* wait longer than before */
delay_msec *= 2;
tpm_msleep(delay_msec);
}
return rc;
......
......@@ -21,9 +21,9 @@
#include <linux/security.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
#include "tpm_eventlog.h"
/*
* calc_tpm2_event_size() - calculate the event size, where event
......
......@@ -25,9 +25,9 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
#include "tpm_eventlog.h"
struct acpi_tcpa {
struct acpi_table_header hdr;
......@@ -102,7 +102,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
memcpy_fromio(log->bios_event_log, virt, len);
acpi_os_unmap_iomem(virt, len);
return 0;
return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
err:
kfree(log->bios_event_log);
......
/*
* Copyright (C) 2017 Google
*
* Authors:
* Thiebaud Weksteen <tweek@google.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/efi.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
/* read binary bios log from EFI configuration table */
int tpm_read_log_efi(struct tpm_chip *chip)
{
struct linux_efi_tpm_eventlog *log_tbl;
struct tpm_bios_log *log;
u32 log_size;
u8 tpm_log_version;
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
return -ENODEV;
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
return -ENODEV;
log = &chip->log;
log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB);
if (!log_tbl) {
pr_err("Could not map UEFI TPM log table !\n");
return -ENOMEM;
}
log_size = log_tbl->size;
memunmap(log_tbl);
log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
MEMREMAP_WB);
if (!log_tbl) {
pr_err("Could not map UEFI TPM log table payload!\n");
return -ENOMEM;
}
/* malloc EventLog space */
log->bios_event_log = kmalloc(log_size, GFP_KERNEL);
if (!log->bios_event_log)
goto err_memunmap;
memcpy(log->bios_event_log, log_tbl->log, log_size);
log->bios_event_log_end = log->bios_event_log + log_size;
tpm_log_version = log_tbl->version;
memunmap(log_tbl);
return tpm_log_version;
err_memunmap:
memunmap(log_tbl);
return -ENOMEM;
}
......@@ -17,9 +17,9 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
#include "tpm_eventlog.h"
int tpm_read_log_of(struct tpm_chip *chip)
{
......@@ -76,5 +76,7 @@ int tpm_read_log_of(struct tpm_chip *chip)
memcpy(log->bios_event_log, __va(base), size);
return 0;
if (chip->flags & TPM_CHIP_FLAG_TPM2)
return EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
}
......@@ -665,9 +665,9 @@ static int tpm_tis_i2c_init(struct device *dev)
}
static const struct i2c_device_id tpm_tis_i2c_table[] = {
{"tpm_i2c_infineon", 0},
{"slb9635tt", 0},
{"slb9645tt", 1},
{"tpm_i2c_infineon"},
{"slb9635tt"},
{"slb9645tt"},
{},
};
......@@ -675,24 +675,9 @@ MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
#ifdef CONFIG_OF
static const struct of_device_id tpm_tis_i2c_of_match[] = {
{
.name = "tpm_i2c_infineon",
.type = "tpm",
.compatible = "infineon,tpm_i2c_infineon",
.data = (void *)0
},
{
.name = "slb9635tt",
.type = "tpm",
.compatible = "infineon,slb9635tt",
.data = (void *)0
},
{
.name = "slb9645tt",
.type = "tpm",
.compatible = "infineon,slb9645tt",
.data = (void *)1
},
{.compatible = "infineon,tpm_i2c_infineon"},
{.compatible = "infineon,slb9635tt"},
{.compatible = "infineon,slb9645tt"},
{},
};
MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
......
......@@ -133,93 +133,14 @@ static int check_acpi_tpm2(struct device *dev)
}
#endif
#ifdef CONFIG_X86
#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
#define ILB_REMAP_SIZE 0x100
#define LPC_CNTRL_REG_OFFSET 0x84
#define LPC_CLKRUN_EN (1 << 2)
static void __iomem *ilb_base_addr;
static inline bool is_bsw(void)
{
return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0);
}
/**
* tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running
*/
static void tpm_platform_begin_xfer(void)
{
u32 clkrun_val;
if (!is_bsw())
return;
clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET);
/* Disable LPC CLKRUN# */
clkrun_val &= ~LPC_CLKRUN_EN;
iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET);
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
}
/**
* tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off
*/
static void tpm_platform_end_xfer(void)
{
u32 clkrun_val;
if (!is_bsw())
return;
clkrun_val = ioread32(ilb_base_addr + LPC_CNTRL_REG_OFFSET);
/* Enable LPC CLKRUN# */
clkrun_val |= LPC_CLKRUN_EN;
iowrite32(clkrun_val, ilb_base_addr + LPC_CNTRL_REG_OFFSET);
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
}
#else
static inline bool is_bsw(void)
{
return false;
}
static void tpm_platform_begin_xfer(void)
{
}
static void tpm_platform_end_xfer(void)
{
}
#endif
static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
u8 *result)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
tpm_platform_begin_xfer();
while (len--)
*result++ = ioread8(phy->iobase + addr);
tpm_platform_end_xfer();
return 0;
}
......@@ -228,13 +149,9 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
tpm_platform_begin_xfer();
while (len--)
iowrite8(*value++, phy->iobase + addr);
tpm_platform_end_xfer();
return 0;
}
......@@ -242,12 +159,8 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
tpm_platform_begin_xfer();
*result = ioread16(phy->iobase + addr);
tpm_platform_end_xfer();
return 0;
}
......@@ -255,12 +168,8 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
tpm_platform_begin_xfer();
*result = ioread32(phy->iobase + addr);
tpm_platform_end_xfer();
return 0;
}
......@@ -268,12 +177,8 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value)
{
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
tpm_platform_begin_xfer();
iowrite32(value, phy->iobase + addr);
tpm_platform_end_xfer();
return 0;
}
......@@ -461,11 +366,6 @@ static int __init init_tis(void)
if (rc)
goto err_force;
#ifdef CONFIG_X86
if (is_bsw())
ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
ILB_REMAP_SIZE);
#endif
rc = platform_driver_register(&tis_drv);
if (rc)
goto err_platform;
......@@ -484,10 +384,6 @@ static int __init init_tis(void)
err_platform:
if (force_pdev)
platform_device_unregister(force_pdev);
#ifdef CONFIG_X86
if (is_bsw())
iounmap(ilb_base_addr);
#endif
err_force:
return rc;
}
......@@ -497,10 +393,6 @@ static void __exit cleanup_tis(void)
pnp_unregister_driver(&tis_pnp_driver);
platform_driver_unregister(&tis_drv);
#ifdef CONFIG_X86
if (is_bsw())
iounmap(ilb_base_addr);
#endif
if (force_pdev)
platform_device_unregister(force_pdev);
}
......
......@@ -31,6 +31,74 @@
#include "tpm.h"
#include "tpm_tis_core.h"
/* This is a polling delay to check for status and burstcount.
* As per ddwg input, expectation is that status check and burstcount
* check should return within few usecs.
*/
#define TPM_POLL_SLEEP 1 /* msec */
static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value);
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
bool check_cancel, bool *canceled)
{
u8 status = chip->ops->status(chip);
*canceled = false;
if ((status & mask) == mask)
return true;
if (check_cancel && chip->ops->req_canceled(chip, status)) {
*canceled = true;
return true;
}
return false;
}
static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
unsigned long timeout, wait_queue_head_t *queue,
bool check_cancel)
{
unsigned long stop;
long rc;
u8 status;
bool canceled = false;
/* check current status */
status = chip->ops->status(chip);
if ((status & mask) == mask)
return 0;
stop = jiffies + timeout;
if (chip->flags & TPM_CHIP_FLAG_IRQ) {
again:
timeout = stop - jiffies;
if ((long)timeout <= 0)
return -ETIME;
rc = wait_event_interruptible_timeout(*queue,
wait_for_tpm_stat_cond(chip, mask, check_cancel,
&canceled),
timeout);
if (rc > 0) {
if (canceled)
return -ECANCELED;
return 0;
}
if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
}
} else {
do {
tpm_msleep(TPM_POLL_SLEEP);
status = chip->ops->status(chip);
if ((status & mask) == mask)
return 0;
} while (time_before(jiffies, stop));
}
return -ETIME;
}
/* Before we attempt to access the TPM we must see that the valid bit is set.
* The specification says that this bit is 0 at reset and remains 0 until the
* 'TPM has gone through its self test and initialization and has established
......@@ -164,7 +232,7 @@ static int get_burstcount(struct tpm_chip *chip)
burstcnt = (value >> 8) & 0xFFFF;
if (burstcnt)
return burstcnt;
tpm_msleep(TPM_TIMEOUT);
tpm_msleep(TPM_POLL_SLEEP);
} while (time_before(jiffies, stop));
return -EBUSY;
}
......@@ -421,19 +489,28 @@ static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
int i, rc;
u32 did_vid;
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true);
rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid);
if (rc < 0)
return rc;
goto out;
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
if (vendor_timeout_overrides[i].did_vid != did_vid)
continue;
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
sizeof(vendor_timeout_overrides[i].timeout_us));
return true;
rc = true;
}
return false;
rc = false;
out:
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, false);
return rc;
}
/*
......@@ -653,14 +730,73 @@ void tpm_tis_remove(struct tpm_chip *chip)
u32 interrupt;
int rc;
tpm_tis_clkrun_enable(chip, true);
rc = tpm_tis_read32(priv, reg, &interrupt);
if (rc < 0)
interrupt = 0;
tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt);
tpm_tis_clkrun_enable(chip, false);
if (priv->ilb_base_addr)
iounmap(priv->ilb_base_addr);
}
EXPORT_SYMBOL_GPL(tpm_tis_remove);
/**
* tpm_tis_clkrun_enable() - Keep clkrun protocol disabled for entire duration
* of a single TPM command
* @chip: TPM chip to use
* @value: 1 - Disable CLKRUN protocol, so that clocks are free running
* 0 - Enable CLKRUN protocol
* Call this function directly in tpm_tis_remove() in error or driver removal
* path, since the chip->ops is set to NULL in tpm_chip_unregister().
*/
static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value)
{
struct tpm_tis_data *data = dev_get_drvdata(&chip->dev);
u32 clkrun_val;
if (!IS_ENABLED(CONFIG_X86) || !is_bsw() ||
!data->ilb_base_addr)
return;
if (value) {
data->clkrun_enabled++;
if (data->clkrun_enabled > 1)
return;
clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET);
/* Disable LPC CLKRUN# */
clkrun_val &= ~LPC_CLKRUN_EN;
iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
} else {
data->clkrun_enabled--;
if (data->clkrun_enabled)
return;
clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET);
/* Enable LPC CLKRUN# */
clkrun_val |= LPC_CLKRUN_EN;
iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET);
/*
* Write any random value on port 0x80 which is on LPC, to make
* sure LPC clock is running before sending any TPM command.
*/
outb(0xCC, 0x80);
}
}
static const struct tpm_class_ops tpm_tis = {
.flags = TPM_OPS_AUTO_STARTUP,
.status = tpm_tis_status,
......@@ -673,13 +809,17 @@ static const struct tpm_class_ops tpm_tis = {
.req_canceled = tpm_tis_req_canceled,
.request_locality = request_locality,
.relinquish_locality = release_locality,
.clk_enable = tpm_tis_clkrun_enable,
};
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
const struct tpm_tis_phy_ops *phy_ops,
acpi_handle acpi_dev_handle)
{
u32 vendor, intfcaps, intmask;
u32 vendor;
u32 intfcaps;
u32 intmask;
u32 clkrun_val;
u8 rid;
int rc, probe;
struct tpm_chip *chip;
......@@ -700,6 +840,23 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
priv->phy_ops = phy_ops;
dev_set_drvdata(&chip->dev, priv);
if (is_bsw()) {
priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
ILB_REMAP_SIZE);
if (!priv->ilb_base_addr)
return -ENOMEM;
clkrun_val = ioread32(priv->ilb_base_addr + LPC_CNTRL_OFFSET);
/* Check if CLKRUN# is already not enabled in the LPC bus */
if (!(clkrun_val & LPC_CLKRUN_EN)) {
iounmap(priv->ilb_base_addr);
priv->ilb_base_addr = NULL;
}
}
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true);
if (wait_startup(chip, 0) != 0) {
rc = -ENODEV;
goto out_err;
......@@ -790,9 +947,20 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
}
}
return tpm_chip_register(chip);
rc = tpm_chip_register(chip);
if (rc)
goto out_err;
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, false);
return 0;
out_err:
if ((chip->ops != NULL) && (chip->ops->clk_enable != NULL))
chip->ops->clk_enable(chip, false);
tpm_tis_remove(chip);
return rc;
}
EXPORT_SYMBOL_GPL(tpm_tis_core_init);
......@@ -804,22 +972,31 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
u32 intmask;
int rc;
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true);
/* reenable interrupts that device may have lost or
* BIOS/firmware may have disabled
*/
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq);
if (rc < 0)
return;
goto out;
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
if (rc < 0)
return;
goto out;
intmask |= TPM_INTF_CMD_READY_INT
| TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
| TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
out:
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, false);
return;
}
int tpm_tis_resume(struct device *dev)
......
......@@ -79,6 +79,11 @@ enum tis_defaults {
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
#define TPM_RID(l) (0x0F04 | ((l) << 12))
#define LPC_CNTRL_OFFSET 0x84
#define LPC_CLKRUN_EN (1 << 2)
#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
#define ILB_REMAP_SIZE 0x100
enum tpm_tis_flags {
TPM_TIS_ITPM_WORKAROUND = BIT(0),
};
......@@ -89,6 +94,8 @@ struct tpm_tis_data {
int irq;
bool irq_tested;
unsigned int flags;
void __iomem *ilb_base_addr;
u16 clkrun_enabled;
wait_queue_head_t int_queue;
wait_queue_head_t read_queue;
const struct tpm_tis_phy_ops *phy_ops;
......@@ -144,6 +151,15 @@ static inline int tpm_tis_write32(struct tpm_tis_data *data, u32 addr,
return data->phy_ops->write32(data, addr, value);
}
static inline bool is_bsw(void)
{
#ifdef CONFIG_X86
return ((boot_cpu_data.x86_model == INTEL_FAM6_ATOM_AIRMONT) ? 1 : 0);
#else
return false;
#endif
}
void tpm_tis_remove(struct tpm_chip *chip);
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
const struct tpm_tis_phy_ops *phy_ops,
......
......@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/freezer.h>
#include <xen/xen.h>
#include <xen/events.h>
#include <xen/interface/io/tpmif.h>
......@@ -39,6 +40,66 @@ enum status_bits {
VTPM_STATUS_CANCELED = 0x8,
};
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
bool check_cancel, bool *canceled)
{
u8 status = chip->ops->status(chip);
*canceled = false;
if ((status & mask) == mask)
return true;
if (check_cancel && chip->ops->req_canceled(chip, status)) {
*canceled = true;
return true;
}
return false;
}
static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
unsigned long timeout, wait_queue_head_t *queue,
bool check_cancel)
{
unsigned long stop;
long rc;
u8 status;
bool canceled = false;
/* check current status */
status = chip->ops->status(chip);
if ((status & mask) == mask)
return 0;
stop = jiffies + timeout;
if (chip->flags & TPM_CHIP_FLAG_IRQ) {
again:
timeout = stop - jiffies;
if ((long)timeout <= 0)
return -ETIME;
rc = wait_event_interruptible_timeout(*queue,
wait_for_tpm_stat_cond(chip, mask, check_cancel,
&canceled),
timeout);
if (rc > 0) {
if (canceled)
return -ECANCELED;
return 0;
}
if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
}
} else {
do {
tpm_msleep(TPM_TIMEOUT);
status = chip->ops->status(chip);
if ((status & mask) == mask)
return 0;
} while (time_before(jiffies, stop));
}
return -ETIME;
}
static u8 vtpm_status(struct tpm_chip *chip)
{
struct tpm_private *priv = dev_get_drvdata(&chip->dev);
......
......@@ -11,7 +11,7 @@
KASAN_SANITIZE_runtime-wrappers.o := n
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o
obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o
obj-$(CONFIG_EFI) += capsule.o memmap.o
obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_ESRT) += esrt.o
......
......@@ -52,6 +52,7 @@ struct efi __read_mostly efi = {
.properties_table = EFI_INVALID_TABLE_ADDR,
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
.rng_seed = EFI_INVALID_TABLE_ADDR,
.tpm_log = EFI_INVALID_TABLE_ADDR
};
EXPORT_SYMBOL(efi);
......@@ -464,6 +465,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{EFI_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
{NULL_GUID, NULL, NULL},
};
......@@ -552,6 +554,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz,
if (efi_enabled(EFI_MEMMAP))
efi_memattr_init();
efi_tpm_eventlog_init();
/* Parse the EFI Properties table if it exists */
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
efi_properties_table_t *tbl;
......
......@@ -30,8 +30,7 @@ OBJECT_FILES_NON_STANDARD := y
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
KCOV_INSTRUMENT := n
lib-y := efi-stub-helper.o gop.o secureboot.o
lib-$(CONFIG_RESET_ATTACK_MITIGATION) += tpm.o
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o
# include the stub's generic dependencies from lib/ when building for ARM/arm64
arm-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c
......
......@@ -4,15 +4,18 @@
* Copyright (C) 2016 CoreOS, Inc
* Copyright (C) 2017 Google, Inc.
* Matthew Garrett <mjg59@google.com>
* Thiebaud Weksteen <tweek@google.com>
*
* This file is part of the Linux kernel, and is made available under the
* terms of the GNU General Public License version 2.
*/
#include <linux/efi.h>
#include <linux/tpm_eventlog.h>
#include <asm/efi.h>
#include "efistub.h"
#ifdef CONFIG_RESET_ATTACK_MITIGATION
static const efi_char16_t efi_MemoryOverWriteRequest_name[] = {
'M', 'e', 'm', 'o', 'r', 'y', 'O', 'v', 'e', 'r', 'w', 'r', 'i', 't',
'e', 'R', 'e', 'q', 'u', 'e', 's', 't', 'C', 'o', 'n', 't', 'r', 'o',
......@@ -56,3 +59,81 @@ void efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg)
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS, sizeof(val), &val);
}
#endif
void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
{
efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
efi_status_t status;
efi_physical_addr_t log_location, log_last_entry;
struct linux_efi_tpm_eventlog *log_tbl;
unsigned long first_entry_addr, last_entry_addr;
size_t log_size, last_entry_size;
efi_bool_t truncated;
void *tcg2_protocol;
status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
&tcg2_protocol);
if (status != EFI_SUCCESS)
return;
status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol,
EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2,
&log_location, &log_last_entry, &truncated);
if (status != EFI_SUCCESS)
return;
if (!log_location)
return;
first_entry_addr = (unsigned long) log_location;
/*
* We populate the EFI table even if the logs are empty.
*/
if (!log_last_entry) {
log_size = 0;
} else {
last_entry_addr = (unsigned long) log_last_entry;
/*
* get_event_log only returns the address of the last entry.
* We need to calculate its size to deduce the full size of
* the logs.
*/
last_entry_size = sizeof(struct tcpa_event) +
((struct tcpa_event *) last_entry_addr)->event_size;
log_size = log_last_entry - log_location + last_entry_size;
}
/* Allocate space for the logs and copy them. */
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
sizeof(*log_tbl) + log_size,
(void **) &log_tbl);
if (status != EFI_SUCCESS) {
efi_printk(sys_table_arg,
"Unable to allocate memory for event log\n");
return;
}
memset(log_tbl, 0, sizeof(*log_tbl) + log_size);
log_tbl->size = log_size;
log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
memcpy(log_tbl->log, (void *) first_entry_addr, log_size);
status = efi_call_early(install_configuration_table,
&linux_eventlog_guid, log_tbl);
if (status != EFI_SUCCESS)
goto err_free;
return;
err_free:
efi_call_early(free_pool, log_tbl);
}
void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table_arg)
{
/* Only try to retrieve the logs in 1.2 format. */
efi_retrieve_tpm2_eventlog_1_2(sys_table_arg);
}
/*
* Copyright (C) 2017 Google, Inc.
* Thiebaud Weksteen <tweek@google.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/memblock.h>
#include <asm/early_ioremap.h>
/*
* Reserve the memory associated with the TPM Event Log configuration table.
*/
int __init efi_tpm_eventlog_init(void)
{
struct linux_efi_tpm_eventlog *log_tbl;
unsigned int tbl_size;
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
return 0;
log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
if (!log_tbl) {
pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
efi.tpm_log);
efi.tpm_log = EFI_INVALID_TABLE_ADDR;
return -ENOMEM;
}
tbl_size = sizeof(*log_tbl) + log_tbl->size;
memblock_reserve(efi.tpm_log, tbl_size);
early_memunmap(log_tbl, sizeof(*log_tbl));
return 0;
}
......@@ -473,6 +473,39 @@ typedef struct {
u64 get_all;
} apple_properties_protocol_64_t;
typedef struct {
u32 get_capability;
u32 get_event_log;
u32 hash_log_extend_event;
u32 submit_command;
u32 get_active_pcr_banks;
u32 set_active_pcr_banks;
u32 get_result_of_set_active_pcr_banks;
} efi_tcg2_protocol_32_t;
typedef struct {
u64 get_capability;
u64 get_event_log;
u64 hash_log_extend_event;
u64 submit_command;
u64 get_active_pcr_banks;
u64 set_active_pcr_banks;
u64 get_result_of_set_active_pcr_banks;
} efi_tcg2_protocol_64_t;
typedef u32 efi_tcg2_event_log_format;
typedef struct {
void *get_capability;
efi_status_t (*get_event_log)(efi_handle_t, efi_tcg2_event_log_format,
efi_physical_addr_t *, efi_physical_addr_t *, efi_bool_t *);
void *hash_log_extend_event;
void *submit_command;
void *get_active_pcr_banks;
void *set_active_pcr_banks;
void *get_result_of_set_active_pcr_banks;
} efi_tcg2_protocol_t;
/*
* Types and defines for EFI ResetSystem
*/
......@@ -623,6 +656,7 @@ void efi_native_runtime_setup(void);
#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
#define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
#define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb, 0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
#define EFI_TCG2_PROTOCOL_GUID EFI_GUID(0x607f766c, 0x7455, 0x42be, 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f)
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
......@@ -635,6 +669,7 @@ void efi_native_runtime_setup(void);
#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
#define LINUX_EFI_RANDOM_SEED_TABLE_GUID EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2, 0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
#define LINUX_EFI_TPM_EVENT_LOG_GUID EFI_GUID(0xb7799cb0, 0xeca2, 0x4943, 0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
typedef struct {
efi_guid_t guid;
......@@ -909,6 +944,7 @@ extern struct efi {
unsigned long properties_table; /* properties table */
unsigned long mem_attr_table; /* memory attributes table */
unsigned long rng_seed; /* UEFI firmware random seed */
unsigned long tpm_log; /* TPM2 Event Log table */
efi_get_time_t *get_time;
efi_set_time_t *set_time;
efi_get_wakeup_time_t *get_wakeup_time;
......@@ -1534,6 +1570,8 @@ static inline void
efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) { }
#endif
void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table);
/*
* Arch code can implement the following three template macros, avoiding
* reptition for the void/non-void return cases of {__,}efi_call_virt():
......@@ -1601,4 +1639,12 @@ struct linux_efi_random_seed {
u8 bits[];
};
struct linux_efi_tpm_eventlog {
u32 size;
u8 version;
u8 log[];
};
extern int efi_tpm_eventlog_init(void);
#endif /* _LINUX_EFI_H */
......@@ -24,11 +24,6 @@
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
/*
* Chip num is this value or a valid tpm idx
*/
#define TPM_ANY_NUM 0xFFFF
struct tpm_chip;
struct trusted_key_payload;
struct trusted_key_options;
......@@ -50,46 +45,52 @@ struct tpm_class_ops {
unsigned long *timeout_cap);
int (*request_locality)(struct tpm_chip *chip, int loc);
void (*relinquish_locality)(struct tpm_chip *chip, int loc);
void (*clk_enable)(struct tpm_chip *chip, bool value);
};
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
extern int tpm_is_tpm2(u32 chip_num);
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
extern int tpm_seal_trusted(u32 chip_num,
extern int tpm_is_tpm2(struct tpm_chip *chip);
extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen);
extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max);
extern int tpm_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
extern int tpm_unseal_trusted(u32 chip_num,
extern int tpm_unseal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options);
#else
static inline int tpm_is_tpm2(u32 chip_num)
static inline int tpm_is_tpm2(struct tpm_chip *chip)
{
return -ENODEV;
}
static inline int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) {
static inline int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
{
return -ENODEV;
}
static inline int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) {
static inline int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx,
const u8 *hash)
{
return -ENODEV;
}
static inline int tpm_send(u32 chip_num, void *cmd, size_t buflen) {
static inline int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
{
return -ENODEV;
}
static inline int tpm_get_random(u32 chip_num, u8 *data, size_t max) {
static inline int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max)
{
return -ENODEV;
}
static inline int tpm_seal_trusted(u32 chip_num,
static inline int tpm_seal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
return -ENODEV;
}
static inline int tpm_unseal_trusted(u32 chip_num,
static inline int tpm_unseal_trusted(struct tpm_chip *chip,
struct trusted_key_payload *payload,
struct trusted_key_options *options)
{
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __TPM_EVENTLOG_H__
#define __TPM_EVENTLOG_H__
#ifndef __LINUX_TPM_EVENTLOG_H__
#define __LINUX_TPM_EVENTLOG_H__
#include <crypto/hash_info.h>
......@@ -10,6 +10,9 @@
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
#define TPM2_ACTIVE_PCR_BANKS 3
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x1
#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x2
#ifdef CONFIG_PPC64
#define do_endian_conversion(x) be32_to_cpu(x)
#else
......@@ -105,6 +108,11 @@ struct tcg_event_field {
u8 event[0];
} __packed;
struct tpm2_digest {
u16 alg_id;
u8 digest[SHA512_DIGEST_SIZE];
} __packed;
struct tcg_pcr_event2 {
u32 pcr_idx;
u32 event_type;
......@@ -113,26 +121,4 @@ struct tcg_pcr_event2 {
struct tcg_event_field event;
} __packed;
extern const struct seq_operations tpm2_binary_b_measurements_seqops;
#if defined(CONFIG_ACPI)
int tpm_read_log_acpi(struct tpm_chip *chip);
#else
static inline int tpm_read_log_acpi(struct tpm_chip *chip)
{
return -ENODEV;
}
#endif
#if defined(CONFIG_OF)
int tpm_read_log_of(struct tpm_chip *chip);
#else
static inline int tpm_read_log_of(struct tpm_chip *chip)
{
return -ENODEV;
}
#endif
int tpm_bios_log_setup(struct tpm_chip *chip);
void tpm_bios_log_teardown(struct tpm_chip *chip);
#endif
......@@ -632,7 +632,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)
if (!ima_used_chip)
return;
if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
if (tpm_pcr_read(NULL, idx, pcr) != 0)
pr_err("Error Communicating to TPM chip\n");
}
......
......@@ -110,7 +110,7 @@ int __init ima_init(void)
int rc;
ima_used_chip = 0;
rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i);
rc = tpm_pcr_read(NULL, 0, pcr_i);
if (rc == 0)
ima_used_chip = 1;
......
......@@ -145,7 +145,7 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
if (!ima_used_chip)
return result;
result = tpm_pcr_extend(TPM_ANY_NUM, pcr, hash);
result = tpm_pcr_extend(NULL, pcr, hash);
if (result != 0)
pr_err("Error Communicating to TPM chip, result: %d\n", result);
return result;
......
......@@ -355,13 +355,12 @@ static int TSS_checkhmac2(unsigned char *buffer,
* For key specific tpm requests, we will generate and send our
* own TPM command packets using the drivers send function.
*/
static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
size_t buflen)
static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
{
int rc;
dump_tpm_buf(cmd);
rc = tpm_send(chip_num, cmd, buflen);
rc = tpm_send(NULL, cmd, buflen);
dump_tpm_buf(cmd);
if (rc > 0)
/* Can't return positive return codes values to keyctl */
......@@ -382,10 +381,10 @@ static int pcrlock(const int pcrnum)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE);
ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);
if (ret != SHA1_DIGEST_SIZE)
return ret;
return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0;
return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;
}
/*
......@@ -398,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
unsigned char ononce[TPM_NONCE_SIZE];
int ret;
ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE);
ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE)
return ret;
......@@ -410,7 +409,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
store32(tb, handle);
storebytes(tb, ononce, TPM_NONCE_SIZE);
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
if (ret < 0)
return ret;
......@@ -434,7 +433,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)
store16(tb, TPM_TAG_RQU_COMMAND);
store32(tb, TPM_OIAP_SIZE);
store32(tb, TPM_ORD_OIAP);
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
if (ret < 0)
return ret;
......@@ -493,7 +492,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
if (ret < 0)
goto out;
ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE);
ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE)
goto out;
ordinal = htonl(TPM_ORD_SEAL);
......@@ -542,7 +541,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
store8(tb, cont);
storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
if (ret < 0)
goto out;
......@@ -603,7 +602,7 @@ static int tpm_unseal(struct tpm_buf *tb,
ordinal = htonl(TPM_ORD_UNSEAL);
keyhndl = htonl(SRKHANDLE);
ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE);
ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);
if (ret != TPM_NONCE_SIZE) {
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
return ret;
......@@ -635,7 +634,7 @@ static int tpm_unseal(struct tpm_buf *tb,
store8(tb, cont);
storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE);
ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);
if (ret < 0) {
pr_info("trusted_key: authhmac failed (%d)\n", ret);
return ret;
......@@ -748,7 +747,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
int i;
int tpm2;
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
tpm2 = tpm_is_tpm2(NULL);
if (tpm2 < 0)
return tpm2;
......@@ -917,7 +916,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
struct trusted_key_options *options;
int tpm2;
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
tpm2 = tpm_is_tpm2(NULL);
if (tpm2 < 0)
return NULL;
......@@ -967,7 +966,7 @@ static int trusted_instantiate(struct key *key,
size_t key_len;
int tpm2;
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
tpm2 = tpm_is_tpm2(NULL);
if (tpm2 < 0)
return tpm2;
......@@ -1008,7 +1007,7 @@ static int trusted_instantiate(struct key *key,
switch (key_cmd) {
case Opt_load:
if (tpm2)
ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options);
ret = tpm_unseal_trusted(NULL, payload, options);
else
ret = key_unseal(payload, options);
dump_payload(payload);
......@@ -1018,13 +1017,13 @@ static int trusted_instantiate(struct key *key,
break;
case Opt_new:
key_len = payload->key_len;
ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len);
ret = tpm_get_random(NULL, payload->key, key_len);
if (ret != key_len) {
pr_info("trusted_key: key_create failed (%d)\n", ret);
goto out;
}
if (tpm2)
ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options);
ret = tpm_seal_trusted(NULL, payload, options);
else
ret = key_seal(payload, options);
if (ret < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment