Commit 4aea4047 authored by Kylene Hall's avatar Kylene Hall Committed by Greg Kroah-Hartman

[PATCH] Add TPM hardware enablement driver

This patch is a device driver to enable new hardware.  The new hardware is
the TPM chip as described by specifications at
<http://www.trustedcomputinggroup.org>.  The TPM chip will enable you to
use hardware to securely store and protect your keys and personal data.
To use the chip according to the specification, you will need the Trusted
Software Stack (TSS) of which an implementation for Linux is available at:
<http://sourceforge.net/projects/trousers>.
Signed-off-by: default avatarLeendert van Doorn <leendert@watson.ibm.com>
Signed-off-by: default avatarReiner Sailer <sailer@watson.ibm.com>
Signed-off-by: default avatarDave Safford <safford@watson.ibm.com>
Signed-off-by: default avatarKylene Hall <kjhall@us.ibm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 6365711d
......@@ -995,5 +995,7 @@ config MMTIMER
The mmtimer device allows direct userspace access to the
Altix system timer.
source "drivers/char/tpm/Kconfig"
endmenu
......@@ -89,7 +89,7 @@ obj-$(CONFIG_PCMCIA) += pcmcia/
obj-$(CONFIG_IPMI_HANDLER) += ipmi/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
......
#
# TPM device configuration
#
menu "TPM devices"
config TCG_TPM
tristate "TPM Hardware Support"
depends on EXPERIMENTAL
---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_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.
endmenu
#
# Makefile for the kernel tpm device drivers.
#
obj-$(CONFIG_TCG_TPM) += tpm.o
obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
This diff is collapsed.
/*
* Copyright (C) 2004 IBM Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*
*/
#include <linux/module.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
#define TPM_TIMEOUT msecs_to_jiffies(5)
/* TPM addresses */
#define TPM_ADDR 0x4E
#define TPM_DATA 0x4F
struct tpm_chip;
struct tpm_vendor_specific {
u8 req_complete_mask;
u8 req_complete_val;
u16 base; /* TPM base address */
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
struct miscdevice miscdev;
};
struct tpm_chip {
struct pci_dev *pci_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;
struct semaphore buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
struct semaphore tpm_mutex; /* tpm is processing */
struct timer_list device_timer; /* tpm is processing */
struct semaphore timer_manipulation_mutex;
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(struct pci_dev *,
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 __devexit tpm_remove(struct pci_dev *);
extern int tpm_pm_suspend(struct pci_dev *, u32);
extern int tpm_pm_resume(struct pci_dev *);
/*
* Copyright (C) 2004 IBM Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
* Dave Safford <safford@watson.ibm.com>
* Reiner Sailer <sailer@watson.ibm.com>
* Kylene Hall <kjhall@us.ibm.com>
*
* Maintained by: <tpmdd_devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
* Specifications at www.trustedcomputinggroup.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2 of the
* License.
*
*/
#include "tpm.h"
/* Atmel definitions */
#define TPM_ATML_BASE 0x400
/* write status bits */
#define ATML_STATUS_ABORT 0x01
#define ATML_STATUS_LASTBYTE 0x04
/* read status bits */
#define ATML_STATUS_BUSY 0x01
#define ATML_STATUS_DATA_AVAIL 0x02
#define ATML_STATUS_REWRITE 0x04
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->pci_dev->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->pci_dev->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->pci_dev->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->pci_dev->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->pci_dev->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->pci_dev->dev, "tpm_atml_send: ");
for (i = 0; i < count; i++) {
dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", 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 struct file_operations atmel_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
.read = tpm_read,
.write = tpm_write,
.release = tpm_release,
};
static struct tpm_vendor_specific tpm_atmel = {
.recv = tpm_atml_recv,
.send = tpm_atml_send,
.cancel = tpm_atml_cancel,
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
.req_complete_val = ATML_STATUS_DATA_AVAIL,
.base = TPM_ATML_BASE,
.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;
if (pci_enable_device(pci_dev))
return -EIO;
if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) {
rc = -ENODEV;
goto out_err;
}
/* verify that it is an Atmel part */
if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T'
|| tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') {
rc = -ENODEV;
goto out_err;
}
/* query chip for its version number */
if ((version[0] = tpm_read_index(0x00)) != 0xFF) {
version[1] = tpm_read_index(0x01);
version[2] = tpm_read_index(0x02);
version[3] = tpm_read_index(0x03);
} else {
dev_info(&pci_dev->dev, "version query failed\n");
rc = -ENODEV;
goto out_err;
}
if ((rc = tpm_register_hardware(pci_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 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_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{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_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);
}
module_init(init_atmel);
module_exit(cleanup_atmel);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
This diff is collapsed.
......@@ -519,6 +519,7 @@
#define PCI_DEVICE_ID_AMD_OPUS_7449 0x7449
# define PCI_DEVICE_ID_AMD_VIPER_7449 PCI_DEVICE_ID_AMD_OPUS_7449
#define PCI_DEVICE_ID_AMD_8111_LAN 0x7462
#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a
#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment