Commit 1a0beef9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tpmdd-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:

 - The .machine keyring, used for Machine Owner Keys (MOK), acquired the
   ability to store only CA enforced keys, and put rest to the .platform
   keyring, thus separating the code signing keys from the keys that are
   used to sign certificates.

   This essentially unlocks the use of the .machine keyring as a trust
   anchor for IMA. It is an opt-in feature, meaning that the additional
   contraints won't brick anyone who does not care about them.

 - Enable interrupt based transactions with discrete TPM chips (tpm_tis).

   There was code for this existing but it never really worked so I
   consider this a new feature rather than a bug fix. Before the driver
   just fell back to the polling mode.

Link: https://lore.kernel.org/linux-integrity/a93b6222-edda-d43c-f010-a59701f2aeef@gmx.de/
Link: https://lore.kernel.org/linux-integrity/20230302164652.83571-1-eric.snowberg@oracle.com/

* tag 'tpmdd-v6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd: (29 commits)
  tpm: Add !tpm_amd_is_rng_defective() to the hwrng_unregister() call site
  tpm_tis: fix stall after iowrite*()s
  tpm/tpm_tis_synquacer: Convert to platform remove callback returning void
  tpm/tpm_tis: Convert to platform remove callback returning void
  tpm/tpm_ftpm_tee: Convert to platform remove callback returning void
  tpm: tpm_tis_spi: Mark ACPI and OF related data as maybe unused
  tpm: st33zp24: Mark ACPI and OF related data as maybe unused
  tpm, tpm_tis: Enable interrupt test
  tpm, tpm_tis: startup chip before testing for interrupts
  tpm, tpm_tis: Claim locality when interrupts are reenabled on resume
  tpm, tpm_tis: Claim locality in interrupt handler
  tpm, tpm_tis: Request threaded interrupt handler
  tpm, tpm: Implement usage counter for locality
  tpm, tpm_tis: do not check for the active locality in interrupt handler
  tpm, tpm_tis: Move interrupt mask checks into own function
  tpm, tpm_tis: Only handle supported interrupts
  tpm, tpm_tis: Claim locality before writing interrupt registers
  tpm, tpm_tis: Do not skip reset of original interrupt vector
  tpm, tpm_tis: Disable interrupts if tpm_tis_probe_irq() failed
  tpm, tpm_tis: Claim locality before writing TPM_INT_ENABLE register
  ...
