mirror of
https://github.com/torvalds/linux.git
synced 2024-12-26 04:42:12 +00:00
Two major features are included into this pull request. The links for
the landed patch sets are below. 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. The 2nd feature is the enablement of 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 falled 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/ -----BEGIN PGP SIGNATURE----- iIgEABYIADAWIQRE6pSOnaBC00OEHEIaerohdGur0gUCZEaRpxIcamFya2tvQGtl cm5lbC5vcmcACgkQGnq6IXRrq9L7OwD+PBjZzXLYCMy0WK++XaVwf2ATZmoRVEKR FJn5hCKL0WoBAJn6rBrty7xd+5OHmoO5YddyX7UreBR1L7Zy2U5mGGcJ =AIR1 -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
1a0beef98b
@ -33,7 +33,11 @@ extern __initconst const unsigned long system_certificate_list_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
|
||||
* 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,
|
||||
#ifdef CONFIG_SECONDARY_TRUSTED_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
|
||||
* 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(
|
||||
secondary_trusted_keys);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Allocate a struct key_restriction for the "builtin and secondary trust"
|
||||
* keyring. Only for use in system_trusted_keyring_init().
|
||||
*/
|
||||
|
@ -108,6 +108,46 @@ int restrict_link_by_signature(struct key *dest_keyring,
|
||||
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,
|
||||
const struct asymmetric_key_id *single)
|
||||
{
|
||||
|
@ -579,6 +579,34 @@ int x509_process_extension(void *context, size_t hdrlen,
|
||||
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) {
|
||||
/* Get hold of the CA key fingerprint */
|
||||
ctx->raw_akid = v;
|
||||
@ -586,6 +614,28 @@ int x509_process_extension(void *context, size_t hdrlen,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ static int tpm_bios_measurements_open(struct inode *inode,
|
||||
inode_unlock(inode);
|
||||
return -ENODEV;
|
||||
}
|
||||
chip_seqops = (struct tpm_chip_seqops *)inode->i_private;
|
||||
chip_seqops = inode->i_private;
|
||||
seqops = chip_seqops->seqops;
|
||||
chip = chip_seqops->chip;
|
||||
get_device(&chip->dev);
|
||||
@ -55,8 +55,8 @@ static int tpm_bios_measurements_open(struct inode *inode,
|
||||
static int tpm_bios_measurements_release(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
struct seq_file *seq = (struct seq_file *)file->private_data;
|
||||
struct tpm_chip *chip = (struct tpm_chip *)seq->private;
|
||||
struct seq_file *seq = file->private_data;
|
||||
struct tpm_chip *chip = seq->private;
|
||||
|
||||
put_device(&chip->dev);
|
||||
|
||||
|
@ -138,13 +138,13 @@ static const struct i2c_device_id 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", },
|
||||
{}
|
||||
};
|
||||
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"},
|
||||
{}
|
||||
};
|
||||
|
@ -255,13 +255,13 @@ static const struct spi_device_id 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", },
|
||||
{}
|
||||
};
|
||||
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"},
|
||||
{}
|
||||
};
|
||||
|
@ -605,6 +605,30 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* tpm_chip_startup() - performs auto startup and allocates the PCRs
|
||||
* @chip: TPM chip to use.
|
||||
*/
|
||||
int tpm_chip_startup(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = tpm_chip_start(chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = tpm_auto_startup(chip);
|
||||
if (rc)
|
||||
goto stop;
|
||||
|
||||
rc = tpm_get_pcr_allocation(chip);
|
||||
stop:
|
||||
tpm_chip_stop(chip);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_chip_startup);
|
||||
|
||||
/*
|
||||
* tpm_chip_register() - create a character device for the TPM chip
|
||||
* @chip: TPM chip to use.
|
||||
@ -620,20 +644,6 @@ int tpm_chip_register(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = tpm_chip_start(chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = tpm_auto_startup(chip);
|
||||
if (rc) {
|
||||
tpm_chip_stop(chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = tpm_get_pcr_allocation(chip);
|
||||
tpm_chip_stop(chip);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
tpm_sysfs_add_device(chip);
|
||||
|
||||
tpm_bios_log_setup(chip);
|
||||
@ -682,7 +692,8 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
|
||||
void tpm_chip_unregister(struct tpm_chip *chip)
|
||||
{
|
||||
tpm_del_legacy_sysfs(chip);
|
||||
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !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);
|
||||
tpm_bios_log_teardown(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)
|
||||
delay_msec * 1000);
|
||||
};
|
||||
|
||||
int tpm_chip_startup(struct tpm_chip *chip);
|
||||
int tpm_chip_start(struct tpm_chip *chip);
|
||||
void tpm_chip_stop(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)
|
||||
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;
|
||||
|
||||
return ftpm_tee_remove(dev);
|
||||
ftpm_tee_remove(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,7 +367,7 @@ static struct platform_driver ftpm_tee_plat_driver = {
|
||||
},
|
||||
.shutdown = ftpm_plat_tee_shutdown,
|
||||
.probe = ftpm_plat_tee_probe,
|
||||
.remove = ftpm_plat_tee_remove,
|
||||
.remove_new = ftpm_plat_tee_remove,
|
||||
};
|
||||
|
||||
/* 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
|
||||
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;
|
||||
module_param(interrupts, int, 0444);
|
||||
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,
|
||||
switch (io_mode) {
|
||||
case TPM_TIS_PHYS_8:
|
||||
while (len--)
|
||||
iowrite8(*value++, phy->iobase + addr);
|
||||
tpm_tis_iowrite8(*value++, phy->iobase, addr);
|
||||
break;
|
||||
case TPM_TIS_PHYS_16:
|
||||
return -EINVAL;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -227,7 +266,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
|
||||
irq = tpm_info->irq;
|
||||
|
||||
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,
|
||||
ACPI_HANDLE(dev));
|
||||
@ -324,14 +363,12 @@ static int tpm_tis_plat_probe(struct platform_device *pdev)
|
||||
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);
|
||||
|
||||
tpm_chip_unregister(chip);
|
||||
tpm_tis_remove(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -344,7 +381,7 @@ MODULE_DEVICE_TABLE(of, tis_of_platform_match);
|
||||
|
||||
static struct platform_driver tis_drv = {
|
||||
.probe = tpm_tis_plat_probe,
|
||||
.remove = tpm_tis_plat_remove,
|
||||
.remove_new = tpm_tis_plat_remove,
|
||||
.driver = {
|
||||
.name = "tpm_tis",
|
||||
.pm = &tpm_tis_pm,
|
||||
|
@ -44,6 +44,20 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
|
||||
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,
|
||||
unsigned long timeout, wait_queue_head_t *queue,
|
||||
bool check_cancel)
|
||||
@ -53,41 +67,56 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
|
||||
long rc;
|
||||
u8 status;
|
||||
bool canceled = false;
|
||||
u8 sts_mask;
|
||||
int ret = 0;
|
||||
|
||||
/* check current status */
|
||||
status = chip->ops->status(chip);
|
||||
if ((status & mask) == mask)
|
||||
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:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
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),
|
||||
timeout);
|
||||
if (rc > 0) {
|
||||
if (canceled)
|
||||
return -ECANCELED;
|
||||
return 0;
|
||||
ret = 0;
|
||||
}
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
usleep_range(priv->timeout_min,
|
||||
priv->timeout_max);
|
||||
status = chip->ops->status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
} while (time_before(jiffies, stop));
|
||||
}
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask &= ~sts_mask;
|
||||
if (!mask) /* all done */
|
||||
return 0;
|
||||
/* process status changes without irq support */
|
||||
do {
|
||||
status = chip->ops->status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
usleep_range(priv->timeout_min,
|
||||
priv->timeout_max);
|
||||
} while (time_before(jiffies, stop));
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
@ -136,16 +165,27 @@ static bool check_locality(struct tpm_chip *chip, int l)
|
||||
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)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
|
||||
tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int request_locality(struct tpm_chip *chip, int l)
|
||||
static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int __tpm_tis_request_locality(struct tpm_chip *chip, int l)
|
||||
{
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
unsigned long stop, timeout;
|
||||
@ -186,6 +226,20 @@ again:
|
||||
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)
|
||||
{
|
||||
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)
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
int rc, status, burstcnt;
|
||||
size_t count = 0;
|
||||
bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
|
||||
bool itpm = test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
|
||||
|
||||
status = tpm_tis_status(chip);
|
||||
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)
|
||||
int rc, irq;
|
||||
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);
|
||||
|
||||
/* Verify receipt of the expected IRQ */
|
||||
@ -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);
|
||||
priv->irq = irq;
|
||||
chip->flags |= TPM_CHIP_FLAG_IRQ;
|
||||
if (!priv->irq_tested)
|
||||
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
|
||||
tpm_msleep(1);
|
||||
if (!priv->irq_tested)
|
||||
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
|
||||
disable_interrupts(chip);
|
||||
priv->irq_tested = true;
|
||||
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -641,7 +696,7 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
size_t len = sizeof(cmd_getticks);
|
||||
u16 vendor;
|
||||
|
||||
if (priv->flags & TPM_TIS_ITPM_WORKAROUND)
|
||||
if (test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags))
|
||||
return 0;
|
||||
|
||||
rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor);
|
||||
@ -652,7 +707,7 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
if (vendor != TPM_VID_INTEL)
|
||||
return 0;
|
||||
|
||||
if (request_locality(chip, 0) != 0)
|
||||
if (tpm_tis_request_locality(chip, 0) != 0)
|
||||
return -EBUSY;
|
||||
|
||||
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
||||
@ -661,19 +716,19 @@ static int probe_itpm(struct tpm_chip *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);
|
||||
if (rc == 0)
|
||||
dev_info(&chip->dev, "Detected an iTPM.\n");
|
||||
else {
|
||||
priv->flags &= ~TPM_TIS_ITPM_WORKAROUND;
|
||||
clear_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
|
||||
rc = -EFAULT;
|
||||
}
|
||||
|
||||
out:
|
||||
tpm_tis_ready(chip);
|
||||
release_locality(chip, priv->locality);
|
||||
tpm_tis_relinquish_locality(chip, priv->locality);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -702,7 +757,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||
struct tpm_chip *chip = dev_id;
|
||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||
u32 interrupt;
|
||||
int i, rc;
|
||||
int rc;
|
||||
|
||||
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &interrupt);
|
||||
if (rc < 0)
|
||||
@ -711,20 +766,19 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||
if (interrupt == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
priv->irq_tested = true;
|
||||
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
|
||||
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
|
||||
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 &
|
||||
(TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT |
|
||||
TPM_INTF_CMD_READY_INT))
|
||||
wake_up_interruptible(&priv->int_queue);
|
||||
|
||||
/* Clear interrupts handled with TPM_EOI */
|
||||
tpm_tis_request_locality(chip, 0);
|
||||
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt);
|
||||
tpm_tis_relinquish_locality(chip, 0);
|
||||
if (rc < 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
@ -732,25 +786,22 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||
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";
|
||||
u32 cap2;
|
||||
cap_t cap;
|
||||
int ret;
|
||||
|
||||
ret = request_locality(chip, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
chip->flags |= TPM_CHIP_FLAG_IRQ;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc);
|
||||
else
|
||||
ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0);
|
||||
|
||||
release_locality(chip, 0);
|
||||
|
||||
return ret;
|
||||
if (ret)
|
||||
chip->flags &= ~TPM_CHIP_FLAG_IRQ;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
int rc;
|
||||
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",
|
||||
irq);
|
||||
return -1;
|
||||
}
|
||||
priv->irq = irq;
|
||||
|
||||
rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality),
|
||||
&original_int_vec);
|
||||
rc = tpm_tis_request_locality(chip, 0);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality),
|
||||
&original_int_vec);
|
||||
if (rc < 0) {
|
||||
tpm_tis_relinquish_locality(chip, priv->locality);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
goto restore_irqs;
|
||||
|
||||
rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
goto restore_irqs;
|
||||
|
||||
/* Clear all existing */
|
||||
rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
goto restore_irqs;
|
||||
/* Turn on */
|
||||
rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality),
|
||||
intmask | TPM_GLOBAL_INT_ENABLE);
|
||||
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
|
||||
* tpm_tis_send
|
||||
*/
|
||||
rc = tpm_tis_gen_interrupt(chip);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
tpm_tis_gen_interrupt(chip);
|
||||
|
||||
restore_irqs:
|
||||
/* tpm_tis_send will either confirm the interrupt is working or it
|
||||
* will call disable_irq which undoes all of the above.
|
||||
*/
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
|
||||
rc = tpm_tis_write8(priv, original_int_vec,
|
||||
TPM_INT_VECTOR(priv->locality));
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return 1;
|
||||
tpm_tis_write8(priv, original_int_vec,
|
||||
TPM_INT_VECTOR(priv->locality));
|
||||
rc = -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
|
||||
@ -932,8 +989,8 @@ static const struct tpm_class_ops tpm_tis = {
|
||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
.req_canceled = tpm_tis_req_canceled,
|
||||
.request_locality = request_locality,
|
||||
.relinquish_locality = release_locality,
|
||||
.request_locality = tpm_tis_request_locality,
|
||||
.relinquish_locality = tpm_tis_relinquish_locality,
|
||||
.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,
|
||||
priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
|
||||
priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
|
||||
priv->phy_ops = phy_ops;
|
||||
priv->locality_count = 0;
|
||||
mutex_init(&priv->locality_count_mutex);
|
||||
|
||||
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,
|
||||
if (rc < 0)
|
||||
goto out_err;
|
||||
|
||||
intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
|
||||
TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
|
||||
/* 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) {
|
||||
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;
|
||||
|
||||
rc = request_locality(chip, 0);
|
||||
rc = tpm_tis_request_locality(chip, 0);
|
||||
if (rc < 0) {
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
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);
|
||||
if (rc)
|
||||
@ -1044,35 +1135,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
||||
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 */
|
||||
init_waitqueue_head(&priv->read_queue);
|
||||
init_waitqueue_head(&priv->int_queue);
|
||||
|
||||
rc = tpm_chip_startup(chip);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
|
||||
if (irq != -1) {
|
||||
/*
|
||||
* 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,
|
||||
* proper timeouts for the driver.
|
||||
*/
|
||||
|
||||
rc = request_locality(chip, 0);
|
||||
rc = tpm_tis_request_locality(chip, 0);
|
||||
if (rc < 0)
|
||||
goto out_err;
|
||||
|
||||
rc = tpm_get_timeouts(chip);
|
||||
|
||||
release_locality(chip, 0);
|
||||
tpm_tis_relinquish_locality(chip, 0);
|
||||
|
||||
if (rc) {
|
||||
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,
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (irq) {
|
||||
if (irq)
|
||||
tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
|
||||
irq);
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
|
||||
dev_err(&chip->dev, FW_BUG
|
||||
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
|
||||
"TPM interrupt not working, polling instead\n");
|
||||
|
||||
disable_interrupts(chip);
|
||||
}
|
||||
} else {
|
||||
tpm_tis_probe_irq(chip, intmask);
|
||||
rc = tpm_tis_request_locality(chip, 0);
|
||||
if (rc < 0)
|
||||
goto out_err;
|
||||
disable_interrupts(chip);
|
||||
tpm_tis_relinquish_locality(chip, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1143,13 +1219,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
|
||||
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;
|
||||
intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE;
|
||||
|
||||
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
|
||||
|
||||
@ -1165,28 +1235,27 @@ int tpm_tis_resume(struct device *dev)
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = tpm_tis_request_locality(chip, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_IRQ)
|
||||
tpm_tis_reenable_interrupts(chip);
|
||||
|
||||
ret = tpm_pm_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* TPM 1.2 requires self-test on resume. This function actually returns
|
||||
* an error code but for unknown reason it isn't handled.
|
||||
*/
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
|
||||
ret = request_locality(chip, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
|
||||
tpm1_do_selftest(chip);
|
||||
out:
|
||||
tpm_tis_relinquish_locality(chip, 0);
|
||||
|
||||
release_locality(chip, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_tis_resume);
|
||||
#endif
|
||||
|
@ -87,13 +87,16 @@ enum tpm_tis_flags {
|
||||
TPM_TIS_ITPM_WORKAROUND = BIT(0),
|
||||
TPM_TIS_INVALID_STATUS = BIT(1),
|
||||
TPM_TIS_DEFAULT_CANCELLATION = BIT(2),
|
||||
TPM_TIS_IRQ_TESTED = BIT(3),
|
||||
};
|
||||
|
||||
struct tpm_tis_data {
|
||||
u16 manufacturer_id;
|
||||
struct mutex locality_count_mutex;
|
||||
unsigned int locality_count;
|
||||
int locality;
|
||||
int irq;
|
||||
bool irq_tested;
|
||||
unsigned int int_mask;
|
||||
unsigned long flags;
|
||||
void __iomem *ilb_base_addr;
|
||||
u16 clkrun_enabled;
|
||||
|
@ -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 */
|
||||
if (!wait_for_completion_timeout(&priv->tpm_ready,
|
||||
msecs_to_jiffies(chip->timeout_a))) {
|
||||
if (!wait_for_completion_timeout(&priv->tpm_ready, chip->timeout_a)) {
|
||||
dev_warn(&chip->dev, "Timeout waiting for TPM ready\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
@ -231,7 +231,7 @@ static const struct spi_device_id 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 = "infineon,slb9670", .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[] = {
|
||||
};
|
||||
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},
|
||||
{}
|
||||
};
|
||||
|
@ -127,14 +127,12 @@ static int tpm_tis_synquacer_probe(struct platform_device *pdev)
|
||||
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);
|
||||
|
||||
tpm_chip_unregister(chip);
|
||||
tpm_tis_remove(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -155,7 +153,7 @@ MODULE_DEVICE_TABLE(acpi, tpm_synquacer_acpi_tbl);
|
||||
|
||||
static struct platform_driver tis_synquacer_drv = {
|
||||
.probe = tpm_tis_synquacer_probe,
|
||||
.remove = tpm_tis_synquacer_remove,
|
||||
.remove_new = tpm_tis_synquacer_remove,
|
||||
.driver = {
|
||||
.name = "tpm_tis_synquacer",
|
||||
.pm = &tpm_tis_synquacer_pm,
|
||||
|
@ -28,6 +28,10 @@ struct public_key {
|
||||
bool key_is_private;
|
||||
const char *id_type;
|
||||
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);
|
||||
@ -71,6 +75,21 @@ extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring,
|
||||
const union key_payload *payload,
|
||||
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 *,
|
||||
struct kernel_pkey_query *);
|
||||
|
||||
@ -80,7 +99,16 @@ extern int create_signature(struct kernel_pkey_params *, const void *, void *);
|
||||
extern int verify_signature(const struct key *,
|
||||
const struct public_key_signature *);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE)
|
||||
int public_key_verify_signature(const struct public_key *pkey,
|
||||
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 */
|
||||
|
@ -68,13 +68,34 @@ config INTEGRITY_MACHINE_KEYRING
|
||||
depends on INTEGRITY_ASYMMETRIC_KEYS
|
||||
depends on SYSTEM_BLACKLIST_KEYRING
|
||||
depends on LOAD_UEFI_KEYS
|
||||
depends on !IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
|
||||
help
|
||||
If set, provide a keyring to which Machine Owner Keys (MOK) may
|
||||
be added. This keyring shall contain just MOK keys. Unlike keys
|
||||
in the platform keyring, keys contained in the .machine keyring will
|
||||
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
|
||||
depends on INTEGRITY_PLATFORM_KEYRING
|
||||
depends on EFI
|
||||
|
@ -132,7 +132,8 @@ int __init integrity_init_keyring(const unsigned int id)
|
||||
| KEY_USR_READ | KEY_USR_SEARCH;
|
||||
|
||||
if (id == INTEGRITY_KEYRING_PLATFORM ||
|
||||
id == INTEGRITY_KEYRING_MACHINE) {
|
||||
(id == INTEGRITY_KEYRING_MACHINE &&
|
||||
!IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING))) {
|
||||
restriction = NULL;
|
||||
goto out;
|
||||
}
|
||||
@ -144,7 +145,10 @@ int __init integrity_init_keyring(const unsigned int id)
|
||||
if (!restriction)
|
||||
return -ENOMEM;
|
||||
|
||||
restriction->check = restrict_link_to_ima;
|
||||
if (id == INTEGRITY_KEYRING_MACHINE)
|
||||
restriction->check = restrict_link_by_ca;
|
||||
else
|
||||
restriction->check = restrict_link_to_ima;
|
||||
|
||||
/*
|
||||
* MOK keys can only be added through a read-only runtime services
|
||||
|
Loading…
Reference in New Issue
Block a user