Commit 8077e8b0 authored by James Morris's avatar James Morris

Merge branch 'for-james' of git://github.com/srajiv/tpm into next

parents 7845bc39 b9e3238a
...@@ -27,6 +27,7 @@ if TCG_TPM ...@@ -27,6 +27,7 @@ if TCG_TPM
config TCG_TIS config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface" tristate "TPM Interface Specification 1.2 Interface"
depends on X86
---help--- ---help---
If you have a TPM security chip that is compliant with the 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 TCG TIS 1.2 TPM specification say Yes and it will be accessible
...@@ -35,6 +36,7 @@ config TCG_TIS ...@@ -35,6 +36,7 @@ config TCG_TIS
config TCG_NSC config TCG_NSC
tristate "National Semiconductor TPM Interface" tristate "National Semiconductor TPM Interface"
depends on X86
---help--- ---help---
If you have a TPM security chip from National Semiconductor If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To say Yes and it will be accessible from within Linux. To
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/freezer.h>
#include "tpm.h" #include "tpm.h"
...@@ -440,7 +441,6 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, ...@@ -440,7 +441,6 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
} }
#define TPM_DIGEST_SIZE 20 #define TPM_DIGEST_SIZE 20
#define TPM_ERROR_SIZE 10
#define TPM_RET_CODE_IDX 6 #define TPM_RET_CODE_IDX 6
enum tpm_capabilities { enum tpm_capabilities {
...@@ -469,12 +469,14 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, ...@@ -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); len = tpm_transmit(chip,(u8 *) cmd, len);
if (len < 0) if (len < 0)
return len; return len;
if (len == TPM_ERROR_SIZE) { else if (len < TPM_HEADER_SIZE)
err = be32_to_cpu(cmd->header.out.return_code); return -EFAULT;
dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
return err; err = be32_to_cpu(cmd->header.out.return_code);
} if (err != 0)
return 0; dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
return err;
} }
#define TPM_INTERNAL_RESULT_SIZE 200 #define TPM_INTERNAL_RESULT_SIZE 200
...@@ -530,7 +532,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip) ...@@ -530,7 +532,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
} }
EXPORT_SYMBOL_GPL(tpm_gen_interrupt); 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 tpm_cmd_t tpm_cmd;
struct timeout_t *timeout_cap; struct timeout_t *timeout_cap;
...@@ -552,7 +554,7 @@ void tpm_get_timeouts(struct tpm_chip *chip) ...@@ -552,7 +554,7 @@ void tpm_get_timeouts(struct tpm_chip *chip)
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
be32_to_cpu(tpm_cmd.header.out.length) be32_to_cpu(tpm_cmd.header.out.length)
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32))
return; return -EINVAL;
timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout;
/* Don't overwrite default if value is 0 */ /* Don't overwrite default if value is 0 */
...@@ -583,12 +585,12 @@ void tpm_get_timeouts(struct tpm_chip *chip) ...@@ -583,12 +585,12 @@ void tpm_get_timeouts(struct tpm_chip *chip)
rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
"attempting to determine the durations"); "attempting to determine the durations");
if (rc) if (rc)
return; return rc;
if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 ||
be32_to_cpu(tpm_cmd.header.out.length) be32_to_cpu(tpm_cmd.header.out.length)
!= sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32))
return; return -EINVAL;
duration_cap = &tpm_cmd.params.getcap_out.cap.duration; duration_cap = &tpm_cmd.params.getcap_out.cap.duration;
chip->vendor.duration[TPM_SHORT] = chip->vendor.duration[TPM_SHORT] =
...@@ -610,20 +612,36 @@ void tpm_get_timeouts(struct tpm_chip *chip) ...@@ -610,20 +612,36 @@ void tpm_get_timeouts(struct tpm_chip *chip)
chip->vendor.duration_adjusted = true; chip->vendor.duration_adjusted = true;
dev_info(chip->dev, "Adjusting TPM timeout parameters."); dev_info(chip->dev, "Adjusting TPM timeout parameters.");
} }
return 0;
} }
EXPORT_SYMBOL_GPL(tpm_get_timeouts); EXPORT_SYMBOL_GPL(tpm_get_timeouts);
void tpm_continue_selftest(struct tpm_chip *chip) #define TPM_ORD_CONTINUE_SELFTEST 83
#define CONTINUE_SELFTEST_RESULT_SIZE 10
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)
{ {
u8 data[] = { int rc;
0, 193, /* TPM_TAG_RQU_COMMAND */ struct tpm_cmd_t cmd;
0, 0, 0, 10, /* length */
0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */
};
tpm_transmit(chip, data, sizeof(data)); 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, ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
char *buf) char *buf)
...@@ -718,7 +736,7 @@ static struct tpm_input_header pcrread_header = { ...@@ -718,7 +736,7 @@ static struct tpm_input_header pcrread_header = {
.ordinal = TPM_ORDINAL_PCRREAD .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; int rc;
struct tpm_cmd_t cmd; struct tpm_cmd_t cmd;
...@@ -798,6 +816,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) ...@@ -798,6 +816,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
} }
EXPORT_SYMBOL_GPL(tpm_pcr_extend); 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) int tpm_send(u32 chip_num, void *cmd, size_t buflen)
{ {
struct tpm_chip *chip; struct tpm_chip *chip;
...@@ -1005,6 +1062,46 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, ...@@ -1005,6 +1062,46 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
} }
EXPORT_SYMBOL_GPL(tpm_store_cancel); 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 * Device file system interface to the TPM
* *
......
...@@ -38,6 +38,8 @@ enum tpm_addr { ...@@ -38,6 +38,8 @@ enum tpm_addr {
TPM_ADDR = 0x4E, 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, extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
char *); char *);
extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
...@@ -279,9 +281,9 @@ struct tpm_cmd_t { ...@@ -279,9 +281,9 @@ struct tpm_cmd_t {
ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); 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_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 unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
extern struct tpm_chip* tpm_register_hardware(struct device *, extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_vendor_specific *); const struct tpm_vendor_specific *);
...@@ -294,7 +296,8 @@ extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); ...@@ -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 void tpm_remove_hardware(struct device *);
extern int tpm_pm_suspend(struct device *, pm_message_t); extern int tpm_pm_suspend(struct device *, pm_message_t);
extern int tpm_pm_resume(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 *);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
extern struct dentry ** tpm_bios_log_setup(char *); extern struct dentry ** tpm_bios_log_setup(char *);
extern void tpm_bios_log_teardown(struct dentry **); extern void tpm_bios_log_teardown(struct dentry **);
......
...@@ -29,8 +29,6 @@ ...@@ -29,8 +29,6 @@
#include <linux/freezer.h> #include <linux/freezer.h>
#include "tpm.h" #include "tpm.h"
#define TPM_HEADER_SIZE 10
enum tis_access { enum tis_access {
TPM_ACCESS_VALID = 0x80, TPM_ACCESS_VALID = 0x80,
TPM_ACCESS_ACTIVE_LOCALITY = 0x20, TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
...@@ -193,54 +191,14 @@ static int get_burstcount(struct tpm_chip *chip) ...@@ -193,54 +191,14 @@ static int get_burstcount(struct tpm_chip *chip)
return -EBUSY; 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) static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
{ {
int size = 0, burstcnt; int size = 0, burstcnt;
while (size < count && while (size < count &&
wait_for_stat(chip, wait_for_tpm_stat(chip,
TPM_STS_DATA_AVAIL | TPM_STS_VALID, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
chip->vendor.timeout_c, chip->vendor.timeout_c,
&chip->vendor.read_queue) &chip->vendor.read_queue)
== 0) { == 0) {
burstcnt = get_burstcount(chip); burstcnt = get_burstcount(chip);
for (; burstcnt > 0 && size < count; burstcnt--) for (; burstcnt > 0 && size < count; burstcnt--)
...@@ -282,8 +240,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -282,8 +240,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto out; goto out;
} }
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue); &chip->vendor.int_queue);
status = tpm_tis_status(chip); status = tpm_tis_status(chip);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */ if (status & TPM_STS_DATA_AVAIL) { /* retry? */
dev_err(chip->dev, "Error left over data\n"); 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) ...@@ -317,7 +275,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
status = tpm_tis_status(chip); status = tpm_tis_status(chip);
if ((status & TPM_STS_COMMAND_READY) == 0) { if ((status & TPM_STS_COMMAND_READY) == 0) {
tpm_tis_ready(chip); tpm_tis_ready(chip);
if (wait_for_stat if (wait_for_tpm_stat
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
&chip->vendor.int_queue) < 0) { &chip->vendor.int_queue) < 0) {
rc = -ETIME; rc = -ETIME;
...@@ -333,8 +291,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -333,8 +291,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
count++; count++;
} }
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue); &chip->vendor.int_queue);
status = tpm_tis_status(chip); status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
rc = -EIO; rc = -EIO;
...@@ -345,8 +303,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -345,8 +303,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
/* write last byte */ /* write last byte */
iowrite8(buf[count], iowrite8(buf[count],
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality)); chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue); &chip->vendor.int_queue);
status = tpm_tis_status(chip); status = tpm_tis_status(chip);
if ((status & TPM_STS_DATA_EXPECT) != 0) { if ((status & TPM_STS_DATA_EXPECT) != 0) {
rc = -EIO; rc = -EIO;
...@@ -381,7 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) ...@@ -381,7 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (chip->vendor.irq) { if (chip->vendor.irq) {
ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
if (wait_for_stat if (wait_for_tpm_stat
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
tpm_calc_ordinal_duration(chip, ordinal), tpm_calc_ordinal_duration(chip, ordinal),
&chip->vendor.read_queue) < 0) { &chip->vendor.read_queue) < 0) {
...@@ -432,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -432,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip)
out: out:
itpm = rem_itpm; itpm = rem_itpm;
tpm_tis_ready(chip); 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); release_locality(chip, chip->vendor.locality, 0);
return rc; return rc;
...@@ -614,7 +575,17 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, ...@@ -614,7 +575,17 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
dev_dbg(dev, "\tData Avail Int Support\n"); dev_dbg(dev, "\tData Avail Int Support\n");
/* get the timeouts before testing for irqs */ /* 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 */ /* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.read_queue);
...@@ -722,7 +693,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, ...@@ -722,7 +693,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
list_add(&chip->vendor.list, &tis_chips); list_add(&chip->vendor.list, &tis_chips);
spin_unlock(&tis_lock); spin_unlock(&tis_lock);
tpm_continue_selftest(chip);
return 0; return 0;
out_err: out_err:
...@@ -790,7 +760,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) ...@@ -790,7 +760,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
ret = tpm_pm_resume(&dev->dev); ret = tpm_pm_resume(&dev->dev);
if (!ret) if (!ret)
tpm_continue_selftest(chip); tpm_do_selftest(chip);
return ret; return ret;
} }
......
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