parents dc7e22a3 bd8621ca
...@@ -33,7 +33,11 @@ extern __initconst const unsigned long system_certificate_list_size; ...@@ -33,7 +33,11 @@ extern __initconst const unsigned long system_certificate_list_size;
extern __initconst const unsigned long module_cert_size; extern __initconst const unsigned long module_cert_size;
/** /**
* restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA * restrict_link_by_builtin_trusted - Restrict keyring addition by built-in CA
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @restriction_key: A ring of keys that can be used to vouch for the new cert.
* *
* Restrict the addition of keys into a keyring based on the key-to-be-added * Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in the built in system keyring. * being vouched for by a key in the built in system keyring.
...@@ -50,7 +54,11 @@ int restrict_link_by_builtin_trusted(struct key *dest_keyring, ...@@ -50,7 +54,11 @@ int restrict_link_by_builtin_trusted(struct key *dest_keyring,
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING #ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
/** /**
* restrict_link_by_builtin_and_secondary_trusted - Restrict keyring * restrict_link_by_builtin_and_secondary_trusted - Restrict keyring
* addition by both builtin and secondary keyrings * addition by both built-in and secondary keyrings.
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @restrict_key: A ring of keys that can be used to vouch for the new cert.
* *
* Restrict the addition of keys into a keyring based on the key-to-be-added * Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in either the built-in or the secondary system * being vouched for by a key in either the built-in or the secondary system
...@@ -75,7 +83,7 @@ int restrict_link_by_builtin_and_secondary_trusted( ...@@ -75,7 +83,7 @@ int restrict_link_by_builtin_and_secondary_trusted(
secondary_trusted_keys); secondary_trusted_keys);
} }
/** /*
* Allocate a struct key_restriction for the "builtin and secondary trust" * Allocate a struct key_restriction for the "builtin and secondary trust"
* keyring. Only for use in system_trusted_keyring_init(). * keyring. Only for use in system_trusted_keyring_init().
*/ */
......
...@@ -108,6 +108,46 @@ int restrict_link_by_signature(struct key *dest_keyring, ...@@ -108,6 +108,46 @@ int restrict_link_by_signature(struct key *dest_keyring,
return ret; return ret;
} }
/**
* restrict_link_by_ca - Restrict additions to a ring of CA keys
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @trust_keyring: Unused.
*
* Check if the new certificate is a CA. If it is a CA, then mark the new
* certificate as being ok to link.
*
* Returns 0 if the new certificate was accepted, -ENOKEY if the
* certificate is not a CA. -ENOPKG if the signature uses unsupported
* crypto, or some other error if there is a matching certificate but
* the signature check cannot be performed.
*/
int restrict_link_by_ca(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring)
{
const struct public_key *pkey;
if (type != &key_type_asymmetric)
return -EOPNOTSUPP;
pkey = payload->data[asym_crypto];
if (!pkey)
return -ENOPKG;
if (!test_bit(KEY_EFLAG_CA, &pkey->key_eflags))
return -ENOKEY;
if (!test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))
return -ENOKEY;
if (!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING_MAX))
return 0;
if (test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))
return -ENOKEY;
return 0;
}
static bool match_either_id(const struct asymmetric_key_id **pair, static bool match_either_id(const struct asymmetric_key_id **pair,
const struct asymmetric_key_id *single) const struct asymmetric_key_id *single)
{ {
......
...@@ -579,6 +579,34 @@ int x509_process_extension(void *context, size_t hdrlen, ...@@ -579,6 +579,34 @@ int x509_process_extension(void *context, size_t hdrlen,
return 0; return 0;
} }
if (ctx->last_oid == OID_keyUsage) {
/*
* Get hold of the keyUsage bit string
* v[1] is the encoding size
* (Expect either 0x02 or 0x03, making it 1 or 2 bytes)
* v[2] is the number of unused bits in the bit string
* (If >= 3 keyCertSign is missing when v[1] = 0x02)
* v[3] and possibly v[4] contain the bit string
*
* From RFC 5280 4.2.1.3:
* 0x04 is where keyCertSign lands in this bit string
* 0x80 is where digitalSignature lands in this bit string
*/
if (v[0] != ASN1_BTS)
return -EBADMSG;
if (vlen < 4)
return -EBADMSG;
if (v[2] >= 8)
return -EBADMSG;
if (v[3] & 0x80)
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_DIGITALSIG;
if (v[1] == 0x02 && v[2] <= 2 && (v[3] & 0x04))
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN;
else if (vlen > 4 && v[1] == 0x03 && (v[3] & 0x04))
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_KEYCERTSIGN;
return 0;
}
if (ctx->last_oid == OID_authorityKeyIdentifier) { if (ctx->last_oid == OID_authorityKeyIdentifier) {
/* Get hold of the CA key fingerprint */ /* Get hold of the CA key fingerprint */
ctx->raw_akid = v; ctx->raw_akid = v;
...@@ -586,6 +614,28 @@ int x509_process_extension(void *context, size_t hdrlen, ...@@ -586,6 +614,28 @@ int x509_process_extension(void *context, size_t hdrlen,
return 0; return 0;
} }
if (ctx->last_oid == OID_basicConstraints) {
/*
* Get hold of the basicConstraints
* v[1] is the encoding size
* (Expect 0x2 or greater, making it 1 or more bytes)
* v[2] is the encoding type
* (Expect an ASN1_BOOL for the CA)
* v[3] is the contents of the ASN1_BOOL
* (Expect 1 if the CA is TRUE)
* vlen should match the entire extension size
*/
if (v[0] != (ASN1_CONS_BIT | ASN1_SEQ))
return -EBADMSG;
if (vlen < 2)
return -EBADMSG;
if (v[1] != vlen - 2)
return -EBADMSG;
if (vlen >= 4 && v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1)
ctx->cert->pub->key_eflags |= 1 << KEY_EFLAG_CA;
return 0;
}
return 0; return 0;
} }
......
...@@ -36,7 +36,7 @@ static int tpm_bios_measurements_open(struct inode *inode, ...@@ -36,7 +36,7 @@ static int tpm_bios_measurements_open(struct inode *inode,
inode_unlock(inode); inode_unlock(inode);
return -ENODEV; return -ENODEV;
} }
chip_seqops = (struct tpm_chip_seqops *)inode->i_private; chip_seqops = inode->i_private;
seqops = chip_seqops->seqops; seqops = chip_seqops->seqops;
chip = chip_seqops->chip; chip = chip_seqops->chip;
get_device(&chip->dev); get_device(&chip->dev);
...@@ -55,8 +55,8 @@ static int tpm_bios_measurements_open(struct inode *inode, ...@@ -55,8 +55,8 @@ static int tpm_bios_measurements_open(struct inode *inode,
static int tpm_bios_measurements_release(struct inode *inode, static int tpm_bios_measurements_release(struct inode *inode,
struct file *file) struct file *file)
{ {
struct seq_file *seq = (struct seq_file *)file->private_data; struct seq_file *seq = file->private_data;
struct tpm_chip *chip = (struct tpm_chip *)seq->private; struct tpm_chip *chip = seq->private;
put_device(&chip->dev); put_device(&chip->dev);
......
...@@ -138,13 +138,13 @@ static const struct i2c_device_id st33zp24_i2c_id[] = { ...@@ -138,13 +138,13 @@ static const struct i2c_device_id st33zp24_i2c_id[] = {
}; };
MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id); MODULE_DEVICE_TABLE(i2c, st33zp24_i2c_id);
static const struct of_device_id of_st33zp24_i2c_match[] = { static const struct of_device_id of_st33zp24_i2c_match[] __maybe_unused = {
{ .compatible = "st,st33zp24-i2c", }, { .compatible = "st,st33zp24-i2c", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match); MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);
static const struct acpi_device_id st33zp24_i2c_acpi_match[] = { static const struct acpi_device_id st33zp24_i2c_acpi_match[] __maybe_unused = {
{"SMO3324"}, {"SMO3324"},
{} {}
}; };
......
...@@ -255,13 +255,13 @@ static const struct spi_device_id st33zp24_spi_id[] = { ...@@ -255,13 +255,13 @@ static const struct spi_device_id st33zp24_spi_id[] = {
}; };
MODULE_DEVICE_TABLE(spi, st33zp24_spi_id); MODULE_DEVICE_TABLE(spi, st33zp24_spi_id);
static const struct of_device_id of_st33zp24_spi_match[] = { static const struct of_device_id of_st33zp24_spi_match[] __maybe_unused = {
{ .compatible = "st,st33zp24-spi", }, { .compatible = "st,st33zp24-spi", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match); MODULE_DEVICE_TABLE(of, of_st33zp24_spi_match);
static const struct acpi_device_id st33zp24_spi_acpi_match[] = { static const struct acpi_device_id st33zp24_spi_acpi_match[] __maybe_unused = {
{"SMO3324"}, {"SMO3324"},
{} {}
}; };
......
...@@ -606,33 +606,43 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip) ...@@ -606,33 +606,43 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip)
} }
/* /*
* tpm_chip_register() - create a character device for the TPM chip * tpm_chip_startup() - performs auto startup and allocates the PCRs
* @chip: TPM chip to use. * @chip: TPM chip to use.
*
* Creates a character device for the TPM chip and adds sysfs attributes for
* the device. As the last step this function adds the chip to the list of TPM
* chips available for in-kernel use.
*
* This function should be only called after the chip initialization is
* complete.
*/ */
int tpm_chip_register(struct tpm_chip *chip) int tpm_chip_startup(struct tpm_chip *chip)
{ {
int rc; int rc;
rc = tpm_chip_start(chip); rc = tpm_chip_start(chip);
if (rc) if (rc)
return rc; return rc;
rc = tpm_auto_startup(chip); rc = tpm_auto_startup(chip);
if (rc) { if (rc)
tpm_chip_stop(chip); goto stop;
return rc;
}
rc = tpm_get_pcr_allocation(chip); rc = tpm_get_pcr_allocation(chip);
stop:
tpm_chip_stop(chip); tpm_chip_stop(chip);
if (rc)
return rc; return rc;
}
EXPORT_SYMBOL_GPL(tpm_chip_startup);
/*
* tpm_chip_register() - create a character device for the TPM chip
* @chip: TPM chip to use.
*
* Creates a character device for the TPM chip and adds sysfs attributes for
* the device. As the last step this function adds the chip to the list of TPM
* chips available for in-kernel use.
*
* This function should be only called after the chip initialization is
* complete.
*/
int tpm_chip_register(struct tpm_chip *chip)
{
int rc;
tpm_sysfs_add_device(chip); tpm_sysfs_add_device(chip);
...@@ -682,7 +692,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); ...@@ -682,7 +692,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) && !tpm_is_firmware_upgrade(chip)) if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip) &&
!tpm_amd_is_rng_defective(chip))
hwrng_unregister(&chip->hwrng); hwrng_unregister(&chip->hwrng);
tpm_bios_log_teardown(chip); tpm_bios_log_teardown(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip))
......
...@@ -263,6 +263,7 @@ static inline void tpm_msleep(unsigned int delay_msec) ...@@ -263,6 +263,7 @@ static inline void tpm_msleep(unsigned int delay_msec)
delay_msec * 1000); delay_msec * 1000);
}; };
int tpm_chip_startup(struct tpm_chip *chip);
int tpm_chip_start(struct tpm_chip *chip); int tpm_chip_start(struct tpm_chip *chip);
void tpm_chip_stop(struct tpm_chip *chip); void tpm_chip_stop(struct tpm_chip *chip);
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip); struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
......
...@@ -334,11 +334,11 @@ static int ftpm_tee_remove(struct device *dev) ...@@ -334,11 +334,11 @@ static int ftpm_tee_remove(struct device *dev)
return 0; return 0;
} }
static int ftpm_plat_tee_remove(struct platform_device *pdev) static void ftpm_plat_tee_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
return ftpm_tee_remove(dev); ftpm_tee_remove(dev);
} }
/** /**
...@@ -367,7 +367,7 @@ static struct platform_driver ftpm_tee_plat_driver = { ...@@ -367,7 +367,7 @@ static struct platform_driver ftpm_tee_plat_driver = {
}, },
.shutdown = ftpm_plat_tee_shutdown, .shutdown = ftpm_plat_tee_shutdown,
.probe = ftpm_plat_tee_probe, .probe = ftpm_plat_tee_probe,
.remove = ftpm_plat_tee_remove, .remove_new = ftpm_plat_tee_remove,
}; };
/* UUID of the fTPM TA */ /* UUID of the fTPM TA */
......
...@@ -50,6 +50,45 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da ...@@ -50,6 +50,45 @@ static inline struct tpm_tis_tcg_phy *to_tpm_tis_tcg_phy(struct tpm_tis_data *da
return container_of(data, struct tpm_tis_tcg_phy, priv); return container_of(data, struct tpm_tis_tcg_phy, priv);
} }
#ifdef CONFIG_PREEMPT_RT
/*
* Flush previous write operations with a dummy read operation to the
* TPM MMIO base address.
*/
static inline void tpm_tis_flush(void __iomem *iobase)
{
ioread8(iobase + TPM_ACCESS(0));
}
#else
#define tpm_tis_flush(iobase) do { } while (0)
#endif
/*
* Write a byte word to the TPM MMIO address, and flush the write queue.
* The flush ensures that the data is sent immediately over the bus and not
* aggregated with further requests and transferred later in a batch. The large
* write requests can lead to unwanted latency spikes by blocking the CPU until
* the complete batch has been transferred.
*/
static inline void tpm_tis_iowrite8(u8 b, void __iomem *iobase, u32 addr)
{
iowrite8(b, iobase + addr);
tpm_tis_flush(iobase);
}
/*
* Write a 32-bit word to the TPM MMIO address, and flush the write queue.
* The flush ensures that the data is sent immediately over the bus and not
* aggregated with further requests and transferred later in a batch. The large
* write requests can lead to unwanted latency spikes by blocking the CPU until
* the complete batch has been transferred.
*/
static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr)
{
iowrite32(b, iobase + addr);
tpm_tis_flush(iobase);
}
static int interrupts = -1; static int interrupts = -1;
module_param(interrupts, int, 0444); module_param(interrupts, int, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts"); MODULE_PARM_DESC(interrupts, "Enable interrupts");
...@@ -186,12 +225,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, ...@@ -186,12 +225,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len,
switch (io_mode) { switch (io_mode) {
case TPM_TIS_PHYS_8: case TPM_TIS_PHYS_8:
while (len--) while (len--)
iowrite8(*value++, phy->iobase + addr); tpm_tis_iowrite8(*value++, phy->iobase, addr);
break; break;
case TPM_TIS_PHYS_16: case TPM_TIS_PHYS_16:
return -EINVAL; return -EINVAL;
case TPM_TIS_PHYS_32: case TPM_TIS_PHYS_32:
iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase + addr); tpm_tis_iowrite32(le32_to_cpu(*((__le32 *)value)), phy->iobase, addr);
break; break;
} }
...@@ -227,7 +266,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info) ...@@ -227,7 +266,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
irq = tpm_info->irq; irq = tpm_info->irq;
if (itpm || is_itpm(ACPI_COMPANION(dev))) if (itpm || is_itpm(ACPI_COMPANION(dev)))
phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND; set_bit(TPM_TIS_ITPM_WORKAROUND, &phy->priv.flags);
return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg, return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
ACPI_HANDLE(dev)); ACPI_HANDLE(dev));
...@@ -324,14 +363,12 @@ static int tpm_tis_plat_probe(struct platform_device *pdev) ...@@ -324,14 +363,12 @@ static int tpm_tis_plat_probe(struct platform_device *pdev)
return tpm_tis_init(&pdev->dev, &tpm_info); return tpm_tis_init(&pdev->dev, &tpm_info);
} }
static int tpm_tis_plat_remove(struct platform_device *pdev) static void tpm_tis_plat_remove(struct platform_device *pdev)
{ {
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
tpm_chip_unregister(chip); tpm_chip_unregister(chip);
tpm_tis_remove(chip); tpm_tis_remove(chip);
return 0;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -344,7 +381,7 @@ MODULE_DEVICE_TABLE(of, tis_of_platform_match); ...@@ -344,7 +381,7 @@ MODULE_DEVICE_TABLE(of, tis_of_platform_match);
static struct platform_driver tis_drv = { static struct platform_driver tis_drv = {
.probe = tpm_tis_plat_probe, .probe = tpm_tis_plat_probe,
.remove = tpm_tis_plat_remove, .remove_new = tpm_tis_plat_remove,
.driver = { .driver = {
.name = "tpm_tis", .name = "tpm_tis",
.pm = &tpm_tis_pm, .pm = &tpm_tis_pm,
......
...@@ -44,6 +44,20 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, ...@@ -44,6 +44,20 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
return false; return false;
} }
static u8 tpm_tis_filter_sts_mask(u8 int_mask, u8 sts_mask)
{
if (!(int_mask & TPM_INTF_STS_VALID_INT))
sts_mask &= ~TPM_STS_VALID;
if (!(int_mask & TPM_INTF_DATA_AVAIL_INT))
sts_mask &= ~TPM_STS_DATA_AVAIL;
if (!(int_mask & TPM_INTF_CMD_READY_INT))
sts_mask &= ~TPM_STS_COMMAND_READY;
return sts_mask;
}
static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
unsigned long timeout, wait_queue_head_t *queue, unsigned long timeout, wait_queue_head_t *queue,
bool check_cancel) bool check_cancel)
...@@ -53,41 +67,56 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, ...@@ -53,41 +67,56 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
long rc; long rc;
u8 status; u8 status;
bool canceled = false; bool canceled = false;
u8 sts_mask;
int ret = 0;
/* check current status */ /* check current status */
status = chip->ops->status(chip); status = chip->ops->status(chip);
if ((status & mask) == mask) if ((status & mask) == mask)
return 0; return 0;
stop = jiffies + timeout; sts_mask = mask & (TPM_STS_VALID | TPM_STS_DATA_AVAIL |
TPM_STS_COMMAND_READY);
/* check what status changes can be handled by irqs */
sts_mask = tpm_tis_filter_sts_mask(priv->int_mask, sts_mask);
if (chip->flags & TPM_CHIP_FLAG_IRQ) { stop = jiffies + timeout;
/* process status changes with irq support */
if (sts_mask) {
ret = -ETIME;
again: again:
timeout = stop - jiffies; timeout = stop - jiffies;
if ((long)timeout <= 0) if ((long)timeout <= 0)
return -ETIME; return -ETIME;
rc = wait_event_interruptible_timeout(*queue, rc = wait_event_interruptible_timeout(*queue,
wait_for_tpm_stat_cond(chip, mask, check_cancel, wait_for_tpm_stat_cond(chip, sts_mask, check_cancel,
&canceled), &canceled),
timeout); timeout);
if (rc > 0) { if (rc > 0) {
if (canceled) if (canceled)
return -ECANCELED; return -ECANCELED;
return 0; ret = 0;
} }
if (rc == -ERESTARTSYS && freezing(current)) { if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING); clear_thread_flag(TIF_SIGPENDING);
goto again; goto again;
} }
} else { }
if (ret)
return ret;
mask &= ~sts_mask;
if (!mask) /* all done */
return 0;
/* process status changes without irq support */
do { do {
usleep_range(priv->timeout_min,
priv->timeout_max);
status = chip->ops->status(chip); status = chip->ops->status(chip);
if ((status & mask) == mask) if ((status & mask) == mask)
return 0; return 0;
usleep_range(priv->timeout_min,
priv->timeout_max);
} while (time_before(jiffies, stop)); } while (time_before(jiffies, stop));
}
return -ETIME; return -ETIME;
} }
...@@ -136,16 +165,27 @@ static bool check_locality(struct tpm_chip *chip, int l) ...@@ -136,16 +165,27 @@ static bool check_locality(struct tpm_chip *chip, int l)
return false; return false;
} }
static int release_locality(struct tpm_chip *chip, int l) static int __tpm_tis_relinquish_locality(struct tpm_tis_data *priv, int l)
{
tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
return 0;
}
static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); mutex_lock(&priv->locality_count_mutex);
priv->locality_count--;
if (priv->locality_count == 0)
__tpm_tis_relinquish_locality(priv, l);
mutex_unlock(&priv->locality_count_mutex);
return 0; return 0;
} }
static int request_locality(struct tpm_chip *chip, int l) static int __tpm_tis_request_locality(struct tpm_chip *chip, int l)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
unsigned long stop, timeout; unsigned long stop, timeout;
...@@ -186,6 +226,20 @@ static int request_locality(struct tpm_chip *chip, int l) ...@@ -186,6 +226,20 @@ static int request_locality(struct tpm_chip *chip, int l)
return -1; return -1;
} }
static int tpm_tis_request_locality(struct tpm_chip *chip, int l)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int ret = 0;
mutex_lock(&priv->locality_count_mutex);
if (priv->locality_count == 0)
ret = __tpm_tis_request_locality(chip, l);
if (!ret)
priv->locality_count++;
mutex_unlock(&priv->locality_count_mutex);
return ret;
}
static u8 tpm_tis_status(struct tpm_chip *chip) static u8 tpm_tis_status(struct tpm_chip *chip)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
...@@ -351,7 +405,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) ...@@ -351,7 +405,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int rc, status, burstcnt; int rc, status, burstcnt;
size_t count = 0; size_t count = 0;
bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND; bool itpm = test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
status = tpm_tis_status(chip); status = tpm_tis_status(chip);
if ((status & TPM_STS_COMMAND_READY) == 0) { if ((status & TPM_STS_COMMAND_READY) == 0) {
...@@ -484,7 +538,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -484,7 +538,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
int rc, irq; int rc, irq;
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
if (!(chip->flags & TPM_CHIP_FLAG_IRQ) || priv->irq_tested) if (!(chip->flags & TPM_CHIP_FLAG_IRQ) ||
test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
return tpm_tis_send_main(chip, buf, len); return tpm_tis_send_main(chip, buf, len);
/* Verify receipt of the expected IRQ */ /* Verify receipt of the expected IRQ */
...@@ -494,11 +549,11 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -494,11 +549,11 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
rc = tpm_tis_send_main(chip, buf, len); rc = tpm_tis_send_main(chip, buf, len);
priv->irq = irq; priv->irq = irq;
chip->flags |= TPM_CHIP_FLAG_IRQ; chip->flags |= TPM_CHIP_FLAG_IRQ;
if (!priv->irq_tested) if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
tpm_msleep(1); tpm_msleep(1);
if (!priv->irq_tested) if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
disable_interrupts(chip); disable_interrupts(chip);
priv->irq_tested = true; set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
return rc; return rc;
} }
...@@ -641,7 +696,7 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -641,7 +696,7 @@ static int probe_itpm(struct tpm_chip *chip)
size_t len = sizeof(cmd_getticks); size_t len = sizeof(cmd_getticks);
u16 vendor; u16 vendor;
if (priv->flags & TPM_TIS_ITPM_WORKAROUND) if (test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags))
return 0; return 0;
rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor); rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor);
...@@ -652,7 +707,7 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -652,7 +707,7 @@ static int probe_itpm(struct tpm_chip *chip)
if (vendor != TPM_VID_INTEL) if (vendor != TPM_VID_INTEL)
return 0; return 0;
if (request_locality(chip, 0) != 0) if (tpm_tis_request_locality(chip, 0) != 0)
return -EBUSY; return -EBUSY;
rc = tpm_tis_send_data(chip, cmd_getticks, len); rc = tpm_tis_send_data(chip, cmd_getticks, len);
...@@ -661,19 +716,19 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -661,19 +716,19 @@ static int probe_itpm(struct tpm_chip *chip)
tpm_tis_ready(chip); tpm_tis_ready(chip);
priv->flags |= TPM_TIS_ITPM_WORKAROUND; set_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
rc = tpm_tis_send_data(chip, cmd_getticks, len); rc = tpm_tis_send_data(chip, cmd_getticks, len);
if (rc == 0) if (rc == 0)
dev_info(&chip->dev, "Detected an iTPM.\n"); dev_info(&chip->dev, "Detected an iTPM.\n");
else { else {
priv->flags &= ~TPM_TIS_ITPM_WORKAROUND; clear_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
rc = -EFAULT; rc = -EFAULT;
} }
out: out:
tpm_tis_ready(chip); tpm_tis_ready(chip);
release_locality(chip, priv->locality); tpm_tis_relinquish_locality(chip, priv->locality);
return rc; return rc;
} }
...@@ -702,7 +757,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) ...@@ -702,7 +757,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
struct tpm_chip *chip = dev_id; struct tpm_chip *chip = dev_id;
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
u32 interrupt; u32 interrupt;
int i, rc; int rc;
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt); rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt);
if (rc < 0) if (rc < 0)
...@@ -711,20 +766,19 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) ...@@ -711,20 +766,19 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
if (interrupt == 0) if (interrupt == 0)
return IRQ_NONE; return IRQ_NONE;
priv->irq_tested = true; set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
if (interrupt & TPM_INTF_DATA_AVAIL_INT) if (interrupt & TPM_INTF_DATA_AVAIL_INT)
wake_up_interruptible(&priv->read_queue); wake_up_interruptible(&priv->read_queue);
if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
for (i = 0; i < 5; i++)
if (check_locality(chip, i))
break;
if (interrupt & if (interrupt &
(TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
TPM_INTF_CMD_READY_INT)) TPM_INTF_CMD_READY_INT))
wake_up_interruptible(&priv->int_queue); wake_up_interruptible(&priv->int_queue);
/* Clear interrupts handled with TPM_EOI */ /* Clear interrupts handled with TPM_EOI */
tpm_tis_request_locality(chip, 0);
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt); rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt);
tpm_tis_relinquish_locality(chip, 0);
if (rc < 0) if (rc < 0)
return IRQ_NONE; return IRQ_NONE;
...@@ -732,25 +786,22 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) ...@@ -732,25 +786,22 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int tpm_tis_gen_interrupt(struct tpm_chip *chip) static void tpm_tis_gen_interrupt(struct tpm_chip *chip)
{ {
const char *desc = "attempting to generate an interrupt"; const char *desc = "attempting to generate an interrupt";
u32 cap2; u32 cap2;
cap_t cap; cap_t cap;
int ret; int ret;
ret = request_locality(chip, 0); chip->flags |= TPM_CHIP_FLAG_IRQ;
if (ret < 0)
return ret;
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
else else
ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0); ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0);
release_locality(chip, 0); if (ret)
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
return ret;
} }
/* Register the IRQ and issue a command that will cause an interrupt. If an /* Register the IRQ and issue a command that will cause an interrupt. If an
...@@ -765,60 +816,66 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, ...@@ -765,60 +816,66 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
int rc; int rc;
u32 int_status; u32 int_status;
if (devm_request_irq(chip->dev.parent, irq, tis_int_handler, flags,
dev_name(&chip->dev), chip) != 0) { rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL,
tis_int_handler, IRQF_ONESHOT | flags,
dev_name(&chip->dev), chip);
if (rc) {
dev_info(&chip->dev, "Unable to request irq: %d for probe\n", dev_info(&chip->dev, "Unable to request irq: %d for probe\n",
irq); irq);
return -1; return -1;
} }
priv->irq = irq; priv->irq = irq;
rc = tpm_tis_request_locality(chip, 0);
if (rc < 0)
return rc;
rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality), rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality),
&original_int_vec); &original_int_vec);
if (rc < 0) if (rc < 0) {
tpm_tis_relinquish_locality(chip, priv->locality);
return rc; return rc;
}
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq); rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq);
if (rc < 0) if (rc < 0)
return rc; goto restore_irqs;
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status); rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status);
if (rc < 0) if (rc < 0)
return rc; goto restore_irqs;
/* Clear all existing */ /* Clear all existing */
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status); rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status);
if (rc < 0) if (rc < 0)
return rc; goto restore_irqs;
/* Turn on */ /* Turn on */
rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality),
intmask | TPM_GLOBAL_INT_ENABLE); intmask | TPM_GLOBAL_INT_ENABLE);
if (rc < 0) if (rc < 0)
return rc; goto restore_irqs;
priv->irq_tested = false; clear_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
/* Generate an interrupt by having the core call through to /* Generate an interrupt by having the core call through to
* tpm_tis_send * tpm_tis_send
*/ */
rc = tpm_tis_gen_interrupt(chip); tpm_tis_gen_interrupt(chip);
if (rc < 0)
return rc;
restore_irqs:
/* tpm_tis_send will either confirm the interrupt is working or it /* tpm_tis_send will either confirm the interrupt is working or it
* will call disable_irq which undoes all of the above. * will call disable_irq which undoes all of the above.
*/ */
if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
rc = tpm_tis_write8(priv, original_int_vec, tpm_tis_write8(priv, original_int_vec,
TPM_INT_VECTOR(priv->locality)); TPM_INT_VECTOR(priv->locality));
if (rc < 0) rc = -1;
return rc;
return 1;
} }
return 0; tpm_tis_relinquish_locality(chip, priv->locality);
return rc;
} }
/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that /* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
...@@ -932,8 +989,8 @@ static const struct tpm_class_ops tpm_tis = { ...@@ -932,8 +989,8 @@ static const struct tpm_class_ops tpm_tis = {
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_canceled = tpm_tis_req_canceled, .req_canceled = tpm_tis_req_canceled,
.request_locality = request_locality, .request_locality = tpm_tis_request_locality,
.relinquish_locality = release_locality, .relinquish_locality = tpm_tis_relinquish_locality,
.clk_enable = tpm_tis_clkrun_enable, .clk_enable = tpm_tis_clkrun_enable,
}; };
...@@ -967,6 +1024,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -967,6 +1024,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
priv->timeout_min = TPM_TIMEOUT_USECS_MIN; priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
priv->timeout_max = TPM_TIMEOUT_USECS_MAX; priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
priv->phy_ops = phy_ops; priv->phy_ops = phy_ops;
priv->locality_count = 0;
mutex_init(&priv->locality_count_mutex);
dev_set_drvdata(&chip->dev, priv); dev_set_drvdata(&chip->dev, priv);
...@@ -1009,18 +1068,50 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1009,18 +1068,50 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
if (rc < 0) if (rc < 0)
goto out_err; goto out_err;
intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | /* Figure out the capabilities */
TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT; rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps);
if (rc < 0)
goto out_err;
dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
intfcaps);
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
dev_dbg(dev, "\tBurst Count Static\n");
if (intfcaps & TPM_INTF_CMD_READY_INT) {
intmask |= TPM_INTF_CMD_READY_INT;
dev_dbg(dev, "\tCommand Ready Int Support\n");
}
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
dev_dbg(dev, "\tInterrupt Edge Falling\n");
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
dev_dbg(dev, "\tInterrupt Edge Rising\n");
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
dev_dbg(dev, "\tInterrupt Level Low\n");
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
dev_dbg(dev, "\tInterrupt Level High\n");
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) {
intmask |= TPM_INTF_LOCALITY_CHANGE_INT;
dev_dbg(dev, "\tLocality Change Int Support\n");
}
if (intfcaps & TPM_INTF_STS_VALID_INT) {
intmask |= TPM_INTF_STS_VALID_INT;
dev_dbg(dev, "\tSts Valid Int Support\n");
}
if (intfcaps & TPM_INTF_DATA_AVAIL_INT) {
intmask |= TPM_INTF_DATA_AVAIL_INT;
dev_dbg(dev, "\tData Avail Int Support\n");
}
intmask &= ~TPM_GLOBAL_INT_ENABLE; intmask &= ~TPM_GLOBAL_INT_ENABLE;
rc = request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) { if (rc < 0) {
rc = -ENODEV; rc = -ENODEV;
goto out_err; goto out_err;
} }
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
release_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
rc = tpm_chip_start(chip); rc = tpm_chip_start(chip);
if (rc) if (rc)
...@@ -1044,35 +1135,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1044,35 +1135,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
goto out_err; goto out_err;
} }
/* Figure out the capabilities */
rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps);
if (rc < 0)
goto out_err;
dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
intfcaps);
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
dev_dbg(dev, "\tBurst Count Static\n");
if (intfcaps & TPM_INTF_CMD_READY_INT)
dev_dbg(dev, "\tCommand Ready Int Support\n");
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
dev_dbg(dev, "\tInterrupt Edge Falling\n");
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
dev_dbg(dev, "\tInterrupt Edge Rising\n");
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
dev_dbg(dev, "\tInterrupt Level Low\n");
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
dev_dbg(dev, "\tInterrupt Level High\n");
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
dev_dbg(dev, "\tLocality Change Int Support\n");
if (intfcaps & TPM_INTF_STS_VALID_INT)
dev_dbg(dev, "\tSts Valid Int Support\n");
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
dev_dbg(dev, "\tData Avail Int Support\n");
/* INTERRUPT Setup */ /* INTERRUPT Setup */
init_waitqueue_head(&priv->read_queue); init_waitqueue_head(&priv->read_queue);
init_waitqueue_head(&priv->int_queue); init_waitqueue_head(&priv->int_queue);
rc = tpm_chip_startup(chip);
if (rc)
goto out_err;
if (irq != -1) { if (irq != -1) {
/* /*
* Before doing irq testing issue a command to the TPM in polling mode * Before doing irq testing issue a command to the TPM in polling mode
...@@ -1080,13 +1150,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1080,13 +1150,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
* proper timeouts for the driver. * proper timeouts for the driver.
*/ */
rc = request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) if (rc < 0)
goto out_err; goto out_err;
rc = tpm_get_timeouts(chip); rc = tpm_get_timeouts(chip);
release_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
if (rc) { if (rc) {
dev_err(dev, "Could not get TPM timeouts and durations\n"); dev_err(dev, "Could not get TPM timeouts and durations\n");
...@@ -1094,17 +1164,23 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1094,17 +1164,23 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
goto out_err; goto out_err;
} }
if (irq) { if (irq)
tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
irq); irq);
if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { else
tpm_tis_probe_irq(chip, intmask);
if (chip->flags & TPM_CHIP_FLAG_IRQ) {
priv->int_mask = intmask;
} else {
dev_err(&chip->dev, FW_BUG dev_err(&chip->dev, FW_BUG
"TPM interrupt not working, polling instead\n"); "TPM interrupt not working, polling instead\n");
rc = tpm_tis_request_locality(chip, 0);
if (rc < 0)
goto out_err;
disable_interrupts(chip); disable_interrupts(chip);
} tpm_tis_relinquish_locality(chip, 0);
} else {
tpm_tis_probe_irq(chip, intmask);
} }
} }
...@@ -1143,13 +1219,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) ...@@ -1143,13 +1219,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
if (rc < 0) if (rc < 0)
goto out; goto out;
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE;
if (rc < 0)
goto out;
intmask |= TPM_INTF_CMD_READY_INT
| TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
| TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
...@@ -1165,28 +1235,27 @@ int tpm_tis_resume(struct device *dev) ...@@ -1165,28 +1235,27 @@ int tpm_tis_resume(struct device *dev)
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
int ret; int ret;
ret = tpm_tis_request_locality(chip, 0);
if (ret < 0)
return ret;
if (chip->flags & TPM_CHIP_FLAG_IRQ) if (chip->flags & TPM_CHIP_FLAG_IRQ)
tpm_tis_reenable_interrupts(chip); tpm_tis_reenable_interrupts(chip);
ret = tpm_pm_resume(dev); ret = tpm_pm_resume(dev);
if (ret) if (ret)
return ret; goto out;
/* /*
* TPM 1.2 requires self-test on resume. This function actually returns * TPM 1.2 requires self-test on resume. This function actually returns
* an error code but for unknown reason it isn't handled. * an error code but for unknown reason it isn't handled.
*/ */
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
ret = request_locality(chip, 0);
if (ret < 0)
return ret;
tpm1_do_selftest(chip); tpm1_do_selftest(chip);
out:
tpm_tis_relinquish_locality(chip, 0);
release_locality(chip, 0); return ret;
}
return 0;
} }
EXPORT_SYMBOL_GPL(tpm_tis_resume); EXPORT_SYMBOL_GPL(tpm_tis_resume);
#endif #endif
......
...@@ -87,13 +87,16 @@ enum tpm_tis_flags { ...@@ -87,13 +87,16 @@ enum tpm_tis_flags {
TPM_TIS_ITPM_WORKAROUND = BIT(0), TPM_TIS_ITPM_WORKAROUND = BIT(0),
TPM_TIS_INVALID_STATUS = BIT(1), TPM_TIS_INVALID_STATUS = BIT(1),
TPM_TIS_DEFAULT_CANCELLATION = BIT(2), TPM_TIS_DEFAULT_CANCELLATION = BIT(2),
TPM_TIS_IRQ_TESTED = BIT(3),
}; };
struct tpm_tis_data { struct tpm_tis_data {
u16 manufacturer_id; u16 manufacturer_id;
struct mutex locality_count_mutex;
unsigned int locality_count;
int locality; int locality;
int irq; int irq;
bool irq_tested; unsigned int int_mask;
unsigned long flags; unsigned long flags;
void __iomem *ilb_base_addr; void __iomem *ilb_base_addr;
u16 clkrun_enabled; u16 clkrun_enabled;
......
...@@ -100,8 +100,7 @@ static int tpm_cr50_i2c_wait_tpm_ready(struct tpm_chip *chip) ...@@ -100,8 +100,7 @@ static int tpm_cr50_i2c_wait_tpm_ready(struct tpm_chip *chip)
} }
/* Wait for interrupt to indicate TPM is ready to respond */ /* Wait for interrupt to indicate TPM is ready to respond */
if (!wait_for_completion_timeout(&priv->tpm_ready, if (!wait_for_completion_timeout(&priv->tpm_ready, chip->timeout_a)) {
msecs_to_jiffies(chip->timeout_a))) {
dev_warn(&chip->dev, "Timeout waiting for TPM ready\n"); dev_warn(&chip->dev, "Timeout waiting for TPM ready\n");
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
...@@ -231,7 +231,7 @@ static const struct spi_device_id tpm_tis_spi_id[] = { ...@@ -231,7 +231,7 @@ static const struct spi_device_id tpm_tis_spi_id[] = {
}; };
MODULE_DEVICE_TABLE(spi, tpm_tis_spi_id); MODULE_DEVICE_TABLE(spi, tpm_tis_spi_id);
static const struct of_device_id of_tis_spi_match[] = { static const struct of_device_id of_tis_spi_match[] __maybe_unused = {
{ .compatible = "st,st33htpm-spi", .data = tpm_tis_spi_probe }, { .compatible = "st,st33htpm-spi", .data = tpm_tis_spi_probe },
{ .compatible = "infineon,slb9670", .data = tpm_tis_spi_probe }, { .compatible = "infineon,slb9670", .data = tpm_tis_spi_probe },
{ .compatible = "tcg,tpm_tis-spi", .data = tpm_tis_spi_probe }, { .compatible = "tcg,tpm_tis-spi", .data = tpm_tis_spi_probe },
...@@ -240,7 +240,7 @@ static const struct of_device_id of_tis_spi_match[] = { ...@@ -240,7 +240,7 @@ static const struct of_device_id of_tis_spi_match[] = {
}; };
MODULE_DEVICE_TABLE(of, of_tis_spi_match); MODULE_DEVICE_TABLE(of, of_tis_spi_match);
static const struct acpi_device_id acpi_tis_spi_match[] = { static const struct acpi_device_id acpi_tis_spi_match[] __maybe_unused = {
{"SMO0768", 0}, {"SMO0768", 0},
{} {}
}; };
......
...@@ -127,14 +127,12 @@ static int tpm_tis_synquacer_probe(struct platform_device *pdev) ...@@ -127,14 +127,12 @@ static int tpm_tis_synquacer_probe(struct platform_device *pdev)
return tpm_tis_synquacer_init(&pdev->dev, &tpm_info); return tpm_tis_synquacer_init(&pdev->dev, &tpm_info);
} }
static int tpm_tis_synquacer_remove(struct platform_device *pdev) static void tpm_tis_synquacer_remove(struct platform_device *pdev)
{ {
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
tpm_chip_unregister(chip); tpm_chip_unregister(chip);
tpm_tis_remove(chip); tpm_tis_remove(chip);
return 0;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -155,7 +153,7 @@ MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl); ...@@ -155,7 +153,7 @@ MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl);
static struct platform_driver tis_synquacer_drv = { static struct platform_driver tis_synquacer_drv = {
.probe = tpm_tis_synquacer_probe, .probe = tpm_tis_synquacer_probe,
.remove = tpm_tis_synquacer_remove, .remove_new = tpm_tis_synquacer_remove,
.driver = { .driver = {
.name = "tpm_tis_synquacer", .name = "tpm_tis_synquacer",
.pm = &tpm_tis_synquacer_pm, .pm = &tpm_tis_synquacer_pm,
......
...@@ -28,6 +28,10 @@ struct public_key { ...@@ -28,6 +28,10 @@ struct public_key {
bool key_is_private; bool key_is_private;
const char *id_type; const char *id_type;
const char *pkey_algo; const char *pkey_algo;
unsigned long key_eflags; /* key extension flags */
#define KEY_EFLAG_CA 0 /* set if the CA basic constraints is set */
#define KEY_EFLAG_DIGITALSIG 1 /* set if the digitalSignature usage is set */
#define KEY_EFLAG_KEYCERTSIGN 2 /* set if the keyCertSign usage is set */
}; };
extern void public_key_free(struct public_key *key); extern void public_key_free(struct public_key *key);
...@@ -71,6 +75,21 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring, ...@@ -71,6 +75,21 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring,
const union key_payload *payload, const union key_payload *payload,
struct key *trusted); struct key *trusted);
#if IS_REACHABLE(CONFIG_ASYMMETRIC_KEY_TYPE)
extern int restrict_link_by_ca(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring);
#else
static inline int restrict_link_by_ca(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring)
{
return 0;
}
#endif
extern int query_asymmetric_key(const struct kernel_pkey_params *, extern int query_asymmetric_key(const struct kernel_pkey_params *,
struct kernel_pkey_query *); struct kernel_pkey_query *);
...@@ -80,7 +99,16 @@ extern int create_signature(struct kernel_pkey_params *, const void *, void *); ...@@ -80,7 +99,16 @@ extern int create_signature(struct kernel_pkey_params *, const void *, void *);
extern int verify_signature(const struct key *, extern int verify_signature(const struct key *,
const struct public_key_signature *); const struct public_key_signature *);
#if IS_REACHABLE(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE)
int public_key_verify_signature(const struct public_key *pkey, int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig); const struct public_key_signature *sig);
#else
static inline
int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig)
{
return -EINVAL;
}
#endif
#endif /* _LINUX_PUBLIC_KEY_H */ #endif /* _LINUX_PUBLIC_KEY_H */
...@@ -68,13 +68,34 @@ config INTEGRITY_MACHINE_KEYRING ...@@ -68,13 +68,34 @@ config INTEGRITY_MACHINE_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS depends on INTEGRITY_ASYMMETRIC_KEYS
depends on SYSTEM_BLACKLIST_KEYRING depends on SYSTEM_BLACKLIST_KEYRING
depends on LOAD_UEFI_KEYS depends on LOAD_UEFI_KEYS
depends on !IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
help help
If set, provide a keyring to which Machine Owner Keys (MOK) may If set, provide a keyring to which Machine Owner Keys (MOK) may
be added. This keyring shall contain just MOK keys. Unlike keys be added. This keyring shall contain just MOK keys. Unlike keys
in the platform keyring, keys contained in the .machine keyring will in the platform keyring, keys contained in the .machine keyring will
be trusted within the kernel. be trusted within the kernel.
config INTEGRITY_CA_MACHINE_KEYRING
bool "Enforce Machine Keyring CA Restrictions"
depends on INTEGRITY_MACHINE_KEYRING
default n
help
The .machine keyring can be configured to enforce CA restriction
on any key added to it. By default no restrictions are in place
and all Machine Owner Keys (MOK) are added to the machine keyring.
If enabled only CA keys are added to the machine keyring, all
other MOK keys load into the platform keyring.
config INTEGRITY_CA_MACHINE_KEYRING_MAX
bool "Only CA keys without DigitialSignature usage set"
depends on INTEGRITY_CA_MACHINE_KEYRING
default n
help
When selected, only load CA keys are loaded into the machine
keyring that contain the CA bit set along with the keyCertSign
Usage field. Keys containing the digitialSignature Usage field
will not be loaded. The remaining MOK keys are loaded into the
.platform keyring.
config LOAD_UEFI_KEYS config LOAD_UEFI_KEYS
depends on INTEGRITY_PLATFORM_KEYRING depends on INTEGRITY_PLATFORM_KEYRING
depends on EFI depends on EFI
......
...@@ -132,7 +132,8 @@ int __init integrity_init_keyring(const unsigned int id) ...@@ -132,7 +132,8 @@ int __init integrity_init_keyring(const unsigned int id)
| KEY_USR_READ | KEY_USR_SEARCH; | KEY_USR_READ | KEY_USR_SEARCH;
if (id == INTEGRITY_KEYRING_PLATFORM || if (id == INTEGRITY_KEYRING_PLATFORM ||
id == INTEGRITY_KEYRING_MACHINE) { (id == INTEGRITY_KEYRING_MACHINE &&
!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING))) {
restriction = NULL; restriction = NULL;
goto out; goto out;
} }
...@@ -144,6 +145,9 @@ int __init integrity_init_keyring(const unsigned int id) ...@@ -144,6 +145,9 @@ int __init integrity_init_keyring(const unsigned int id)
if (!restriction) if (!restriction)
return -ENOMEM; return -ENOMEM;
if (id == INTEGRITY_KEYRING_MACHINE)
restriction->check = restrict_link_by_ca;
else
restriction->check = restrict_link_to_ima; restriction->check = restrict_link_to_ima;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment