ia64/xen-unstable
changeset 7218:e6ecfb4f4a24
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>
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>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Wed Oct 05 13:52:18 2005 +0100 (2005-10-05) |
parents | 303d51d0d578 |
children | b4b12c9f1200 |
files | linux-2.6-xen-sparse/drivers/char/tpm/Kconfig linux-2.6-xen-sparse/drivers/char/tpm/Makefile linux-2.6-xen-sparse/drivers/char/tpm/tpm.c linux-2.6-xen-sparse/drivers/char/tpm/tpm.h linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/Kconfig Wed Oct 05 13:52:18 2005 +0100 1.3 @@ -0,0 +1,58 @@ 1.4 +# 1.5 +# TPM device configuration 1.6 +# 1.7 + 1.8 +menu "TPM devices" 1.9 + 1.10 +config TCG_TPM 1.11 + tristate "TPM Hardware Support" 1.12 + depends on EXPERIMENTAL && PCI 1.13 + ---help--- 1.14 + If you have a TPM security chip in your system, which 1.15 + implements the Trusted Computing Group's specification, 1.16 + say Yes and it will be accessible from within Linux. For 1.17 + more information see <http://www.trustedcomputinggroup.org>. 1.18 + An implementation of the Trusted Software Stack (TSS), the 1.19 + userspace enablement piece of the specification, can be 1.20 + obtained at: <http://sourceforge.net/projects/trousers>. To 1.21 + compile this driver as a module, choose M here; the module 1.22 + will be called tpm. If unsure, say N. 1.23 + 1.24 +config TCG_TIS 1.25 + tristate "TPM Interface Specification 1.2 Interface" 1.26 + depends on TCG_TPM 1.27 + ---help--- 1.28 + If you have a TPM security chip that is compliant with the 1.29 + TCG TIS 1.2 TPM specification say Yes and it will be accessible 1.30 + from within Linux. To compile this driver as a module, choose 1.31 + M here; the module will be called tpm_tis. 1.32 + 1.33 +config TCG_NSC 1.34 + tristate "National Semiconductor TPM Interface" 1.35 + depends on TCG_TPM 1.36 + ---help--- 1.37 + If you have a TPM security chip from National Semicondutor 1.38 + say Yes and it will be accessible from within Linux. To 1.39 + compile this driver as a module, choose M here; the module 1.40 + will be called tpm_nsc. 1.41 + 1.42 +config TCG_ATMEL 1.43 + tristate "Atmel TPM Interface" 1.44 + depends on TCG_TPM 1.45 + ---help--- 1.46 + If you have a TPM security chip from Atmel say Yes and it 1.47 + will be accessible from within Linux. To compile this driver 1.48 + as a module, choose M here; the module will be called tpm_atmel. 1.49 + 1.50 +config TCG_XEN 1.51 + tristate "XEN TPM Interface" 1.52 + depends on TCG_TPM && ARCH_XEN && XEN_TPMDEV_FRONTEND 1.53 + ---help--- 1.54 + If you want to make TPM support available to a Xen 1.55 + user domain, say Yes and it will 1.56 + be accessible from within Linux. To compile this driver 1.57 + as a module, choose M here; the module will be called 1.58 + tpm_xen. 1.59 + 1.60 +endmenu 1.61 +
2.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/Makefile Wed Oct 05 13:41:59 2005 +0100 2.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/Makefile Wed Oct 05 13:52:18 2005 +0100 2.3 @@ -5,8 +5,9 @@ ifeq ($(CONFIG_XEN_PHYSDEV_ACCESS),y) 2.4 obj-$(CONFIG_TCG_TPM) += tpm.o 2.5 obj-$(CONFIG_TCG_NSC) += tpm_nsc.o 2.6 obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o 2.7 -obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o 2.8 +obj-$(CONFIG_TCG_TIS) += tpm_tis.o 2.9 +obj-$(CONFIG_TCG_XEN) += tpm_xen.o 2.10 else 2.11 -obj-$(CONFIG_TCG_TPM) += tpm_nopci.o 2.12 +obj-$(CONFIG_TCG_TPM) += tpm.o 2.13 obj-$(CONFIG_TCG_XEN) += tpm_xen.o 2.14 endif
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.c Wed Oct 05 13:52:18 2005 +0100 3.3 @@ -0,0 +1,657 @@ 3.4 +/* 3.5 + * Copyright (C) 2004 IBM Corporation 3.6 + * 3.7 + * Authors: 3.8 + * Leendert van Doorn <leendert@watson.ibm.com> 3.9 + * Dave Safford <safford@watson.ibm.com> 3.10 + * Reiner Sailer <sailer@watson.ibm.com> 3.11 + * Kylene Hall <kjhall@us.ibm.com> 3.12 + * 3.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net> 3.14 + * 3.15 + * Device driver for TCG/TCPA TPM (trusted platform module). 3.16 + * Specifications at www.trustedcomputinggroup.org 3.17 + * 3.18 + * This program is free software; you can redistribute it and/or 3.19 + * modify it under the terms of the GNU General Public License as 3.20 + * published by the Free Software Foundation, version 2 of the 3.21 + * License. 3.22 + * 3.23 + * Note, the TPM chip is not interrupt driven (only polling) 3.24 + * and can have very long timeouts (minutes!). Hence the unusual 3.25 + * calls to msleep. 3.26 + * 3.27 + */ 3.28 + 3.29 +#include <linux/sched.h> 3.30 +#include <linux/poll.h> 3.31 +#include <linux/spinlock.h> 3.32 +#include "tpm.h" 3.33 + 3.34 +#define TPM_CHIP_NUM_MASK 0x0000ffff 3.35 +#define TPM_CHIP_TYPE_SHIFT 16 3.36 + 3.37 +enum tpm_const { 3.38 + TPM_MINOR = 224, /* officially assigned */ 3.39 + TPM_MIN_BUFSIZE = 2048, 3.40 + TPM_MAX_BUFSIZE = 64 * 1024, 3.41 + TPM_NUM_DEVICES = 256, 3.42 + TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) 3.43 +}; 3.44 + 3.45 +static LIST_HEAD(tpm_chip_list); 3.46 +static DEFINE_SPINLOCK(driver_lock); 3.47 +static int dev_mask[TPM_NUM_MASK_ENTRIES]; 3.48 + 3.49 +static void user_reader_timeout(unsigned long ptr) 3.50 +{ 3.51 + struct tpm_chip *chip = (struct tpm_chip *) ptr; 3.52 + 3.53 + down(&chip->buffer_mutex); 3.54 + atomic_set(&chip->data_pending, 0); 3.55 + memset(chip->data_buffer, 0, chip->vendor->buffersize); 3.56 + up(&chip->buffer_mutex); 3.57 +} 3.58 + 3.59 +/* 3.60 + * Internal kernel interface to transmit TPM commands 3.61 + */ 3.62 +static ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf, 3.63 + size_t bufsiz) 3.64 +{ 3.65 + ssize_t rc; 3.66 + u32 count; 3.67 + unsigned long stop; 3.68 + 3.69 + if (!chip) 3.70 + return -ENODEV; 3.71 + 3.72 + if ( !chip ) 3.73 + return -ENODEV; 3.74 + 3.75 + count = be32_to_cpu(*((__be32 *) (buf + 2))); 3.76 + 3.77 + if (count == 0) 3.78 + return -ENODATA; 3.79 + if (count > bufsiz) { 3.80 + dev_err(chip->dev, 3.81 + "invalid count value %x %zx \n", count, bufsiz); 3.82 + return -E2BIG; 3.83 + } 3.84 + 3.85 + down(&chip->tpm_mutex); 3.86 + 3.87 + if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { 3.88 + dev_err(chip->dev, 3.89 + "tpm_transmit: tpm_send: error %zd\n", rc); 3.90 + goto out; 3.91 + } 3.92 + 3.93 + stop = jiffies + 2 * 60 * HZ; 3.94 + do { 3.95 + u8 status = chip->vendor->status(chip); 3.96 + if ((status & chip->vendor->req_complete_mask) == 3.97 + chip->vendor->req_complete_val) { 3.98 + goto out_recv; 3.99 + } 3.100 + 3.101 + if ((status == chip->vendor->req_canceled)) { 3.102 + dev_err(chip->dev, "Operation Canceled\n"); 3.103 + rc = -ECANCELED; 3.104 + goto out; 3.105 + } 3.106 + 3.107 + msleep(TPM_TIMEOUT); /* CHECK */ 3.108 + rmb(); 3.109 + } while (time_before(jiffies, stop)); 3.110 + 3.111 + 3.112 + chip->vendor->cancel(chip); 3.113 + dev_err(chip->dev, "Operation Timed out\n"); 3.114 + rc = -ETIME; 3.115 + goto out; 3.116 + 3.117 +out_recv: 3.118 + rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); 3.119 + if (rc < 0) 3.120 + dev_err(chip->dev, 3.121 + "tpm_transmit: tpm_recv: error %zd\n", rc); 3.122 +out: 3.123 + up(&chip->tpm_mutex); 3.124 + return rc; 3.125 +} 3.126 + 3.127 +#define TPM_DIGEST_SIZE 20 3.128 +#define CAP_PCR_RESULT_SIZE 18 3.129 +static const u8 cap_pcr[] = { 3.130 + 0, 193, /* TPM_TAG_RQU_COMMAND */ 3.131 + 0, 0, 0, 22, /* length */ 3.132 + 0, 0, 0, 101, /* TPM_ORD_GetCapability */ 3.133 + 0, 0, 0, 5, 3.134 + 0, 0, 0, 4, 3.135 + 0, 0, 1, 1 3.136 +}; 3.137 + 3.138 +#define READ_PCR_RESULT_SIZE 30 3.139 +static const u8 pcrread[] = { 3.140 + 0, 193, /* TPM_TAG_RQU_COMMAND */ 3.141 + 0, 0, 0, 14, /* length */ 3.142 + 0, 0, 0, 21, /* TPM_ORD_PcrRead */ 3.143 + 0, 0, 0, 0 /* PCR index */ 3.144 +}; 3.145 + 3.146 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) 3.147 +ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, 3.148 + char *buf) 3.149 +#else 3.150 +ssize_t tpm_show_pcrs(struct device *dev, 3.151 + char *buf) 3.152 +#endif 3.153 +{ 3.154 + u8 data[READ_PCR_RESULT_SIZE]; 3.155 + ssize_t len; 3.156 + int i, j, num_pcrs; 3.157 + __be32 index; 3.158 + char *str = buf; 3.159 + 3.160 + struct tpm_chip *chip = dev_get_drvdata(dev); 3.161 + if (chip == NULL) 3.162 + return -ENODEV; 3.163 + 3.164 + memcpy(data, cap_pcr, sizeof(cap_pcr)); 3.165 + if ((len = tpm_transmit(chip, data, sizeof(data))) 3.166 + < CAP_PCR_RESULT_SIZE) { 3.167 + dev_dbg(chip->dev, "A TPM error (%d) occurred " 3.168 + "attempting to determine the number of PCRS\n", 3.169 + be32_to_cpu(*((__be32 *) (data + 6)))); 3.170 + return 0; 3.171 + } 3.172 + 3.173 + num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); 3.174 + 3.175 + for (i = 0; i < num_pcrs; i++) { 3.176 + memcpy(data, pcrread, sizeof(pcrread)); 3.177 + index = cpu_to_be32(i); 3.178 + memcpy(data + 10, &index, 4); 3.179 + if ((len = tpm_transmit(chip, data, sizeof(data))) 3.180 + < READ_PCR_RESULT_SIZE){ 3.181 + dev_dbg(chip->dev, "A TPM error (%d) occurred" 3.182 + " attempting to read PCR %d of %d\n", 3.183 + be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs); 3.184 + goto out; 3.185 + } 3.186 + str += sprintf(str, "PCR-%02d: ", i); 3.187 + for (j = 0; j < TPM_DIGEST_SIZE; j++) 3.188 + str += sprintf(str, "%02X ", *(data + 10 + j)); 3.189 + str += sprintf(str, "\n"); 3.190 + } 3.191 +out: 3.192 + return str - buf; 3.193 +} 3.194 +EXPORT_SYMBOL_GPL(tpm_show_pcrs); 3.195 + 3.196 +#define READ_PUBEK_RESULT_SIZE 314 3.197 +static const u8 readpubek[] = { 3.198 + 0, 193, /* TPM_TAG_RQU_COMMAND */ 3.199 + 0, 0, 0, 30, /* length */ 3.200 + 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ 3.201 +}; 3.202 + 3.203 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) 3.204 +ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, 3.205 + char *buf) 3.206 +#else 3.207 +ssize_t tpm_show_pubek(struct device *dev, 3.208 + char *buf) 3.209 +#endif 3.210 +{ 3.211 + u8 *data; 3.212 + ssize_t len; 3.213 + int i, rc; 3.214 + char *str = buf; 3.215 + 3.216 + struct tpm_chip *chip = dev_get_drvdata(dev); 3.217 + if (chip == NULL) 3.218 + return -ENODEV; 3.219 + 3.220 + data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); 3.221 + if (!data) 3.222 + return -ENOMEM; 3.223 + 3.224 + memcpy(data, readpubek, sizeof(readpubek)); 3.225 + memset(data + sizeof(readpubek), 0, 20); /* zero nonce */ 3.226 + 3.227 + if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < 3.228 + READ_PUBEK_RESULT_SIZE) { 3.229 + dev_dbg(chip->dev, "A TPM error (%d) occurred " 3.230 + "attempting to read the PUBEK\n", 3.231 + be32_to_cpu(*((__be32 *) (data + 6)))); 3.232 + rc = 0; 3.233 + goto out; 3.234 + } 3.235 + 3.236 + /* 3.237 + ignore header 10 bytes 3.238 + algorithm 32 bits (1 == RSA ) 3.239 + encscheme 16 bits 3.240 + sigscheme 16 bits 3.241 + parameters (RSA 12->bytes: keybit, #primes, expbit) 3.242 + keylenbytes 32 bits 3.243 + 256 byte modulus 3.244 + ignore checksum 20 bytes 3.245 + */ 3.246 + 3.247 + str += 3.248 + sprintf(str, 3.249 + "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" 3.250 + "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X" 3.251 + " %02X %02X %02X %02X %02X %02X %02X %02X\n" 3.252 + "Modulus length: %d\nModulus: \n", 3.253 + data[10], data[11], data[12], data[13], data[14], 3.254 + data[15], data[16], data[17], data[22], data[23], 3.255 + data[24], data[25], data[26], data[27], data[28], 3.256 + data[29], data[30], data[31], data[32], data[33], 3.257 + be32_to_cpu(*((__be32 *) (data + 34)))); 3.258 + 3.259 + for (i = 0; i < 256; i++) { 3.260 + str += sprintf(str, "%02X ", data[i + 38]); 3.261 + if ((i + 1) % 16 == 0) 3.262 + str += sprintf(str, "\n"); 3.263 + } 3.264 + rc = str - buf; 3.265 +out: 3.266 + kfree(data); 3.267 + return rc; 3.268 +} 3.269 + 3.270 +EXPORT_SYMBOL_GPL(tpm_show_pubek); 3.271 + 3.272 +#define CAP_VER_RESULT_SIZE 18 3.273 +static const u8 cap_version[] = { 3.274 + 0, 193, /* TPM_TAG_RQU_COMMAND */ 3.275 + 0, 0, 0, 18, /* length */ 3.276 + 0, 0, 0, 101, /* TPM_ORD_GetCapability */ 3.277 + 0, 0, 0, 6, 3.278 + 0, 0, 0, 0 3.279 +}; 3.280 + 3.281 +#define CAP_MANUFACTURER_RESULT_SIZE 18 3.282 +static const u8 cap_manufacturer[] = { 3.283 + 0, 193, /* TPM_TAG_RQU_COMMAND */ 3.284 + 0, 0, 0, 22, /* length */ 3.285 + 0, 0, 0, 101, /* TPM_ORD_GetCapability */ 3.286 + 0, 0, 0, 5, 3.287 + 0, 0, 0, 4, 3.288 + 0, 0, 1, 3 3.289 +}; 3.290 + 3.291 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) 3.292 +ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, 3.293 + char *buf) 3.294 +#else 3.295 +ssize_t tpm_show_caps(struct device *dev, 3.296 + char *buf) 3.297 +#endif 3.298 +{ 3.299 + u8 data[sizeof(cap_manufacturer)]; 3.300 + ssize_t len; 3.301 + char *str = buf; 3.302 + 3.303 + struct tpm_chip *chip = dev_get_drvdata(dev); 3.304 + if (chip == NULL) 3.305 + return -ENODEV; 3.306 + 3.307 + memcpy(data, cap_manufacturer, sizeof(cap_manufacturer)); 3.308 + 3.309 + if ((len = tpm_transmit(chip, data, sizeof(data))) < 3.310 + CAP_MANUFACTURER_RESULT_SIZE) 3.311 + return len; 3.312 + 3.313 + str += sprintf(str, "Manufacturer: 0x%x\n", 3.314 + be32_to_cpu(*((__be32 *) (data + 14)))); 3.315 + 3.316 + memcpy(data, cap_version, sizeof(cap_version)); 3.317 + 3.318 + if ((len = tpm_transmit(chip, data, sizeof(data))) < 3.319 + CAP_VER_RESULT_SIZE) 3.320 + return len; 3.321 + 3.322 + str += 3.323 + sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", 3.324 + (int) data[14], (int) data[15], (int) data[16], 3.325 + (int) data[17]); 3.326 + 3.327 + return str - buf; 3.328 +} 3.329 +EXPORT_SYMBOL_GPL(tpm_show_caps); 3.330 + 3.331 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) 3.332 +ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, 3.333 + const char *buf, size_t count) 3.334 +#else 3.335 +ssize_t tpm_store_cancel(struct device *dev, 3.336 + const char *buf, size_t count) 3.337 +#endif 3.338 +{ 3.339 + struct tpm_chip *chip = dev_get_drvdata(dev); 3.340 + if (chip == NULL) 3.341 + return 0; 3.342 + 3.343 + chip->vendor->cancel(chip); 3.344 + return count; 3.345 +} 3.346 +EXPORT_SYMBOL_GPL(tpm_store_cancel); 3.347 + 3.348 + 3.349 +/* 3.350 + * Device file system interface to the TPM 3.351 + */ 3.352 +int tpm_open(struct inode *inode, struct file *file) 3.353 +{ 3.354 + int rc = 0, minor = iminor(inode); 3.355 + struct tpm_chip *chip = NULL, *pos; 3.356 + 3.357 + spin_lock(&driver_lock); 3.358 + 3.359 + list_for_each_entry(pos, &tpm_chip_list, list) { 3.360 + if (pos->vendor->miscdev.minor == minor) { 3.361 + chip = pos; 3.362 + break; 3.363 + } 3.364 + } 3.365 + 3.366 + if (chip == NULL) { 3.367 + rc = -ENODEV; 3.368 + goto err_out; 3.369 + } 3.370 + 3.371 + if (chip->num_opens) { 3.372 + dev_dbg(chip->dev, 3.373 + "Another process owns this TPM\n"); 3.374 + rc = -EBUSY; 3.375 + goto err_out; 3.376 + } 3.377 + 3.378 + chip->num_opens++; 3.379 + get_device(chip->dev); 3.380 + 3.381 + spin_unlock(&driver_lock); 3.382 + 3.383 + chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8), GFP_KERNEL); 3.384 + if (chip->data_buffer == NULL) { 3.385 + chip->num_opens--; 3.386 + put_device(chip->dev); 3.387 + return -ENOMEM; 3.388 + } 3.389 + 3.390 + atomic_set(&chip->data_pending, 0); 3.391 + 3.392 + file->private_data = chip; 3.393 + return 0; 3.394 + 3.395 +err_out: 3.396 + spin_unlock(&driver_lock); 3.397 + return rc; 3.398 +} 3.399 + 3.400 +EXPORT_SYMBOL_GPL(tpm_open); 3.401 + 3.402 +int tpm_release(struct inode *inode, struct file *file) 3.403 +{ 3.404 + struct tpm_chip *chip = file->private_data; 3.405 + 3.406 + spin_lock(&driver_lock); 3.407 + file->private_data = NULL; 3.408 + chip->num_opens--; 3.409 + del_singleshot_timer_sync(&chip->user_read_timer); 3.410 + atomic_set(&chip->data_pending, 0); 3.411 + put_device(chip->dev); 3.412 + kfree(chip->data_buffer); 3.413 + spin_unlock(&driver_lock); 3.414 + return 0; 3.415 +} 3.416 + 3.417 +EXPORT_SYMBOL_GPL(tpm_release); 3.418 + 3.419 +ssize_t tpm_write(struct file * file, const char __user * buf, 3.420 + size_t size, loff_t * off) 3.421 +{ 3.422 + struct tpm_chip *chip = file->private_data; 3.423 + int in_size = size, out_size; 3.424 + 3.425 + /* cannot perform a write until the read has cleared 3.426 + either via tpm_read or a user_read_timer timeout */ 3.427 + while (atomic_read(&chip->data_pending) != 0) 3.428 + msleep(TPM_TIMEOUT); 3.429 + 3.430 + down(&chip->buffer_mutex); 3.431 + 3.432 + if (in_size > chip->vendor->buffersize) 3.433 + in_size = chip->vendor->buffersize; 3.434 + 3.435 + if (copy_from_user 3.436 + (chip->data_buffer, (void __user *) buf, in_size)) { 3.437 + up(&chip->buffer_mutex); 3.438 + return -EFAULT; 3.439 + } 3.440 + 3.441 + /* atomic tpm command send and result receive */ 3.442 + out_size = tpm_transmit(chip, chip->data_buffer, 3.443 + chip->vendor->buffersize); 3.444 + 3.445 + atomic_set(&chip->data_pending, out_size); 3.446 + atomic_set(&chip->data_position, 0); 3.447 + up(&chip->buffer_mutex); 3.448 + 3.449 + /* Set a timeout by which the reader must come claim the result */ 3.450 + mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); 3.451 + 3.452 + return in_size; 3.453 +} 3.454 + 3.455 +EXPORT_SYMBOL_GPL(tpm_write); 3.456 + 3.457 +ssize_t tpm_read(struct file * file, char __user * buf, 3.458 + size_t size, loff_t * off) 3.459 +{ 3.460 + struct tpm_chip *chip = file->private_data; 3.461 + int ret_size; 3.462 + int pos, pending = 0; 3.463 + 3.464 + ret_size = atomic_read(&chip->data_pending); 3.465 + if (ret_size > 0) { /* relay data */ 3.466 + if (size < ret_size) 3.467 + ret_size = size; 3.468 + 3.469 + pos = atomic_read(&chip->data_position); 3.470 + 3.471 + down(&chip->buffer_mutex); 3.472 + if (copy_to_user 3.473 + ((void __user *) buf, &chip->data_buffer[pos], ret_size)) { 3.474 + ret_size = -EFAULT; 3.475 + } else { 3.476 + pending = atomic_read(&chip->data_pending) - ret_size; 3.477 + if ( pending ) { 3.478 + atomic_set( &chip->data_pending, pending ); 3.479 + atomic_set( &chip->data_position, pos+ret_size ); 3.480 + } 3.481 + } 3.482 + up(&chip->buffer_mutex); 3.483 + } 3.484 + 3.485 + if ( ret_size <= 0 || pending == 0 ) { 3.486 + atomic_set( &chip->data_pending, 0 ); 3.487 + del_singleshot_timer_sync(&chip->user_read_timer); 3.488 + } 3.489 + 3.490 + return ret_size; 3.491 +} 3.492 + 3.493 +EXPORT_SYMBOL_GPL(tpm_read); 3.494 + 3.495 +void tpm_remove_hardware(struct device *dev) 3.496 +{ 3.497 + struct tpm_chip *chip = dev_get_drvdata(dev); 3.498 + 3.499 + if (chip == NULL) { 3.500 + dev_err(dev, "No device data found\n"); 3.501 + return; 3.502 + } 3.503 + 3.504 + spin_lock(&driver_lock); 3.505 + 3.506 + list_del(&chip->list); 3.507 + 3.508 + spin_unlock(&driver_lock); 3.509 + 3.510 + dev_set_drvdata(dev, NULL); 3.511 + misc_deregister(&chip->vendor->miscdev); 3.512 + kfree(chip->vendor->miscdev.name); 3.513 + 3.514 + sysfs_remove_group(&dev->kobj, chip->vendor->attr_group); 3.515 + 3.516 + dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); 3.517 + 3.518 + kfree(chip); 3.519 + 3.520 + put_device(dev); 3.521 +} 3.522 + 3.523 +EXPORT_SYMBOL_GPL(tpm_remove_hardware); 3.524 + 3.525 +static u8 savestate[] = { 3.526 + 0, 193, /* TPM_TAG_RQU_COMMAND */ 3.527 + 0, 0, 0, 10, /* blob length (in bytes) */ 3.528 + 0, 0, 0, 152 /* TPM_ORD_SaveState */ 3.529 +}; 3.530 + 3.531 +/* 3.532 + * We are about to suspend. Save the TPM state 3.533 + * so that it can be restored. 3.534 + */ 3.535 +int tpm_pm_suspend(struct pci_dev *pci_dev, pm_message_t pm_state) 3.536 +{ 3.537 + struct tpm_chip *chip = pci_get_drvdata(pci_dev); 3.538 + if (chip == NULL) 3.539 + return -ENODEV; 3.540 + 3.541 + tpm_transmit(chip, savestate, sizeof(savestate)); 3.542 + return 0; 3.543 +} 3.544 + 3.545 +EXPORT_SYMBOL_GPL(tpm_pm_suspend); 3.546 + 3.547 +/* 3.548 + * Resume from a power safe. The BIOS already restored 3.549 + * the TPM state. 3.550 + */ 3.551 +int tpm_pm_resume(struct pci_dev *pci_dev) 3.552 +{ 3.553 + struct tpm_chip *chip = pci_get_drvdata(pci_dev); 3.554 + 3.555 + if (chip == NULL) 3.556 + return -ENODEV; 3.557 + 3.558 + return 0; 3.559 +} 3.560 + 3.561 +EXPORT_SYMBOL_GPL(tpm_pm_resume); 3.562 + 3.563 +/* 3.564 + * Called from tpm_<specific>.c probe function only for devices 3.565 + * the driver has determined it should claim. Prior to calling 3.566 + * this function the specific probe function has called pci_enable_device 3.567 + * upon errant exit from this function specific probe function should call 3.568 + * pci_disable_device 3.569 + */ 3.570 +int tpm_register_hardware(struct device *dev, 3.571 + struct tpm_vendor_specific *entry) 3.572 +{ 3.573 +#define DEVNAME_SIZE 7 3.574 + 3.575 + char *devname; 3.576 + struct tpm_chip *chip; 3.577 + int i, j; 3.578 + 3.579 + /* Driver specific per-device data */ 3.580 + chip = kmalloc(sizeof(*chip), GFP_KERNEL); 3.581 + if (chip == NULL) 3.582 + return -ENOMEM; 3.583 + 3.584 + memset(chip, 0, sizeof(struct tpm_chip)); 3.585 + 3.586 + init_MUTEX(&chip->buffer_mutex); 3.587 + init_MUTEX(&chip->tpm_mutex); 3.588 + INIT_LIST_HEAD(&chip->list); 3.589 + 3.590 + init_timer(&chip->user_read_timer); 3.591 + chip->user_read_timer.function = user_reader_timeout; 3.592 + chip->user_read_timer.data = (unsigned long) chip; 3.593 + 3.594 + chip->vendor = entry; 3.595 + 3.596 + if (entry->buffersize < TPM_MIN_BUFSIZE) { 3.597 + entry->buffersize = TPM_MIN_BUFSIZE; 3.598 + } else if (entry->buffersize > TPM_MAX_BUFSIZE) { 3.599 + entry->buffersize = TPM_MAX_BUFSIZE; 3.600 + } 3.601 + 3.602 + chip->dev_num = -1; 3.603 + 3.604 + for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) 3.605 + for (j = 0; j < 8 * sizeof(int); j++) 3.606 + if ((dev_mask[i] & (1 << j)) == 0) { 3.607 + chip->dev_num = 3.608 + i * TPM_NUM_MASK_ENTRIES + j; 3.609 + dev_mask[i] |= 1 << j; 3.610 + goto dev_num_search_complete; 3.611 + } 3.612 + 3.613 +dev_num_search_complete: 3.614 + if (chip->dev_num < 0) { 3.615 + dev_err(dev, 3.616 + "No available tpm device numbers\n"); 3.617 + kfree(chip); 3.618 + return -ENODEV; 3.619 + } else if (chip->dev_num == 0) 3.620 + chip->vendor->miscdev.minor = TPM_MINOR; 3.621 + else 3.622 + chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; 3.623 + 3.624 + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); 3.625 + scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); 3.626 + chip->vendor->miscdev.name = devname; 3.627 + 3.628 + chip->vendor->miscdev.dev = dev; 3.629 + chip->dev = get_device(dev); 3.630 + 3.631 + if (misc_register(&chip->vendor->miscdev)) { 3.632 + dev_err(chip->dev, 3.633 + "unable to misc_register %s, minor %d\n", 3.634 + chip->vendor->miscdev.name, 3.635 + chip->vendor->miscdev.minor); 3.636 + put_device(dev); 3.637 + kfree(chip); 3.638 + dev_mask[i] &= !(1 << j); 3.639 + return -ENODEV; 3.640 + } 3.641 + 3.642 + spin_lock(&driver_lock); 3.643 + 3.644 + dev_set_drvdata(dev, chip); 3.645 + 3.646 + list_add(&chip->list, &tpm_chip_list); 3.647 + 3.648 + spin_unlock(&driver_lock); 3.649 + 3.650 + sysfs_create_group(&dev->kobj, chip->vendor->attr_group); 3.651 + 3.652 + return 0; 3.653 +} 3.654 + 3.655 +EXPORT_SYMBOL_GPL(tpm_register_hardware); 3.656 + 3.657 +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 3.658 +MODULE_DESCRIPTION("TPM Driver"); 3.659 +MODULE_VERSION("2.0"); 3.660 +MODULE_LICENSE("GPL");
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm.h Wed Oct 05 13:52:18 2005 +0100 4.3 @@ -0,0 +1,118 @@ 4.4 +/* 4.5 + * Copyright (C) 2004 IBM Corporation 4.6 + * 4.7 + * Authors: 4.8 + * Leendert van Doorn <leendert@watson.ibm.com> 4.9 + * Dave Safford <safford@watson.ibm.com> 4.10 + * Reiner Sailer <sailer@watson.ibm.com> 4.11 + * Kylene Hall <kjhall@us.ibm.com> 4.12 + * 4.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net> 4.14 + * 4.15 + * Device driver for TCG/TCPA TPM (trusted platform module). 4.16 + * Specifications at www.trustedcomputinggroup.org 4.17 + * 4.18 + * This program is free software; you can redistribute it and/or 4.19 + * modify it under the terms of the GNU General Public License as 4.20 + * published by the Free Software Foundation, version 2 of the 4.21 + * License. 4.22 + * 4.23 + */ 4.24 +#include <linux/module.h> 4.25 +#include <linux/version.h> 4.26 +#include <linux/pci.h> 4.27 +#include <linux/delay.h> 4.28 +#include <linux/fs.h> 4.29 +#include <linux/miscdevice.h> 4.30 + 4.31 +enum tpm_timeout { 4.32 + TPM_TIMEOUT = 5, /* msecs */ 4.33 +}; 4.34 + 4.35 +/* TPM addresses */ 4.36 +enum tpm_addr { 4.37 + TPM_SUPERIO_ADDR = 0x2E, 4.38 + TPM_ADDR = 0x4E, 4.39 +}; 4.40 + 4.41 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) 4.42 +extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, 4.43 + char *); 4.44 +extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, 4.45 + char *); 4.46 +extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, 4.47 + char *); 4.48 +extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, 4.49 + const char *, size_t); 4.50 +#else 4.51 +extern ssize_t tpm_show_pubek(struct device *, 4.52 + char *); 4.53 +extern ssize_t tpm_show_pcrs(struct device *, 4.54 + char *); 4.55 +extern ssize_t tpm_show_caps(struct device *, 4.56 + char *); 4.57 +extern ssize_t tpm_store_cancel(struct device *, 4.58 + const char *, size_t); 4.59 +#endif 4.60 + 4.61 +struct tpm_chip; 4.62 + 4.63 +struct tpm_vendor_specific { 4.64 + u8 req_complete_mask; 4.65 + u8 req_complete_val; 4.66 + u8 req_canceled; 4.67 + u16 base; /* TPM base address */ 4.68 + int drv_type; 4.69 + u32 buffersize; 4.70 + 4.71 + int (*recv) (struct tpm_chip *, u8 *, size_t); 4.72 + int (*send) (struct tpm_chip *, u8 *, size_t); 4.73 + void (*cancel) (struct tpm_chip *); 4.74 + u8 (*status) (struct tpm_chip *); 4.75 + struct miscdevice miscdev; 4.76 + struct attribute_group *attr_group; 4.77 +}; 4.78 + 4.79 +struct tpm_chip { 4.80 + struct device *dev; /* Device stuff */ 4.81 + 4.82 + int dev_num; /* /dev/tpm# */ 4.83 + int num_opens; /* only one allowed */ 4.84 + int time_expired; 4.85 + 4.86 + /* Data passed to and from the tpm via the read/write calls */ 4.87 + u8 *data_buffer; 4.88 + atomic_t data_pending; 4.89 + atomic_t data_position; 4.90 + struct semaphore buffer_mutex; 4.91 + 4.92 + struct timer_list user_read_timer; /* user needs to claim result */ 4.93 + struct semaphore tpm_mutex; /* tpm is processing */ 4.94 + 4.95 + struct tpm_vendor_specific *vendor; 4.96 + 4.97 + struct list_head list; 4.98 +}; 4.99 + 4.100 +static inline int tpm_read_index(int base, int index) 4.101 +{ 4.102 + outb(index, base); 4.103 + return inb(base+1) & 0xFF; 4.104 +} 4.105 + 4.106 +static inline void tpm_write_index(int base, int index, int value) 4.107 +{ 4.108 + outb(index, base); 4.109 + outb(value & 0xFF, base+1); 4.110 +} 4.111 + 4.112 +extern int tpm_register_hardware(struct device *, 4.113 + struct tpm_vendor_specific *); 4.114 +extern int tpm_open(struct inode *, struct file *); 4.115 +extern int tpm_release(struct inode *, struct file *); 4.116 +extern ssize_t tpm_write(struct file *, const char __user *, size_t, 4.117 + loff_t *); 4.118 +extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); 4.119 +extern void tpm_remove_hardware(struct device *); 4.120 +extern int tpm_pm_suspend(struct pci_dev *, pm_message_t); 4.121 +extern int tpm_pm_resume(struct pci_dev *);
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_atmel.c Wed Oct 05 13:52:18 2005 +0100 5.3 @@ -0,0 +1,263 @@ 5.4 +/* 5.5 + * Copyright (C) 2004 IBM Corporation 5.6 + * 5.7 + * Authors: 5.8 + * Leendert van Doorn <leendert@watson.ibm.com> 5.9 + * Dave Safford <safford@watson.ibm.com> 5.10 + * Reiner Sailer <sailer@watson.ibm.com> 5.11 + * Kylene Hall <kjhall@us.ibm.com> 5.12 + * 5.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net> 5.14 + * 5.15 + * Device driver for TCG/TCPA TPM (trusted platform module). 5.16 + * Specifications at www.trustedcomputinggroup.org 5.17 + * 5.18 + * This program is free software; you can redistribute it and/or 5.19 + * modify it under the terms of the GNU General Public License as 5.20 + * published by the Free Software Foundation, version 2 of the 5.21 + * License. 5.22 + * 5.23 + */ 5.24 + 5.25 +#include "tpm.h" 5.26 + 5.27 +/* Atmel definitions */ 5.28 +enum tpm_atmel_addr { 5.29 + TPM_ATMEL_BASE_ADDR_LO = 0x08, 5.30 + TPM_ATMEL_BASE_ADDR_HI = 0x09 5.31 +}; 5.32 + 5.33 +/* write status bits */ 5.34 +enum tpm_atmel_write_status { 5.35 + ATML_STATUS_ABORT = 0x01, 5.36 + ATML_STATUS_LASTBYTE = 0x04 5.37 +}; 5.38 +/* read status bits */ 5.39 +enum tpm_atmel_read_status { 5.40 + ATML_STATUS_BUSY = 0x01, 5.41 + ATML_STATUS_DATA_AVAIL = 0x02, 5.42 + ATML_STATUS_REWRITE = 0x04, 5.43 + ATML_STATUS_READY = 0x08 5.44 +}; 5.45 + 5.46 +static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) 5.47 +{ 5.48 + u8 status, *hdr = buf; 5.49 + u32 size; 5.50 + int i; 5.51 + __be32 *native_size; 5.52 + 5.53 + /* start reading header */ 5.54 + if (count < 6) 5.55 + return -EIO; 5.56 + 5.57 + for (i = 0; i < 6; i++) { 5.58 + status = inb(chip->vendor->base + 1); 5.59 + if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 5.60 + dev_err(chip->dev, 5.61 + "error reading header\n"); 5.62 + return -EIO; 5.63 + } 5.64 + *buf++ = inb(chip->vendor->base); 5.65 + } 5.66 + 5.67 + /* size of the data received */ 5.68 + native_size = (__force __be32 *) (hdr + 2); 5.69 + size = be32_to_cpu(*native_size); 5.70 + 5.71 + if (count < size) { 5.72 + dev_err(chip->dev, 5.73 + "Recv size(%d) less than available space\n", size); 5.74 + for (; i < size; i++) { /* clear the waiting data anyway */ 5.75 + status = inb(chip->vendor->base + 1); 5.76 + if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 5.77 + dev_err(chip->dev, 5.78 + "error reading data\n"); 5.79 + return -EIO; 5.80 + } 5.81 + } 5.82 + return -EIO; 5.83 + } 5.84 + 5.85 + /* read all the data available */ 5.86 + for (; i < size; i++) { 5.87 + status = inb(chip->vendor->base + 1); 5.88 + if ((status & ATML_STATUS_DATA_AVAIL) == 0) { 5.89 + dev_err(chip->dev, 5.90 + "error reading data\n"); 5.91 + return -EIO; 5.92 + } 5.93 + *buf++ = inb(chip->vendor->base); 5.94 + } 5.95 + 5.96 + /* make sure data available is gone */ 5.97 + status = inb(chip->vendor->base + 1); 5.98 + if (status & ATML_STATUS_DATA_AVAIL) { 5.99 + dev_err(chip->dev, "data available is stuck\n"); 5.100 + return -EIO; 5.101 + } 5.102 + 5.103 + return size; 5.104 +} 5.105 + 5.106 +static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count) 5.107 +{ 5.108 + int i; 5.109 + 5.110 + dev_dbg(chip->dev, "tpm_atml_send:\n"); 5.111 + for (i = 0; i < count; i++) { 5.112 + dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); 5.113 + outb(buf[i], chip->vendor->base); 5.114 + } 5.115 + 5.116 + return count; 5.117 +} 5.118 + 5.119 +static void tpm_atml_cancel(struct tpm_chip *chip) 5.120 +{ 5.121 + outb(ATML_STATUS_ABORT, chip->vendor->base + 1); 5.122 +} 5.123 + 5.124 +static u8 tpm_atml_status(struct tpm_chip *chip) 5.125 +{ 5.126 + return inb(chip->vendor->base + 1); 5.127 +} 5.128 + 5.129 +static struct file_operations atmel_ops = { 5.130 + .owner = THIS_MODULE, 5.131 + .llseek = no_llseek, 5.132 + .open = tpm_open, 5.133 + .read = tpm_read, 5.134 + .write = tpm_write, 5.135 + .release = tpm_release, 5.136 +}; 5.137 + 5.138 +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 5.139 +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 5.140 +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 5.141 +static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); 5.142 + 5.143 +static struct attribute* atmel_attrs[] = { 5.144 + &dev_attr_pubek.attr, 5.145 + &dev_attr_pcrs.attr, 5.146 + &dev_attr_caps.attr, 5.147 + &dev_attr_cancel.attr, 5.148 + 0, 5.149 +}; 5.150 + 5.151 +static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; 5.152 + 5.153 +static struct tpm_vendor_specific tpm_atmel = { 5.154 + .recv = tpm_atml_recv, 5.155 + .send = tpm_atml_send, 5.156 + .cancel = tpm_atml_cancel, 5.157 + .status = tpm_atml_status, 5.158 + .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, 5.159 + .req_complete_val = ATML_STATUS_DATA_AVAIL, 5.160 + .req_canceled = ATML_STATUS_READY, 5.161 + .attr_group = &atmel_attr_grp, 5.162 + .miscdev = { .fops = &atmel_ops, }, 5.163 +}; 5.164 + 5.165 +static int __devinit tpm_atml_init(struct pci_dev *pci_dev, 5.166 + const struct pci_device_id *pci_id) 5.167 +{ 5.168 + u8 version[4]; 5.169 + int rc = 0; 5.170 + int lo, hi; 5.171 + 5.172 + if (pci_enable_device(pci_dev)) 5.173 + return -EIO; 5.174 + 5.175 + lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); 5.176 + hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); 5.177 + 5.178 + tpm_atmel.base = (hi<<8)|lo; 5.179 + dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); 5.180 + 5.181 + /* verify that it is an Atmel part */ 5.182 + if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' 5.183 + || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { 5.184 + rc = -ENODEV; 5.185 + goto out_err; 5.186 + } 5.187 + 5.188 + /* query chip for its version number */ 5.189 + if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { 5.190 + version[1] = tpm_read_index(TPM_ADDR, 0x01); 5.191 + version[2] = tpm_read_index(TPM_ADDR, 0x02); 5.192 + version[3] = tpm_read_index(TPM_ADDR, 0x03); 5.193 + } else { 5.194 + dev_info(&pci_dev->dev, "version query failed\n"); 5.195 + rc = -ENODEV; 5.196 + goto out_err; 5.197 + } 5.198 + 5.199 + if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_atmel)) < 0) 5.200 + goto out_err; 5.201 + 5.202 + dev_info(&pci_dev->dev, 5.203 + "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1], 5.204 + version[2], version[3]); 5.205 + 5.206 + return 0; 5.207 +out_err: 5.208 + pci_disable_device(pci_dev); 5.209 + return rc; 5.210 +} 5.211 + 5.212 +static void __devexit tpm_atml_remove(struct pci_dev *pci_dev) 5.213 +{ 5.214 + struct tpm_chip *chip = pci_get_drvdata(pci_dev); 5.215 + 5.216 + if ( chip ) 5.217 + tpm_remove_hardware(chip->dev); 5.218 +} 5.219 + 5.220 +static struct pci_device_id tpm_pci_tbl[] __devinitdata = { 5.221 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, 5.222 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, 5.223 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, 5.224 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, 5.225 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, 5.226 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, 5.227 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, 5.228 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, 5.229 + {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, 5.230 +#ifndef PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 5.231 +#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227 5.232 +#else 5.233 +#warning Remove the define of PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 5.234 +#endif 5.235 + {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, 5.236 + {0,} 5.237 +}; 5.238 + 5.239 +MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); 5.240 + 5.241 +static struct pci_driver atmel_pci_driver = { 5.242 + .name = "tpm_atmel", 5.243 + .id_table = tpm_pci_tbl, 5.244 + .probe = tpm_atml_init, 5.245 + .remove = __devexit_p(tpm_atml_remove), 5.246 + .suspend = tpm_pm_suspend, 5.247 + .resume = tpm_pm_resume, 5.248 +}; 5.249 + 5.250 +static int __init init_atmel(void) 5.251 +{ 5.252 + return pci_register_driver(&atmel_pci_driver); 5.253 +} 5.254 + 5.255 +static void __exit cleanup_atmel(void) 5.256 +{ 5.257 + pci_unregister_driver(&atmel_pci_driver); 5.258 +} 5.259 + 5.260 +fs_initcall(init_atmel); 5.261 +module_exit(cleanup_atmel); 5.262 + 5.263 +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 5.264 +MODULE_DESCRIPTION("TPM Driver"); 5.265 +MODULE_VERSION("2.0"); 5.266 +MODULE_LICENSE("GPL");
6.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.c Wed Oct 05 13:41:59 2005 +0100 6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 6.3 @@ -1,751 +0,0 @@ 6.4 -/* 6.5 - * Copyright (C) 2004 IBM Corporation 6.6 - * 6.7 - * Authors: 6.8 - * Leendert van Doorn <leendert@watson.ibm.com> 6.9 - * Dave Safford <safford@watson.ibm.com> 6.10 - * Reiner Sailer <sailer@watson.ibm.com> 6.11 - * Kylene Hall <kjhall@us.ibm.com> 6.12 - * 6.13 - * Maintained by: <tpmdd_devel@lists.sourceforge.net> 6.14 - * 6.15 - * Device driver for TCG/TCPA TPM (trusted platform module). 6.16 - * Specifications at www.trustedcomputinggroup.org 6.17 - * 6.18 - * This program is free software; you can redistribute it and/or 6.19 - * modify it under the terms of the GNU General Public License as 6.20 - * published by the Free Software Foundation, version 2 of the 6.21 - * License. 6.22 - * 6.23 - * Note, the TPM chip is not interrupt driven (only polling) 6.24 - * and can have very long timeouts (minutes!). Hence the unusual 6.25 - * calls to schedule_timeout. 6.26 - * 6.27 - */ 6.28 - 6.29 -#include <linux/sched.h> 6.30 -#include <linux/poll.h> 6.31 -#include <linux/spinlock.h> 6.32 -#include "tpm_nopci.h" 6.33 - 6.34 -enum { 6.35 - TPM_MINOR = 224, /* officially assigned */ 6.36 - TPM_MIN_BUFSIZE = 2048, 6.37 - TPM_MAX_BUFSIZE = 65536, 6.38 - TPM_NUM_DEVICES = 256, 6.39 - TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) 6.40 -}; 6.41 - 6.42 - /* PCI configuration addresses */ 6.43 -enum { 6.44 - PCI_GEN_PMCON_1 = 0xA0, 6.45 - PCI_GEN1_DEC = 0xE4, 6.46 - PCI_LPC_EN = 0xE6, 6.47 - PCI_GEN2_DEC = 0xEC 6.48 -}; 6.49 - 6.50 -enum { 6.51 - TPM_LOCK_REG = 0x0D, 6.52 - TPM_INTERUPT_REG = 0x0A, 6.53 - TPM_BASE_ADDR_LO = 0x08, 6.54 - TPM_BASE_ADDR_HI = 0x09, 6.55 - TPM_UNLOCK_VALUE = 0x55, 6.56 - TPM_LOCK_VALUE = 0xAA, 6.57 - TPM_DISABLE_INTERUPT_VALUE = 0x00 6.58 -}; 6.59 - 6.60 -static LIST_HEAD(tpm_chip_list); 6.61 -static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; 6.62 -static int dev_mask[32]; 6.63 - 6.64 -static void user_reader_timeout(unsigned long ptr) 6.65 -{ 6.66 - struct tpm_chip *chip = (struct tpm_chip *) ptr; 6.67 - 6.68 - down(&chip->buffer_mutex); 6.69 - atomic_set(&chip->data_pending, 0); 6.70 - memset(chip->data_buffer, 0, chip->vendor->buffersize); 6.71 - up(&chip->buffer_mutex); 6.72 -} 6.73 - 6.74 -void tpm_time_expired(unsigned long ptr) 6.75 -{ 6.76 - int *exp = (int *) ptr; 6.77 - *exp = 1; 6.78 -} 6.79 - 6.80 -EXPORT_SYMBOL_GPL(tpm_time_expired); 6.81 - 6.82 - 6.83 -/* 6.84 - * This function should be used by other kernel subsystems attempting to use the tpm through the tpm_transmit interface. 6.85 - * 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. 6.86 - * 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. 6.87 - */ 6.88 -struct tpm_chip* tpm_chip_lookup(int chip_num) 6.89 -{ 6.90 - 6.91 - struct tpm_chip *pos; 6.92 - list_for_each_entry(pos, &tpm_chip_list, list) 6.93 - if (pos->dev_num == chip_num || 6.94 - chip_num == TPM_ANY_NUM) 6.95 - return pos; 6.96 - 6.97 - return NULL; 6.98 - 6.99 -} 6.100 - 6.101 -/* 6.102 - * Internal kernel interface to transmit TPM commands 6.103 - */ 6.104 -ssize_t tpm_transmit(struct tpm_chip * chip, const char *buf, 6.105 - size_t bufsiz) 6.106 -{ 6.107 - ssize_t rc; 6.108 - u32 count; 6.109 - unsigned long stop; 6.110 - 6.111 - count = be32_to_cpu(*((__be32 *) (buf + 2))); 6.112 - 6.113 - if (count == 0) 6.114 - return -ENODATA; 6.115 - if (count > bufsiz) { 6.116 - dev_err(chip->dev, 6.117 - "invalid count value %x %x \n", count, bufsiz); 6.118 - return -E2BIG; 6.119 - } 6.120 - 6.121 - dev_dbg(chip->dev, "TPM Ordinal: %d\n", 6.122 - be32_to_cpu(*((__be32 *) (buf + 6)))); 6.123 - dev_dbg(chip->dev, "Chip Status: %x\n", 6.124 - inb(chip->vendor->base + 1)); 6.125 - 6.126 - down(&chip->tpm_mutex); 6.127 - 6.128 - if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { 6.129 - dev_err(chip->dev, 6.130 - "tpm_transmit: tpm_send: error %d\n", rc); 6.131 - goto out; 6.132 - } 6.133 - 6.134 - stop = jiffies + 2 * 60 * HZ; 6.135 - do { 6.136 - u8 status = chip->vendor->status(chip); 6.137 - if ((status & chip->vendor->req_complete_mask) == 6.138 - chip->vendor->req_complete_val) { 6.139 - goto out_recv; 6.140 - } 6.141 - 6.142 - if ((status == chip->vendor->req_canceled)) { 6.143 - dev_err(chip->dev, "Operation Canceled\n"); 6.144 - rc = -ECANCELED; 6.145 - goto out; 6.146 - } 6.147 - 6.148 - msleep(TPM_TIMEOUT); /* CHECK */ 6.149 - rmb(); 6.150 - } 6.151 - while (time_before(jiffies, stop)); 6.152 - 6.153 - 6.154 - chip->vendor->cancel(chip); 6.155 - dev_err(chip->dev, "Operation Timed out\n"); 6.156 - rc = -ETIME; 6.157 - goto out; 6.158 - 6.159 -out_recv: 6.160 - rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); 6.161 - if (rc < 0) 6.162 - dev_err(chip->dev, 6.163 - "tpm_transmit: tpm_recv: error %d\n", rc); 6.164 - atomic_set(&chip->data_position, 0); 6.165 - 6.166 -out: 6.167 - up(&chip->tpm_mutex); 6.168 - return rc; 6.169 -} 6.170 - 6.171 -EXPORT_SYMBOL_GPL(tpm_transmit); 6.172 - 6.173 -#define TPM_DIGEST_SIZE 20 6.174 -#define CAP_PCR_RESULT_SIZE 18 6.175 -static const u8 cap_pcr[] = { 6.176 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.177 - 0, 0, 0, 22, /* length */ 6.178 - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ 6.179 - 0, 0, 0, 5, 6.180 - 0, 0, 0, 4, 6.181 - 0, 0, 1, 1 6.182 -}; 6.183 - 6.184 -#define READ_PCR_RESULT_SIZE 30 6.185 -static const u8 pcrread[] = { 6.186 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.187 - 0, 0, 0, 14, /* length */ 6.188 - 0, 0, 0, 21, /* TPM_ORD_PcrRead */ 6.189 - 0, 0, 0, 0 /* PCR index */ 6.190 -}; 6.191 - 6.192 -ssize_t tpm_show_pcrs(struct device *dev, char *buf) 6.193 -{ 6.194 - u8 data[READ_PCR_RESULT_SIZE]; 6.195 - ssize_t len; 6.196 - int i, j, num_pcrs; 6.197 - __be32 index; 6.198 - char *str = buf; 6.199 - 6.200 - struct tpm_chip *chip = dev_get_drvdata(dev); 6.201 - if (chip == NULL) 6.202 - return -ENODEV; 6.203 - 6.204 - memcpy(data, cap_pcr, sizeof(cap_pcr)); 6.205 - if ((len = tpm_transmit(chip, data, sizeof(data))) 6.206 - < CAP_PCR_RESULT_SIZE) 6.207 - return len; 6.208 - 6.209 - num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); 6.210 - 6.211 - for (i = 0; i < num_pcrs; i++) { 6.212 - memcpy(data, pcrread, sizeof(pcrread)); 6.213 - index = cpu_to_be32(i); 6.214 - memcpy(data + 10, &index, 4); 6.215 - if ((len = tpm_transmit(chip, data, sizeof(data))) 6.216 - < READ_PCR_RESULT_SIZE) 6.217 - return len; 6.218 - str += sprintf(str, "PCR-%02d: ", i); 6.219 - for (j = 0; j < TPM_DIGEST_SIZE; j++) 6.220 - str += sprintf(str, "%02X ", *(data + 10 + j)); 6.221 - str += sprintf(str, "\n"); 6.222 - } 6.223 - return str - buf; 6.224 -} 6.225 - 6.226 -EXPORT_SYMBOL_GPL(tpm_show_pcrs); 6.227 - 6.228 -/* 6.229 - * Return 0 on success. On error pass along error code. 6.230 - * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY 6.231 - * Lower 2 bytes equal tpm idx # or AN& 6.232 - * res_buf must fit a TPM_PCR (20 bytes) or NULL if you don't care 6.233 - */ 6.234 -int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size ) 6.235 -{ 6.236 - u8 data[READ_PCR_RESULT_SIZE]; 6.237 - int rc; 6.238 - __be32 index; 6.239 - int chip_num = chip_id & TPM_CHIP_NUM_MASK; 6.240 - struct tpm_chip* chip; 6.241 - 6.242 - if ( res_buf && res_buf_size < TPM_DIGEST_SIZE ) 6.243 - return -ENOSPC; 6.244 - if ( (chip = tpm_chip_lookup( chip_num /*, 6.245 - chip_id >> TPM_CHIP_TYPE_SHIFT*/ ) ) == NULL ) { 6.246 - printk("chip %d not found.\n",chip_num); 6.247 - return -ENODEV; 6.248 - } 6.249 - memcpy(data, pcrread, sizeof(pcrread)); 6.250 - index = cpu_to_be32(pcr_idx); 6.251 - memcpy(data + 10, &index, 4); 6.252 - if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 ) 6.253 - rc = be32_to_cpu(*((u32*)(data+6))); 6.254 - 6.255 - if ( rc == 0 && res_buf ) 6.256 - memcpy(res_buf, data+10, TPM_DIGEST_SIZE); 6.257 - return rc; 6.258 -} 6.259 -EXPORT_SYMBOL_GPL(tpm_pcr_read); 6.260 - 6.261 -#define EXTEND_PCR_SIZE 34 6.262 -static const u8 pcrextend[] = { 6.263 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.264 - 0, 0, 0, 34, /* length */ 6.265 - 0, 0, 0, 20, /* TPM_ORD_Extend */ 6.266 - 0, 0, 0, 0 /* PCR index */ 6.267 -}; 6.268 - 6.269 -/* 6.270 - * Return 0 on success. On error pass along error code. 6.271 - * chip_id Upper 2 bytes equal ANY, HW_ONLY or SW_ONLY 6.272 - * Lower 2 bytes equal tpm idx # or ANY 6.273 - */ 6.274 -int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash) 6.275 -{ 6.276 - u8 data[EXTEND_PCR_SIZE]; 6.277 - int rc; 6.278 - __be32 index; 6.279 - int chip_num = chip_id & TPM_CHIP_NUM_MASK; 6.280 - struct tpm_chip* chip; 6.281 - 6.282 - if ( (chip = tpm_chip_lookup( chip_num /*, 6.283 - chip_id >> TPM_CHIP_TYPE_SHIFT */)) == NULL ) 6.284 - return -ENODEV; 6.285 - 6.286 - memcpy(data, pcrextend, sizeof(pcrextend)); 6.287 - index = cpu_to_be32(pcr_idx); 6.288 - memcpy(data + 10, &index, 4); 6.289 - memcpy( data + 14, hash, TPM_DIGEST_SIZE ); 6.290 - if ((rc = tpm_transmit(chip, data, sizeof(data))) > 0 ) 6.291 - rc = be32_to_cpu(*((u32*)(data+6))); 6.292 - return rc; 6.293 -} 6.294 -EXPORT_SYMBOL_GPL(tpm_pcr_extend); 6.295 - 6.296 - 6.297 - 6.298 -#define READ_PUBEK_RESULT_SIZE 314 6.299 -static const u8 readpubek[] = { 6.300 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.301 - 0, 0, 0, 30, /* length */ 6.302 - 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ 6.303 -}; 6.304 - 6.305 -ssize_t tpm_show_pubek(struct device *dev, char *buf) 6.306 -{ 6.307 - u8 *data; 6.308 - ssize_t len; 6.309 - int i, rc; 6.310 - char *str = buf; 6.311 - 6.312 - struct tpm_chip *chip = dev_get_drvdata(dev); 6.313 - if (chip == NULL) 6.314 - return -ENODEV; 6.315 - 6.316 - data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); 6.317 - if (!data) 6.318 - return -ENOMEM; 6.319 - 6.320 - memcpy(data, readpubek, sizeof(readpubek)); 6.321 - memset(data + sizeof(readpubek), 0, 20); /* zero nonce */ 6.322 - 6.323 - if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < 6.324 - READ_PUBEK_RESULT_SIZE) { 6.325 - rc = len; 6.326 - goto out; 6.327 - } 6.328 - 6.329 - /* 6.330 - ignore header 10 bytes 6.331 - algorithm 32 bits (1 == RSA ) 6.332 - encscheme 16 bits 6.333 - sigscheme 16 bits 6.334 - parameters (RSA 12->bytes: keybit, #primes, expbit) 6.335 - keylenbytes 32 bits 6.336 - 256 byte modulus 6.337 - ignore checksum 20 bytes 6.338 - */ 6.339 - 6.340 - str += 6.341 - sprintf(str, 6.342 - "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" 6.343 - "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X" 6.344 - " %02X %02X %02X %02X %02X %02X %02X %02X\n" 6.345 - "Modulus length: %d\nModulus: \n", 6.346 - data[10], data[11], data[12], data[13], data[14], 6.347 - data[15], data[16], data[17], data[22], data[23], 6.348 - data[24], data[25], data[26], data[27], data[28], 6.349 - data[29], data[30], data[31], data[32], data[33], 6.350 - be32_to_cpu(*((__be32 *) (data + 32)))); 6.351 - 6.352 - for (i = 0; i < 256; i++) { 6.353 - str += sprintf(str, "%02X ", data[i + 39]); 6.354 - if ((i + 1) % 16 == 0) 6.355 - str += sprintf(str, "\n"); 6.356 - } 6.357 - rc = str - buf; 6.358 -out: 6.359 - kfree(data); 6.360 - return rc; 6.361 -} 6.362 - 6.363 -EXPORT_SYMBOL_GPL(tpm_show_pubek); 6.364 - 6.365 -#define CAP_VER_RESULT_SIZE 18 6.366 -static const u8 cap_version[] = { 6.367 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.368 - 0, 0, 0, 18, /* length */ 6.369 - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ 6.370 - 0, 0, 0, 6, 6.371 - 0, 0, 0, 0 6.372 -}; 6.373 - 6.374 -#define CAP_MANUFACTURER_RESULT_SIZE 18 6.375 -static const u8 cap_manufacturer[] = { 6.376 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.377 - 0, 0, 0, 22, /* length */ 6.378 - 0, 0, 0, 101, /* TPM_ORD_GetCapability */ 6.379 - 0, 0, 0, 5, 6.380 - 0, 0, 0, 4, 6.381 - 0, 0, 1, 3 6.382 -}; 6.383 - 6.384 -ssize_t tpm_show_caps(struct device *dev, char *buf) 6.385 -{ 6.386 - u8 data[sizeof(cap_manufacturer)]; 6.387 - ssize_t len; 6.388 - char *str = buf; 6.389 - 6.390 - struct tpm_chip *chip = dev_get_drvdata(dev); 6.391 - if (chip == NULL) 6.392 - return -ENODEV; 6.393 - 6.394 - memcpy(data, cap_manufacturer, sizeof(cap_manufacturer)); 6.395 - 6.396 - if ((len = tpm_transmit(chip, data, sizeof(data))) < 6.397 - CAP_MANUFACTURER_RESULT_SIZE) 6.398 - return len; 6.399 - 6.400 - str += sprintf(str, "Manufacturer: 0x%x\n", 6.401 - be32_to_cpu(*((__be32 *)(data + 14)))); 6.402 - 6.403 - memcpy(data, cap_version, sizeof(cap_version)); 6.404 - 6.405 - if ((len = tpm_transmit(chip, data, sizeof(data))) < 6.406 - CAP_VER_RESULT_SIZE) 6.407 - return len; 6.408 - 6.409 - str += 6.410 - sprintf(str, "TCG version: %d.%d\nFirmware version: %d.%d\n", 6.411 - (int) data[14], (int) data[15], (int) data[16], 6.412 - (int) data[17]); 6.413 - 6.414 - return str - buf; 6.415 -} 6.416 - 6.417 -EXPORT_SYMBOL_GPL(tpm_show_caps); 6.418 - 6.419 -ssize_t tpm_store_cancel(struct device * dev, const char *buf, 6.420 - size_t count) 6.421 -{ 6.422 - struct tpm_chip *chip = dev_get_drvdata(dev); 6.423 - if (chip == NULL) 6.424 - return 0; 6.425 - 6.426 - chip->vendor->cancel(chip); 6.427 - return count; 6.428 -} 6.429 - 6.430 -EXPORT_SYMBOL_GPL(tpm_store_cancel); 6.431 - 6.432 -/* 6.433 - * Device file system interface to the TPM 6.434 - */ 6.435 -int tpm_open(struct inode *inode, struct file *file) 6.436 -{ 6.437 - int rc = 0, minor = iminor(inode); 6.438 - struct tpm_chip *chip = NULL, *pos; 6.439 - 6.440 - spin_lock(&driver_lock); 6.441 - 6.442 - list_for_each_entry(pos, &tpm_chip_list, list) { 6.443 - if (pos->vendor->miscdev.minor == minor) { 6.444 - chip = pos; 6.445 - break; 6.446 - } 6.447 - } 6.448 - 6.449 - if (chip == NULL) { 6.450 - rc = -ENODEV; 6.451 - goto err_out; 6.452 - } 6.453 - 6.454 - if (chip->num_opens) { 6.455 - dev_dbg(chip->dev, "Another process owns this TPM\n"); 6.456 - rc = -EBUSY; 6.457 - goto err_out; 6.458 - } 6.459 - 6.460 - chip->num_opens++; 6.461 - get_device(chip->dev); 6.462 - 6.463 - spin_unlock(&driver_lock); 6.464 - 6.465 - chip->data_buffer = kmalloc(chip->vendor->buffersize * sizeof(u8), 6.466 - GFP_KERNEL); 6.467 - if (chip->data_buffer == NULL) { 6.468 - chip->num_opens--; 6.469 - put_device(chip->dev); 6.470 - return -ENOMEM; 6.471 - } 6.472 - 6.473 - atomic_set(&chip->data_pending, 0); 6.474 - 6.475 - file->private_data = chip; 6.476 - return 0; 6.477 - 6.478 -err_out: 6.479 - spin_unlock(&driver_lock); 6.480 - return rc; 6.481 -} 6.482 - 6.483 -EXPORT_SYMBOL_GPL(tpm_open); 6.484 - 6.485 -int tpm_release(struct inode *inode, struct file *file) 6.486 -{ 6.487 - struct tpm_chip *chip = file->private_data; 6.488 - 6.489 - spin_lock(&driver_lock); 6.490 - file->private_data = NULL; 6.491 - chip->num_opens--; 6.492 - del_singleshot_timer_sync(&chip->user_read_timer); 6.493 - atomic_set(&chip->data_pending, 0); 6.494 - put_device(chip->dev); 6.495 - kfree(chip->data_buffer); 6.496 - spin_unlock(&driver_lock); 6.497 - return 0; 6.498 -} 6.499 - 6.500 -EXPORT_SYMBOL_GPL(tpm_release); 6.501 - 6.502 -ssize_t tpm_write(struct file * file, const char __user * buf, 6.503 - size_t size, loff_t * off) 6.504 -{ 6.505 - struct tpm_chip *chip = file->private_data; 6.506 - int in_size = size, out_size; 6.507 - 6.508 - /* cannot perform a write until the read has cleared 6.509 - either via tpm_read or a user_read_timer timeout */ 6.510 - while (atomic_read(&chip->data_pending) != 0) 6.511 - msleep(TPM_TIMEOUT); 6.512 - 6.513 - down(&chip->buffer_mutex); 6.514 - 6.515 - if (in_size > chip->vendor->buffersize) 6.516 - in_size = chip->vendor->buffersize; 6.517 - 6.518 - if (copy_from_user 6.519 - (chip->data_buffer, (void __user *) buf, in_size)) { 6.520 - up(&chip->buffer_mutex); 6.521 - return -EFAULT; 6.522 - } 6.523 - 6.524 - /* atomic tpm command send and result receive */ 6.525 - out_size = tpm_transmit(chip, 6.526 - chip->data_buffer, 6.527 - chip->vendor->buffersize); 6.528 - 6.529 - atomic_set(&chip->data_pending, out_size); 6.530 - up(&chip->buffer_mutex); 6.531 - 6.532 - /* Set a timeout by which the reader must come claim the result */ 6.533 - mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); 6.534 - 6.535 - return in_size; 6.536 -} 6.537 - 6.538 -EXPORT_SYMBOL_GPL(tpm_write); 6.539 - 6.540 -ssize_t tpm_read(struct file * file, char __user * buf, 6.541 - size_t size, loff_t * off) 6.542 -{ 6.543 - struct tpm_chip *chip = file->private_data; 6.544 - int ret_size; 6.545 - 6.546 - del_singleshot_timer_sync(&chip->user_read_timer); 6.547 - ret_size = atomic_read(&chip->data_pending); 6.548 - 6.549 - if (ret_size > 0) { /* relay data */ 6.550 - int position = atomic_read(&chip->data_position); 6.551 - 6.552 - if (size < ret_size) 6.553 - ret_size = size; 6.554 - 6.555 - down(&chip->buffer_mutex); 6.556 - 6.557 - if (copy_to_user((void __user *) buf, 6.558 - &chip->data_buffer[position], 6.559 - ret_size)) { 6.560 - ret_size = -EFAULT; 6.561 - } else { 6.562 - int pending = atomic_read(&chip->data_pending) - ret_size; 6.563 - atomic_set(&chip->data_pending, 6.564 - pending); 6.565 - atomic_set(&chip->data_position, 6.566 - position + ret_size); 6.567 - } 6.568 - up(&chip->buffer_mutex); 6.569 - } 6.570 - 6.571 - return ret_size; 6.572 -} 6.573 - 6.574 -EXPORT_SYMBOL_GPL(tpm_read); 6.575 - 6.576 -void tpm_remove_hardware(struct device *dev) 6.577 -{ 6.578 - struct tpm_chip *chip = dev_get_drvdata(dev); 6.579 - int i; 6.580 - 6.581 - if (chip == NULL) { 6.582 - dev_err(dev, "No device data found\n"); 6.583 - return; 6.584 - } 6.585 - 6.586 - spin_lock(&driver_lock); 6.587 - 6.588 - list_del(&chip->list); 6.589 - 6.590 - spin_unlock(&driver_lock); 6.591 - 6.592 - dev_set_drvdata(dev, NULL); 6.593 - misc_deregister(&chip->vendor->miscdev); 6.594 - 6.595 - for (i = 0; i < TPM_NUM_ATTR; i++) 6.596 - device_remove_file(dev, &chip->vendor->attr[i]); 6.597 - 6.598 - dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES] &= 6.599 - !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); 6.600 - 6.601 - kfree(chip); 6.602 - 6.603 - put_device(dev); 6.604 -} 6.605 - 6.606 -EXPORT_SYMBOL_GPL(tpm_remove_hardware); 6.607 - 6.608 -static const u8 savestate[] = { 6.609 - 0, 193, /* TPM_TAG_RQU_COMMAND */ 6.610 - 0, 0, 0, 10, /* blob length (in bytes) */ 6.611 - 0, 0, 0, 152 /* TPM_ORD_SaveState */ 6.612 -}; 6.613 - 6.614 -/* 6.615 - * We are about to suspend. Save the TPM state 6.616 - * so that it can be restored. 6.617 - */ 6.618 -int tpm_pm_suspend(struct pci_dev *pci_dev, u32 pm_state) 6.619 -{ 6.620 - struct tpm_chip *chip = pci_get_drvdata(pci_dev); 6.621 - if (chip == NULL) 6.622 - return -ENODEV; 6.623 - 6.624 - tpm_transmit(chip, savestate, sizeof(savestate)); 6.625 - return 0; 6.626 -} 6.627 - 6.628 -EXPORT_SYMBOL_GPL(tpm_pm_suspend); 6.629 - 6.630 -/* 6.631 - * Resume from a power safe. The BIOS already restored 6.632 - * the TPM state. 6.633 - */ 6.634 -int tpm_pm_resume(struct pci_dev *pci_dev) 6.635 -{ 6.636 - struct tpm_chip *chip = pci_get_drvdata(pci_dev); 6.637 - 6.638 - if (chip == NULL) 6.639 - return -ENODEV; 6.640 - 6.641 - return 0; 6.642 -} 6.643 - 6.644 -EXPORT_SYMBOL_GPL(tpm_pm_resume); 6.645 - 6.646 -/* 6.647 - * Called from tpm_<specific>.c probe function only for devices 6.648 - * the driver has determined it should claim. Prior to calling 6.649 - * this function the specific probe function has called pci_enable_device 6.650 - * upon errant exit from this function specific probe function should call 6.651 - * pci_disable_device 6.652 - */ 6.653 -int tpm_register_hardware_nopci(struct device *dev, 6.654 - struct tpm_vendor_specific *entry) 6.655 -{ 6.656 - char devname[7]; 6.657 - struct tpm_chip *chip; 6.658 - int i, j; 6.659 - 6.660 - /* Driver specific per-device data */ 6.661 - chip = kmalloc(sizeof(*chip), GFP_KERNEL); 6.662 - if (chip == NULL) 6.663 - return -ENOMEM; 6.664 - 6.665 - memset(chip, 0, sizeof(struct tpm_chip)); 6.666 - 6.667 - init_MUTEX(&chip->buffer_mutex); 6.668 - init_MUTEX(&chip->tpm_mutex); 6.669 - INIT_LIST_HEAD(&chip->list); 6.670 - 6.671 - init_timer(&chip->user_read_timer); 6.672 - chip->user_read_timer.function = user_reader_timeout; 6.673 - chip->user_read_timer.data = (unsigned long) chip; 6.674 - 6.675 - chip->vendor = entry; 6.676 - 6.677 - if (entry->buffersize < TPM_MIN_BUFSIZE) { 6.678 - entry->buffersize = TPM_MIN_BUFSIZE; 6.679 - } else if (entry->buffersize > TPM_MAX_BUFSIZE) { 6.680 - entry->buffersize = TPM_MAX_BUFSIZE; 6.681 - } 6.682 - 6.683 - chip->dev_num = -1; 6.684 - 6.685 - for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) 6.686 - for (j = 0; j < 8 * sizeof(int); j++) 6.687 - if ((dev_mask[i] & (1 << j)) == 0) { 6.688 - chip->dev_num = 6.689 - i * TPM_NUM_MASK_ENTRIES + j; 6.690 - dev_mask[i] |= 1 << j; 6.691 - goto dev_num_search_complete; 6.692 - } 6.693 - 6.694 -dev_num_search_complete: 6.695 - if (chip->dev_num < 0) { 6.696 - dev_err(dev, "No available tpm device numbers\n"); 6.697 - kfree(chip); 6.698 - return -ENODEV; 6.699 - } else if (chip->dev_num == 0) 6.700 - chip->vendor->miscdev.minor = TPM_MINOR; 6.701 - else 6.702 - chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; 6.703 - 6.704 - snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num); 6.705 - chip->vendor->miscdev.name = devname; 6.706 - 6.707 - chip->vendor->miscdev.dev = dev; 6.708 - chip->dev = get_device(dev); 6.709 - 6.710 - 6.711 - if (misc_register(&chip->vendor->miscdev)) { 6.712 - dev_err(chip->dev, 6.713 - "unable to misc_register %s, minor %d\n", 6.714 - chip->vendor->miscdev.name, 6.715 - chip->vendor->miscdev.minor); 6.716 - put_device(dev); 6.717 - kfree(chip); 6.718 - dev_mask[i] &= !(1 << j); 6.719 - return -ENODEV; 6.720 - } 6.721 - 6.722 - spin_lock(&driver_lock); 6.723 - 6.724 - dev_set_drvdata(dev, chip); 6.725 - 6.726 - list_add(&chip->list, &tpm_chip_list); 6.727 - 6.728 - spin_unlock(&driver_lock); 6.729 - 6.730 - for (i = 0; i < TPM_NUM_ATTR; i++) 6.731 - device_create_file(dev, &chip->vendor->attr[i]); 6.732 - 6.733 - return 0; 6.734 -} 6.735 - 6.736 -EXPORT_SYMBOL_GPL(tpm_register_hardware_nopci); 6.737 - 6.738 -static int __init init_tpm(void) 6.739 -{ 6.740 - return 0; 6.741 -} 6.742 - 6.743 -static void __exit cleanup_tpm(void) 6.744 -{ 6.745 - 6.746 -} 6.747 - 6.748 -module_init(init_tpm); 6.749 -module_exit(cleanup_tpm); 6.750 - 6.751 -MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 6.752 -MODULE_DESCRIPTION("TPM Driver"); 6.753 -MODULE_VERSION("2.0"); 6.754 -MODULE_LICENSE("GPL");
7.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nopci.h Wed Oct 05 13:41:59 2005 +0100 7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 7.3 @@ -1,128 +0,0 @@ 7.4 -/* 7.5 - * Copyright (C) 2004 IBM Corporation 7.6 - * 7.7 - * Authors: 7.8 - * Leendert van Doorn <leendert@watson.ibm.com> 7.9 - * Dave Safford <safford@watson.ibm.com> 7.10 - * Reiner Sailer <sailer@watson.ibm.com> 7.11 - * Kylene Hall <kjhall@us.ibm.com> 7.12 - * 7.13 - * Maintained by: <tpmdd_devel@lists.sourceforge.net> 7.14 - * 7.15 - * Device driver for TCG/TCPA TPM (trusted platform module). 7.16 - * Specifications at www.trustedcomputinggroup.org 7.17 - * 7.18 - * This program is free software; you can redistribute it and/or 7.19 - * modify it under the terms of the GNU General Public License as 7.20 - * published by the Free Software Foundation, version 2 of the 7.21 - * License. 7.22 - * 7.23 - */ 7.24 -#include <linux/module.h> 7.25 -#include <linux/version.h> 7.26 -#include <linux/pci.h> 7.27 -#include <linux/delay.h> 7.28 -#include <linux/miscdevice.h> 7.29 - 7.30 -enum { 7.31 - TPM_TIMEOUT = 5, /* msecs */ 7.32 - TPM_NUM_ATTR = 4 7.33 -}; 7.34 - 7.35 -/* TPM addresses */ 7.36 -enum { 7.37 - TPM_ADDR = 0x4E, 7.38 - TPM_DATA = 0x4F 7.39 -}; 7.40 - 7.41 -/* 7.42 - * Chip num is this value or a valid tpm idx in lower two bytes of chip_id 7.43 - */ 7.44 -enum tpm_chip_num { 7.45 - TPM_ANY_NUM = 0xFFFF, 7.46 -}; 7.47 - 7.48 -#define TPM_CHIP_NUM_MASK 0x0000ffff 7.49 - 7.50 -extern ssize_t tpm_show_pubek(struct device *, char *); 7.51 -extern ssize_t tpm_show_pcrs(struct device *, char *); 7.52 -extern ssize_t tpm_show_caps(struct device *, char *); 7.53 -extern ssize_t tpm_store_cancel(struct device *, const char *, size_t); 7.54 - 7.55 -#define TPM_DEVICE_ATTRS { \ 7.56 - __ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL), \ 7.57 - __ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL), \ 7.58 - __ATTR(caps, S_IRUGO, tpm_show_caps, NULL), \ 7.59 - __ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel) } 7.60 - 7.61 -struct tpm_chip; 7.62 - 7.63 -struct tpm_vendor_specific { 7.64 - u8 req_complete_mask; 7.65 - u8 req_complete_val; 7.66 - u8 req_canceled; 7.67 - u16 base; /* TPM base address */ 7.68 - u32 buffersize; /* The device's requested buffersize */ 7.69 - 7.70 - int (*recv) (struct tpm_chip *, u8 *, size_t); 7.71 - int (*send) (struct tpm_chip *, u8 *, size_t); 7.72 - void (*cancel) (struct tpm_chip *); 7.73 - u8(*status) (struct tpm_chip *); 7.74 - struct miscdevice miscdev; 7.75 - struct device_attribute attr[TPM_NUM_ATTR]; 7.76 -}; 7.77 - 7.78 -struct tpm_chip { 7.79 - struct device *dev; /* PCI device stuff */ 7.80 - 7.81 - int dev_num; /* /dev/tpm# */ 7.82 - int num_opens; /* only one allowed */ 7.83 - int time_expired; 7.84 - 7.85 - /* Data passed to and from the tpm via the read/write calls */ 7.86 - u8 *data_buffer; 7.87 - atomic_t data_pending; 7.88 - atomic_t data_position; 7.89 - struct semaphore buffer_mutex; 7.90 - 7.91 - struct timer_list user_read_timer; /* user needs to claim result */ 7.92 - struct semaphore tpm_mutex; /* tpm is processing */ 7.93 - 7.94 - struct tpm_vendor_specific *vendor; 7.95 - 7.96 - struct list_head list; 7.97 -}; 7.98 - 7.99 -static inline int tpm_read_index(int index) 7.100 -{ 7.101 - outb(index, TPM_ADDR); 7.102 - return inb(TPM_DATA) & 0xFF; 7.103 -} 7.104 - 7.105 -static inline void tpm_write_index(int index, int value) 7.106 -{ 7.107 - outb(index, TPM_ADDR); 7.108 - outb(value & 0xFF, TPM_DATA); 7.109 -} 7.110 - 7.111 -extern void tpm_time_expired(unsigned long); 7.112 -extern int tpm_lpc_bus_init(struct pci_dev *, u16); 7.113 - 7.114 -extern int tpm_register_hardware_nopci(struct device *, 7.115 - struct tpm_vendor_specific *); 7.116 -extern void tpm_remove_hardware(struct device *); 7.117 -extern int tpm_open(struct inode *, struct file *); 7.118 -extern int tpm_release(struct inode *, struct file *); 7.119 -extern ssize_t tpm_write(struct file *, const char __user *, size_t, 7.120 - loff_t *); 7.121 -extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); 7.122 -extern int tpm_pcr_extend(u32 chip_id, int pcr_idx, const u8* hash); 7.123 -extern int tpm_pcr_read( u32 chip_id, int pcr_idx, u8* res_buf, int res_buf_size ); 7.124 - 7.125 -extern int tpm_pm_suspend(struct pci_dev *, u32); 7.126 -extern int tpm_pm_resume(struct pci_dev *); 7.127 - 7.128 -/* internal kernel interface */ 7.129 -extern ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, 7.130 - size_t bufsiz); 7.131 -extern struct tpm_chip *tpm_chip_lookup(int chip_num);
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_nsc.c Wed Oct 05 13:52:18 2005 +0100 8.3 @@ -0,0 +1,386 @@ 8.4 +/* 8.5 + * Copyright (C) 2004 IBM Corporation 8.6 + * 8.7 + * Authors: 8.8 + * Leendert van Doorn <leendert@watson.ibm.com> 8.9 + * Dave Safford <safford@watson.ibm.com> 8.10 + * Reiner Sailer <sailer@watson.ibm.com> 8.11 + * Kylene Hall <kjhall@us.ibm.com> 8.12 + * 8.13 + * Maintained by: <tpmdd_devel@lists.sourceforge.net> 8.14 + * 8.15 + * Device driver for TCG/TCPA TPM (trusted platform module). 8.16 + * Specifications at www.trustedcomputinggroup.org 8.17 + * 8.18 + * This program is free software; you can redistribute it and/or 8.19 + * modify it under the terms of the GNU General Public License as 8.20 + * published by the Free Software Foundation, version 2 of the 8.21 + * License. 8.22 + * 8.23 + */ 8.24 + 8.25 +#include "tpm.h" 8.26 + 8.27 +/* National definitions */ 8.28 +enum tpm_nsc_addr{ 8.29 + TPM_NSC_IRQ = 0x07, 8.30 + TPM_NSC_BASE0_HI = 0x60, 8.31 + TPM_NSC_BASE0_LO = 0x61, 8.32 + TPM_NSC_BASE1_HI = 0x62, 8.33 + TPM_NSC_BASE1_LO = 0x63 8.34 +}; 8.35 + 8.36 +enum tpm_nsc_index { 8.37 + NSC_LDN_INDEX = 0x07, 8.38 + NSC_SID_INDEX = 0x20, 8.39 + NSC_LDC_INDEX = 0x30, 8.40 + NSC_DIO_INDEX = 0x60, 8.41 + NSC_CIO_INDEX = 0x62, 8.42 + NSC_IRQ_INDEX = 0x70, 8.43 + NSC_ITS_INDEX = 0x71 8.44 +}; 8.45 + 8.46 +enum tpm_nsc_status_loc { 8.47 + NSC_STATUS = 0x01, 8.48 + NSC_COMMAND = 0x01, 8.49 + NSC_DATA = 0x00 8.50 +}; 8.51 + 8.52 +/* status bits */ 8.53 +enum tpm_nsc_status { 8.54 + NSC_STATUS_OBF = 0x01, /* output buffer full */ 8.55 + NSC_STATUS_IBF = 0x02, /* input buffer full */ 8.56 + NSC_STATUS_F0 = 0x04, /* F0 */ 8.57 + NSC_STATUS_A2 = 0x08, /* A2 */ 8.58 + NSC_STATUS_RDY = 0x10, /* ready to receive command */ 8.59 + NSC_STATUS_IBR = 0x20 /* ready to receive data */ 8.60 +}; 8.61 + 8.62 +/* command bits */ 8.63 +enum tpm_nsc_cmd_mode { 8.64 + NSC_COMMAND_NORMAL = 0x01, /* normal mode */ 8.65 + NSC_COMMAND_EOC = 0x03, 8.66 + NSC_COMMAND_CANCEL = 0x22 8.67 +}; 8.68 +/* 8.69 + * Wait for a certain status to appear 8.70 + */ 8.71 +static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) 8.72 +{ 8.73 + unsigned long stop; 8.74 + 8.75 + /* status immediately available check */ 8.76 + *data = inb(chip->vendor->base + NSC_STATUS); 8.77 + if ((*data & mask) == val) 8.78 + return 0; 8.79 + 8.80 + /* wait for status */ 8.81 + stop = jiffies + 10 * HZ; 8.82 + do { 8.83 + msleep(TPM_TIMEOUT); 8.84 + *data = inb(chip->vendor->base + 1); 8.85 + if ((*data & mask) == val) 8.86 + return 0; 8.87 + } 8.88 + while (time_before(jiffies, stop)); 8.89 + 8.90 + return -EBUSY; 8.91 +} 8.92 + 8.93 +static int nsc_wait_for_ready(struct tpm_chip *chip) 8.94 +{ 8.95 + int status; 8.96 + unsigned long stop; 8.97 + 8.98 + /* status immediately available check */ 8.99 + status = inb(chip->vendor->base + NSC_STATUS); 8.100 + if (status & NSC_STATUS_OBF) 8.101 + status = inb(chip->vendor->base + NSC_DATA); 8.102 + if (status & NSC_STATUS_RDY) 8.103 + return 0; 8.104 + 8.105 + /* wait for status */ 8.106 + stop = jiffies + 100; 8.107 + do { 8.108 + msleep(TPM_TIMEOUT); 8.109 + status = inb(chip->vendor->base + NSC_STATUS); 8.110 + if (status & NSC_STATUS_OBF) 8.111 + status = inb(chip->vendor->base + NSC_DATA); 8.112 + if (status & NSC_STATUS_RDY) 8.113 + return 0; 8.114 + } 8.115 + while (time_before(jiffies, stop)); 8.116 + 8.117 + dev_info(chip->dev, "wait for ready failed\n"); 8.118 + return -EBUSY; 8.119 +} 8.120 + 8.121 + 8.122 +static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) 8.123 +{ 8.124 + u8 *buffer = buf; 8.125 + u8 data, *p; 8.126 + u32 size; 8.127 + __be32 *native_size; 8.128 + 8.129 + if (count < 6) 8.130 + return -EIO; 8.131 + 8.132 + if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) { 8.133 + dev_err(chip->dev, "F0 timeout\n"); 8.134 + return -EIO; 8.135 + } 8.136 + if ((data = 8.137 + inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) { 8.138 + dev_err(chip->dev, "not in normal mode (0x%x)\n", 8.139 + data); 8.140 + return -EIO; 8.141 + } 8.142 + 8.143 + /* read the whole packet */ 8.144 + for (p = buffer; p < &buffer[count]; p++) { 8.145 + if (wait_for_stat 8.146 + (chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) { 8.147 + dev_err(chip->dev, 8.148 + "OBF timeout (while reading data)\n"); 8.149 + return -EIO; 8.150 + } 8.151 + if (data & NSC_STATUS_F0) 8.152 + break; 8.153 + *p = inb(chip->vendor->base + NSC_DATA); 8.154 + } 8.155 + 8.156 + if ((data & NSC_STATUS_F0) == 0 && 8.157 + (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { 8.158 + dev_err(chip->dev, "F0 not set\n"); 8.159 + return -EIO; 8.160 + } 8.161 + if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) { 8.162 + dev_err(chip->dev, 8.163 + "expected end of command(0x%x)\n", data); 8.164 + return -EIO; 8.165 + } 8.166 + 8.167 + native_size = (__force __be32 *) (buf + 2); 8.168 + size = be32_to_cpu(*native_size); 8.169 + 8.170 + if (count < size) 8.171 + return -EIO; 8.172 + 8.173 + return size; 8.174 +} 8.175 + 8.176 +static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count) 8.177 +{ 8.178 + u8 data; 8.179 + int i; 8.180 + 8.181 + /* 8.182 + * If we hit the chip with back to back commands it locks up 8.183 + * and never set IBF. Hitting it with this "hammer" seems to 8.184 + * fix it. Not sure why this is needed, we followed the flow 8.185 + * chart in the manual to the letter. 8.186 + */ 8.187 + outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); 8.188 + 8.189 + if (nsc_wait_for_ready(chip) != 0) 8.190 + return -EIO; 8.191 + 8.192 + if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { 8.193 + dev_err(chip->dev, "IBF timeout\n"); 8.194 + return -EIO; 8.195 + } 8.196 + 8.197 + outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND); 8.198 + if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { 8.199 + dev_err(chip->dev, "IBR timeout\n"); 8.200 + return -EIO; 8.201 + } 8.202 + 8.203 + for (i = 0; i < count; i++) { 8.204 + if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { 8.205 + dev_err(chip->dev, 8.206 + "IBF timeout (while writing data)\n"); 8.207 + return -EIO; 8.208 + } 8.209 + outb(buf[i], chip->vendor->base + NSC_DATA); 8.210 + } 8.211 + 8.212 + if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { 8.213 + dev_err(chip->dev, "IBF timeout\n"); 8.214 + return -EIO; 8.215 + } 8.216 + outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND); 8.217 + 8.218 + return count; 8.219 +} 8.220 + 8.221 +static void tpm_nsc_cancel(struct tpm_chip *chip) 8.222 +{ 8.223 + outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); 8.224 +} 8.225 + 8.226 +static u8 tpm_nsc_status(struct tpm_chip *chip) 8.227 +{ 8.228 + return inb(chip->vendor->base + NSC_STATUS); 8.229 +} 8.230 + 8.231 +static struct file_operations nsc_ops = { 8.232 + .owner = THIS_MODULE, 8.233 + .llseek = no_llseek, 8.234 + .open = tpm_open, 8.235 + .read = tpm_read, 8.236 + .write = tpm_write, 8.237 + .release = tpm_release, 8.238 +}; 8.239 + 8.240 +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 8.241 +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 8.242 +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 8.243 +static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel); 8.244 + 8.245 +static struct attribute * nsc_attrs[] = { 8.246 + &dev_attr_pubek.attr, 8.247 + &dev_attr_pcrs.attr, 8.248 + &dev_attr_caps.attr, 8.249 + &dev_attr_cancel.attr, 8.250 + 0, 8.251 +}; 8.252 + 8.253 +static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; 8.254 + 8.255 +static struct tpm_vendor_specific tpm_nsc = { 8.256 + .recv = tpm_nsc_recv, 8.257 + .send = tpm_nsc_send, 8.258 + .cancel = tpm_nsc_cancel, 8.259 + .status = tpm_nsc_status, 8.260 + .req_complete_mask = NSC_STATUS_OBF, 8.261 + .req_complete_val = NSC_STATUS_OBF, 8.262 + .req_canceled = NSC_STATUS_RDY, 8.263 + .attr_group = &nsc_attr_grp, 8.264 + .miscdev = { .fops = &nsc_ops, }, 8.265 +}; 8.266 + 8.267 +static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, 8.268 + const struct pci_device_id *pci_id) 8.269 +{ 8.270 + int rc = 0; 8.271 + int lo, hi; 8.272 + int nscAddrBase = TPM_ADDR; 8.273 + 8.274 + 8.275 + if (pci_enable_device(pci_dev)) 8.276 + return -EIO; 8.277 + 8.278 + /* select PM channel 1 */ 8.279 + tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12); 8.280 + 8.281 + /* verify that it is a National part (SID) */ 8.282 + if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { 8.283 + nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)| 8.284 + (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE); 8.285 + if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) { 8.286 + rc = -ENODEV; 8.287 + goto out_err; 8.288 + } 8.289 + } 8.290 + 8.291 + hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); 8.292 + lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); 8.293 + tpm_nsc.base = (hi<<8) | lo; 8.294 + 8.295 + dev_dbg(&pci_dev->dev, "NSC TPM detected\n"); 8.296 + dev_dbg(&pci_dev->dev, 8.297 + "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", 8.298 + tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20), 8.299 + tpm_read_index(nscAddrBase,0x27)); 8.300 + dev_dbg(&pci_dev->dev, 8.301 + "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n", 8.302 + tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25), 8.303 + tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28)); 8.304 + dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n", 8.305 + (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61)); 8.306 + dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n", 8.307 + (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63)); 8.308 + dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n", 8.309 + tpm_read_index(nscAddrBase,0x70)); 8.310 + dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n", 8.311 + tpm_read_index(nscAddrBase,0x71)); 8.312 + dev_dbg(&pci_dev->dev, 8.313 + "NSC DMA channel select0 0x%x, select1 0x%x\n", 8.314 + tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75)); 8.315 + dev_dbg(&pci_dev->dev, 8.316 + "NSC Config " 8.317 + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", 8.318 + tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1), 8.319 + tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3), 8.320 + tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5), 8.321 + tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7), 8.322 + tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9)); 8.323 + 8.324 + dev_info(&pci_dev->dev, 8.325 + "NSC TPM revision %d\n", 8.326 + tpm_read_index(nscAddrBase, 0x27) & 0x1F); 8.327 + 8.328 + /* enable the DPM module */ 8.329 + tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); 8.330 + 8.331 + if ((rc = tpm_register_hardware(&pci_dev->dev, &tpm_nsc)) < 0) 8.332 + goto out_err; 8.333 + 8.334 + return 0; 8.335 + 8.336 +out_err: 8.337 + pci_disable_device(pci_dev); 8.338 + return rc; 8.339 +} 8.340 + 8.341 +static void __devexit tpm_nsc_remove(struct pci_dev *pci_dev) 8.342 +{ 8.343 + struct tpm_chip *chip = pci_get_drvdata(pci_dev); 8.344 + 8.345 + if ( chip ) 8.346 + tpm_remove_hardware(chip->dev); 8.347 +} 8.348 + 8.349 +static struct pci_device_id tpm_pci_tbl[] __devinitdata = { 8.350 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, 8.351 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, 8.352 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, 8.353 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, 8.354 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, 8.355 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, 8.356 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, 8.357 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, 8.358 + {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, 8.359 + {0,} 8.360 +}; 8.361 + 8.362 +MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); 8.363 + 8.364 +static struct pci_driver nsc_pci_driver = { 8.365 + .name = "tpm_nsc", 8.366 + .id_table = tpm_pci_tbl, 8.367 + .probe = tpm_nsc_init, 8.368 + .remove = __devexit_p(tpm_nsc_remove), 8.369 + .suspend = tpm_pm_suspend, 8.370 + .resume = tpm_pm_resume, 8.371 +}; 8.372 + 8.373 +static int __init init_nsc(void) 8.374 +{ 8.375 + return pci_register_driver(&nsc_pci_driver); 8.376 +} 8.377 + 8.378 +static void __exit cleanup_nsc(void) 8.379 +{ 8.380 + pci_unregister_driver(&nsc_pci_driver); 8.381 +} 8.382 + 8.383 +fs_initcall(init_nsc); 8.384 +module_exit(cleanup_nsc); 8.385 + 8.386 +MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 8.387 +MODULE_DESCRIPTION("TPM Driver"); 8.388 +MODULE_VERSION("2.0"); 8.389 +MODULE_LICENSE("GPL");
9.1 --- a/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c Wed Oct 05 13:41:59 2005 +0100 9.2 +++ b/linux-2.6-xen-sparse/drivers/char/tpm/tpm_xen.c Wed Oct 05 13:52:18 2005 +0100 9.3 @@ -25,7 +25,7 @@ 9.4 #include <linux/tpmfe.h> 9.5 #include <linux/device.h> 9.6 #include <linux/interrupt.h> 9.7 -#include "tpm_nopci.h" 9.8 +#include "tpm.h" 9.9 9.10 /* read status bits */ 9.11 enum { 9.12 @@ -434,6 +434,21 @@ static struct file_operations tpm_xen_op 9.13 .release = tpm_release, 9.14 }; 9.15 9.16 +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 9.17 +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 9.18 +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 9.19 +static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); 9.20 + 9.21 +static struct attribute* xen_attrs[] = { 9.22 + &dev_attr_pubek.attr, 9.23 + &dev_attr_pcrs.attr, 9.24 + &dev_attr_caps.attr, 9.25 + &dev_attr_cancel.attr, 9.26 + 0, 9.27 +}; 9.28 + 9.29 +static struct attribute_group xen_attr_grp = { .attrs = xen_attrs }; 9.30 + 9.31 static struct tpm_vendor_specific tpm_xen = { 9.32 .recv = tpm_xen_recv, 9.33 .send = tpm_xen_send, 9.34 @@ -443,7 +458,7 @@ static struct tpm_vendor_specific tpm_xe 9.35 .req_complete_val = STATUS_DATA_AVAIL, 9.36 .req_canceled = STATUS_READY, 9.37 .base = 0, 9.38 - .attr = TPM_DEVICE_ATTRS, 9.39 + .attr_group = &xen_attr_grp, 9.40 .miscdev.fops = &tpm_xen_ops, 9.41 .buffersize = 64 * 1024, 9.42 }; 9.43 @@ -480,7 +495,7 @@ static int __init init_xen(void) 9.44 9.45 tpm_xen.buffersize = tpmfe.max_tx_size; 9.46 9.47 - if ((rc = tpm_register_hardware_nopci(&tpm_device, &tpm_xen)) < 0) { 9.48 + if ((rc = tpm_register_hardware(&tpm_device, &tpm_xen)) < 0) { 9.49 device_unregister(&tpm_device); 9.50 tpm_fe_unregister_receiver(); 9.51 return rc;
10.1 --- a/patches/linux-2.6.12/tpm_partial_read.patch Wed Oct 05 13:41:59 2005 +0100 10.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 10.3 @@ -1,74 +0,0 @@ 10.4 ---- ref-linux-2.6.12/drivers/char/tpm/tpm.c 2005-06-17 15:48:29.000000000 -0400 10.5 -+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.c 2005-09-15 14:56:05.000000000 -0400 10.6 -@@ -473,6 +401,7 @@ ssize_t tpm_write(struct file * file, co 10.7 - out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); 10.8 - 10.9 - atomic_set(&chip->data_pending, out_size); 10.10 -+ atomic_set(&chip->data_position, 0); 10.11 - up(&chip->buffer_mutex); 10.12 - 10.13 - /* Set a timeout by which the reader must come claim the result */ 10.14 -@@ -494,29 +423,34 @@ ssize_t tpm_read(struct file * file, cha 10.15 - { 10.16 - struct tpm_chip *chip = file->private_data; 10.17 - int ret_size = -ENODATA; 10.18 -+ int pos, pending = 0; 10.19 - 10.20 -- if (atomic_read(&chip->data_pending) != 0) { /* Result available */ 10.21 -+ down(&chip->buffer_mutex); 10.22 -+ ret_size = atomic_read(&chip->data_pending); 10.23 -+ if ( ret_size > 0 ) { /* Result available */ 10.24 -+ if (size < ret_size) 10.25 -+ ret_size = size; 10.26 -+ 10.27 -+ pos = atomic_read(&chip->data_position); 10.28 -+ 10.29 -+ if (copy_to_user((void __user *) buf, 10.30 -+ &chip->data_buffer[pos], ret_size)) { 10.31 -+ ret_size = -EFAULT; 10.32 -+ } else { 10.33 -+ pending = atomic_read(&chip->data_pending) - ret_size; 10.34 -+ if ( pending ) { 10.35 -+ atomic_set( &chip->data_pending, pending ); 10.36 -+ atomic_set( &chip->data_position, pos+ret_size ); 10.37 -+ } 10.38 -+ } 10.39 -+ } 10.40 -+ up(&chip->buffer_mutex); 10.41 -+ 10.42 -+ if ( ret_size <= 0 || pending == 0 ) { 10.43 -+ atomic_set( &chip->data_pending, 0 ); 10.44 - down(&chip->timer_manipulation_mutex); 10.45 - del_singleshot_timer_sync(&chip->user_read_timer); 10.46 - up(&chip->timer_manipulation_mutex); 10.47 -- 10.48 -- down(&chip->buffer_mutex); 10.49 -- 10.50 -- ret_size = atomic_read(&chip->data_pending); 10.51 -- atomic_set(&chip->data_pending, 0); 10.52 -- 10.53 -- if (ret_size == 0) /* timeout just occurred */ 10.54 -- ret_size = -ETIME; 10.55 -- else if (ret_size > 0) { /* relay data */ 10.56 -- if (size < ret_size) 10.57 -- ret_size = size; 10.58 -- 10.59 -- if (copy_to_user((void __user *) buf, 10.60 -- chip->data_buffer, ret_size)) { 10.61 -- ret_size = -EFAULT; 10.62 -- } 10.63 -- } 10.64 -- up(&chip->buffer_mutex); 10.65 - } 10.66 - 10.67 - return ret_size; 10.68 ---- ref-linux-2.6.12/drivers/char/tpm/tpm.h 2005-06-17 15:48:29.000000000 -0400 10.69 -+++ linux-2.6-xen-sparse/drivers/char/tpm/tpm.h 2005-09-15 14:56:05.000000000 -0400 10.70 -@@ -54,6 +54,7 @@ struct tpm_chip { 10.71 - /* Data passed to and from the tpm via the read/write calls */ 10.72 - u8 *data_buffer; 10.73 - atomic_t data_pending; 10.74 -+ atomic_t data_position; 10.75 - struct semaphore buffer_mutex; 10.76 - 10.77 - struct timer_list user_read_timer; /* user needs to claim result */