aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-10-05 13:52:18 +0100
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-10-05 13:52:18 +0100
commit862b6e64648870e3427402ef63ffc16e66b2da21 (patch)
tree7db6263d9a417d8e1809efa31993673ad93efd04
parentee256fbc4042aba2db3a39ebcf434e6abce71a88 (diff)
downloadxen-862b6e64648870e3427402ef63ffc16e66b2da21.tar.gz
xen-862b6e64648870e3427402ef63ffc16e66b2da21.tar.bz2
xen-862b6e64648870e3427402ef63ffc16e66b2da21.zip
The attached patch places an updated TPM driver into the sparse directory.
This driver allows to build a Xen0 kernel with TPM front- and backend support and use it as a user domain kernel - something that is not possible to do with the current TPM driver in the 2.6.12 kernel. Once this driver appears in similar form in the kernel, I will remove it from the sparse directory. Signed-off-by: Stefan Berger <stefanb@us.ibm.com> Signed-off-by: Kylene Hall <kjhall@us.ibm.com> Signed-off-by: Leendert van Doorn <leendert@watson.ibm.com>
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/Kconfig58
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/Makefile5
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/tpm.c (renamed from linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c)318
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/tpm.h (renamed from linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h)90
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c263
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c386
-rw-r--r--linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c21
-rw-r--r--patches/linux-2.6.12/tpm_partial_read.patch74
8 files changed, 880 insertions, 335 deletions
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
new file mode 100644
index 0000000000..03826ecf16
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
@@ -0,0 +1,58 @@
+#
+# TPM device configuration
+#
+
+menu "TPM devices"
+
+config TCG_TPM
+ tristate "TPM Hardware Support"
+ depends on EXPERIMENTAL && PCI
+ ---help---
+ If you have a TPM security chip in your system, which
+ implements the Trusted Computing Group's specification,
+ say Yes and it will be accessible from within Linux. For
+ more information see <http://www.trustedcomputinggroup.org>.
+ An implementation of the Trusted Software Stack (TSS), the
+ userspace enablement piece of the specification, can be
+ obtained at: <http://sourceforge.net/projects/trousers>. To
+ compile this driver as a module, choose M here; the module
+ will be called tpm. If unsure, say N.
+
+config TCG_TIS
+ tristate "TPM Interface Specification 1.2 Interface"
+ depends on TCG_TPM
+ ---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
+ from within Linux. To compile this driver as a module, choose
+ M here; the module will be called tpm_tis.
+
+config TCG_NSC
+ tristate "National Semiconductor TPM Interface"
+ depends on TCG_TPM
+ ---help---
+ If you have a TPM security chip from National Semicondutor
+ 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_nsc.
+
+config TCG_ATMEL
+ tristate "Atmel TPM Interface"
+ depends on TCG_TPM
+ ---help---
+ If you have a TPM security chip from Atmel 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_atmel.
+
+config TCG_XEN
+ tristate "XEN TPM Interface"
+ depends on TCG_TPM && ARCH_XEN && XEN_TPMDEV_FRONTEND
+ ---help---
+ If you want to make TPM support available to a Xen
+ user domain, 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_xen.
+
+endmenu
+
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile
index dc60d2be87..c28feccc91 100644
--- a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile
@@ -5,8 +5,9 @@ ifeq ($(CONFIG_XEN_PHYSDEV_ACCESS),y)
obj-$(CONFIG_TCG_TPM) += tpm.o
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
-obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
+obj-$(CONFIG_TCG_TIS) += tpm_tis.o
+obj-$(CONFIG_TCG_XEN) += tpm_xen.o
else
-obj-$(CONFIG_TCG_TPM) += tpm_nopci.o
+obj-$(CONFIG_TCG_TPM) += tpm.o
obj-$(CONFIG_TCG_XEN) += tpm_xen.o
endif
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.c
index 872cf33e43..559d663fe4 100644
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.c
@@ -10,53 +10,38 @@
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
+ * Specifications at www.trustedcomputinggroup.org
*
* 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, version 2 of the
* License.
- *
+ *
* Note, the TPM chip is not interrupt driven (only polling)
* and can have very long timeouts (minutes!). Hence the unusual
- * calls to schedule_timeout.
+ * calls to msleep.
*
*/
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
-#include "tpm_nopci.h"
+#include "tpm.h"
+
+#define TPM_CHIP_NUM_MASK 0x0000ffff
+#define TPM_CHIP_TYPE_SHIFT 16
-enum {
+enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
TPM_MIN_BUFSIZE = 2048,
- TPM_MAX_BUFSIZE = 65536,
+ TPM_MAX_BUFSIZE = 64 * 1024,
TPM_NUM_DEVICES = 256,
TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
};
- /* PCI configuration addresses */
-enum {
- PCI_GEN_PMCON_1 = 0xA0,
- PCI_GEN1_DEC = 0xE4,
- PCI_LPC_EN = 0xE6,
- PCI_GEN2_DEC = 0xEC
-};
-
-enum {
- TPM_LOCK_REG = 0x0D,
- TPM_INTERUPT_REG = 0x0A,
- TPM_BASE_ADDR_LO = 0x08,
- TPM_BASE_ADDR_HI = 0x09,
- TPM_UNLOCK_VALUE = 0x55,
- TPM_LOCK_VALUE = 0xAA,
- TPM_DISABLE_INTERUPT_VALUE = 0x00
-};
-
static LIST_HEAD(tpm_chip_list);
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
-static int dev_mask[32];
+static DEFINE_SPINLOCK(driver_lock);
+static int dev_mask[TPM_NUM_MASK_ENTRIES];
static void user_reader_timeout(unsigned long ptr)
{
@@ -68,63 +53,37 @@ static void user_reader_timeout(unsigned long ptr)
up(&chip->buffer_mutex);
}
-void tpm_time_expired(unsigned long ptr)
-{
- int *exp = (int *) ptr;
- *exp = 1;
-}
-
-EXPORT_SYMBOL_GPL(tpm_time_expired);
-
-
-/*
- * This function should be used by other kernel subsystems attempting to use the tpm through the tpm_transmit interface.
- * A call to this function will return the chip structure corresponding to the TPM you are looking for that can then be sent with your command to tpm_transmit.
- * Passing 0 as the argument corresponds to /dev/tpm0 and thus the first and probably primary TPM on the system. Passing 1 corresponds to /dev/tpm1 and the next TPM discovered. If a TPM with the given chip_num does not exist NULL will be returned.
- */
-struct tpm_chip* tpm_chip_lookup(int chip_num)
-{
-
- struct tpm_chip *pos;
- list_for_each_entry(pos, &tpm_chip_list, list)
- if (pos->dev_num == chip_num ||
- chip_num == TPM_ANY_NUM)
- return pos;
-
- return NULL;
-
-}
-
/*
* Internal kernel interface to transmit TPM commands
*/
-ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
- size_t bufsiz)
+static ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
+ size_t bufsiz)
{
ssize_t rc;
u32 count;
unsigned long stop;
+ if (!chip)
+ return -ENODEV;
+
+ if ( !chip )
+ return -ENODEV;
+
count = be32_to_cpu(*((__be32 *) (buf + 2)));
if (count == 0)
return -ENODATA;
if (count > bufsiz) {
dev_err(chip->dev,
- "invalid count value %x %x \n", count, bufsiz);
+ "invalid count value %x %zx \n", count, bufsiz);
return -E2BIG;
}
- dev_dbg(chip->dev, "TPM Ordinal: %d\n",
- be32_to_cpu(*((__be32 *) (buf + 6))));
- dev_dbg(chip->dev, "Chip Status: %x\n",
- inb(chip->vendor->base + 1));
-
down(&chip->tpm_mutex);
if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
dev_err(chip->dev,
- "tpm_transmit: tpm_send: error %d\n", rc);
+ "tpm_transmit: tpm_send: error %zd\n", rc);
goto out;
}
@@ -144,8 +103,7 @@ ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf,
msleep(TPM_TIMEOUT); /* CHECK */
rmb();
- }
- while (time_before(jiffies, stop));
+ } while (time_before(jiffies, stop));
chip->vendor->cancel(chip);
@@ -157,16 +115,12 @@ out_recv:
rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
if (rc < 0)
dev_err(chip->dev,
- "tpm_transmit: tpm_recv: error %d\n", rc);
- atomic_set(&chip->data_position, 0);
-
+ "tpm_transmit: tpm_recv: error %zd\n", rc);
out:
up(&chip->tpm_mutex);
return rc;
}
-EXPORT_SYMBOL_GPL(tpm_transmit);
-
#define TPM_DIGEST_SIZE 20
#define CAP_PCR_RESULT_SIZE 18
static const u8 cap_pcr[] = {
@@ -186,7 +140,13 @@ static const u8 pcrread[] = {
0, 0, 0, 0 /* PCR index */
};
-ssize_t tpm_show_pcrs(struct device *dev, char *buf)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
+ char *buf)
+#else
+ssize_t tpm_show_pcrs(struct device *dev,
+ char *buf)
+#endif
{
u8 data[READ_PCR_RESULT_SIZE];
ssize_t len;
@@ -200,8 +160,12 @@ ssize_t tpm_show_pcrs(struct device *dev, char *buf)
memcpy(data, cap_pcr, sizeof(cap_pcr));
if ((len = tpm_transmit(chip, data, sizeof(data)))
- < CAP_PCR_RESULT_SIZE)
- return len;
+ < CAP_PCR_RESULT_SIZE) {
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to determine the number of PCRS\n",
+ be32_to_cpu(*((__be32 *) (data + 6))));
+ return 0;
+ }
num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
@@ -210,88 +174,22 @@ ssize_t tpm_show_pcrs(struct device *dev, char *buf)
index = cpu_to_be32(i);
memcpy(data + 10, &index, 4);
if ((len = tpm_transmit(chip, data, sizeof(data)))
- < READ_PCR_RESULT_SIZE)
- return len;
+ < READ_PCR_RESULT_SIZE){
+ dev_dbg(chip->dev, "A TPM error (%d) occurred"
+ " attempting to read PCR %d of %d\n",
+ be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs);
+ goto out;
+ }
str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", *(data + 10 + j));
str += sprintf(str, "\n");
}
+out:
return str - buf;
}
-
EXPORT_SYMBOL_GPL(tpm_show_pcrs);
-/*
- * Return 0 on success. On error pass along error code.
- * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
- * Lower 2 bytes equal tpm idx # or AN&
- * res_buf must fit a TPM_PCR (20 bytes) or NULL if you don't care
- */
-int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size )
-{
- u8 data[READ_PCR_RESULT_SIZE];
- int rc;
- __be32 index;
- int chip_num = chip_id & TPM_CHIP_NUM_MASK;
- struct tpm_chip* chip;
-
- if ( res_buf && res_buf_size < TPM_DIGEST_SIZE )
- return -ENOSPC;
- if ( (chip = tpm_chip_lookup( chip_num /*,
- chip_id >> TPM_CHIP_TYPE_SHIFT*/ ) ) == NULL ) {
- printk("chip %d not found.\n",chip_num);
- return -ENODEV;
- }
- memcpy(data, pcrread, sizeof(pcrread));
- index = cpu_to_be32(pcr_idx);
- memcpy(data + 10, &index, 4);
- if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
- rc = be32_to_cpu(*((u32*)(data+6)));
-
- if ( rc == 0 && res_buf )
- memcpy(res_buf, data+10, TPM_DIGEST_SIZE);
- return rc;
-}
-EXPORT_SYMBOL_GPL(tpm_pcr_read);
-
-#define EXTEND_PCR_SIZE 34
-static const u8 pcrextend[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 34, /* length */
- 0, 0, 0, 20, /* TPM_ORD_Extend */
- 0, 0, 0, 0 /* PCR index */
-};
-
-/*
- * Return 0 on success. On error pass along error code.
- * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY
- * Lower 2 bytes equal tpm idx # or ANY
- */
-int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash)
-{
- u8 data[EXTEND_PCR_SIZE];
- int rc;
- __be32 index;
- int chip_num = chip_id & TPM_CHIP_NUM_MASK;
- struct tpm_chip* chip;
-
- if ( (chip = tpm_chip_lookup( chip_num /*,
- chip_id >> TPM_CHIP_TYPE_SHIFT */)) == NULL )
- return -ENODEV;
-
- memcpy(data, pcrextend, sizeof(pcrextend));
- index = cpu_to_be32(pcr_idx);
- memcpy(data + 10, &index, 4);
- memcpy( data + 14, hash, TPM_DIGEST_SIZE );
- if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 )
- rc = be32_to_cpu(*((u32*)(data+6)));
- return rc;
-}
-EXPORT_SYMBOL_GPL(tpm_pcr_extend);
-
-
-
#define READ_PUBEK_RESULT_SIZE 314
static const u8 readpubek[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
@@ -299,7 +197,13 @@ static const u8 readpubek[] = {
0, 0, 0, 124, /* TPM_ORD_ReadPubek */
};
-ssize_t tpm_show_pubek(struct device *dev, char *buf)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+ char *buf)
+#else
+ssize_t tpm_show_pubek(struct device *dev,
+ char *buf)
+#endif
{
u8 *data;
ssize_t len;
@@ -319,16 +223,19 @@ ssize_t tpm_show_pubek(struct device *dev, char *buf)
if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
READ_PUBEK_RESULT_SIZE) {
- rc = len;
+ dev_dbg(chip->dev, "A TPM error (%d) occurred "
+ "attempting to read the PUBEK\n",
+ be32_to_cpu(*((__be32 *) (data + 6))));
+ rc = 0;
goto out;
}
- /*
+ /*
ignore header 10 bytes
algorithm 32 bits (1 == RSA )
encscheme 16 bits
sigscheme 16 bits
- parameters (RSA 12->bytes: keybit, #primes, expbit)
+ parameters (RSA 12->bytes: keybit, #primes, expbit)
keylenbytes 32 bits
256 byte modulus
ignore checksum 20 bytes
@@ -344,10 +251,10 @@ ssize_t tpm_show_pubek(struct device *dev, char *buf)
data[15], data[16], data[17], data[22], data[23],
data[24], data[25], data[26], data[27], data[28],
data[29], data[30], data[31], data[32], data[33],
- be32_to_cpu(*((__be32 *) (data + 32))));
+ be32_to_cpu(*((__be32 *) (data + 34))));
for (i = 0; i < 256; i++) {
- str += sprintf(str, "%02X ", data[i + 39]);
+ str += sprintf(str, "%02X ", data[i + 38]);
if ((i + 1) % 16 == 0)
str += sprintf(str, "\n");
}
@@ -378,7 +285,13 @@ static const u8 cap_manufacturer[] = {
0, 0, 1, 3
};
-ssize_t tpm_show_caps(struct device *dev, char *buf)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
+ char *buf)
+#else
+ssize_t tpm_show_caps(struct device *dev,
+ char *buf)
+#endif
{
u8 data[sizeof(cap_manufacturer)];
ssize_t len;
@@ -395,7 +308,7 @@ ssize_t tpm_show_caps(struct device *dev, char *buf)
return len;
str += sprintf(str, "Manufacturer: 0x%x\n",
- be32_to_cpu(*((__be32 *)(data + 14))));
+ be32_to_cpu(*((__be32 *) (data + 14))));
memcpy(data, cap_version, sizeof(cap_version));
@@ -410,11 +323,15 @@ ssize_t tpm_show_caps(struct device *dev, char *buf)
return str - buf;
}
-
EXPORT_SYMBOL_GPL(tpm_show_caps);
-ssize_t tpm_store_cancel(struct device * dev, const char *buf,
- size_t count)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+#else
+ssize_t tpm_store_cancel(struct device *dev,
+ const char *buf, size_t count)
+#endif
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if (chip == NULL)
@@ -423,9 +340,9 @@ ssize_t tpm_store_cancel(struct device * dev, const char *buf,
chip->vendor->cancel(chip);
return count;
}
-
EXPORT_SYMBOL_GPL(tpm_store_cancel);
+
/*
* Device file system interface to the TPM
*/
@@ -449,7 +366,8 @@ int tpm_open(struct inode *inode, struct file *file)
}
if (chip->num_opens) {
- dev_dbg(chip->dev, "Another process owns this TPM\n");
+ dev_dbg(chip->dev,
+ "Another process owns this TPM\n");
rc = -EBUSY;
goto err_out;
}
@@ -459,8 +377,7 @@ int tpm_open(struct inode *inode, struct file *file)
spin_unlock(&driver_lock);
- chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8),
- GFP_KERNEL);
+ chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8), GFP_KERNEL);
if (chip->data_buffer == NULL) {
chip->num_opens--;
put_device(chip->dev);
@@ -519,11 +436,11 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
}
/* atomic tpm command send and result receive */
- out_size = tpm_transmit(chip,
- chip->data_buffer,
+ out_size = tpm_transmit(chip, chip->data_buffer,
chip->vendor->buffersize);
atomic_set(&chip->data_pending, out_size);
+ atomic_set(&chip->data_position, 0);
up(&chip->buffer_mutex);
/* Set a timeout by which the reader must come claim the result */
@@ -539,31 +456,33 @@ ssize_t tpm_read(struct file * file, char __user * buf,
{
struct tpm_chip *chip = file->private_data;
int ret_size;
+ int pos, pending = 0;
- del_singleshot_timer_sync(&chip->user_read_timer);
ret_size = atomic_read(&chip->data_pending);
-
if (ret_size > 0) { /* relay data */
- int position = atomic_read(&chip->data_position);
-
if (size < ret_size)
ret_size = size;
- down(&chip->buffer_mutex);
+ pos = atomic_read(&chip->data_position);
- if (copy_to_user((void __user *) buf,
- &chip->data_buffer[position],
- ret_size)) {
+ down(&chip->buffer_mutex);
+ if (copy_to_user
+ ((void __user *) buf, &chip->data_buffer[pos], ret_size)) {
ret_size = -EFAULT;
} else {
- int pending = atomic_read(&chip->data_pending) - ret_size;
- atomic_set(&chip->data_pending,
- pending);
- atomic_set(&chip->data_position,
- position + ret_size);
+ pending = atomic_read(&chip->data_pending) - ret_size;
+ if ( pending ) {
+ atomic_set( &chip->data_pending, pending );
+ atomic_set( &chip->data_position, pos+ret_size );
+ }
}
up(&chip->buffer_mutex);
}
+
+ if ( ret_size <= 0 || pending == 0 ) {
+ atomic_set( &chip->data_pending, 0 );
+ del_singleshot_timer_sync(&chip->user_read_timer);
+ }
return ret_size;
}
@@ -573,7 +492,6 @@ EXPORT_SYMBOL_GPL(tpm_read);
void tpm_remove_hardware(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
- int i;
if (chip == NULL) {
dev_err(dev, "No device data found\n");
@@ -588,12 +506,11 @@ void tpm_remove_hardware(struct device *dev)
dev_set_drvdata(dev, NULL);
misc_deregister(&chip->vendor->miscdev);
+ kfree(chip->vendor->miscdev.name);
- for (i = 0; i < TPM_NUM_ATTR; i++)
- device_remove_file(dev, &chip->vendor->attr[i]);
+ sysfs_remove_group(&dev->kobj, chip->vendor->attr_group);
- dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &=
- !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
+ dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
kfree(chip);
@@ -602,7 +519,7 @@ void tpm_remove_hardware(struct device *dev)
EXPORT_SYMBOL_GPL(tpm_remove_hardware);
-static const u8 savestate[] = {
+static u8 savestate[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 10, /* blob length (in bytes) */
0, 0, 0, 152 /* TPM_ORD_SaveState */
@@ -612,7 +529,7 @@ static const u8 savestate[] = {
* We are about to suspend. Save the TPM state
* so that it can be restored.
*/
-int tpm_pm_suspend(struct pci_dev *pci_dev, u32 pm_state)
+int tpm_pm_suspend(struct pci_dev *pci_dev, pm_message_t pm_state)
{
struct tpm_chip *chip = pci_get_drvdata(pci_dev);
if (chip == NULL)
@@ -641,16 +558,18 @@ int tpm_pm_resume(struct pci_dev *pci_dev)
EXPORT_SYMBOL_GPL(tpm_pm_resume);
/*
- * Called from tpm_<specific>.c probe function only for devices
+ * Called from tpm_<specific>.c probe function only for devices
* the driver has determined it should claim. Prior to calling
* this function the specific probe function has called pci_enable_device
* upon errant exit from this function specific probe function should call
* pci_disable_device
*/
-int tpm_register_hardware_nopci(struct device *dev,
- struct tpm_vendor_specific *entry)
+int tpm_register_hardware(struct device *dev,
+ struct tpm_vendor_specific *entry)
{
- char devname[7];
+#define DEVNAME_SIZE 7
+
+ char *devname;
struct tpm_chip *chip;
int i, j;
@@ -670,7 +589,7 @@ int tpm_register_hardware_nopci(struct device *dev,
chip->user_read_timer.data = (unsigned long) chip;
chip->vendor = entry;
-
+
if (entry->buffersize < TPM_MIN_BUFSIZE) {
entry->buffersize = TPM_MIN_BUFSIZE;
} else if (entry->buffersize > TPM_MAX_BUFSIZE) {
@@ -690,7 +609,8 @@ int tpm_register_hardware_nopci(struct device *dev,
dev_num_search_complete:
if (chip->dev_num < 0) {
- dev_err(dev, "No available tpm device numbers\n");
+ dev_err(dev,
+ "No available tpm device numbers\n");
kfree(chip);
return -ENODEV;
} else if (chip->dev_num == 0)
@@ -698,13 +618,13 @@ dev_num_search_complete:
else
chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
- snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
+ devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+ scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
chip->vendor->miscdev.name = devname;
chip->vendor->miscdev.dev = dev;
chip->dev = get_device(dev);
-
if (misc_register(&chip->vendor->miscdev)) {
dev_err(chip->dev,
"unable to misc_register %s, minor %d\n",
@@ -724,26 +644,12 @@ dev_num_search_complete:
spin_unlock(&driver_lock);
- for (i = 0; i < TPM_NUM_ATTR; i++)
- device_create_file(dev, &chip->vendor->attr[i]);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_register_hardware_nopci);
+ sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
-static int __init init_tpm(void)
-{
return 0;
}
-static void __exit cleanup_tpm(void)
-{
-
-}
-
-module_init(init_tpm);
-module_exit(cleanup_tpm);
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.h
index e1988549c6..56f7ec5561 100644
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.h
@@ -10,50 +10,50 @@
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
+ * Specifications at www.trustedcomputinggroup.org
*
* 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, version 2 of the
* License.
- *
+ *
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/fs.h>
#include <linux/miscdevice.h>
-enum {
+enum tpm_timeout {
TPM_TIMEOUT = 5, /* msecs */
- TPM_NUM_ATTR = 4
};
/* TPM addresses */
-enum {
+enum tpm_addr {
+ TPM_SUPERIO_ADDR = 0x2E,
TPM_ADDR = 0x4E,
- TPM_DATA = 0x4F
-};
-
-/*
- * Chip num is this value or a valid tpm idx in lower two bytes of chip_id
- */
-enum tpm_chip_num {
- TPM_ANY_NUM = 0xFFFF,
};
-#define TPM_CHIP_NUM_MASK 0x0000ffff
-
-extern ssize_t tpm_show_pubek(struct device *, char *);
-extern ssize_t tpm_show_pcrs(struct device *, char *);
-extern ssize_t tpm_show_caps(struct device *, char *);
-extern ssize_t tpm_store_cancel(struct device *, const char *, size_t);
-
-#define TPM_DEVICE_ATTRS { \
- __ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL), \
- __ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL), \
- __ATTR(caps, S_IRUGO, tpm_show_caps, NULL), \
- __ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel) }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
+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,
+ char *);
+extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
+ const char *, size_t);
+#else
+extern ssize_t tpm_show_pubek(struct device *,
+ char *);
+extern ssize_t tpm_show_pcrs(struct device *,
+ char *);
+extern ssize_t tpm_show_caps(struct device *,
+ char *);
+extern ssize_t tpm_store_cancel(struct device *,
+ const char *, size_t);
+#endif
struct tpm_chip;
@@ -62,18 +62,19 @@ struct tpm_vendor_specific {
u8 req_complete_val;
u8 req_canceled;
u16 base; /* TPM base address */
- u32 buffersize; /* The device's requested buffersize */
+ int drv_type;
+ u32 buffersize;
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
- u8(*status) (struct tpm_chip *);
+ u8 (*status) (struct tpm_chip *);
struct miscdevice miscdev;
- struct device_attribute attr[TPM_NUM_ATTR];
+ struct attribute_group *attr_group;
};
struct tpm_chip {
- struct device *dev; /* PCI device stuff */
+ struct device *dev; /* Device stuff */
int dev_num; /* /dev/tpm# */
int num_opens; /* only one allowed */
@@ -93,36 +94,25 @@ struct tpm_chip {
struct list_head list;
};
-static inline int tpm_read_index(int index)
+static inline int tpm_read_index(int base, int index)
{
- outb(index, TPM_ADDR);
- return inb(TPM_DATA) & 0xFF;
+ outb(index, base);
+ return inb(base+1) & 0xFF;
}
-static inline void tpm_write_index(int index, int value)
+static inline void tpm_write_index(int base, int index, int value)
{
- outb(index, TPM_ADDR);
- outb(value & 0xFF, TPM_DATA);
+ outb(index, base);
+ outb(value & 0xFF, base+1);
}
-extern void tpm_time_expired(unsigned long);
-extern int tpm_lpc_bus_init(struct pci_dev *, u16);
-
-extern int tpm_register_hardware_nopci(struct device *,
- struct tpm_vendor_specific *);
-extern void tpm_remove_hardware(struct device *);
+extern int tpm_register_hardware(struct device *,
+ struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
extern int tpm_release(struct inode *, struct file *);
extern ssize_t tpm_write(struct file *, const char __user *, size_t,
loff_t *);
extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
-extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash);
-extern int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size );
-
-extern int tpm_pm_suspend(struct pci_dev *, u32);
+extern void tpm_remove_hardware(struct device *);
+extern int tpm_pm_suspend(struct pci_dev *, pm_message_t);
extern int tpm_pm_resume(struct pci_dev *);
-
-/* internal kernel interface */
-extern ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
- size_t bufsiz);
-extern struct tpm_chip *tpm_chip_lookup(int chip_num);
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c
new file mode 100644
index 0000000000..00a3a57a23
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ */
+
+#include "tpm.h"
+
+/* Atmel definitions */
+enum tpm_atmel_addr {
+ TPM_ATMEL_BASE_ADDR_LO = 0x08,
+ TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
+
+/* write status bits */
+enum tpm_atmel_write_status {
+ ATML_STATUS_ABORT = 0x01,
+ ATML_STATUS_LASTBYTE = 0x04
+};
+/* read status bits */
+enum tpm_atmel_read_status {
+ ATML_STATUS_BUSY = 0x01,
+ ATML_STATUS_DATA_AVAIL = 0x02,
+ ATML_STATUS_REWRITE = 0x04,
+ ATML_STATUS_READY = 0x08
+};
+
+static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+ u8 status, *hdr = buf;
+ u32 size;
+ int i;
+ __be32 *native_size;
+
+ /* start reading header */
+ if (count < 6)
+ return -EIO;
+
+ for (i = 0; i < 6; i++) {
+ status = inb(chip->vendor->base + 1);
+ if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+ dev_err(chip->dev,
+ "error reading header\n");
+ return -EIO;
+ }
+ *buf++ = inb(chip->vendor->base);
+ }
+
+ /* size of the data received */
+ native_size = (__force __be32 *) (hdr + 2);
+ size = be32_to_cpu(*native_size);
+
+ if (count < size) {
+ dev_err(chip->dev,
+ "Recv size(%d) less than available space\n", size);
+ for (; i < size; i++) { /* clear the waiting data anyway */
+ status = inb(chip->vendor->base + 1);
+ if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+ dev_err(chip->dev,
+ "error reading data\n");
+ return -EIO;
+ }
+ }
+ return -EIO;
+ }
+
+ /* read all the data available */
+ for (; i < size; i++) {
+ status = inb(chip->vendor->base + 1);
+ if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
+ dev_err(chip->dev,
+ "error reading data\n");
+ return -EIO;
+ }
+ *buf++ = inb(chip->vendor->base);
+ }
+
+ /* make sure data available is gone */
+ status = inb(chip->vendor->base + 1);
+ if (status & ATML_STATUS_DATA_AVAIL) {
+ dev_err(chip->dev, "data available is stuck\n");
+ return -EIO;
+ }
+
+ return size;
+}
+
+static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+ int i;
+
+ dev_dbg(chip->dev, "tpm_atml_send:\n");
+ for (i = 0; i < count; i++) {
+ dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
+ outb(buf[i], chip->vendor->base);
+ }
+
+ return count;
+}
+
+static void tpm_atml_cancel(struct tpm_chip *chip)
+{
+ outb(ATML_STATUS_ABORT, chip->vendor->base + 1);
+}
+
+static u8 tpm_atml_status(struct tpm_chip *chip)
+{
+ return inb(chip->vendor->base + 1);
+}
+
+static struct file_operations atmel_ops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = tpm_open,
+ .read = tpm_read,
+ .write = tpm_write,
+ .release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* atmel_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
+
+static struct tpm_vendor_specific tpm_atmel = {
+ .recv = tpm_atml_recv,
+ .send = tpm_atml_send,
+ .cancel = tpm_atml_cancel,
+ .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,
+ .attr_group = &atmel_attr_grp,
+ .miscdev = { .fops = &atmel_ops, },
+};
+
+static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ u8 version[4];
+ int rc = 0;
+ int lo, hi;
+
+ if (pci_enable_device(pci_dev))
+ return -EIO;
+
+ lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+ hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+ tpm_atmel.base = (hi<<8)|lo;
+ dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base);
+
+ /* verify that it is an Atmel part */
+ if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
+ || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
+ rc = -ENODEV;
+ goto out_err;
+ }
+
+ /* query chip for its version number */
+ if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) {
+ version[1] = tpm_read_index(TPM_ADDR, 0x01);
+ version[2] = tpm_read_index(TPM_ADDR, 0x02);
+ version[3] = tpm_read_index(TPM_ADDR, 0x03);
+ } else {
+ dev_info(&pci_dev->dev, "version query failed\n");
+ rc = -ENODEV;
+ goto out_err;
+ }
+
+ if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_atmel)) < 0)
+ goto out_err;
+
+ dev_info(&pci_dev->dev,
+ "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1],
+ version[2], version[3]);
+
+ return 0;
+out_err:
+ pci_disable_device(pci_dev);
+ return rc;
+}
+
+static void __devexit tpm_atml_remove(struct pci_dev *pci_dev)
+{
+ struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+ if ( chip )
+ tpm_remove_hardware(chip->dev);
+}
+
+static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB6LPC
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
+#else
+#warning Remove the define of PCI_DEVICE_ID_SERVERWORKS_CSB6LPC
+#endif
+ {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
+
+static struct pci_driver atmel_pci_driver = {
+ .name = "tpm_atmel",
+ .id_table = tpm_pci_tbl,
+ .probe = tpm_atml_init,
+ .remove = __devexit_p(tpm_atml_remove),
+ .suspend = tpm_pm_suspend,
+ .resume = tpm_pm_resume,
+};
+
+static int __init init_atmel(void)
+{
+ return pci_register_driver(&atmel_pci_driver);
+}
+
+static void __exit cleanup_atmel(void)
+{
+ pci_unregister_driver(&atmel_pci_driver);
+}
+
+fs_initcall(init_atmel);
+module_exit(cleanup_atmel);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c
new file mode 100644
index 0000000000..9d3a82ba09
--- /dev/null
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at www.trustedcomputinggroup.org
+ *
+ * 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, version 2 of the
+ * License.
+ *
+ */
+
+#include "tpm.h"
+
+/* National definitions */
+enum tpm_nsc_addr{
+ TPM_NSC_IRQ = 0x07,
+ TPM_NSC_BASE0_HI = 0x60,
+ TPM_NSC_BASE0_LO = 0x61,
+ TPM_NSC_BASE1_HI = 0x62,
+ TPM_NSC_BASE1_LO = 0x63
+};
+
+enum tpm_nsc_index {
+ NSC_LDN_INDEX = 0x07,
+ NSC_SID_INDEX = 0x20,
+ NSC_LDC_INDEX = 0x30,
+ NSC_DIO_INDEX = 0x60,
+ NSC_CIO_INDEX = 0x62,
+ NSC_IRQ_INDEX = 0x70,
+ NSC_ITS_INDEX = 0x71
+};
+
+enum tpm_nsc_status_loc {
+ NSC_STATUS = 0x01,
+ NSC_COMMAND = 0x01,
+ NSC_DATA = 0x00
+};
+
+/* status bits */
+enum tpm_nsc_status {
+ NSC_STATUS_OBF = 0x01, /* output buffer full */
+ NSC_STATUS_IBF = 0x02, /* input buffer full */
+ NSC_STATUS_F0 = 0x04, /* F0 */
+ NSC_STATUS_A2 = 0x08, /* A2 */
+ NSC_STATUS_RDY = 0x10, /* ready to receive command */
+ NSC_STATUS_IBR = 0x20 /* ready to receive data */
+};
+
+/* command bits */
+enum tpm_nsc_cmd_mode {
+ NSC_COMMAND_NORMAL = 0x01, /* normal mode */
+ NSC_COMMAND_EOC = 0x03,
+ NSC_COMMAND_CANCEL = 0x22
+};
+/*
+ * Wait for a certain status to appear
+ */
+static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
+{
+ unsigned long stop;
+
+ /* status immediately available check */
+ *data = inb(chip->vendor->base + NSC_STATUS);
+ if ((*data & mask) == val)
+ return 0;
+
+ /* wait for status */
+ stop = jiffies + 10 * HZ;
+ do {
+ msleep(TPM_TIMEOUT);
+ *data = inb(chip->vendor->base + 1);
+ if ((*data & mask) == val)
+ return 0;
+ }
+ while (time_before(jiffies, stop));
+
+ return -EBUSY;
+}
+
+static int nsc_wait_for_ready(struct tpm_chip *chip)
+{
+ int status;
+ unsigned long stop;
+
+ /* status immediately available check */
+ status = inb(chip->vendor->base + NSC_STATUS);
+ if (status & NSC_STATUS_OBF)
+ status = inb(chip->vendor->base + NSC_DATA);
+ if (status & NSC_STATUS_RDY)
+ return 0;
+
+ /* wait for status */
+ stop = jiffies + 100;
+ do {
+ msleep(TPM_TIMEOUT);
+ status = inb(chip->vendor->base + NSC_STATUS);
+ if (status & NSC_STATUS_OBF)
+ status = inb(chip->vendor->base + NSC_DATA);
+ if (status & NSC_STATUS_RDY)
+ return 0;
+ }
+ while (time_before(jiffies, stop));
+
+ dev_info(chip->dev, "wait for ready failed\n");
+ return -EBUSY;
+}
+
+
+static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+ u8 *buffer = buf;
+ u8 data, *p;
+ u32 size;
+ __be32 *native_size;
+
+ if (count < 6)
+ return -EIO;
+
+ if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
+ dev_err(chip->dev, "F0 timeout\n");
+ return -EIO;
+ }
+ if ((data =
+ inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
+ dev_err(chip->dev, "not in normal mode (0x%x)\n",
+ data);
+ return -EIO;
+ }
+
+ /* read the whole packet */
+ for (p = buffer; p < &buffer[count]; p++) {
+ if (wait_for_stat
+ (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
+ dev_err(chip->dev,
+ "OBF timeout (while reading data)\n");
+ return -EIO;
+ }
+ if (data & NSC_STATUS_F0)
+ break;
+ *p = inb(chip->vendor->base + NSC_DATA);
+ }
+
+ if ((data & NSC_STATUS_F0) == 0 &&
+ (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
+ dev_err(chip->dev, "F0 not set\n");
+ return -EIO;
+ }
+ if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) {
+ dev_err(chip->dev,
+ "expected end of command(0x%x)\n", data);
+ return -EIO;
+ }
+
+ native_size = (__force __be32 *) (buf + 2);
+ size = be32_to_cpu(*native_size);
+
+ if (count < size)
+ return -EIO;
+
+ return size;
+}
+
+static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
+{
+ u8 data;
+ int i;
+
+ /*
+ * If we hit the chip with back to back commands it locks up
+ * and never set IBF. Hitting it with this "hammer" seems to
+ * fix it. Not sure why this is needed, we followed the flow
+ * chart in the manual to the letter.
+ */
+ outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+
+ if (nsc_wait_for_ready(chip) != 0)
+ return -EIO;
+
+ if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+ dev_err(chip->dev, "IBF timeout\n");
+ return -EIO;
+ }
+
+ outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND);
+ if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
+ dev_err(chip->dev, "IBR timeout\n");
+ return -EIO;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+ dev_err(chip->dev,
+ "IBF timeout (while writing data)\n");
+ return -EIO;
+ }
+ outb(buf[i], chip->vendor->base + NSC_DATA);
+ }
+
+ if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
+ dev_err(chip->dev, "IBF timeout\n");
+ return -EIO;
+ }
+ outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND);
+
+ return count;
+}
+
+static void tpm_nsc_cancel(struct tpm_chip *chip)
+{
+ outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND);
+}
+
+static u8 tpm_nsc_status(struct tpm_chip *chip)
+{
+ return inb(chip->vendor->base + NSC_STATUS);
+}
+
+static struct file_operations nsc_ops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .open = tpm_open,
+ .read = tpm_read,
+ .write = tpm_write,
+ .release = tpm_release,
+};
+
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute * nsc_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
+
+static struct tpm_vendor_specific tpm_nsc = {
+ .recv = tpm_nsc_recv,
+ .send = tpm_nsc_send,
+ .cancel = tpm_nsc_cancel,
+ .status = tpm_nsc_status,
+ .req_complete_mask = NSC_STATUS_OBF,
+ .req_complete_val = NSC_STATUS_OBF,
+ .req_canceled = NSC_STATUS_RDY,
+ .attr_group = &nsc_attr_grp,
+ .miscdev = { .fops = &nsc_ops, },
+};
+
+static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
+ const struct pci_device_id *pci_id)
+{
+ int rc = 0;
+ int lo, hi;
+ int nscAddrBase = TPM_ADDR;
+
+
+ if (pci_enable_device(pci_dev))
+ return -EIO;
+
+ /* select PM channel 1 */
+ tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12);
+
+ /* verify that it is a National part (SID) */
+ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
+ nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
+ (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
+ if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) {
+ rc = -ENODEV;
+ goto out_err;
+ }
+ }
+
+ hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+ lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+ tpm_nsc.base = (hi<<8) | lo;
+
+ dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
+ dev_dbg(&pci_dev->dev,
+ "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
+ tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
+ tpm_read_index(nscAddrBase,0x27));
+ dev_dbg(&pci_dev->dev,
+ "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
+ tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
+ tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
+ dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
+ (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
+ dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
+ (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
+ dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
+ tpm_read_index(nscAddrBase,0x70));
+ dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
+ tpm_read_index(nscAddrBase,0x71));
+ dev_dbg(&pci_dev->dev,
+ "NSC DMA channel select0 0x%x, select1 0x%x\n",
+ tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
+ dev_dbg(&pci_dev->dev,
+ "NSC Config "
+ "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+ tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
+ tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
+ tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
+ tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
+ tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
+
+ dev_info(&pci_dev->dev,
+ "NSC TPM revision %d\n",
+ tpm_read_index(nscAddrBase, 0x27) & 0x1F);
+
+ /* enable the DPM module */
+ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
+
+ if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_nsc)) < 0)
+ goto out_err;
+
+ return 0;
+
+out_err:
+ pci_disable_device(pci_dev);
+ return rc;
+}
+
+static void __devexit tpm_nsc_remove(struct pci_dev *pci_dev)
+{
+ struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+ if ( chip )
+ tpm_remove_hardware(chip->dev);
+}
+
+static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, tpm_pci_tbl);
+
+static struct pci_driver nsc_pci_driver = {
+ .name = "tpm_nsc",
+ .id_table = tpm_pci_tbl,
+ .probe = tpm_nsc_init,
+ .remove = __devexit_p(tpm_nsc_remove),
+ .suspend = tpm_pm_suspend,
+ .resume = tpm_pm_resume,
+};
+
+static int __init init_nsc(void)
+{
+ return pci_register_driver(&nsc_pci_driver);
+}
+
+static void __exit cleanup_nsc(void)
+{
+ pci_unregister_driver(&nsc_pci_driver);
+}
+
+fs_initcall(init_nsc);
+module_exit(cleanup_nsc);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff --git a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
index 2dcb31b857..2557d586d6 100644
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
@@ -25,7 +25,7 @@
#include <linux/tpmfe.h>
#include <linux/device.h>
#include <linux/interrupt.h>
-#include "tpm_nopci.h"
+#include "tpm.h"
/* read status bits */
enum {
@@ -434,6 +434,21 @@ static struct file_operations tpm_xen_ops = {
.release = tpm_release,
};
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* xen_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group xen_attr_grp = { .attrs = xen_attrs };
+
static struct tpm_vendor_specific tpm_xen = {
.recv = tpm_xen_recv,
.send = tpm_xen_send,
@@ -443,7 +458,7 @@ static struct tpm_vendor_specific tpm_xen = {
.req_complete_val = STATUS_DATA_AVAIL,
.req_canceled = STATUS_READY,
.base = 0,
- .attr = TPM_DEVICE_ATTRS,
+ .attr_group = &xen_attr_grp,
.miscdev.fops = &tpm_xen_ops,
.buffersize = 64 * 1024,
};
@@ -480,7 +495,7 @@ static int __init init_xen(void)
tpm_xen.buffersize = tpmfe.max_tx_size;
- if ((rc = tpm_register_hardware_nopci(&tpm_device, &tpm_xen)) < 0) {
+ if ((rc = tpm_register_hardware(&tpm_device, &tpm_xen)) < 0) {
device_unregister(&tpm_device);
tpm_fe_unregister_receiver();
return rc;
diff --git a/patches/linux-2.6.12/tpm_partial_read.patch b/patches/linux-2.6.12/tpm_partial_read.patch
deleted file mode 100644
index d682c9b392..0000000000
--- a/patches/linux-2.6.12/tpm_partial_read.patch
+++ /dev/null
@@ -1,74 +0,0 @@
---- ref-linux-2.6.12/drivers/char/tpm/tpm.c 2005-06-17 15:48:29.000000000 -0400
-+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.c 2005-09-15 14:56:05.000000000 -0400
-@@ -473,6 +401,7 @@ ssize_t tpm_write(struct file * file, co
- out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
-
- atomic_set(&chip->data_pending, out_size);
-+ atomic_set(&chip->data_position, 0);
- up(&chip->buffer_mutex);
-
- /* Set a timeout by which the reader must come claim the result */
-@@ -494,29 +423,34 @@ ssize_t tpm_read(struct file * file, cha
- {
- struct tpm_chip *chip = file->private_data;
- int ret_size = -ENODATA;
-+ int pos, pending = 0;
-
-- if (atomic_read(&chip->data_pending) != 0) { /* Result available */
-+ down(&chip->buffer_mutex);
-+ ret_size = atomic_read(&chip->data_pending);
-+ if ( ret_size > 0 ) { /* Result available */
-+ if (size < ret_size)
-+ ret_size = size;
-+
-+ pos = atomic_read(&chip->data_position);
-+
-+ if (copy_to_user((void __user *) buf,
-+ &chip->data_buffer[pos], ret_size)) {
-+ ret_size = -EFAULT;
-+ } else {
-+ pending = atomic_read(&chip->data_pending) - ret_size;
-+ if ( pending ) {
-+ atomic_set( &chip->data_pending, pending );
-+ atomic_set( &chip->data_position, pos+ret_size );
-+ }
-+ }
-+ }
-+ up(&chip->buffer_mutex);
-+
-+ if ( ret_size <= 0 || pending == 0 ) {
-+ atomic_set( &chip->data_pending, 0 );
- down(&chip->timer_manipulation_mutex);
- del_singleshot_timer_sync(&chip->user_read_timer);
- up(&chip->timer_manipulation_mutex);
--
-- down(&chip->buffer_mutex);
--
-- ret_size = atomic_read(&chip->data_pending);
-- atomic_set(&chip->data_pending, 0);
--
-- if (ret_size == 0) /* timeout just occurred */
-- ret_size = -ETIME;
-- else if (ret_size > 0) { /* relay data */
-- if (size < ret_size)
-- ret_size = size;
--
-- if (copy_to_user((void __user *) buf,
-- chip->data_buffer, ret_size)) {
-- ret_size = -EFAULT;
-- }
-- }
-- up(&chip->buffer_mutex);
- }
-
- return ret_size;
---- ref-linux-2.6.12/drivers/char/tpm/tpm.h 2005-06-17 15:48:29.000000000 -0400
-+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.h 2005-09-15 14:56:05.000000000 -0400
-@@ -54,6 +54,7 @@ struct tpm_chip {
- /* Data passed to and from the tpm via the read/write calls */
- u8 *data_buffer;
- atomic_t data_pending;
-+ atomic_t data_position;
- struct semaphore buffer_mutex;
-
- struct timer_list user_read_timer; /* user needs to claim result */