mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
Merge branch 'for-james' of git://github.com/srajiv/tpm into next
This commit is contained in:
commit
8077e8b059
@ -27,6 +27,7 @@ if TCG_TPM
|
||||
|
||||
config TCG_TIS
|
||||
tristate "TPM Interface Specification 1.2 Interface"
|
||||
depends on X86
|
||||
---help---
|
||||
If you have a TPM security chip that is compliant with the
|
||||
TCG TIS 1.2 TPM specification say Yes and it will be accessible
|
||||
@ -35,6 +36,7 @@ config TCG_TIS
|
||||
|
||||
config TCG_NSC
|
||||
tristate "National Semiconductor TPM Interface"
|
||||
depends on X86
|
||||
---help---
|
||||
If you have a TPM security chip from National Semiconductor
|
||||
say Yes and it will be accessible from within Linux. To
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/freezer.h>
|
||||
|
||||
#include "tpm.h"
|
||||
|
||||
@ -440,7 +441,6 @@ out:
|
||||
}
|
||||
|
||||
#define TPM_DIGEST_SIZE 20
|
||||
#define TPM_ERROR_SIZE 10
|
||||
#define TPM_RET_CODE_IDX 6
|
||||
|
||||
enum tpm_capabilities {
|
||||
@ -469,12 +469,14 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
|
||||
len = tpm_transmit(chip,(u8 *) cmd, len);
|
||||
if (len < 0)
|
||||
return len;
|
||||
if (len == TPM_ERROR_SIZE) {
|
||||
err = be32_to_cpu(cmd->header.out.return_code);
|
||||
dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
else if (len < TPM_HEADER_SIZE)
|
||||
return -EFAULT;
|
||||
|
||||
err = be32_to_cpu(cmd->header.out.return_code);
|
||||
if (err != 0)
|
||||
dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define TPM_INTERNAL_RESULT_SIZE 200
|
||||
@ -530,7 +532,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
|
||||
|
||||
void tpm_get_timeouts(struct tpm_chip *chip)
|
||||
int tpm_get_timeouts(struct tpm_chip *chip)
|
||||
{
|
||||
struct tpm_cmd_t tpm_cmd;
|
||||
struct timeout_t *timeout_cap;
|
||||
@ -552,7 +554,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
|
||||
/* Don't overwrite default if value is 0 */
|
||||
@ -583,12 +585,12 @@ duration:
|
||||
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
|
||||
"attempting to determine the durations");
|
||||
if (rc)
|
||||
return;
|
||||
return rc;
|
||||
|
||||
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
|
||||
be32_to_cpu(tpm_cmd.header.out.length)
|
||||
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
|
||||
return;
|
||||
return -EINVAL;
|
||||
|
||||
duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
|
||||
chip->vendor.duration[TPM_SHORT] =
|
||||
@ -610,20 +612,36 @@ duration:
|
||||
chip->vendor.duration_adjusted = true;
|
||||
dev_info(chip->dev, "Adjusting TPM timeout parameters.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_get_timeouts);
|
||||
|
||||
void tpm_continue_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
u8 data[] = {
|
||||
0, 193, /* TPM_TAG_RQU_COMMAND */
|
||||
0, 0, 0, 10, /* length */
|
||||
0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */
|
||||
};
|
||||
#define TPM_ORD_CONTINUE_SELFTEST 83
|
||||
#define CONTINUE_SELFTEST_RESULT_SIZE 10
|
||||
|
||||
tpm_transmit(chip, data, sizeof(data));
|
||||
static struct tpm_input_header continue_selftest_header = {
|
||||
.tag = TPM_TAG_RQU_COMMAND,
|
||||
.length = cpu_to_be32(10),
|
||||
.ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
|
||||
};
|
||||
|
||||
/**
|
||||
* tpm_continue_selftest -- run TPM's selftest
|
||||
* @chip: TPM chip to use
|
||||
*
|
||||
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
|
||||
* a TPM error code.
|
||||
*/
|
||||
static int tpm_continue_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
struct tpm_cmd_t cmd;
|
||||
|
||||
cmd.header.in = continue_selftest_header;
|
||||
rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
|
||||
"continue selftest");
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_continue_selftest);
|
||||
|
||||
ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
|
||||
char *buf)
|
||||
@ -718,7 +736,7 @@ static struct tpm_input_header pcrread_header = {
|
||||
.ordinal = TPM_ORDINAL_PCRREAD
|
||||
};
|
||||
|
||||
int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||
static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
|
||||
{
|
||||
int rc;
|
||||
struct tpm_cmd_t cmd;
|
||||
@ -798,6 +816,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_pcr_extend);
|
||||
|
||||
/**
|
||||
* tpm_do_selftest - have the TPM continue its selftest and wait until it
|
||||
* can receive further commands
|
||||
* @chip: TPM chip to use
|
||||
*
|
||||
* Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
|
||||
* a TPM error code.
|
||||
*/
|
||||
int tpm_do_selftest(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
u8 digest[TPM_DIGEST_SIZE];
|
||||
unsigned int loops;
|
||||
unsigned int delay_msec = 1000;
|
||||
unsigned long duration;
|
||||
|
||||
duration = tpm_calc_ordinal_duration(chip,
|
||||
TPM_ORD_CONTINUE_SELFTEST);
|
||||
|
||||
loops = jiffies_to_msecs(duration) / delay_msec;
|
||||
|
||||
rc = tpm_continue_selftest(chip);
|
||||
/* This may fail if there was no TPM driver during a suspend/resume
|
||||
* cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
|
||||
*/
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
do {
|
||||
rc = __tpm_pcr_read(chip, 0, digest);
|
||||
if (rc != TPM_WARN_DOING_SELFTEST)
|
||||
return rc;
|
||||
msleep(delay_msec);
|
||||
} while (--loops > 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_do_selftest);
|
||||
|
||||
int tpm_send(u32 chip_num, void *cmd, size_t buflen)
|
||||
{
|
||||
struct tpm_chip *chip;
|
||||
@ -1005,6 +1062,46 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpm_store_cancel);
|
||||
|
||||
int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
wait_queue_head_t *queue)
|
||||
{
|
||||
unsigned long stop;
|
||||
long rc;
|
||||
u8 status;
|
||||
|
||||
/* check current status */
|
||||
status = chip->vendor.status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
|
||||
stop = jiffies + timeout;
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
again:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
rc = wait_event_interruptible_timeout(*queue,
|
||||
((chip->vendor.status(chip)
|
||||
& mask) == mask),
|
||||
timeout);
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
msleep(TPM_TIMEOUT);
|
||||
status = chip->vendor.status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
} while (time_before(jiffies, stop));
|
||||
}
|
||||
return -ETIME;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
|
||||
/*
|
||||
* Device file system interface to the TPM
|
||||
*
|
||||
|
@ -38,6 +38,8 @@ enum tpm_addr {
|
||||
TPM_ADDR = 0x4E,
|
||||
};
|
||||
|
||||
#define TPM_WARN_DOING_SELFTEST 0x802
|
||||
#define TPM_HEADER_SIZE 10
|
||||
extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
|
||||
char *);
|
||||
extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
|
||||
@ -279,9 +281,9 @@ struct tpm_cmd_t {
|
||||
|
||||
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
|
||||
|
||||
extern void tpm_get_timeouts(struct tpm_chip *);
|
||||
extern int tpm_get_timeouts(struct tpm_chip *);
|
||||
extern void tpm_gen_interrupt(struct tpm_chip *);
|
||||
extern void tpm_continue_selftest(struct tpm_chip *);
|
||||
extern int tpm_do_selftest(struct tpm_chip *);
|
||||
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
|
||||
extern struct tpm_chip* tpm_register_hardware(struct device *,
|
||||
const struct tpm_vendor_specific *);
|
||||
@ -294,7 +296,8 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
|
||||
extern void tpm_remove_hardware(struct device *);
|
||||
extern int tpm_pm_suspend(struct device *, pm_message_t);
|
||||
extern int tpm_pm_resume(struct device *);
|
||||
|
||||
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
|
||||
wait_queue_head_t *);
|
||||
#ifdef CONFIG_ACPI
|
||||
extern struct dentry ** tpm_bios_log_setup(char *);
|
||||
extern void tpm_bios_log_teardown(struct dentry **);
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include <linux/freezer.h>
|
||||
#include "tpm.h"
|
||||
|
||||
#define TPM_HEADER_SIZE 10
|
||||
|
||||
enum tis_access {
|
||||
TPM_ACCESS_VALID = 0x80,
|
||||
TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
|
||||
@ -193,54 +191,14 @@ static int get_burstcount(struct tpm_chip *chip)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
wait_queue_head_t *queue)
|
||||
{
|
||||
unsigned long stop;
|
||||
long rc;
|
||||
u8 status;
|
||||
|
||||
/* check current status */
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
|
||||
stop = jiffies + timeout;
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
again:
|
||||
timeout = stop - jiffies;
|
||||
if ((long)timeout <= 0)
|
||||
return -ETIME;
|
||||
rc = wait_event_interruptible_timeout(*queue,
|
||||
((tpm_tis_status
|
||||
(chip) & mask) ==
|
||||
mask), timeout);
|
||||
if (rc > 0)
|
||||
return 0;
|
||||
if (rc == -ERESTARTSYS && freezing(current)) {
|
||||
clear_thread_flag(TIF_SIGPENDING);
|
||||
goto again;
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
msleep(TPM_TIMEOUT);
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & mask) == mask)
|
||||
return 0;
|
||||
} while (time_before(jiffies, stop));
|
||||
}
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
int size = 0, burstcnt;
|
||||
while (size < count &&
|
||||
wait_for_stat(chip,
|
||||
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
chip->vendor.timeout_c,
|
||||
&chip->vendor.read_queue)
|
||||
wait_for_tpm_stat(chip,
|
||||
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
chip->vendor.timeout_c,
|
||||
&chip->vendor.read_queue)
|
||||
== 0) {
|
||||
burstcnt = get_burstcount(chip);
|
||||
for (; burstcnt > 0 && size < count; burstcnt--)
|
||||
@ -282,8 +240,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
|
||||
dev_err(chip->dev, "Error left over data\n");
|
||||
@ -317,7 +275,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & TPM_STS_COMMAND_READY) == 0) {
|
||||
tpm_tis_ready(chip);
|
||||
if (wait_for_stat
|
||||
if (wait_for_tpm_stat
|
||||
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
|
||||
&chip->vendor.int_queue) < 0) {
|
||||
rc = -ETIME;
|
||||
@ -333,8 +291,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
count++;
|
||||
}
|
||||
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
|
||||
rc = -EIO;
|
||||
@ -345,8 +303,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
/* write last byte */
|
||||
iowrite8(buf[count],
|
||||
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
|
||||
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
|
||||
&chip->vendor.int_queue);
|
||||
status = tpm_tis_status(chip);
|
||||
if ((status & TPM_STS_DATA_EXPECT) != 0) {
|
||||
rc = -EIO;
|
||||
@ -381,7 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
|
||||
|
||||
if (chip->vendor.irq) {
|
||||
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
|
||||
if (wait_for_stat
|
||||
if (wait_for_tpm_stat
|
||||
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
|
||||
tpm_calc_ordinal_duration(chip, ordinal),
|
||||
&chip->vendor.read_queue) < 0) {
|
||||
@ -432,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip)
|
||||
out:
|
||||
itpm = rem_itpm;
|
||||
tpm_tis_ready(chip);
|
||||
/* some TPMs need a break here otherwise they will not work
|
||||
* correctly on the immediately subsequent command */
|
||||
msleep(chip->vendor.timeout_b);
|
||||
release_locality(chip, chip->vendor.locality, 0);
|
||||
|
||||
return rc;
|
||||
@ -614,7 +575,17 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||
dev_dbg(dev, "\tData Avail Int Support\n");
|
||||
|
||||
/* get the timeouts before testing for irqs */
|
||||
tpm_get_timeouts(chip);
|
||||
if (tpm_get_timeouts(chip)) {
|
||||
dev_err(dev, "Could not get TPM timeouts and durations\n");
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (tpm_do_selftest(chip)) {
|
||||
dev_err(dev, "TPM self test failed\n");
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* INTERRUPT Setup */
|
||||
init_waitqueue_head(&chip->vendor.read_queue);
|
||||
@ -722,7 +693,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
|
||||
list_add(&chip->vendor.list, &tis_chips);
|
||||
spin_unlock(&tis_lock);
|
||||
|
||||
tpm_continue_selftest(chip);
|
||||
|
||||
return 0;
|
||||
out_err:
|
||||
@ -790,7 +760,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
|
||||
|
||||
ret = tpm_pm_resume(&dev->dev);
|
||||
if (!ret)
|
||||
tpm_continue_selftest(chip);
|
||||
tpm_do_selftest(chip);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user