Merge branch 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull tpm updates from James Morris: - reduce polling delays in tpm_tis - support retrieving TPM 2.0 Event Log through EFI before ExitBootServices - replace tpm-rng.c with a hwrng device managed by the driver for each TPM device - TPM resource manager synthesizes TPM_RC_COMMAND_CODE response instead of returning -EINVAL for unknown TPM commands. This makes user space more sound. - CLKRUN fixes: * Keep #CLKRUN disable through the entier TPM command/response flow * Check whether #CLKRUN is enabled before disabling and enabling it again because enabling it breaks PS/2 devices on a system where it is disabled * 'next-tpm' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: tpm: remove unused variables tpm: remove unused data fields from I2C and OF device ID tables tpm: only attempt to disable the LPC CLKRUN if is already enabled tpm: follow coding style for variable declaration in tpm_tis_core_init() tpm: delete the TPM_TIS_CLK_ENABLE flag tpm: Update MAINTAINERS for Jason Gunthorpe tpm: Keep CLKRUN enabled throughout the duration of transmit_cmd() tpm_tis: Move ilb_base_addr to tpm_tis_data tpm2-cmd: allow more attempts for selftest execution tpm: return a TPM_RC_COMMAND_CODE response if command is not implemented tpm: Move Linux RNG connection to hwrng tpm: use struct tpm_chip for tpm_chip_find_get() tpm: parse TPM event logs based on EFI table efi: call get_event_log before ExitBootServices tpm: add event log format version tpm: rename event log provider files tpm: move tpm_eventlog.h outside of drivers folder tpm: use tpm_msleep() value as max delay tpm: reduce tpm polling delay in tpm_tis_core tpm: move wait_for_tpm_stat() to respective driver files
This commit is contained in:
commit
ae0cb7be35
|
@ -13869,9 +13869,10 @@ F: drivers/platform/x86/toshiba-wmi.c
|
||||||
TPM DEVICE DRIVER
|
TPM DEVICE DRIVER
|
||||||
M: Peter Huewe <peterhuewe@gmx.de>
|
M: Peter Huewe <peterhuewe@gmx.de>
|
||||||
M: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
|
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
|
L: linux-integrity@vger.kernel.org
|
||||||
Q: https://patchwork.kernel.org/project/linux-integrity/list/
|
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
|
T: git git://git.infradead.org/users/jjs/linux-tpmdd.git
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/char/tpm/
|
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 */
|
/* Ask the firmware to clear memory on unclean shutdown */
|
||||||
efi_enable_reset_attack_mitigation(sys_table);
|
efi_enable_reset_attack_mitigation(sys_table);
|
||||||
|
efi_retrieve_tpm2_eventlog(sys_table);
|
||||||
|
|
||||||
setup_graphics(boot_params);
|
setup_graphics(boot_params);
|
||||||
|
|
||||||
|
|
|
@ -306,19 +306,6 @@ config HW_RANDOM_POWERNV
|
||||||
|
|
||||||
If unsure, say Y.
|
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
|
config HW_RANDOM_HISI
|
||||||
tristate "Hisilicon Random Number Generator support"
|
tristate "Hisilicon Random Number Generator support"
|
||||||
depends on HW_RANDOM && ARCH_HISI
|
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_PSERIES) += pseries-rng.o
|
||||||
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
|
obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
|
||||||
obj-$(CONFIG_HW_RANDOM_HISI) += hisi-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_BCM2835) += bcm2835-rng.o
|
||||||
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
|
obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
|
||||||
obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
|
obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2012 Kent Yoder IBM Corporation
|
|
||||||
*
|
|
||||||
* HWRNG interfaces to pull RNG data from a TPM
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/hw_random.h>
|
|
||||||
#include <linux/tpm.h>
|
|
||||||
|
|
||||||
#define MODULE_NAME "tpm-rng"
|
|
||||||
|
|
||||||
static int tpm_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
|
|
||||||
{
|
|
||||||
return tpm_get_random(TPM_ANY_NUM, data, max);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct hwrng tpm_rng = {
|
|
||||||
.name = MODULE_NAME,
|
|
||||||
.read = tpm_rng_read,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init rng_init(void)
|
|
||||||
{
|
|
||||||
return hwrng_register(&tpm_rng);
|
|
||||||
}
|
|
||||||
module_init(rng_init);
|
|
||||||
|
|
||||||
static void __exit rng_exit(void)
|
|
||||||
{
|
|
||||||
hwrng_unregister(&tpm_rng);
|
|
||||||
}
|
|
||||||
module_exit(rng_exit);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
||||||
MODULE_AUTHOR("Kent Yoder <key@linux.vnet.ibm.com>");
|
|
||||||
MODULE_DESCRIPTION("RNG driver for TPM devices");
|
|
|
@ -26,6 +26,17 @@ menuconfig TCG_TPM
|
||||||
|
|
||||||
if 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
|
config TCG_TIS_CORE
|
||||||
tristate
|
tristate
|
||||||
---help---
|
---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-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 \
|
tpm-dev-common.o tpmrm-dev.o tpm1_eventlog.o tpm2_eventlog.o \
|
||||||
tpm2-space.o
|
tpm2-space.o
|
||||||
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o
|
tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_eventlog_acpi.o
|
||||||
tpm-$(CONFIG_OF) += tpm_of.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_CORE) += tpm_tis_core.o
|
||||||
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
|
obj-$(CONFIG_TCG_TIS) += tpm_tis.o
|
||||||
obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
|
obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o
|
||||||
|
|
|
@ -26,8 +26,9 @@
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
#include <linux/major.h>
|
#include <linux/major.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
#include <linux/hw_random.h>
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
|
||||||
|
|
||||||
DEFINE_IDR(dev_nums_idr);
|
DEFINE_IDR(dev_nums_idr);
|
||||||
static DEFINE_MUTEX(idr_lock);
|
static DEFINE_MUTEX(idr_lock);
|
||||||
|
@ -80,21 +81,26 @@ void tpm_put_ops(struct tpm_chip *chip)
|
||||||
EXPORT_SYMBOL_GPL(tpm_put_ops);
|
EXPORT_SYMBOL_GPL(tpm_put_ops);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_chip_find_get() - return tpm_chip for a given chip number
|
* tpm_chip_find_get() - find and reserve a TPM chip
|
||||||
* @chip_num: id to find
|
* @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
|
* Finds a TPM chip and reserves its class device and operations. The chip must
|
||||||
* tpm_put_ops
|
* 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;
|
int chip_prev;
|
||||||
|
|
||||||
mutex_lock(&idr_lock);
|
mutex_lock(&idr_lock);
|
||||||
|
|
||||||
if (chip_num == TPM_ANY_NUM) {
|
if (!chip) {
|
||||||
chip_num = 0;
|
|
||||||
do {
|
do {
|
||||||
chip_prev = chip_num;
|
chip_prev = chip_num;
|
||||||
chip = idr_get_next(&dev_nums_idr, &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);
|
} while (chip_prev != chip_num);
|
||||||
} else {
|
} else {
|
||||||
chip = idr_find(&dev_nums_idr, chip_num);
|
if (!tpm_try_get_ops(chip))
|
||||||
if (chip && !tpm_try_get_ops(chip))
|
|
||||||
res = chip;
|
res = chip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,6 +392,26 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
|
||||||
|
|
||||||
return 0;
|
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
|
* tpm_chip_register() - create a character device for the TPM chip
|
||||||
* @chip: TPM chip to use.
|
* @chip: TPM chip to use.
|
||||||
|
@ -419,11 +444,13 @@ int tpm_chip_register(struct tpm_chip *chip)
|
||||||
|
|
||||||
tpm_add_ppi(chip);
|
tpm_add_ppi(chip);
|
||||||
|
|
||||||
|
rc = tpm_add_hwrng(chip);
|
||||||
|
if (rc)
|
||||||
|
goto out_ppi;
|
||||||
|
|
||||||
rc = tpm_add_char_device(chip);
|
rc = tpm_add_char_device(chip);
|
||||||
if (rc) {
|
if (rc)
|
||||||
tpm_bios_log_teardown(chip);
|
goto out_hwrng;
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = tpm_add_legacy_sysfs(chip);
|
rc = tpm_add_legacy_sysfs(chip);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -432,6 +459,14 @@ int tpm_chip_register(struct tpm_chip *chip)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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);
|
EXPORT_SYMBOL_GPL(tpm_chip_register);
|
||||||
|
|
||||||
|
@ -451,6 +486,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
|
||||||
void tpm_chip_unregister(struct tpm_chip *chip)
|
void tpm_chip_unregister(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
tpm_del_legacy_sysfs(chip);
|
tpm_del_legacy_sysfs(chip);
|
||||||
|
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
|
||||||
|
hwrng_unregister(&chip->hwrng);
|
||||||
tpm_bios_log_teardown(chip);
|
tpm_bios_log_teardown(chip);
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
cdev_device_del(&chip->cdevs, &chip->devs);
|
cdev_device_del(&chip->cdevs, &chip->devs);
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/freezer.h>
|
#include <linux/freezer.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
|
||||||
|
|
||||||
#define TPM_MAX_ORDINAL 243
|
#define TPM_MAX_ORDINAL 243
|
||||||
#define TSC_MAX_ORDINAL 12
|
#define TSC_MAX_ORDINAL 12
|
||||||
|
@ -328,7 +328,7 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration);
|
||||||
|
|
||||||
static bool tpm_validate_command(struct tpm_chip *chip,
|
static int tpm_validate_command(struct tpm_chip *chip,
|
||||||
struct tpm_space *space,
|
struct tpm_space *space,
|
||||||
const u8 *cmd,
|
const u8 *cmd,
|
||||||
size_t len)
|
size_t len)
|
||||||
|
@ -340,10 +340,10 @@ static bool tpm_validate_command(struct tpm_chip *chip,
|
||||||
unsigned int nr_handles;
|
unsigned int nr_handles;
|
||||||
|
|
||||||
if (len < TPM_HEADER_SIZE)
|
if (len < TPM_HEADER_SIZE)
|
||||||
return false;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!space)
|
if (!space)
|
||||||
return true;
|
return 0;
|
||||||
|
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
|
if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
|
||||||
cc = be32_to_cpu(header->ordinal);
|
cc = be32_to_cpu(header->ordinal);
|
||||||
|
@ -352,7 +352,7 @@ static bool tpm_validate_command(struct tpm_chip *chip,
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
|
dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
|
||||||
cc);
|
cc);
|
||||||
return false;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs = chip->cc_attrs_tbl[i];
|
attrs = chip->cc_attrs_tbl[i];
|
||||||
|
@ -362,11 +362,11 @@ static bool tpm_validate_command(struct tpm_chip *chip,
|
||||||
goto err_len;
|
goto err_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 0;
|
||||||
err_len:
|
err_len:
|
||||||
dev_dbg(&chip->dev,
|
dev_dbg(&chip->dev,
|
||||||
"%s: insufficient command length %zu", __func__, len);
|
"%s: insufficient command length %zu", __func__, len);
|
||||||
return false;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -391,8 +391,20 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||||
unsigned long stop;
|
unsigned long stop;
|
||||||
bool need_locality;
|
bool need_locality;
|
||||||
|
|
||||||
if (!tpm_validate_command(chip, space, buf, bufsiz))
|
rc = tpm_validate_command(chip, space, buf, bufsiz);
|
||||||
return -EINVAL;
|
if (rc == -EINVAL)
|
||||||
|
return rc;
|
||||||
|
/*
|
||||||
|
* If the command is not implemented by the TPM, synthesize a
|
||||||
|
* response with a TPM2_RC_COMMAND_CODE return for user-space.
|
||||||
|
*/
|
||||||
|
if (rc == -EOPNOTSUPP) {
|
||||||
|
header->length = cpu_to_be32(sizeof(*header));
|
||||||
|
header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
|
||||||
|
header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
|
||||||
|
TSS2_RESMGR_TPM_RC_LAYER);
|
||||||
|
return bufsiz;
|
||||||
|
}
|
||||||
|
|
||||||
if (bufsiz > TPM_BUFSIZE)
|
if (bufsiz > TPM_BUFSIZE)
|
||||||
bufsiz = TPM_BUFSIZE;
|
bufsiz = TPM_BUFSIZE;
|
||||||
|
@ -413,6 +425,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
||||||
if (chip->dev.parent)
|
if (chip->dev.parent)
|
||||||
pm_runtime_get_sync(chip->dev.parent);
|
pm_runtime_get_sync(chip->dev.parent);
|
||||||
|
|
||||||
|
if (chip->ops->clk_enable != NULL)
|
||||||
|
chip->ops->clk_enable(chip, true);
|
||||||
|
|
||||||
/* Store the decision as chip->locality will be changed. */
|
/* Store the decision as chip->locality will be changed. */
|
||||||
need_locality = chip->locality == -1;
|
need_locality = chip->locality == -1;
|
||||||
|
|
||||||
|
@ -489,6 +504,9 @@ out:
|
||||||
chip->locality = -1;
|
chip->locality = -1;
|
||||||
}
|
}
|
||||||
out_no_locality:
|
out_no_locality:
|
||||||
|
if (chip->ops->clk_enable != NULL)
|
||||||
|
chip->ops->clk_enable(chip, false);
|
||||||
|
|
||||||
if (chip->dev.parent)
|
if (chip->dev.parent)
|
||||||
pm_runtime_put_sync(chip->dev.parent);
|
pm_runtime_put_sync(chip->dev.parent);
|
||||||
|
|
||||||
|
@ -809,19 +827,20 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_is_tpm2 - is the chip a TPM2 chip?
|
* tpm_is_tpm2 - do we a have a TPM2 chip?
|
||||||
* @chip_num: tpm idx # or ANY
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
*
|
*
|
||||||
* Returns < 0 on error, and 1 or 0 on success depending whether the chip
|
* Return:
|
||||||
* is a TPM2 chip.
|
* 1 if we have a TPM2 chip.
|
||||||
|
* 0 if we don't have a TPM2 chip.
|
||||||
|
* A negative number for system errors (errno).
|
||||||
*/
|
*/
|
||||||
int tpm_is_tpm2(u32 chip_num)
|
int tpm_is_tpm2(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL)
|
if (!chip)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
|
rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
|
||||||
|
@ -833,23 +852,19 @@ int tpm_is_tpm2(u32 chip_num)
|
||||||
EXPORT_SYMBOL_GPL(tpm_is_tpm2);
|
EXPORT_SYMBOL_GPL(tpm_is_tpm2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_pcr_read - read a pcr value
|
* tpm_pcr_read - read a PCR value from SHA1 bank
|
||||||
* @chip_num: tpm idx # or ANY
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
* @pcr_idx: pcr idx to retrieve
|
* @pcr_idx: the PCR to be retrieved
|
||||||
* @res_buf: TPM_PCR value
|
* @res_buf: the value of the PCR
|
||||||
* size of res_buf is 20 bytes (or NULL if you don't care)
|
|
||||||
*
|
*
|
||||||
* The TPM driver should be built-in, but for whatever reason it
|
* Return: same as with tpm_transmit_cmd()
|
||||||
* isn't, protect against the chip disappearing, by incrementing
|
|
||||||
* the module usage count.
|
|
||||||
*/
|
*/
|
||||||
int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
|
int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL)
|
if (!chip)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||||
rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
|
rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
|
||||||
|
@ -889,25 +904,26 @@ static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_pcr_extend - extend pcr value with hash
|
* tpm_pcr_extend - extend a PCR value in SHA1 bank.
|
||||||
* @chip_num: tpm idx # or AN&
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
* @pcr_idx: pcr idx to extend
|
* @pcr_idx: the PCR to be retrieved
|
||||||
* @hash: hash value used to extend pcr value
|
* @hash: the hash value used to extend the PCR value
|
||||||
*
|
*
|
||||||
* The TPM driver should be built-in, but for whatever reason it
|
* Note: with TPM 2.0 extends also those banks with a known digest size to the
|
||||||
* isn't, protect against the chip disappearing, by incrementing
|
* cryto subsystem in order to prevent malicious use of those PCR banks. In the
|
||||||
* the module usage count.
|
* future we should dynamically determine digest sizes.
|
||||||
|
*
|
||||||
|
* Return: same as with tpm_transmit_cmd()
|
||||||
*/
|
*/
|
||||||
int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
|
int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct tpm_chip *chip;
|
|
||||||
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
|
struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL)
|
if (!chip)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
|
@ -1019,82 +1035,29 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tpm_send(u32 chip_num, void *cmd, size_t buflen)
|
/**
|
||||||
|
* tpm_send - send a TPM command
|
||||||
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
|
* @cmd: a TPM command buffer
|
||||||
|
* @buflen: the length of the TPM command buffer
|
||||||
|
*
|
||||||
|
* Return: same as with tpm_transmit_cmd()
|
||||||
|
*/
|
||||||
|
int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL)
|
if (!chip)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
|
rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
|
||||||
"attempting tpm_cmd");
|
"attempting to a send a command");
|
||||||
tpm_put_ops(chip);
|
tpm_put_ops(chip);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_send);
|
EXPORT_SYMBOL_GPL(tpm_send);
|
||||||
|
|
||||||
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
|
|
||||||
bool check_cancel, bool *canceled)
|
|
||||||
{
|
|
||||||
u8 status = chip->ops->status(chip);
|
|
||||||
|
|
||||||
*canceled = false;
|
|
||||||
if ((status & mask) == mask)
|
|
||||||
return true;
|
|
||||||
if (check_cancel && chip->ops->req_canceled(chip, status)) {
|
|
||||||
*canceled = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
|
||||||
wait_queue_head_t *queue, bool check_cancel)
|
|
||||||
{
|
|
||||||
unsigned long stop;
|
|
||||||
long rc;
|
|
||||||
u8 status;
|
|
||||||
bool canceled = false;
|
|
||||||
|
|
||||||
/* check current status */
|
|
||||||
status = chip->ops->status(chip);
|
|
||||||
if ((status & mask) == mask)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
stop = jiffies + timeout;
|
|
||||||
|
|
||||||
if (chip->flags & TPM_CHIP_FLAG_IRQ) {
|
|
||||||
again:
|
|
||||||
timeout = stop - jiffies;
|
|
||||||
if ((long)timeout <= 0)
|
|
||||||
return -ETIME;
|
|
||||||
rc = wait_event_interruptible_timeout(*queue,
|
|
||||||
wait_for_tpm_stat_cond(chip, mask, check_cancel,
|
|
||||||
&canceled),
|
|
||||||
timeout);
|
|
||||||
if (rc > 0) {
|
|
||||||
if (canceled)
|
|
||||||
return -ECANCELED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
|
||||||
clear_thread_flag(TIF_SIGPENDING);
|
|
||||||
goto again;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
tpm_msleep(TPM_TIMEOUT);
|
|
||||||
status = chip->ops->status(chip);
|
|
||||||
if ((status & mask) == mask)
|
|
||||||
return 0;
|
|
||||||
} while (time_before(jiffies, stop));
|
|
||||||
}
|
|
||||||
return -ETIME;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
|
||||||
|
|
||||||
#define TPM_ORD_SAVESTATE 152
|
#define TPM_ORD_SAVESTATE 152
|
||||||
#define SAVESTATE_RESULT_SIZE 10
|
#define SAVESTATE_RESULT_SIZE 10
|
||||||
|
|
||||||
|
@ -1187,16 +1150,15 @@ static const struct tpm_input_header tpm_getrandom_header = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_get_random() - Get random bytes from the tpm's RNG
|
* tpm_get_random() - get random bytes from the TPM's RNG
|
||||||
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
* @out: destination buffer for the random bytes
|
* @out: destination buffer for the random bytes
|
||||||
* @max: the max number of bytes to write to @out
|
* @max: the max number of bytes to write to @out
|
||||||
*
|
*
|
||||||
* Returns < 0 on error and the number of bytes read on success
|
* Return: same as with tpm_transmit_cmd()
|
||||||
*/
|
*/
|
||||||
int tpm_get_random(u32 chip_num, u8 *out, size_t max)
|
int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
|
||||||
struct tpm_cmd_t tpm_cmd;
|
struct tpm_cmd_t tpm_cmd;
|
||||||
u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
|
u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
|
||||||
int err, total = 0, retries = 5;
|
int err, total = 0, retries = 5;
|
||||||
|
@ -1205,8 +1167,8 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
|
||||||
if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
|
if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL)
|
if (!chip)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||||
|
@ -1248,22 +1210,23 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
|
||||||
EXPORT_SYMBOL_GPL(tpm_get_random);
|
EXPORT_SYMBOL_GPL(tpm_get_random);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_seal_trusted() - seal a trusted key
|
* tpm_seal_trusted() - seal a trusted key payload
|
||||||
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
* @options: authentication values and other options
|
* @options: authentication values and other options
|
||||||
* @payload: the key data in clear and encrypted form
|
* @payload: the key data in clear and encrypted form
|
||||||
*
|
*
|
||||||
* Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
|
* Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in
|
||||||
* are supported.
|
* the keyring subsystem.
|
||||||
|
*
|
||||||
|
* Return: same as with tpm_transmit_cmd()
|
||||||
*/
|
*/
|
||||||
int tpm_seal_trusted(u32 chip_num, struct trusted_key_payload *payload,
|
int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload,
|
||||||
struct trusted_key_options *options)
|
struct trusted_key_options *options)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
|
if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rc = tpm2_seal_trusted(chip, payload, options);
|
rc = tpm2_seal_trusted(chip, payload, options);
|
||||||
|
@ -1275,21 +1238,23 @@ EXPORT_SYMBOL_GPL(tpm_seal_trusted);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tpm_unseal_trusted() - unseal a trusted key
|
* tpm_unseal_trusted() - unseal a trusted key
|
||||||
* @chip_num: A specific chip number for the request or TPM_ANY_NUM
|
* @chip: a &struct tpm_chip instance, %NULL for the default chip
|
||||||
* @options: authentication values and other options
|
* @options: authentication values and other options
|
||||||
* @payload: the key data in clear and encrypted form
|
* @payload: the key data in clear and encrypted form
|
||||||
*
|
*
|
||||||
* Returns < 0 on error and 0 on success. At the moment, only TPM 2.0 chips
|
* Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in
|
||||||
* are supported.
|
* the keyring subsystem.
|
||||||
|
*
|
||||||
|
* Return: same as with tpm_transmit_cmd()
|
||||||
*/
|
*/
|
||||||
int tpm_unseal_trusted(u32 chip_num, struct trusted_key_payload *payload,
|
int tpm_unseal_trusted(struct tpm_chip *chip,
|
||||||
|
struct trusted_key_payload *payload,
|
||||||
struct trusted_key_options *options)
|
struct trusted_key_options *options)
|
||||||
{
|
{
|
||||||
struct tpm_chip *chip;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
chip = tpm_chip_find_get(chip_num);
|
chip = tpm_chip_find_get(chip);
|
||||||
if (chip == NULL || !(chip->flags & TPM_CHIP_FLAG_TPM2))
|
if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rc = tpm2_unseal_trusted(chip, payload, options);
|
rc = tpm2_unseal_trusted(chip, payload, options);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/hw_random.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
#include <linux/highmem.h>
|
#include <linux/highmem.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
#include <crypto/hash_info.h>
|
#include <crypto/hash_info.h>
|
||||||
|
|
||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
|
@ -93,12 +95,17 @@ enum tpm2_structures {
|
||||||
TPM2_ST_SESSIONS = 0x8002,
|
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 {
|
enum tpm2_return_codes {
|
||||||
TPM2_RC_SUCCESS = 0x0000,
|
TPM2_RC_SUCCESS = 0x0000,
|
||||||
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
|
TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
|
||||||
TPM2_RC_HANDLE = 0x008B,
|
TPM2_RC_HANDLE = 0x008B,
|
||||||
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
|
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
|
||||||
TPM2_RC_DISABLED = 0x0120,
|
TPM2_RC_DISABLED = 0x0120,
|
||||||
|
TPM2_RC_COMMAND_CODE = 0x0143,
|
||||||
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
|
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
|
||||||
TPM2_RC_REFERENCE_H0 = 0x0910,
|
TPM2_RC_REFERENCE_H0 = 0x0910,
|
||||||
};
|
};
|
||||||
|
@ -210,6 +217,9 @@ struct tpm_chip {
|
||||||
int dev_num; /* /dev/tpm# */
|
int dev_num; /* /dev/tpm# */
|
||||||
unsigned long is_open; /* only one allowed */
|
unsigned long is_open; /* only one allowed */
|
||||||
|
|
||||||
|
char hwrng_name[64];
|
||||||
|
struct hwrng hwrng;
|
||||||
|
|
||||||
struct mutex tpm_mutex; /* tpm is processing */
|
struct mutex tpm_mutex; /* tpm is processing */
|
||||||
|
|
||||||
unsigned long timeout_a; /* jiffies */
|
unsigned long timeout_a; /* jiffies */
|
||||||
|
@ -385,10 +395,6 @@ struct tpm_cmd_t {
|
||||||
tpm_cmd_params params;
|
tpm_cmd_params params;
|
||||||
} __packed;
|
} __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
|
/* 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
|
* 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);
|
unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal);
|
||||||
int tpm_pm_suspend(struct device *dev);
|
int tpm_pm_suspend(struct device *dev);
|
||||||
int tpm_pm_resume(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)
|
static inline void tpm_msleep(unsigned int delay_msec)
|
||||||
{
|
{
|
||||||
usleep_range(delay_msec * 1000,
|
usleep_range((delay_msec * 1000) - TPM_TIMEOUT_RANGE_US,
|
||||||
(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);
|
__must_check int tpm_try_get_ops(struct tpm_chip *chip);
|
||||||
void tpm_put_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);
|
u8 *cmd);
|
||||||
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
|
int tpm2_commit_space(struct tpm_chip *chip, struct tpm_space *space,
|
||||||
u32 cc, u8 *buf, size_t *bufsiz);
|
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
|
#endif
|
||||||
|
|
|
@ -21,13 +21,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/efi.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
|
||||||
|
|
||||||
|
|
||||||
static const char* tcpa_event_type_strings[] = {
|
static const char* tcpa_event_type_strings[] = {
|
||||||
|
@ -371,6 +372,10 @@ static int tpm_read_log(struct tpm_chip *chip)
|
||||||
if (rc != -ENODEV)
|
if (rc != -ENODEV)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
rc = tpm_read_log_efi(chip);
|
||||||
|
if (rc != -ENODEV)
|
||||||
|
return rc;
|
||||||
|
|
||||||
return tpm_read_log_of(chip);
|
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);
|
const char *name = dev_name(&chip->dev);
|
||||||
unsigned int cnt;
|
unsigned int cnt;
|
||||||
|
int log_version;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
rc = tpm_read_log(chip);
|
rc = tpm_read_log(chip);
|
||||||
if (rc)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
log_version = rc;
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
|
chip->bios_dir[cnt] = securityfs_create_dir(name, NULL);
|
||||||
|
@ -404,7 +411,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip)
|
||||||
cnt++;
|
cnt++;
|
||||||
|
|
||||||
chip->bin_log_seqops.chip = chip;
|
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 =
|
chip->bin_log_seqops.seqops =
|
||||||
&tpm2_binary_b_measurements_seqops;
|
&tpm2_binary_b_measurements_seqops;
|
||||||
else
|
else
|
||||||
|
|
|
@ -849,28 +849,26 @@ static const struct tpm_input_header tpm2_selftest_header = {
|
||||||
static int tpm2_do_selftest(struct tpm_chip *chip)
|
static int tpm2_do_selftest(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
unsigned int delay_msec = 20;
|
unsigned int delay_msec = 10;
|
||||||
long duration;
|
long duration;
|
||||||
struct tpm2_cmd cmd;
|
struct tpm2_cmd cmd;
|
||||||
|
|
||||||
duration = jiffies_to_msecs(
|
duration = jiffies_to_msecs(
|
||||||
tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
|
tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST));
|
||||||
|
|
||||||
while (duration > 0) {
|
while (1) {
|
||||||
cmd.header.in = tpm2_selftest_header;
|
cmd.header.in = tpm2_selftest_header;
|
||||||
cmd.params.selftest_in.full_test = 0;
|
cmd.params.selftest_in.full_test = 0;
|
||||||
|
|
||||||
rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
|
rc = tpm_transmit_cmd(chip, NULL, &cmd, TPM2_SELF_TEST_IN_SIZE,
|
||||||
0, 0, "continue selftest");
|
0, 0, "continue selftest");
|
||||||
|
|
||||||
if (rc != TPM2_RC_TESTING)
|
if (rc != TPM2_RC_TESTING || delay_msec >= duration)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
tpm_msleep(delay_msec);
|
/* wait longer than before */
|
||||||
duration -= delay_msec;
|
|
||||||
|
|
||||||
/* wait longer the next round */
|
|
||||||
delay_msec *= 2;
|
delay_msec *= 2;
|
||||||
|
tpm_msleep(delay_msec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* calc_tpm2_event_size() - calculate the event size, where event
|
* calc_tpm2_event_size() - calculate the event size, where event
|
||||||
|
|
|
@ -25,9 +25,9 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
|
||||||
|
|
||||||
struct acpi_tcpa {
|
struct acpi_tcpa {
|
||||||
struct acpi_table_header hdr;
|
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);
|
memcpy_fromio(log->bios_event_log, virt, len);
|
||||||
|
|
||||||
acpi_os_unmap_iomem(virt, len);
|
acpi_os_unmap_iomem(virt, len);
|
||||||
return 0;
|
return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
kfree(log->bios_event_log);
|
kfree(log->bios_event_log);
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Google
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Thiebaud Weksteen <tweek@google.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version
|
||||||
|
* 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/efi.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
|
||||||
|
#include "tpm.h"
|
||||||
|
|
||||||
|
/* read binary bios log from EFI configuration table */
|
||||||
|
int tpm_read_log_efi(struct tpm_chip *chip)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct linux_efi_tpm_eventlog *log_tbl;
|
||||||
|
struct tpm_bios_log *log;
|
||||||
|
u32 log_size;
|
||||||
|
u8 tpm_log_version;
|
||||||
|
|
||||||
|
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
log = &chip->log;
|
||||||
|
|
||||||
|
log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl), MEMREMAP_WB);
|
||||||
|
if (!log_tbl) {
|
||||||
|
pr_err("Could not map UEFI TPM log table !\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_size = log_tbl->size;
|
||||||
|
memunmap(log_tbl);
|
||||||
|
|
||||||
|
log_tbl = memremap(efi.tpm_log, sizeof(*log_tbl) + log_size,
|
||||||
|
MEMREMAP_WB);
|
||||||
|
if (!log_tbl) {
|
||||||
|
pr_err("Could not map UEFI TPM log table payload!\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* malloc EventLog space */
|
||||||
|
log->bios_event_log = kmalloc(log_size, GFP_KERNEL);
|
||||||
|
if (!log->bios_event_log)
|
||||||
|
goto err_memunmap;
|
||||||
|
memcpy(log->bios_event_log, log_tbl->log, log_size);
|
||||||
|
log->bios_event_log_end = log->bios_event_log + log_size;
|
||||||
|
|
||||||
|
tpm_log_version = log_tbl->version;
|
||||||
|
memunmap(log_tbl);
|
||||||
|
return tpm_log_version;
|
||||||
|
|
||||||
|
err_memunmap:
|
||||||
|
memunmap(log_tbl);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
|
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_eventlog.h"
|
|
||||||
|
|
||||||
int tpm_read_log_of(struct tpm_chip *chip)
|
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);
|
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 @@ out_err:
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id tpm_tis_i2c_table[] = {
|
static const struct i2c_device_id tpm_tis_i2c_table[] = {
|
||||||
{"tpm_i2c_infineon", 0},
|
{"tpm_i2c_infineon"},
|
||||||
{"slb9635tt", 0},
|
{"slb9635tt"},
|
||||||
{"slb9645tt", 1},
|
{"slb9645tt"},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -675,24 +675,9 @@ MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table);
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
static const struct of_device_id tpm_tis_i2c_of_match[] = {
|
static const struct of_device_id tpm_tis_i2c_of_match[] = {
|
||||||
{
|
{.compatible = "infineon,tpm_i2c_infineon"},
|
||||||
.name = "tpm_i2c_infineon",
|
{.compatible = "infineon,slb9635tt"},
|
||||||
.type = "tpm",
|
{.compatible = "infineon,slb9645tt"},
|
||||||
.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
|
|
||||||
},
|
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
|
MODULE_DEVICE_TABLE(of, tpm_tis_i2c_of_match);
|
||||||
|
|
|
@ -133,93 +133,14 @@ static int check_acpi_tpm2(struct device *dev)
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||||
u8 *result)
|
u8 *result)
|
||||||
{
|
{
|
||||||
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
||||||
|
|
||||||
tpm_platform_begin_xfer();
|
|
||||||
|
|
||||||
while (len--)
|
while (len--)
|
||||||
*result++ = ioread8(phy->iobase + addr);
|
*result++ = ioread8(phy->iobase + addr);
|
||||||
|
|
||||||
tpm_platform_end_xfer();
|
|
||||||
|
|
||||||
return 0;
|
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);
|
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
||||||
|
|
||||||
tpm_platform_begin_xfer();
|
|
||||||
|
|
||||||
while (len--)
|
while (len--)
|
||||||
iowrite8(*value++, phy->iobase + addr);
|
iowrite8(*value++, phy->iobase + addr);
|
||||||
|
|
||||||
tpm_platform_end_xfer();
|
|
||||||
|
|
||||||
return 0;
|
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);
|
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
||||||
|
|
||||||
tpm_platform_begin_xfer();
|
|
||||||
|
|
||||||
*result = ioread16(phy->iobase + addr);
|
*result = ioread16(phy->iobase + addr);
|
||||||
|
|
||||||
tpm_platform_end_xfer();
|
|
||||||
|
|
||||||
return 0;
|
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);
|
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
||||||
|
|
||||||
tpm_platform_begin_xfer();
|
|
||||||
|
|
||||||
*result = ioread32(phy->iobase + addr);
|
*result = ioread32(phy->iobase + addr);
|
||||||
|
|
||||||
tpm_platform_end_xfer();
|
|
||||||
|
|
||||||
return 0;
|
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);
|
struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data);
|
||||||
|
|
||||||
tpm_platform_begin_xfer();
|
|
||||||
|
|
||||||
iowrite32(value, phy->iobase + addr);
|
iowrite32(value, phy->iobase + addr);
|
||||||
|
|
||||||
tpm_platform_end_xfer();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,11 +366,6 @@ static int __init init_tis(void)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_force;
|
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);
|
rc = platform_driver_register(&tis_drv);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_platform;
|
goto err_platform;
|
||||||
|
@ -484,10 +384,6 @@ err_pnp:
|
||||||
err_platform:
|
err_platform:
|
||||||
if (force_pdev)
|
if (force_pdev)
|
||||||
platform_device_unregister(force_pdev);
|
platform_device_unregister(force_pdev);
|
||||||
#ifdef CONFIG_X86
|
|
||||||
if (is_bsw())
|
|
||||||
iounmap(ilb_base_addr);
|
|
||||||
#endif
|
|
||||||
err_force:
|
err_force:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -497,10 +393,6 @@ static void __exit cleanup_tis(void)
|
||||||
pnp_unregister_driver(&tis_pnp_driver);
|
pnp_unregister_driver(&tis_pnp_driver);
|
||||||
platform_driver_unregister(&tis_drv);
|
platform_driver_unregister(&tis_drv);
|
||||||
|
|
||||||
#ifdef CONFIG_X86
|
|
||||||
if (is_bsw())
|
|
||||||
iounmap(ilb_base_addr);
|
|
||||||
#endif
|
|
||||||
if (force_pdev)
|
if (force_pdev)
|
||||||
platform_device_unregister(force_pdev);
|
platform_device_unregister(force_pdev);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,74 @@
|
||||||
#include "tpm.h"
|
#include "tpm.h"
|
||||||
#include "tpm_tis_core.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.
|
/* 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
|
* 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
|
* '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;
|
burstcnt = (value >> 8) & 0xFFFF;
|
||||||
if (burstcnt)
|
if (burstcnt)
|
||||||
return burstcnt;
|
return burstcnt;
|
||||||
tpm_msleep(TPM_TIMEOUT);
|
tpm_msleep(TPM_POLL_SLEEP);
|
||||||
} while (time_before(jiffies, stop));
|
} while (time_before(jiffies, stop));
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
@ -421,19 +489,28 @@ static bool tpm_tis_update_timeouts(struct tpm_chip *chip,
|
||||||
int i, rc;
|
int i, rc;
|
||||||
u32 did_vid;
|
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);
|
rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
|
for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) {
|
||||||
if (vendor_timeout_overrides[i].did_vid != did_vid)
|
if (vendor_timeout_overrides[i].did_vid != did_vid)
|
||||||
continue;
|
continue;
|
||||||
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
|
memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us,
|
||||||
sizeof(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;
|
u32 interrupt;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
tpm_tis_clkrun_enable(chip, true);
|
||||||
|
|
||||||
rc = tpm_tis_read32(priv, reg, &interrupt);
|
rc = tpm_tis_read32(priv, reg, &interrupt);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
interrupt = 0;
|
interrupt = 0;
|
||||||
|
|
||||||
tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt);
|
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);
|
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 = {
|
static const struct tpm_class_ops tpm_tis = {
|
||||||
.flags = TPM_OPS_AUTO_STARTUP,
|
.flags = TPM_OPS_AUTO_STARTUP,
|
||||||
.status = tpm_tis_status,
|
.status = tpm_tis_status,
|
||||||
|
@ -673,13 +809,17 @@ static const struct tpm_class_ops tpm_tis = {
|
||||||
.req_canceled = tpm_tis_req_canceled,
|
.req_canceled = tpm_tis_req_canceled,
|
||||||
.request_locality = request_locality,
|
.request_locality = request_locality,
|
||||||
.relinquish_locality = release_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,
|
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
||||||
const struct tpm_tis_phy_ops *phy_ops,
|
const struct tpm_tis_phy_ops *phy_ops,
|
||||||
acpi_handle acpi_dev_handle)
|
acpi_handle acpi_dev_handle)
|
||||||
{
|
{
|
||||||
u32 vendor, intfcaps, intmask;
|
u32 vendor;
|
||||||
|
u32 intfcaps;
|
||||||
|
u32 intmask;
|
||||||
|
u32 clkrun_val;
|
||||||
u8 rid;
|
u8 rid;
|
||||||
int rc, probe;
|
int rc, probe;
|
||||||
struct tpm_chip *chip;
|
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;
|
priv->phy_ops = phy_ops;
|
||||||
dev_set_drvdata(&chip->dev, priv);
|
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) {
|
if (wait_startup(chip, 0) != 0) {
|
||||||
rc = -ENODEV;
|
rc = -ENODEV;
|
||||||
goto out_err;
|
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:
|
out_err:
|
||||||
|
if ((chip->ops != NULL) && (chip->ops->clk_enable != NULL))
|
||||||
|
chip->ops->clk_enable(chip, false);
|
||||||
|
|
||||||
tpm_tis_remove(chip);
|
tpm_tis_remove(chip);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(tpm_tis_core_init);
|
EXPORT_SYMBOL_GPL(tpm_tis_core_init);
|
||||||
|
@ -804,22 +972,31 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
||||||
u32 intmask;
|
u32 intmask;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (chip->ops->clk_enable != NULL)
|
||||||
|
chip->ops->clk_enable(chip, true);
|
||||||
|
|
||||||
/* reenable interrupts that device may have lost or
|
/* reenable interrupts that device may have lost or
|
||||||
* BIOS/firmware may have disabled
|
* BIOS/firmware may have disabled
|
||||||
*/
|
*/
|
||||||
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq);
|
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
|
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return;
|
goto out;
|
||||||
|
|
||||||
intmask |= TPM_INTF_CMD_READY_INT
|
intmask |= TPM_INTF_CMD_READY_INT
|
||||||
| TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
|
| TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
|
||||||
| TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
|
| TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
|
||||||
|
|
||||||
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
|
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)
|
int tpm_tis_resume(struct device *dev)
|
||||||
|
|
|
@ -79,6 +79,11 @@ enum tis_defaults {
|
||||||
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
|
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
|
||||||
#define TPM_RID(l) (0x0F04 | ((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 {
|
enum tpm_tis_flags {
|
||||||
TPM_TIS_ITPM_WORKAROUND = BIT(0),
|
TPM_TIS_ITPM_WORKAROUND = BIT(0),
|
||||||
};
|
};
|
||||||
|
@ -89,6 +94,8 @@ struct tpm_tis_data {
|
||||||
int irq;
|
int irq;
|
||||||
bool irq_tested;
|
bool irq_tested;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
void __iomem *ilb_base_addr;
|
||||||
|
u16 clkrun_enabled;
|
||||||
wait_queue_head_t int_queue;
|
wait_queue_head_t int_queue;
|
||||||
wait_queue_head_t read_queue;
|
wait_queue_head_t read_queue;
|
||||||
const struct tpm_tis_phy_ops *phy_ops;
|
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);
|
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);
|
void tpm_tis_remove(struct tpm_chip *chip);
|
||||||
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
||||||
const struct tpm_tis_phy_ops *phy_ops,
|
const struct tpm_tis_phy_ops *phy_ops,
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/freezer.h>
|
||||||
#include <xen/xen.h>
|
#include <xen/xen.h>
|
||||||
#include <xen/events.h>
|
#include <xen/events.h>
|
||||||
#include <xen/interface/io/tpmif.h>
|
#include <xen/interface/io/tpmif.h>
|
||||||
|
@ -39,6 +40,66 @@ enum status_bits {
|
||||||
VTPM_STATUS_CANCELED = 0x8,
|
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)
|
static u8 vtpm_status(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
struct tpm_private *priv = dev_get_drvdata(&chip->dev);
|
struct tpm_private *priv = dev_get_drvdata(&chip->dev);
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
KASAN_SANITIZE_runtime-wrappers.o := n
|
KASAN_SANITIZE_runtime-wrappers.o := n
|
||||||
|
|
||||||
obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
|
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) += capsule.o memmap.o
|
||||||
obj-$(CONFIG_EFI_VARS) += efivars.o
|
obj-$(CONFIG_EFI_VARS) += efivars.o
|
||||||
obj-$(CONFIG_EFI_ESRT) += esrt.o
|
obj-$(CONFIG_EFI_ESRT) += esrt.o
|
||||||
|
|
|
@ -52,6 +52,7 @@ struct efi __read_mostly efi = {
|
||||||
.properties_table = EFI_INVALID_TABLE_ADDR,
|
.properties_table = EFI_INVALID_TABLE_ADDR,
|
||||||
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
|
.mem_attr_table = EFI_INVALID_TABLE_ADDR,
|
||||||
.rng_seed = EFI_INVALID_TABLE_ADDR,
|
.rng_seed = EFI_INVALID_TABLE_ADDR,
|
||||||
|
.tpm_log = EFI_INVALID_TABLE_ADDR
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL(efi);
|
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_PROPERTIES_TABLE_GUID, "PROP", &efi.properties_table},
|
||||||
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
|
{EFI_MEMORY_ATTRIBUTES_TABLE_GUID, "MEMATTR", &efi.mem_attr_table},
|
||||||
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
|
{LINUX_EFI_RANDOM_SEED_TABLE_GUID, "RNG", &efi.rng_seed},
|
||||||
|
{LINUX_EFI_TPM_EVENT_LOG_GUID, "TPMEventLog", &efi.tpm_log},
|
||||||
{NULL_GUID, NULL, NULL},
|
{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))
|
if (efi_enabled(EFI_MEMMAP))
|
||||||
efi_memattr_init();
|
efi_memattr_init();
|
||||||
|
|
||||||
|
efi_tpm_eventlog_init();
|
||||||
|
|
||||||
/* Parse the EFI Properties table if it exists */
|
/* Parse the EFI Properties table if it exists */
|
||||||
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
|
if (efi.properties_table != EFI_INVALID_TABLE_ADDR) {
|
||||||
efi_properties_table_t *tbl;
|
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.
|
# Prevents link failures: __sanitizer_cov_trace_pc() is not linked in.
|
||||||
KCOV_INSTRUMENT := n
|
KCOV_INSTRUMENT := n
|
||||||
|
|
||||||
lib-y := efi-stub-helper.o gop.o secureboot.o
|
lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o
|
||||||
lib-$(CONFIG_RESET_ATTACK_MITIGATION) += tpm.o
|
|
||||||
|
|
||||||
# include the stub's generic dependencies from lib/ when building for ARM/arm64
|
# 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
|
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) 2016 CoreOS, Inc
|
||||||
* Copyright (C) 2017 Google, Inc.
|
* Copyright (C) 2017 Google, Inc.
|
||||||
* Matthew Garrett <mjg59@google.com>
|
* Matthew Garrett <mjg59@google.com>
|
||||||
|
* Thiebaud Weksteen <tweek@google.com>
|
||||||
*
|
*
|
||||||
* This file is part of the Linux kernel, and is made available under the
|
* This file is part of the Linux kernel, and is made available under the
|
||||||
* terms of the GNU General Public License version 2.
|
* terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
#include <linux/efi.h>
|
#include <linux/efi.h>
|
||||||
|
#include <linux/tpm_eventlog.h>
|
||||||
#include <asm/efi.h>
|
#include <asm/efi.h>
|
||||||
|
|
||||||
#include "efistub.h"
|
#include "efistub.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_RESET_ATTACK_MITIGATION
|
||||||
static const efi_char16_t efi_MemoryOverWriteRequest_name[] = {
|
static const efi_char16_t efi_MemoryOverWriteRequest_name[] = {
|
||||||
'M', 'e', 'm', 'o', 'r', 'y', 'O', 'v', 'e', 'r', 'w', 'r', 'i', 't',
|
'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',
|
'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_BOOTSERVICE_ACCESS |
|
||||||
EFI_VARIABLE_RUNTIME_ACCESS, sizeof(val), &val);
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Google, Inc.
|
||||||
|
* Thiebaud Weksteen <tweek@google.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/efi.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/memblock.h>
|
||||||
|
|
||||||
|
#include <asm/early_ioremap.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reserve the memory associated with the TPM Event Log configuration table.
|
||||||
|
*/
|
||||||
|
int __init efi_tpm_eventlog_init(void)
|
||||||
|
{
|
||||||
|
struct linux_efi_tpm_eventlog *log_tbl;
|
||||||
|
unsigned int tbl_size;
|
||||||
|
|
||||||
|
if (efi.tpm_log == EFI_INVALID_TABLE_ADDR)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
log_tbl = early_memremap(efi.tpm_log, sizeof(*log_tbl));
|
||||||
|
if (!log_tbl) {
|
||||||
|
pr_err("Failed to map TPM Event Log table @ 0x%lx\n",
|
||||||
|
efi.tpm_log);
|
||||||
|
efi.tpm_log = EFI_INVALID_TABLE_ADDR;
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl_size = sizeof(*log_tbl) + log_tbl->size;
|
||||||
|
memblock_reserve(efi.tpm_log, tbl_size);
|
||||||
|
early_memunmap(log_tbl, sizeof(*log_tbl));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -475,6 +475,39 @@ typedef struct {
|
||||||
u64 get_all;
|
u64 get_all;
|
||||||
} apple_properties_protocol_64_t;
|
} 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
|
* Types and defines for EFI ResetSystem
|
||||||
*/
|
*/
|
||||||
|
@ -625,6 +658,7 @@ void efi_native_runtime_setup(void);
|
||||||
#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
|
#define EFI_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 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 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_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)
|
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
|
||||||
|
@ -637,6 +671,7 @@ void efi_native_runtime_setup(void);
|
||||||
#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
|
#define LINUX_EFI_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_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_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 {
|
typedef struct {
|
||||||
efi_guid_t guid;
|
efi_guid_t guid;
|
||||||
|
@ -911,6 +946,7 @@ extern struct efi {
|
||||||
unsigned long properties_table; /* properties table */
|
unsigned long properties_table; /* properties table */
|
||||||
unsigned long mem_attr_table; /* memory attributes table */
|
unsigned long mem_attr_table; /* memory attributes table */
|
||||||
unsigned long rng_seed; /* UEFI firmware random seed */
|
unsigned long rng_seed; /* UEFI firmware random seed */
|
||||||
|
unsigned long tpm_log; /* TPM2 Event Log table */
|
||||||
efi_get_time_t *get_time;
|
efi_get_time_t *get_time;
|
||||||
efi_set_time_t *set_time;
|
efi_set_time_t *set_time;
|
||||||
efi_get_wakeup_time_t *get_wakeup_time;
|
efi_get_wakeup_time_t *get_wakeup_time;
|
||||||
|
@ -1536,6 +1572,8 @@ static inline void
|
||||||
efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) { }
|
efi_enable_reset_attack_mitigation(efi_system_table_t *sys_table_arg) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void efi_retrieve_tpm2_eventlog(efi_system_table_t *sys_table);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arch code can implement the following three template macros, avoiding
|
* Arch code can implement the following three template macros, avoiding
|
||||||
* reptition for the void/non-void return cases of {__,}efi_call_virt():
|
* reptition for the void/non-void return cases of {__,}efi_call_virt():
|
||||||
|
@ -1603,4 +1641,12 @@ struct linux_efi_random_seed {
|
||||||
u8 bits[];
|
u8 bits[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct linux_efi_tpm_eventlog {
|
||||||
|
u32 size;
|
||||||
|
u8 version;
|
||||||
|
u8 log[];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int efi_tpm_eventlog_init(void);
|
||||||
|
|
||||||
#endif /* _LINUX_EFI_H */
|
#endif /* _LINUX_EFI_H */
|
||||||
|
|
|
@ -24,11 +24,6 @@
|
||||||
|
|
||||||
#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
|
#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 tpm_chip;
|
||||||
struct trusted_key_payload;
|
struct trusted_key_payload;
|
||||||
struct trusted_key_options;
|
struct trusted_key_options;
|
||||||
|
@ -50,46 +45,52 @@ struct tpm_class_ops {
|
||||||
unsigned long *timeout_cap);
|
unsigned long *timeout_cap);
|
||||||
int (*request_locality)(struct tpm_chip *chip, int loc);
|
int (*request_locality)(struct tpm_chip *chip, int loc);
|
||||||
void (*relinquish_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)
|
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
|
||||||
|
|
||||||
extern int tpm_is_tpm2(u32 chip_num);
|
extern int tpm_is_tpm2(struct tpm_chip *chip);
|
||||||
extern int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf);
|
extern int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
|
||||||
extern int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash);
|
extern int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
|
||||||
extern int tpm_send(u32 chip_num, void *cmd, size_t buflen);
|
extern int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen);
|
||||||
extern int tpm_get_random(u32 chip_num, u8 *data, size_t max);
|
extern int tpm_get_random(struct tpm_chip *chip, u8 *data, size_t max);
|
||||||
extern int tpm_seal_trusted(u32 chip_num,
|
extern int tpm_seal_trusted(struct tpm_chip *chip,
|
||||||
struct trusted_key_payload *payload,
|
struct trusted_key_payload *payload,
|
||||||
struct trusted_key_options *options);
|
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_payload *payload,
|
||||||
struct trusted_key_options *options);
|
struct trusted_key_options *options);
|
||||||
#else
|
#else
|
||||||
static inline int tpm_is_tpm2(u32 chip_num)
|
static inline int tpm_is_tpm2(struct tpm_chip *chip)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
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;
|
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;
|
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;
|
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;
|
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_payload *payload,
|
||||||
struct trusted_key_options *options)
|
struct trusted_key_options *options)
|
||||||
{
|
{
|
||||||
return -ENODEV;
|
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_payload *payload,
|
||||||
struct trusted_key_options *options)
|
struct trusted_key_options *options)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0 */
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
|
||||||
#ifndef __TPM_EVENTLOG_H__
|
#ifndef __LINUX_TPM_EVENTLOG_H__
|
||||||
#define __TPM_EVENTLOG_H__
|
#define __LINUX_TPM_EVENTLOG_H__
|
||||||
|
|
||||||
#include <crypto/hash_info.h>
|
#include <crypto/hash_info.h>
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@
|
||||||
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
|
#define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */
|
||||||
#define TPM2_ACTIVE_PCR_BANKS 3
|
#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
|
#ifdef CONFIG_PPC64
|
||||||
#define do_endian_conversion(x) be32_to_cpu(x)
|
#define do_endian_conversion(x) be32_to_cpu(x)
|
||||||
#else
|
#else
|
||||||
|
@ -105,6 +108,11 @@ struct tcg_event_field {
|
||||||
u8 event[0];
|
u8 event[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct tpm2_digest {
|
||||||
|
u16 alg_id;
|
||||||
|
u8 digest[SHA512_DIGEST_SIZE];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct tcg_pcr_event2 {
|
struct tcg_pcr_event2 {
|
||||||
u32 pcr_idx;
|
u32 pcr_idx;
|
||||||
u32 event_type;
|
u32 event_type;
|
||||||
|
@ -113,26 +121,4 @@ struct tcg_pcr_event2 {
|
||||||
struct tcg_event_field event;
|
struct tcg_event_field event;
|
||||||
} __packed;
|
} __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
|
#endif
|
|
@ -632,7 +632,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)
|
||||||
if (!ima_used_chip)
|
if (!ima_used_chip)
|
||||||
return;
|
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");
|
pr_err("Error Communicating to TPM chip\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ int __init ima_init(void)
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
ima_used_chip = 0;
|
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)
|
if (rc == 0)
|
||||||
ima_used_chip = 1;
|
ima_used_chip = 1;
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ static int ima_pcr_extend(const u8 *hash, int pcr)
|
||||||
if (!ima_used_chip)
|
if (!ima_used_chip)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
result = tpm_pcr_extend(TPM_ANY_NUM, pcr, hash);
|
result = tpm_pcr_extend(NULL, pcr, hash);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
pr_err("Error Communicating to TPM chip, result: %d\n", result);
|
pr_err("Error Communicating to TPM chip, result: %d\n", result);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -355,13 +355,12 @@ out:
|
||||||
* For key specific tpm requests, we will generate and send our
|
* For key specific tpm requests, we will generate and send our
|
||||||
* own TPM command packets using the drivers send function.
|
* own TPM command packets using the drivers send function.
|
||||||
*/
|
*/
|
||||||
static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd,
|
static int trusted_tpm_send(unsigned char *cmd, size_t buflen)
|
||||||
size_t buflen)
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
dump_tpm_buf(cmd);
|
dump_tpm_buf(cmd);
|
||||||
rc = tpm_send(chip_num, cmd, buflen);
|
rc = tpm_send(NULL, cmd, buflen);
|
||||||
dump_tpm_buf(cmd);
|
dump_tpm_buf(cmd);
|
||||||
if (rc > 0)
|
if (rc > 0)
|
||||||
/* Can't return positive return codes values to keyctl */
|
/* Can't return positive return codes values to keyctl */
|
||||||
|
@ -382,10 +381,10 @@ static int pcrlock(const int pcrnum)
|
||||||
|
|
||||||
if (!capable(CAP_SYS_ADMIN))
|
if (!capable(CAP_SYS_ADMIN))
|
||||||
return -EPERM;
|
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)
|
if (ret != SHA1_DIGEST_SIZE)
|
||||||
return ret;
|
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];
|
unsigned char ononce[TPM_NONCE_SIZE];
|
||||||
int ret;
|
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)
|
if (ret != TPM_NONCE_SIZE)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -410,7 +409,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,
|
||||||
store32(tb, handle);
|
store32(tb, handle);
|
||||||
storebytes(tb, ononce, TPM_NONCE_SIZE);
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
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);
|
store16(tb, TPM_TAG_RQU_COMMAND);
|
||||||
store32(tb, TPM_OIAP_SIZE);
|
store32(tb, TPM_OIAP_SIZE);
|
||||||
store32(tb, TPM_ORD_OIAP);
|
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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -493,7 +492,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
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)
|
if (ret != TPM_NONCE_SIZE)
|
||||||
goto out;
|
goto out;
|
||||||
ordinal = htonl(TPM_ORD_SEAL);
|
ordinal = htonl(TPM_ORD_SEAL);
|
||||||
|
@ -542,7 +541,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,
|
||||||
store8(tb, cont);
|
store8(tb, cont);
|
||||||
storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE);
|
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)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -603,7 +602,7 @@ static int tpm_unseal(struct tpm_buf *tb,
|
||||||
|
|
||||||
ordinal = htonl(TPM_ORD_UNSEAL);
|
ordinal = htonl(TPM_ORD_UNSEAL);
|
||||||
keyhndl = htonl(SRKHANDLE);
|
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) {
|
if (ret != TPM_NONCE_SIZE) {
|
||||||
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
|
pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -635,7 +634,7 @@ static int tpm_unseal(struct tpm_buf *tb,
|
||||||
store8(tb, cont);
|
store8(tb, cont);
|
||||||
storebytes(tb, authdata2, SHA1_DIGEST_SIZE);
|
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) {
|
if (ret < 0) {
|
||||||
pr_info("trusted_key: authhmac failed (%d)\n", ret);
|
pr_info("trusted_key: authhmac failed (%d)\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -748,7 +747,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
|
||||||
int i;
|
int i;
|
||||||
int tpm2;
|
int tpm2;
|
||||||
|
|
||||||
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
|
tpm2 = tpm_is_tpm2(NULL);
|
||||||
if (tpm2 < 0)
|
if (tpm2 < 0)
|
||||||
return tpm2;
|
return tpm2;
|
||||||
|
|
||||||
|
@ -917,7 +916,7 @@ static struct trusted_key_options *trusted_options_alloc(void)
|
||||||
struct trusted_key_options *options;
|
struct trusted_key_options *options;
|
||||||
int tpm2;
|
int tpm2;
|
||||||
|
|
||||||
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
|
tpm2 = tpm_is_tpm2(NULL);
|
||||||
if (tpm2 < 0)
|
if (tpm2 < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -967,7 +966,7 @@ static int trusted_instantiate(struct key *key,
|
||||||
size_t key_len;
|
size_t key_len;
|
||||||
int tpm2;
|
int tpm2;
|
||||||
|
|
||||||
tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
|
tpm2 = tpm_is_tpm2(NULL);
|
||||||
if (tpm2 < 0)
|
if (tpm2 < 0)
|
||||||
return tpm2;
|
return tpm2;
|
||||||
|
|
||||||
|
@ -1008,7 +1007,7 @@ static int trusted_instantiate(struct key *key,
|
||||||
switch (key_cmd) {
|
switch (key_cmd) {
|
||||||
case Opt_load:
|
case Opt_load:
|
||||||
if (tpm2)
|
if (tpm2)
|
||||||
ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options);
|
ret = tpm_unseal_trusted(NULL, payload, options);
|
||||||
else
|
else
|
||||||
ret = key_unseal(payload, options);
|
ret = key_unseal(payload, options);
|
||||||
dump_payload(payload);
|
dump_payload(payload);
|
||||||
|
@ -1018,13 +1017,13 @@ static int trusted_instantiate(struct key *key,
|
||||||
break;
|
break;
|
||||||
case Opt_new:
|
case Opt_new:
|
||||||
key_len = payload->key_len;
|
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) {
|
if (ret != key_len) {
|
||||||
pr_info("trusted_key: key_create failed (%d)\n", ret);
|
pr_info("trusted_key: key_create failed (%d)\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (tpm2)
|
if (tpm2)
|
||||||
ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options);
|
ret = tpm_seal_trusted(NULL, payload, options);
|
||||||
else
|
else
|
||||||
ret = key_seal(payload, options);
|
ret = key_seal(payload, options);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
Loading…
Reference in New Issue