You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: "This is basically a maintenance update for the TPM driver and EVM/IMA" Fix up conflicts in lib/digsig.c and security/integrity/ima/ima_main.c * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (45 commits) tpm/ibmvtpm: build only when IBM pseries is configured ima: digital signature verification using asymmetric keys ima: rename hash calculation functions ima: use new crypto_shash API instead of old crypto_hash ima: add policy support for file system uuid evm: add file system uuid to EVM hmac tpm_tis: check pnp_acpi_device return code char/tpm/tpm_i2c_stm_st33: drop temporary variable for return value char/tpm/tpm_i2c_stm_st33: remove dead assignment in tpm_st33_i2c_probe char/tpm/tpm_i2c_stm_st33: Remove __devexit attribute char/tpm/tpm_i2c_stm_st33: Don't use memcpy for one byte assignment tpm_i2c_stm_st33: removed unused variables/code TPM: Wait for TPM_ACCESS tpmRegValidSts to go high at startup tpm: Fix cancellation of TPM commands (interrupt mode) tpm: Fix cancellation of TPM commands (polling mode) tpm: Store TPM vendor ID TPM: Work around buggy TPMs that block during continue self test tpm_i2c_stm_st33: fix oops when i2c client is unavailable char/tpm: Use struct dev_pm_ops for power management TPM: STMicroelectronics ST33 I2C BUILD STUFF ...
This commit is contained in:
@@ -75,10 +75,20 @@ config TCG_INFINEON
|
||||
|
||||
config TCG_IBMVTPM
|
||||
tristate "IBM VTPM Interface"
|
||||
depends on PPC64
|
||||
depends on PPC_PSERIES
|
||||
---help---
|
||||
If you have IBM virtual TPM (VTPM) support say Yes and it
|
||||
will be accessible from within Linux. To compile this driver
|
||||
as a module, choose M here; the module will be called tpm_ibmvtpm.
|
||||
|
||||
config TCG_ST33_I2C
|
||||
tristate "STMicroelectronics ST33 I2C TPM"
|
||||
depends on I2C
|
||||
depends on GPIOLIB
|
||||
---help---
|
||||
If you have a TPM security chip from STMicroelectronics working with
|
||||
an I2C bus say Yes and it will be accessible from within Linux.
|
||||
To compile this driver as a module, choose M here; the module will be
|
||||
called tpm_stm_st33_i2c.
|
||||
|
||||
endif # TCG_TPM
|
||||
|
||||
@@ -17,3 +17,4 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
|
||||
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
|
||||
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
|
||||
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
|
||||
obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
|
||||
|
||||
+80
-34
@@ -40,8 +40,9 @@ enum tpm_duration {
|
||||
};
|
||||
|
||||
#define TPM_MAX_ORDINAL 243
|
||||
#define TPM_MAX_PROTECTED_ORDINAL 12
|
||||
#define TPM_PROTECTED_ORDINAL_MASK 0xFF
|
||||
#define TSC_MAX_ORDINAL 12
|
||||
#define TPM_PROTECTED_COMMAND 0x00
|
||||
#define TPM_CONNECTION_COMMAND 0x40
|
||||
|
||||
/*
|
||||
* Bug workaround - some TPM's don't flush the most
|
||||
@@ -65,21 +66,6 @@ static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
|
||||
* values of the SHORT, MEDIUM, and LONG durations are retrieved
|
||||
* from the chip during initialization with a call to tpm_get_timeouts.
|
||||
*/
|
||||
static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
|
||||
TPM_UNDEFINED, /* 0 */
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED, /* 5 */
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED,
|
||||
TPM_UNDEFINED,
|
||||
TPM_SHORT, /* 10 */
|
||||
TPM_SHORT,
|
||||
};
|
||||
|
||||
static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
|
||||
TPM_UNDEFINED, /* 0 */
|
||||
TPM_UNDEFINED,
|
||||
@@ -351,14 +337,11 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
|
||||
{
|
||||
int duration_idx = TPM_UNDEFINED;
|
||||
int duration = 0;
|
||||
u8 category = (ordinal >> 24) & 0xFF;
|
||||
|
||||
if (ordinal < TPM_MAX_ORDINAL)
|
||||
if ((category == TPM_PROTECTED_COMMAND && ordinal < TPM_MAX_ORDINAL) ||
|
||||
(category == TPM_CONNECTION_COMMAND && ordinal < TSC_MAX_ORDINAL))
|
||||
duration_idx = tpm_ordinal_duration[ordinal];
|
||||
else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
|
||||
TPM_MAX_PROTECTED_ORDINAL)
|
||||
duration_idx =
|
||||
tpm_protected_ordinal_duration[ordinal &
|
||||
TPM_PROTECTED_ORDINAL_MASK];
|
||||
|
||||
if (duration_idx != TPM_UNDEFINED)
|
||||
duration = chip->vendor.duration[duration_idx];
|
||||
@@ -410,7 +393,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
|
||||
chip->vendor.req_complete_val)
|
||||
goto out_recv;
|
||||
|
||||
if ((status == chip->vendor.req_canceled)) {
|
||||
if (chip->vendor.req_canceled(chip, status)) {
|
||||
dev_err(chip->dev, "Operation Canceled\n");
|
||||
rc = -ECANCELED;
|
||||
goto out;
|
||||
@@ -468,7 +451,7 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
||||
return -EFAULT;
|
||||
|
||||
err = be32_to_cpu(cmd->header.out.return_code);
|
||||
if (err != 0)
|
||||
if (err != 0 && desc)
|
||||
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
||||
|
||||
return err;
|
||||
@@ -528,6 +511,25 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
|
||||
|
||||
#define TPM_ORD_STARTUP cpu_to_be32(153)
|
||||
#define TPM_ST_CLEAR cpu_to_be16(1)
|
||||
#define TPM_ST_STATE cpu_to_be16(2)
|
||||
#define TPM_ST_DEACTIVATED cpu_to_be16(3)
|
||||
static const struct tpm_input_header tpm_startup_header = {
|
||||
.tag = TPM_TAG_RQU_COMMAND,
|
||||
.length = cpu_to_be32(12),
|
||||
.ordinal = TPM_ORD_STARTUP
|
||||
};
|
||||
|
||||
static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
|
||||
{
|
||||
struct tpm_cmd_t start_cmd;
|
||||
start_cmd.header.in = tpm_startup_header;
|
||||
start_cmd.params.startup_in.startup_type = startup_type;
|
||||
return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||
"attempting to start the TPM");
|
||||
}
|
||||
|
||||
int tpm_get_timeouts(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_cmd_t tpm_cmd;
|
||||
@@ -541,11 +543,28 @@ int tpm_get_timeouts(struct tpm_chip *chip)
|
||||
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
|
||||
|
||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||
"attempting to determine the timeouts");
|
||||
if (rc)
|
||||
if (rc == TPM_ERR_INVALID_POSTINIT) {
|
||||
/* The TPM is not started, we are the first to talk to it.
|
||||
Execute a startup command. */
|
||||
dev_info(chip->dev, "Issuing TPM_STARTUP");
|
||||
if (tpm_startup(chip, TPM_ST_CLEAR))
|
||||
return rc;
|
||||
|
||||
tpm_cmd.header.in = tpm_getcap_header;
|
||||
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
|
||||
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
|
||||
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
|
||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||
NULL);
|
||||
}
|
||||
if (rc) {
|
||||
dev_err(chip->dev,
|
||||
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
|
||||
rc);
|
||||
goto duration;
|
||||
}
|
||||
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
@@ -824,7 +843,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
unsigned int loops;
|
||||
unsigned int delay_msec = 1000;
|
||||
unsigned int delay_msec = 100;
|
||||
unsigned long duration;
|
||||
struct tpm_cmd_t cmd;
|
||||
|
||||
@@ -845,6 +864,14 @@ int tpm_do_selftest(struct tpm_chip *chip)
|
||||
cmd.header.in = pcrread_header;
|
||||
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0);
|
||||
rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE);
|
||||
/* Some buggy TPMs will not respond to tpm_tis_ready() for
|
||||
* around 300ms while the self test is ongoing, keep trying
|
||||
* until the self test duration expires. */
|
||||
if (rc == -ETIME) {
|
||||
dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test");
|
||||
msleep(delay_msec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc < TPM_HEADER_SIZE)
|
||||
return -EFAULT;
|
||||
@@ -1075,12 +1102,28 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_store_cancel);
|
||||
|
||||
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel,
|
||||
bool *canceled)
|
||||
{
|
||||
u8 status = chip->vendor.status(chip);
|
||||
|
||||
*canceled = false;
|
||||
if ((status & mask) == mask)
|
||||
return true;
|
||||
if (check_cancel && chip->vendor.req_canceled(chip, status)) {
|
||||
*canceled = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
wait_queue_head_t *queue)
|
||||
wait_queue_head_t *queue, bool check_cancel)
|
||||
{
|
||||
unsigned long stop;
|
||||
long rc;
|
||||
u8 status;
|
||||
bool canceled = false;
|
||||
|
||||
/* check current status */
|
||||
status = chip->vendor.status(chip);
|
||||
@@ -1095,11 +1138,14 @@ again:
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
rc = wait_event_interruptible_timeout(*queue,
|
||||
((chip->vendor.status(chip)
|
||||
& mask) == mask),
|
||||
timeout);
|
||||
if (rc > 0)
|
||||
wait_for_tpm_stat_cond(chip, mask, check_cancel,
|
||||
&canceled),
|
||||
timeout);
|
||||
if (rc > 0) {
|
||||
if (canceled)
|
||||
return -ECANCELED;
|
||||
return 0;
|
||||
}
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
|
||||
+32
-20
@@ -47,6 +47,7 @@ enum tpm_addr {
|
||||
#define TPM_WARN_DOING_SELFTEST 0x802
|
||||
#define TPM_ERR_DEACTIVATED 0x6
|
||||
#define TPM_ERR_DISABLED 0x7
|
||||
#define TPM_ERR_INVALID_POSTINIT 38
|
||||
|
||||
#define TPM_HEADER_SIZE 10
|
||||
extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
|
||||
@@ -77,7 +78,7 @@ struct tpm_chip;
|
||||
struct tpm_vendor_specific {
|
||||
const u8 req_complete_mask;
|
||||
const u8 req_complete_val;
|
||||
const u8 req_canceled;
|
||||
bool (*req_canceled)(struct tpm_chip *chip, u8 status);
|
||||
void __iomem *iobase; /* ioremapped address */
|
||||
unsigned long base; /* TPM base address */
|
||||
|
||||
@@ -100,13 +101,19 @@ struct tpm_vendor_specific {
|
||||
bool timeout_adjusted;
|
||||
unsigned long duration[3]; /* jiffies */
|
||||
bool duration_adjusted;
|
||||
void *data;
|
||||
void *priv;
|
||||
|
||||
wait_queue_head_t read_queue;
|
||||
wait_queue_head_t int_queue;
|
||||
|
||||
u16 manufacturer_id;
|
||||
};
|
||||
|
||||
#define TPM_VPRIV(c) (c)->vendor.priv
|
||||
|
||||
#define TPM_VID_INTEL 0x8086
|
||||
#define TPM_VID_WINBOND 0x1050
|
||||
#define TPM_VID_STM 0x104A
|
||||
|
||||
struct tpm_chip {
|
||||
struct device *dev; /* Device stuff */
|
||||
@@ -154,13 +161,13 @@ struct tpm_input_header {
|
||||
__be16 tag;
|
||||
__be32 length;
|
||||
__be32 ordinal;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_output_header {
|
||||
__be16 tag;
|
||||
__be32 length;
|
||||
__be32 return_code;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct stclear_flags_t {
|
||||
__be16 tag;
|
||||
@@ -169,14 +176,14 @@ struct stclear_flags_t {
|
||||
u8 physicalPresence;
|
||||
u8 physicalPresenceLock;
|
||||
u8 bGlobalLock;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_version_t {
|
||||
u8 Major;
|
||||
u8 Minor;
|
||||
u8 revMajor;
|
||||
u8 revMinor;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_version_1_2_t {
|
||||
__be16 tag;
|
||||
@@ -184,20 +191,20 @@ struct tpm_version_1_2_t {
|
||||
u8 Minor;
|
||||
u8 revMajor;
|
||||
u8 revMinor;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct timeout_t {
|
||||
__be32 a;
|
||||
__be32 b;
|
||||
__be32 c;
|
||||
__be32 d;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct duration_t {
|
||||
__be32 tpm_short;
|
||||
__be32 tpm_medium;
|
||||
__be32 tpm_long;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct permanent_flags_t {
|
||||
__be16 tag;
|
||||
@@ -221,7 +228,7 @@ struct permanent_flags_t {
|
||||
u8 tpmEstablished;
|
||||
u8 maintenanceDone;
|
||||
u8 disableFullDALogicInfo;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
typedef union {
|
||||
struct permanent_flags_t perm_flags;
|
||||
@@ -239,12 +246,12 @@ struct tpm_getcap_params_in {
|
||||
__be32 cap;
|
||||
__be32 subcap_size;
|
||||
__be32 subcap;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_getcap_params_out {
|
||||
__be32 cap_size;
|
||||
cap_t cap;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_readpubek_params_out {
|
||||
u8 algorithm[4];
|
||||
@@ -255,7 +262,7 @@ struct tpm_readpubek_params_out {
|
||||
__be32 keysize;
|
||||
u8 modulus[256];
|
||||
u8 checksum[20];
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
typedef union {
|
||||
struct tpm_input_header in;
|
||||
@@ -265,16 +272,16 @@ typedef union {
|
||||
#define TPM_DIGEST_SIZE 20
|
||||
struct tpm_pcrread_out {
|
||||
u8 pcr_result[TPM_DIGEST_SIZE];
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_pcrread_in {
|
||||
__be32 pcr_idx;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_pcrextend_in {
|
||||
__be32 pcr_idx;
|
||||
u8 hash[TPM_DIGEST_SIZE];
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
/* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18
|
||||
* bytes, but 128 is still a relatively large number of random bytes and
|
||||
@@ -285,11 +292,15 @@ struct tpm_pcrextend_in {
|
||||
struct tpm_getrandom_out {
|
||||
__be32 rng_data_len;
|
||||
u8 rng_data[TPM_MAX_RNG_DATA];
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_getrandom_in {
|
||||
__be32 num_bytes;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
struct tpm_startup_in {
|
||||
__be16 startup_type;
|
||||
} __packed;
|
||||
|
||||
typedef union {
|
||||
struct tpm_getcap_params_out getcap_out;
|
||||
@@ -301,12 +312,13 @@ typedef union {
|
||||
struct tpm_pcrextend_in pcrextend_in;
|
||||
struct tpm_getrandom_in getrandom_in;
|
||||
struct tpm_getrandom_out getrandom_out;
|
||||
struct tpm_startup_in startup_in;
|
||||
} tpm_cmd_params;
|
||||
|
||||
struct tpm_cmd_t {
|
||||
tpm_cmd_header header;
|
||||
tpm_cmd_params params;
|
||||
}__attribute__((packed));
|
||||
} __packed;
|
||||
|
||||
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
||||
|
||||
@@ -326,7 +338,7 @@ extern void tpm_remove_hardware(struct device *);
|
||||
extern int tpm_pm_suspend(struct device *);
|
||||
extern int tpm_pm_resume(struct device *);
|
||||
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
|
||||
wait_queue_head_t *);
|
||||
wait_queue_head_t *, bool);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
extern int tpm_add_ppi(struct kobject *);
|
||||
|
||||
@@ -33,13 +33,13 @@ struct acpi_tcpa {
|
||||
u16 platform_class;
|
||||
union {
|
||||
struct client_hdr {
|
||||
u32 log_max_len __attribute__ ((packed));
|
||||
u64 log_start_addr __attribute__ ((packed));
|
||||
u32 log_max_len __packed;
|
||||
u64 log_start_addr __packed;
|
||||
} client;
|
||||
struct server_hdr {
|
||||
u16 reserved;
|
||||
u64 log_max_len __attribute__ ((packed));
|
||||
u64 log_start_addr __attribute__ ((packed));
|
||||
u64 log_max_len __packed;
|
||||
u64 log_start_addr __packed;
|
||||
} server;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -116,6 +116,11 @@ static u8 tpm_atml_status(struct tpm_chip *chip)
|
||||
return ioread8(chip->vendor.iobase + 1);
|
||||
}
|
||||
|
||||
static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
return (status == ATML_STATUS_READY);
|
||||
}
|
||||
|
||||
static const struct file_operations atmel_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
@@ -147,7 +152,7 @@ static const struct tpm_vendor_specific tpm_atmel = {
|
||||
.status = tpm_atml_status,
|
||||
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
|
||||
.req_complete_val = ATML_STATUS_DATA_AVAIL,
|
||||
.req_canceled = ATML_STATUS_READY,
|
||||
.req_canceled = tpm_atml_req_canceled,
|
||||
.attr_group = &atmel_attr_grp,
|
||||
.miscdev = { .fops = &atmel_ops, },
|
||||
};
|
||||
|
||||
@@ -505,6 +505,11 @@ out_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
return (status == TPM_STS_COMMAND_READY);
|
||||
}
|
||||
|
||||
static const struct file_operations tis_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
@@ -550,7 +555,7 @@ static struct tpm_vendor_specific tpm_tis_i2c = {
|
||||
.cancel = tpm_tis_i2c_ready,
|
||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
.req_canceled = TPM_STS_COMMAND_READY,
|
||||
.req_canceled = tpm_tis_i2c_req_canceled,
|
||||
.attr_group = &tis_attr_grp,
|
||||
.miscdev.fops = &tis_ops,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
|
||||
* Copyright (C) 2009, 2010 STMicroelectronics
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* STMicroelectronics version 1.2.0, Copyright (C) 2010
|
||||
* STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
|
||||
* This is free software, and you are welcome to redistribute it
|
||||
* under certain conditions.
|
||||
*
|
||||
* @Author: Christophe RICARD tpmsupport@st.com
|
||||
*
|
||||
* @File: stm_st33_tpm_i2c.h
|
||||
*
|
||||
* @Date: 09/15/2010
|
||||
*/
|
||||
#ifndef __STM_ST33_TPM_I2C_MAIN_H__
|
||||
#define __STM_ST33_TPM_I2C_MAIN_H__
|
||||
|
||||
#define TPM_ACCESS (0x0)
|
||||
#define TPM_STS (0x18)
|
||||
#define TPM_HASH_END (0x20)
|
||||
#define TPM_DATA_FIFO (0x24)
|
||||
#define TPM_HASH_DATA (0x24)
|
||||
#define TPM_HASH_START (0x28)
|
||||
#define TPM_INTF_CAPABILITY (0x14)
|
||||
#define TPM_INT_STATUS (0x10)
|
||||
#define TPM_INT_ENABLE (0x08)
|
||||
|
||||
#define TPM_DUMMY_BYTE 0xAA
|
||||
#define TPM_WRITE_DIRECTION 0x80
|
||||
#define TPM_HEADER_SIZE 10
|
||||
#define TPM_BUFSIZE 2048
|
||||
|
||||
#define LOCALITY0 0
|
||||
|
||||
#define TPM_ST33_I2C "st33zp24_i2c"
|
||||
|
||||
struct st33zp24_platform_data {
|
||||
int io_serirq;
|
||||
int io_lpcpd;
|
||||
struct i2c_client *client;
|
||||
u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
|
||||
struct completion irq_detection;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
|
||||
@@ -64,7 +64,7 @@ static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
if (chip)
|
||||
return (struct ibmvtpm_dev *)chip->vendor.data;
|
||||
return (struct ibmvtpm_dev *)TPM_VPRIV(chip);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
u16 len;
|
||||
int sig;
|
||||
|
||||
ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
|
||||
ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
|
||||
|
||||
if (!ibmvtpm->rtce_buf) {
|
||||
dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
|
||||
@@ -127,7 +127,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
u64 *word = (u64 *) &crq;
|
||||
int rc;
|
||||
|
||||
ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data;
|
||||
ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
|
||||
|
||||
if (!ibmvtpm->rtce_buf) {
|
||||
dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n");
|
||||
@@ -398,6 +398,11 @@ static int tpm_ibmvtpm_resume(struct device *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
return (status == 0);
|
||||
}
|
||||
|
||||
static const struct file_operations ibmvtpm_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
@@ -441,7 +446,7 @@ static const struct tpm_vendor_specific tpm_ibmvtpm = {
|
||||
.status = tpm_ibmvtpm_status,
|
||||
.req_complete_mask = 0,
|
||||
.req_complete_val = 0,
|
||||
.req_canceled = 0,
|
||||
.req_canceled = tpm_ibmvtpm_req_canceled,
|
||||
.attr_group = &ibmvtpm_attr_grp,
|
||||
.miscdev = { .fops = &ibmvtpm_ops, },
|
||||
};
|
||||
@@ -647,7 +652,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
|
||||
|
||||
ibmvtpm->dev = dev;
|
||||
ibmvtpm->vdev = vio_dev;
|
||||
chip->vendor.data = (void *)ibmvtpm;
|
||||
TPM_VPRIV(chip) = (void *)ibmvtpm;
|
||||
|
||||
spin_lock_init(&ibmvtpm->rtce_lock);
|
||||
|
||||
|
||||
@@ -227,6 +227,11 @@ static u8 tpm_nsc_status(struct tpm_chip *chip)
|
||||
return inb(chip->vendor.base + NSC_STATUS);
|
||||
}
|
||||
|
||||
static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
return (status == NSC_STATUS_RDY);
|
||||
}
|
||||
|
||||
static const struct file_operations nsc_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
@@ -258,7 +263,7 @@ static const struct tpm_vendor_specific tpm_nsc = {
|
||||
.status = tpm_nsc_status,
|
||||
.req_complete_mask = NSC_STATUS_OBF,
|
||||
.req_complete_val = NSC_STATUS_OBF,
|
||||
.req_canceled = NSC_STATUS_RDY,
|
||||
.req_canceled = tpm_nsc_req_canceled,
|
||||
.attr_group = &nsc_attr_grp,
|
||||
.miscdev = { .fops = &nsc_ops, },
|
||||
};
|
||||
|
||||
+51
-13
@@ -84,6 +84,9 @@ static int is_itpm(struct pnp_dev *dev)
|
||||
struct acpi_device *acpi = pnp_acpi_device(dev);
|
||||
struct acpi_hardware_id *id;
|
||||
|
||||
if (!acpi)
|
||||
return 0;
|
||||
|
||||
list_for_each_entry(id, &acpi->pnp.ids, list) {
|
||||
if (!strcmp("INTC0102", id->id))
|
||||
return 1;
|
||||
@@ -98,6 +101,22 @@ static inline int is_itpm(struct pnp_dev *dev)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Before we attempt to access the TPM we must see that the valid bit is set.
|
||||
* The specification says that this bit is 0 at reset and remains 0 until the
|
||||
* 'TPM has gone through its self test and initialization and has established
|
||||
* correct values in the other bits.' */
|
||||
static int wait_startup(struct tpm_chip *chip, int l)
|
||||
{
|
||||
unsigned long stop = jiffies + chip->vendor.timeout_a;
|
||||
do {
|
||||
if (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
|
||||
TPM_ACCESS_VALID)
|
||||
return 0;
|
||||
msleep(TPM_TIMEOUT);
|
||||
} while (time_before(jiffies, stop));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int check_locality(struct tpm_chip *chip, int l)
|
||||
{
|
||||
if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) &
|
||||
@@ -198,7 +217,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
wait_for_tpm_stat(chip,
|
||||
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
chip->vendor.timeout_c,
|
||||
&chip->vendor.read_queue)
|
||||
&chip->vendor.read_queue, true)
|
||||
== 0) {
|
||||
burstcnt = get_burstcount(chip);
|
||||
for (; burstcnt > 0 && size < count; burstcnt--)
|
||||
@@ -241,7 +260,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
}
|
||||
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
&chip->vendor.int_queue, false);
|
||||
status = tpm_tis_status(chip);
|
||||
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
||||
dev_err(chip->dev, "Error left over data\n");
|
||||
@@ -277,7 +296,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
tpm_tis_ready(chip);
|
||||
if (wait_for_tpm_stat
|
||||
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
|
||||
&chip->vendor.int_queue) < 0) {
|
||||
&chip->vendor.int_queue, false) < 0) {
|
||||
rc = -ETIME;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -292,7 +311,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
}
|
||||
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
&chip->vendor.int_queue, false);
|
||||
status = tpm_tis_status(chip);
|
||||
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
|
||||
rc = -EIO;
|
||||
@@ -304,7 +323,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
iowrite8(buf[count],
|
||||
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
&chip->vendor.int_queue, false);
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & TPM_STS_DATA_EXPECT) != 0) {
|
||||
rc = -EIO;
|
||||
@@ -342,7 +361,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
if (wait_for_tpm_stat
|
||||
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
tpm_calc_ordinal_duration(chip, ordinal),
|
||||
&chip->vendor.read_queue) < 0) {
|
||||
&chip->vendor.read_queue, false) < 0) {
|
||||
rc = -ETIME;
|
||||
goto out_err;
|
||||
}
|
||||
@@ -374,7 +393,7 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
if (vendor != TPM_VID_INTEL)
|
||||
return 0;
|
||||
|
||||
itpm = 0;
|
||||
itpm = false;
|
||||
|
||||
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
||||
if (rc == 0)
|
||||
@@ -383,7 +402,7 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
tpm_tis_ready(chip);
|
||||
release_locality(chip, chip->vendor.locality, 0);
|
||||
|
||||
itpm = 1;
|
||||
itpm = true;
|
||||
|
||||
rc = tpm_tis_send_data(chip, cmd_getticks, len);
|
||||
if (rc == 0) {
|
||||
@@ -400,6 +419,19 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
switch (chip->vendor.manufacturer_id) {
|
||||
case TPM_VID_WINBOND:
|
||||
return ((status == TPM_STS_VALID) ||
|
||||
(status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
|
||||
case TPM_VID_STM:
|
||||
return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
|
||||
default:
|
||||
return (status == TPM_STS_COMMAND_READY);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct file_operations tis_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
@@ -445,7 +477,7 @@ static struct tpm_vendor_specific tpm_tis = {
|
||||
.cancel = tpm_tis_ready,
|
||||
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
.req_canceled = TPM_STS_COMMAND_READY,
|
||||
.req_canceled = tpm_tis_req_canceled,
|
||||
.attr_group = &tis_attr_grp,
|
||||
.miscdev = {
|
||||
.fops = &tis_ops,},
|
||||
@@ -502,7 +534,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static bool interrupts = 1;
|
||||
static bool interrupts = true;
|
||||
module_param(interrupts, bool, 0444);
|
||||
MODULE_PARM_DESC(interrupts, "Enable interrupts");
|
||||
|
||||
@@ -528,12 +560,18 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
||||
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
||||
|
||||
if (wait_startup(chip, 0) != 0) {
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (request_locality(chip, 0) != 0) {
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
|
||||
chip->vendor.manufacturer_id = vendor;
|
||||
|
||||
dev_info(dev,
|
||||
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
|
||||
@@ -545,7 +583,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
itpm = (probe == 0) ? 0 : 1;
|
||||
itpm = !!probe;
|
||||
}
|
||||
|
||||
if (itpm)
|
||||
@@ -741,10 +779,10 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
|
||||
if (pnp_irq_valid(pnp_dev, 0))
|
||||
irq = pnp_irq(pnp_dev, 0);
|
||||
else
|
||||
interrupts = 0;
|
||||
interrupts = false;
|
||||
|
||||
if (is_itpm(pnp_dev))
|
||||
itpm = 1;
|
||||
itpm = true;
|
||||
|
||||
return tpm_tis_init(&pnp_dev->dev, start, len, irq);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user