# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID e6ecfb4f4a24cec27be0bd36af6230004d8e590b
# Parent 303d51d0d57898334b92a66d827afb91b5659ac0
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@xxxxxxxxxx>
Signed-off-by: Kylene Hall <kjhall@xxxxxxxxxx>
Signed-off-by: Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
diff -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/Makefile
--- a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile Wed Oct 5 12:52:18 2005
@@ -5,8 +5,9 @@
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 -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c Wed Oct 5 12:52:18 2005
@@ -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 @@
.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 @@
.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 @@
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 -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/Kconfig
--- /dev/null Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig Wed Oct 5 12:52:18 2005
@@ -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 -r 303d51d0d578 -r e6ecfb4f4a24 linux-2.6-xen-sparse/drivers/char/tpm/tpm.c
--- /dev/null Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.c Wed Oct 5 12:52:18 2005
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * 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.
+ *
+ * Note, the TPM chip is not interrupt driven (only polling)
+ * and can have very long timeouts (minutes!). Hence the unusual
+ * calls to msleep.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/poll.h>
+#include <linux/spinlock.h>
+#include "tpm.h"
+
+#define TPM_CHIP_NUM_MASK 0x0000ffff
+#define TPM_CHIP_TYPE_SHIFT 16
+
+enum tpm_const {
+ TPM_MINOR = 224, /* officially assigned */
+ TPM_MIN_BUFSIZE = 2048,
+ TPM_MAX_BUFSIZE = 64 * 1024,
+ TPM_NUM_DEVICES = 256,
+ TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
+};
+
+static LIST_HEAD(tpm_chip_list);
+static DEFINE_SPINLOCK(driver_lock);
+static int dev_mask[TPM_NUM_MASK_ENTRIES];
+
+static void user_reader_timeout(unsigned long ptr)
+{
+ struct tpm_chip *chip = (struct tpm_chip *) ptr;
+
+ down(&chip->buffer_mutex);
+ atomic_set(&chip->data_pending, 0);
+ memset(chip->data_buffer, 0, chip->vendor->buffersize);
+ up(&chip->buffer_mutex);
+}
+
+/*
+ * Internal kernel interface to transmit TPM commands
+ */
+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 %zx \n", count, bufsiz);
+ return -E2BIG;
+ }
+
+ down(&chip->tpm_mutex);
+
+ if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+ dev_err(chip->dev,
+ "tpm_transmit: tpm_send: error %zd\n", rc);
+ goto out;
+ }
+
+ stop = jiffies + 2 * 60 * HZ;
+ do {
+ u8 status = chip->vendor->status(chip);
+ if ((status & chip->vendor->req_complete_mask) ==
+ chip->vendor->req_complete_val) {
+ goto out_recv;
+ }
+
+ if ((status == chip->vendor->req_canceled)) {
+ dev_err(chip->dev, "Operation Canceled\n");
+ rc = -ECANCELED;
+ goto out;
+ }
+
+ msleep(TPM_TIMEOUT); /* CHECK */
+ rmb();
+ } while (time_before(jiffies, stop));
+
+
+ chip->vendor->cancel(chip);
+ dev_err(chip->dev, "Operation Timed out\n");
+ rc = -ETIME;
+ goto out;
+
+out_recv:
+ rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+ if (rc < 0)
+ dev_err(chip->dev,
+ "tpm_transmit: tpm_recv: error %zd\n", rc);
+out:
+ up(&chip->tpm_mutex);
+ return rc;
+}
+
+#define TPM_DIGEST_SIZE 20
+#define CAP_PCR_RESULT_SIZE 18
+static const u8 cap_pcr[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 22, /* length */
+ 0, 0, 0, 101, /* TPM_ORD_GetCapability */
+ 0, 0, 0, 5,
+ 0, 0, 0, 4,
+ 0, 0, 1, 1
+};
+
+#define READ_PCR_RESULT_SIZE 30
+static const u8 pcrread[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 14, /* length */
+ 0, 0, 0, 21, /* TPM_ORD_PcrRead */
+ 0, 0, 0, 0 /* PCR index */
+};
+
+#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;
+ int i, j, num_pcrs;
+ __be32 index;
+ char *str = buf;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, cap_pcr, sizeof(cap_pcr));
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ < 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)));
+
+ for (i = 0; i < num_pcrs; i++) {
+ memcpy(data, pcrread, sizeof(pcrread));
+ index = cpu_to_be32(i);
+ memcpy(data + 10, &index, 4);
+ if ((len = tpm_transmit(chip, data, sizeof(data)))
+ < 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);
+
+#define READ_PUBEK_RESULT_SIZE 314
+static const u8 readpubek[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 30, /* length */
+ 0, 0, 0, 124, /* TPM_ORD_ReadPubek */
+};
+
+#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;
+ int i, rc;
+ char *str = buf;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ memcpy(data, readpubek, sizeof(readpubek));
+ memset(data + sizeof(readpubek), 0, 20); /* zero nonce */
+
+ if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
+ READ_PUBEK_RESULT_SIZE) {
+ 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)
+ keylenbytes 32 bits
+ 256 byte modulus
+ ignore checksum 20 bytes
+ */
+
+ str +=
+ sprintf(str,
+ "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
+ "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
+ " %02X %02X %02X %02X %02X %02X %02X %02X\n"
+ "Modulus length: %d\nModulus: \n",
+ data[10], data[11], data[12], data[13], data[14],
+ 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 + 34))));
+
+ for (i = 0; i < 256; i++) {
+ str += sprintf(str, "%02X ", data[i + 38]);
+ if ((i + 1) % 16 == 0)
+ str += sprintf(str, "\n");
+ }
+ rc = str - buf;
+out:
+ kfree(data);
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(tpm_show_pubek);
+
+#define CAP_VER_RESULT_SIZE 18
+static const u8 cap_version[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 18, /* length */
+ 0, 0, 0, 101, /* TPM_ORD_GetCapability */
+ 0, 0, 0, 6,
+ 0, 0, 0, 0
+};
+
+#define CAP_MANUFACTURER_RESULT_SIZE 18
+static const u8 cap_manufacturer[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 22, /* length */
+ 0, 0, 0, 101, /* TPM_ORD_GetCapability */
+ 0, 0, 0, 5,
+ 0, 0, 0, 4,
+ 0, 0, 1, 3
+};
+
+#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;
+ char *str = buf;
+
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
+
+ if ((len = tpm_transmit(chip, data, sizeof(data))) <
+ CAP_MANUFACTURER_RESULT_SIZE)
+ return len;
+
+ str += sprintf(str, "Manufacturer: 0x%x\n",
+ be32_to_cpu(*((__be32 *) (data + 14))));
+
+ memcpy(data, cap_version, sizeof(cap_version));
+
+ if ((len = tpm_transmit(chip, data, sizeof(data))) <
+ CAP_VER_RESULT_SIZE)
+ return len;
+
+ str +=
+ sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
+ (int) data[14], (int) data[15], (int) data[16],
+ (int) data[17]);
+
+ return str - buf;
+}
+EXPORT_SYMBOL_GPL(tpm_show_caps);
+
+#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)
+ return 0;
+
+ chip->vendor->cancel(chip);
+ return count;
+}
+EXPORT_SYMBOL_GPL(tpm_store_cancel);
+
+
+/*
+ * Device file system interface to the TPM
+ */
+int tpm_open(struct inode *inode, struct file *file)
+{
+ int rc = 0, minor = iminor(inode);
+ struct tpm_chip *chip = NULL, *pos;
+
+ spin_lock(&driver_lock);
+
+ list_for_each_entry(pos, &tpm_chip_list, list) {
+ if (pos->vendor->miscdev.minor == minor) {
+ chip = pos;
+ break;
+ }
+ }
+
+ if (chip == NULL) {
+ rc = -ENODEV;
+ goto err_out;
+ }
+
+ if (chip->num_opens) {
+ dev_dbg(chip->dev,
+ "Another process owns this TPM\n");
+ rc = -EBUSY;
+ goto err_out;
+ }
+
+ chip->num_opens++;
+ get_device(chip->dev);
+
+ spin_unlock(&driver_lock);
+
+ chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8),
GFP_KERNEL);
+ if (chip->data_buffer == NULL) {
+ chip->num_opens--;
+ put_device(chip->dev);
+ return -ENOMEM;
+ }
+
+ atomic_set(&chip->data_pending, 0);
+
+ file->private_data = chip;
+ return 0;
+
+err_out:
+ spin_unlock(&driver_lock);
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(tpm_open);
+
+int tpm_release(struct inode *inode, struct file *file)
+{
+ struct tpm_chip *chip = file->private_data;
+
+ spin_lock(&driver_lock);
+ file->private_data = NULL;
+ chip->num_opens--;
+ del_singleshot_timer_sync(&chip->user_read_timer);
+ atomic_set(&chip->data_pending, 0);
+ put_device(chip->dev);
+ kfree(chip->data_buffer);
+ spin_unlock(&driver_lock);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_release);
+
+ssize_t tpm_write(struct file * file, const char __user * buf,
+ size_t size, loff_t * off)
+{
+ struct tpm_chip *chip = file->private_data;
+ int in_size = size, out_size;
+
+ /* cannot perform a write until the read has cleared
+ either via tpm_read or a user_read_timer timeout */
+ while (atomic_read(&chip->data_pending) != 0)
+ msleep(TPM_TIMEOUT);
+
+ down(&chip->buffer_mutex);
+
+ if (in_size > chip->vendor->buffersize)
+ in_size = chip->vendor->buffersize;
+
+ if (copy_from_user
+ (chip->data_buffer, (void __user *) buf, in_size)) {
+ up(&chip->buffer_mutex);
+ return -EFAULT;
+ }
+
+ /* atomic tpm command send and result receive */
+ 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 */
+ mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
+
+ return in_size;
+}
+
+EXPORT_SYMBOL_GPL(tpm_write);
+
+ssize_t tpm_read(struct file * file, char __user * buf,
+ size_t size, loff_t * off)
+{
+ struct tpm_chip *chip = file->private_data;
+ int ret_size;
+ int pos, pending = 0;
+
+ ret_size = atomic_read(&chip->data_pending);
+ if (ret_size > 0) { /* relay data */
+ if (size < ret_size)
+ ret_size = size;
+
+ pos = atomic_read(&chip->data_position);
+
+ down(&chip->buffer_mutex);
+ 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 );
+ del_singleshot_timer_sync(&chip->user_read_timer);
+ }
+
+ return ret_size;
+}
+
+EXPORT_SYMBOL_GPL(tpm_read);
+
+void tpm_remove_hardware(struct device *dev)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ if (chip == NULL) {
+ dev_err(dev, "No device data found\n");
+ return;
+ }
+
+ spin_lock(&driver_lock);
+
+ list_del(&chip->list);
+
+ spin_unlock(&driver_lock);
+
+ dev_set_drvdata(dev, NULL);
+ misc_deregister(&chip->vendor->miscdev);
+ kfree(chip->vendor->miscdev.name);
+
+ 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));
+
+ kfree(chip);
+
+ put_device(dev);
+}
+
+EXPORT_SYMBOL_GPL(tpm_remove_hardware);
+
+static u8 savestate[] = {
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 10, /* blob length (in bytes) */
+ 0, 0, 0, 152 /* TPM_ORD_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, pm_message_t pm_state)
+{
+ struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+ if (chip == NULL)
+ return -ENODEV;
+
+ tpm_transmit(chip, savestate, sizeof(savestate));
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_pm_suspend);
+
+/*
+ * Resume from a power safe. The BIOS already restored
+ * the TPM state.
+ */
+int tpm_pm_resume(struct pci_dev *pci_dev)
+{
+ struct tpm_chip *chip = pci_get_drvdata(pci_dev);
+
+ if (chip == NULL)
+ return -ENODEV;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_pm_resume);
+
+/*
+ * 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(struct device *dev,
+ struct tpm_vendor_specific *entry)
+{
+#define DEVNAME_SIZE 7
+
+ char *devname;
+ struct tpm_chip *chip;
+ int i, j;
+
+ /* Driver specific per-device data */
+ chip = kmalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
+ return -ENOMEM;
+
+ memset(chip, 0, sizeof(struct tpm_chip));
+
+ init_MUTEX(&chip->buffer_mutex);
+ init_MUTEX(&chip->tpm_mutex);
+ INIT_LIST_HEAD(&chip->list);
+
+ init_timer(&chip->user_read_timer);
+ chip->user_read_timer.function = user_reader_timeout;
+ 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) {
+ entry->buffersize = TPM_MAX_BUFSIZE;
+ }
+
+ chip->dev_num = -1;
+
+ for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
+ for (j = 0; j < 8 * sizeof(int); j++)
+ if ((dev_mask[i] & (1 << j)) == 0) {
+ chip->dev_num =
+ i * TPM_NUM_MASK_ENTRIES + j;
+ dev_mask[i] |= 1 << j;
+ goto dev_num_search_complete;
+ }
+
+dev_num_search_complete:
+ if (chip->dev_num < 0) {
+ dev_err(dev,
+ "No available tpm device numbers\n");
+ kfree(chip);
+ return -ENODEV;
+ } else if (chip->dev_num == 0)
+ chip->vendor->miscdev.minor = TPM_MINOR;
+ else
+ chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
+
+ 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",
+ chip->vendor->miscdev.name,
+ chip->vendor->miscdev.minor);
+ put_device(dev);
+ kfree(chip);
+ dev_mask[i] &= !(1 << j);
+ return -ENODEV;
+ }
+
+ spin_lock(&driver_lock);
+
+ dev_set_drvdata(dev, chip);
+
+ list_add(&chip->list, &tpm_chip_list);
+
+ spin_unlock(&driver_lock);
+
+ sysfs_create_group(&dev->kobj, chip->vendor->attr_group);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
+
+MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24 linux-2.6-xen-sparse/drivers/char/tpm/tpm.h
--- /dev/null Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.h Wed Oct 5 12:52:18 2005
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * 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 <linux/module.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+
+enum tpm_timeout {
+ TPM_TIMEOUT = 5, /* msecs */
+};
+
+/* TPM addresses */
+enum tpm_addr {
+ TPM_SUPERIO_ADDR = 0x2E,
+ TPM_ADDR = 0x4E,
+};
+
+#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;
+
+struct tpm_vendor_specific {
+ u8 req_complete_mask;
+ u8 req_complete_val;
+ u8 req_canceled;
+ u16 base; /* TPM base address */
+ 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 *);
+ struct miscdevice miscdev;
+ struct attribute_group *attr_group;
+};
+
+struct tpm_chip {
+ struct device *dev; /* Device stuff */
+
+ int dev_num; /* /dev/tpm# */
+ int num_opens; /* only one allowed */
+ int time_expired;
+
+ /* 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 */
+ struct semaphore tpm_mutex; /* tpm is processing */
+
+ struct tpm_vendor_specific *vendor;
+
+ struct list_head list;
+};
+
+static inline int tpm_read_index(int base, int index)
+{
+ outb(index, base);
+ return inb(base+1) & 0xFF;
+}
+
+static inline void tpm_write_index(int base, int index, int value)
+{
+ outb(index, base);
+ outb(value & 0xFF, base+1);
+}
+
+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 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 *);
diff -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c
--- /dev/null Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c Wed Oct 5 12:52:18 2005
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * 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@xxxxxxxxxxxxxx)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c
--- /dev/null Wed Oct 5 12:41:59 2005
+++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c Wed Oct 5 12:52:18 2005
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
+ * Dave Safford <safford@xxxxxxxxxxxxxx>
+ * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
+ * Kylene Hall <kjhall@xxxxxxxxxx>
+ *
+ * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * 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@xxxxxxxxxxxxxx)");
+MODULE_DESCRIPTION("TPM Driver");
+MODULE_VERSION("2.0");
+MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c Wed Oct 5 12:41:59 2005
+++ /dev/null Wed Oct 5 12:52:18 2005
@@ -1,751 +0,0 @@
-/*
- * Copyright (C) 2004 IBM Corporation
- *
- * Authors:
- * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
- * Dave Safford <safford@xxxxxxxxxxxxxx>
- * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
- * Kylene Hall <kjhall@xxxxxxxxxx>
- *
- * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
- *
- * 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.
- *
- * Note, the TPM chip is not interrupt driven (only polling)
- * and can have very long timeouts (minutes!). Hence the unusual
- * calls to schedule_timeout.
- *
- */
-
-#include <linux/sched.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include "tpm_nopci.h"
-
-enum {
- TPM_MINOR = 224, /* officially assigned */
- TPM_MIN_BUFSIZE = 2048,
- TPM_MAX_BUFSIZE = 65536,
- 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 void user_reader_timeout(unsigned long ptr)
-{
- struct tpm_chip *chip = (struct tpm_chip *) ptr;
-
- down(&chip->buffer_mutex);
- atomic_set(&chip->data_pending, 0);
- memset(chip->data_buffer, 0, chip->vendor->buffersize);
- 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)
-{
- ssize_t rc;
- u32 count;
- unsigned long stop;
-
- 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);
- 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);
- goto out;
- }
-
- stop = jiffies + 2 * 60 * HZ;
- do {
- u8 status = chip->vendor->status(chip);
- if ((status & chip->vendor->req_complete_mask) ==
- chip->vendor->req_complete_val) {
- goto out_recv;
- }
-
- if ((status == chip->vendor->req_canceled)) {
- dev_err(chip->dev, "Operation Canceled\n");
- rc = -ECANCELED;
- goto out;
- }
-
- msleep(TPM_TIMEOUT); /* CHECK */
- rmb();
- }
- while (time_before(jiffies, stop));
-
-
- chip->vendor->cancel(chip);
- dev_err(chip->dev, "Operation Timed out\n");
- rc = -ETIME;
- goto out;
-
-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);
-
-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[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 22, /* length */
- 0, 0, 0, 101, /* TPM_ORD_GetCapability */
- 0, 0, 0, 5,
- 0, 0, 0, 4,
- 0, 0, 1, 1
-};
-
-#define READ_PCR_RESULT_SIZE 30
-static const u8 pcrread[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 14, /* length */
- 0, 0, 0, 21, /* TPM_ORD_PcrRead */
- 0, 0, 0, 0 /* PCR index */
-};
-
-ssize_t tpm_show_pcrs(struct device *dev, char *buf)
-{
- u8 data[READ_PCR_RESULT_SIZE];
- ssize_t len;
- int i, j, num_pcrs;
- __be32 index;
- char *str = buf;
-
- struct tpm_chip *chip = dev_get_drvdata(dev);
- if (chip == NULL)
- return -ENODEV;
-
- memcpy(data, cap_pcr, sizeof(cap_pcr));
- if ((len = tpm_transmit(chip, data, sizeof(data)))
- < CAP_PCR_RESULT_SIZE)
- return len;
-
- num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
-
- for (i = 0; i < num_pcrs; i++) {
- memcpy(data, pcrread, sizeof(pcrread));
- index = cpu_to_be32(i);
- memcpy(data + 10, &index, 4);
- if ((len = tpm_transmit(chip, data, sizeof(data)))
- < READ_PCR_RESULT_SIZE)
- return len;
- 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");
- }
- 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 */
- 0, 0, 0, 30, /* length */
- 0, 0, 0, 124, /* TPM_ORD_ReadPubek */
-};
-
-ssize_t tpm_show_pubek(struct device *dev, char *buf)
-{
- u8 *data;
- ssize_t len;
- int i, rc;
- char *str = buf;
-
- struct tpm_chip *chip = dev_get_drvdata(dev);
- if (chip == NULL)
- return -ENODEV;
-
- data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- memcpy(data, readpubek, sizeof(readpubek));
- memset(data + sizeof(readpubek), 0, 20); /* zero nonce */
-
- if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
- READ_PUBEK_RESULT_SIZE) {
- rc = len;
- goto out;
- }
-
- /*
- ignore header 10 bytes
- algorithm 32 bits (1 == RSA )
- encscheme 16 bits
- sigscheme 16 bits
- parameters (RSA 12->bytes: keybit, #primes, expbit)
- keylenbytes 32 bits
- 256 byte modulus
- ignore checksum 20 bytes
- */
-
- str +=
- sprintf(str,
- "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
- "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X"
- " %02X %02X %02X %02X %02X %02X %02X %02X\n"
- "Modulus length: %d\nModulus: \n",
- data[10], data[11], data[12], data[13], data[14],
- 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))));
-
- for (i = 0; i < 256; i++) {
- str += sprintf(str, "%02X ", data[i + 39]);
- if ((i + 1) % 16 == 0)
- str += sprintf(str, "\n");
- }
- rc = str - buf;
-out:
- kfree(data);
- return rc;
-}
-
-EXPORT_SYMBOL_GPL(tpm_show_pubek);
-
-#define CAP_VER_RESULT_SIZE 18
-static const u8 cap_version[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 18, /* length */
- 0, 0, 0, 101, /* TPM_ORD_GetCapability */
- 0, 0, 0, 6,
- 0, 0, 0, 0
-};
-
-#define CAP_MANUFACTURER_RESULT_SIZE 18
-static const u8 cap_manufacturer[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 22, /* length */
- 0, 0, 0, 101, /* TPM_ORD_GetCapability */
- 0, 0, 0, 5,
- 0, 0, 0, 4,
- 0, 0, 1, 3
-};
-
-ssize_t tpm_show_caps(struct device *dev, char *buf)
-{
- u8 data[sizeof(cap_manufacturer)];
- ssize_t len;
- char *str = buf;
-
- struct tpm_chip *chip = dev_get_drvdata(dev);
- if (chip == NULL)
- return -ENODEV;
-
- memcpy(data, cap_manufacturer, sizeof(cap_manufacturer));
-
- if ((len = tpm_transmit(chip, data, sizeof(data))) <
- CAP_MANUFACTURER_RESULT_SIZE)
- return len;
-
- str += sprintf(str, "Manufacturer: 0x%x\n",
- be32_to_cpu(*((__be32 *)(data + 14))));
-
- memcpy(data, cap_version, sizeof(cap_version));
-
- if ((len = tpm_transmit(chip, data, sizeof(data))) <
- CAP_VER_RESULT_SIZE)
- return len;
-
- str +=
- sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n",
- (int) data[14], (int) data[15], (int) data[16],
- (int) data[17]);
-
- return str - buf;
-}
-
-EXPORT_SYMBOL_GPL(tpm_show_caps);
-
-ssize_t tpm_store_cancel(struct device * dev, const char *buf,
- size_t count)
-{
- struct tpm_chip *chip = dev_get_drvdata(dev);
- if (chip == NULL)
- return 0;
-
- chip->vendor->cancel(chip);
- return count;
-}
-
-EXPORT_SYMBOL_GPL(tpm_store_cancel);
-
-/*
- * Device file system interface to the TPM
- */
-int tpm_open(struct inode *inode, struct file *file)
-{
- int rc = 0, minor = iminor(inode);
- struct tpm_chip *chip = NULL, *pos;
-
- spin_lock(&driver_lock);
-
- list_for_each_entry(pos, &tpm_chip_list, list) {
- if (pos->vendor->miscdev.minor == minor) {
- chip = pos;
- break;
- }
- }
-
- if (chip == NULL) {
- rc = -ENODEV;
- goto err_out;
- }
-
- if (chip->num_opens) {
- dev_dbg(chip->dev, "Another process owns this TPM\n");
- rc = -EBUSY;
- goto err_out;
- }
-
- chip->num_opens++;
- get_device(chip->dev);
-
- spin_unlock(&driver_lock);
-
- chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8),
- GFP_KERNEL);
- if (chip->data_buffer == NULL) {
- chip->num_opens--;
- put_device(chip->dev);
- return -ENOMEM;
- }
-
- atomic_set(&chip->data_pending, 0);
-
- file->private_data = chip;
- return 0;
-
-err_out:
- spin_unlock(&driver_lock);
- return rc;
-}
-
-EXPORT_SYMBOL_GPL(tpm_open);
-
-int tpm_release(struct inode *inode, struct file *file)
-{
- struct tpm_chip *chip = file->private_data;
-
- spin_lock(&driver_lock);
- file->private_data = NULL;
- chip->num_opens--;
- del_singleshot_timer_sync(&chip->user_read_timer);
- atomic_set(&chip->data_pending, 0);
- put_device(chip->dev);
- kfree(chip->data_buffer);
- spin_unlock(&driver_lock);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_release);
-
-ssize_t tpm_write(struct file * file, const char __user * buf,
- size_t size, loff_t * off)
-{
- struct tpm_chip *chip = file->private_data;
- int in_size = size, out_size;
-
- /* cannot perform a write until the read has cleared
- either via tpm_read or a user_read_timer timeout */
- while (atomic_read(&chip->data_pending) != 0)
- msleep(TPM_TIMEOUT);
-
- down(&chip->buffer_mutex);
-
- if (in_size > chip->vendor->buffersize)
- in_size = chip->vendor->buffersize;
-
- if (copy_from_user
- (chip->data_buffer, (void __user *) buf, in_size)) {
- up(&chip->buffer_mutex);
- return -EFAULT;
- }
-
- /* atomic tpm command send and result receive */
- out_size = tpm_transmit(chip,
- chip->data_buffer,
- chip->vendor->buffersize);
-
- atomic_set(&chip->data_pending, out_size);
- up(&chip->buffer_mutex);
-
- /* Set a timeout by which the reader must come claim the result */
- mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
-
- return in_size;
-}
-
-EXPORT_SYMBOL_GPL(tpm_write);
-
-ssize_t tpm_read(struct file * file, char __user * buf,
- size_t size, loff_t * off)
-{
- struct tpm_chip *chip = file->private_data;
- int ret_size;
-
- 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);
-
- if (copy_to_user((void __user *) buf,
- &chip->data_buffer[position],
- 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);
- }
- up(&chip->buffer_mutex);
- }
-
- return ret_size;
-}
-
-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");
- return;
- }
-
- spin_lock(&driver_lock);
-
- list_del(&chip->list);
-
- spin_unlock(&driver_lock);
-
- dev_set_drvdata(dev, NULL);
- misc_deregister(&chip->vendor->miscdev);
-
- for (i = 0; i < TPM_NUM_ATTR; i++)
- device_remove_file(dev, &chip->vendor->attr[i]);
-
- dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &=
- !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
-
- kfree(chip);
-
- put_device(dev);
-}
-
-EXPORT_SYMBOL_GPL(tpm_remove_hardware);
-
-static const u8 savestate[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 10, /* blob length (in bytes) */
- 0, 0, 0, 152 /* TPM_ORD_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)
-{
- struct tpm_chip *chip = pci_get_drvdata(pci_dev);
- if (chip == NULL)
- return -ENODEV;
-
- tpm_transmit(chip, savestate, sizeof(savestate));
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_pm_suspend);
-
-/*
- * Resume from a power safe. The BIOS already restored
- * the TPM state.
- */
-int tpm_pm_resume(struct pci_dev *pci_dev)
-{
- struct tpm_chip *chip = pci_get_drvdata(pci_dev);
-
- if (chip == NULL)
- return -ENODEV;
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_pm_resume);
-
-/*
- * 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)
-{
- char devname[7];
- struct tpm_chip *chip;
- int i, j;
-
- /* Driver specific per-device data */
- chip = kmalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
- return -ENOMEM;
-
- memset(chip, 0, sizeof(struct tpm_chip));
-
- init_MUTEX(&chip->buffer_mutex);
- init_MUTEX(&chip->tpm_mutex);
- INIT_LIST_HEAD(&chip->list);
-
- init_timer(&chip->user_read_timer);
- chip->user_read_timer.function = user_reader_timeout;
- 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) {
- entry->buffersize = TPM_MAX_BUFSIZE;
- }
-
- chip->dev_num = -1;
-
- for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
- for (j = 0; j < 8 * sizeof(int); j++)
- if ((dev_mask[i] & (1 << j)) == 0) {
- chip->dev_num =
- i * TPM_NUM_MASK_ENTRIES + j;
- dev_mask[i] |= 1 << j;
- goto dev_num_search_complete;
- }
-
-dev_num_search_complete:
- if (chip->dev_num < 0) {
- dev_err(dev, "No available tpm device numbers\n");
- kfree(chip);
- return -ENODEV;
- } else if (chip->dev_num == 0)
- chip->vendor->miscdev.minor = TPM_MINOR;
- else
- chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
-
- snprintf(devname, sizeof(devname), "%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",
- chip->vendor->miscdev.name,
- chip->vendor->miscdev.minor);
- put_device(dev);
- kfree(chip);
- dev_mask[i] &= !(1 << j);
- return -ENODEV;
- }
-
- spin_lock(&driver_lock);
-
- dev_set_drvdata(dev, chip);
-
- list_add(&chip->list, &tpm_chip_list);
-
- 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);
-
-static int __init init_tpm(void)
-{
- return 0;
-}
-
-static void __exit cleanup_tpm(void)
-{
-
-}
-
-module_init(init_tpm);
-module_exit(cleanup_tpm);
-
-MODULE_AUTHOR("Leendert van Doorn (leendert@xxxxxxxxxxxxxx)");
-MODULE_DESCRIPTION("TPM Driver");
-MODULE_VERSION("2.0");
-MODULE_LICENSE("GPL");
diff -r 303d51d0d578 -r e6ecfb4f4a24
linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h
--- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h Wed Oct 5 12:41:59 2005
+++ /dev/null Wed Oct 5 12:52:18 2005
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2004 IBM Corporation
- *
- * Authors:
- * Leendert van Doorn <leendert@xxxxxxxxxxxxxx>
- * Dave Safford <safford@xxxxxxxxxxxxxx>
- * Reiner Sailer <sailer@xxxxxxxxxxxxxx>
- * Kylene Hall <kjhall@xxxxxxxxxx>
- *
- * Maintained by: <tpmdd_devel@xxxxxxxxxxxxxxxxxxxxx>
- *
- * 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 <linux/module.h>
-#include <linux/version.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-
-enum {
- TPM_TIMEOUT = 5, /* msecs */
- TPM_NUM_ATTR = 4
-};
-
-/* TPM addresses */
-enum {
- 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) }
-
-struct tpm_chip;
-
-struct tpm_vendor_specific {
- u8 req_complete_mask;
- u8 req_complete_val;
- u8 req_canceled;
- u16 base; /* TPM base address */
- u32 buffersize; /* The device's requested 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 *);
- struct miscdevice miscdev;
- struct device_attribute attr[TPM_NUM_ATTR];
-};
-
-struct tpm_chip {
- struct device *dev; /* PCI device stuff */
-
- int dev_num; /* /dev/tpm# */
- int num_opens; /* only one allowed */
- int time_expired;
-
- /* 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 */
- struct semaphore tpm_mutex; /* tpm is processing */
-
- struct tpm_vendor_specific *vendor;
-
- struct list_head list;
-};
-
-static inline int tpm_read_index(int index)
-{
- outb(index, TPM_ADDR);
- return inb(TPM_DATA) & 0xFF;
-}
-
-static inline void tpm_write_index(int index, int value)
-{
- outb(index, TPM_ADDR);
- outb(value & 0xFF, TPM_DATA);
-}
-
-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_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 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 -r 303d51d0d578 -r e6ecfb4f4a24 patches/linux-2.6.12/tpm_partial_read.patch
--- a/patches/linux-2.6.12/tpm_partial_read.patch Wed Oct 5 12:41:59 2005
+++ /dev/null Wed Oct 5 12:52:18 2005
@@ -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 */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|