From: Stefan Berger <stefanb@linux.vnet.ibm.com>
To: stefanb@linux.vnet.ibm.com, seabios@seabios.org
Cc: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH V5 1/9] Add an implementation of a TPM TIS driver
Date: Wed, 06 Jul 2011 12:31:59 -0400 [thread overview]
Message-ID: <20110706163232.471254631@linux.vnet.ibm.com> (raw)
In-Reply-To: 20110706163158.459850865@linux.vnet.ibm.com
[-- Attachment #1: tcgbios_tpm_drivers.diff --]
[-- Type: text/plain, Size: 8073 bytes --]
This patch adds an implementation of a TPM TIS driver for the TPM TIS
emulation supported by Qemu (patches posted, not in git yet). Usage of the
driver is broken up into several functions. The driver is cleanly separated
from the rest of the code through an interface holding pointers to the driver's
functions. A client using this driver first probes whether the TPM TIS
interface is available (probe function) and then invokes the interface
function to initialze the interface and send requests and receive responses.
Possible future extensions *could* include a virtio interface for the TPM
with a corresponding driver here.
v5:
- introducing a configurable threashold as part of the driver interface
structure below which the TPM is used for calculating the sha1
v2:
- adapted tpm_drivers.c to be under LGPLv3
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
src/tpm_drivers.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/tpm_drivers.h | 58 +++++++++++++++
2 files changed, 257 insertions(+)
Index: seabios/src/tpm_drivers.c
===================================================================
--- /dev/null
+++ seabios/src/tpm_drivers.c
@@ -0,0 +1,199 @@
+// Implementation of a TPM driver for the TPM TIS interface
+//
+// Copyright (C) 2006-2011 IBM Corporation
+// Copyright (C) 2006-2011 Stefan Berger <stefanb@us.ibm.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "config.h"
+#include "util.h"
+#include "tpm_drivers.h"
+#include "tcgbios.h"
+
+/* if device is not there, return '0', '1' otherwise */
+static u32 tis_probe(void)
+{
+ u32 rc = 0;
+ u32 didvid = readl(TIS_REG(0, TIS_REG_DID_VID));
+
+ if ((didvid != 0) && (didvid != 0xffffffff))
+ rc = 1;
+
+ return rc;
+}
+
+static u32 tis_init(void)
+{
+ writeb(TIS_REG(0, TIS_REG_INT_ENABLE), 0);
+
+ return 1;
+}
+
+static u32 tis_wait_sts(u8 locty, u32 time, u8 mask, u8 expect)
+{
+ u32 rc = 1;
+
+ while (time > 0) {
+ u8 sts = readb(TIS_REG(locty, TIS_REG_STS));
+ if ((sts & mask) == expect) {
+ rc = 0;
+ break;
+ }
+ msleep(1);
+ time--;
+ }
+ return rc;
+}
+
+static u32 tis_activate(u8 locty)
+{
+ u32 rc = 0;
+ u8 acc;
+ int l;
+
+ if (!(readb(TIS_REG(locty, TIS_REG_ACCESS)) &
+ TIS_ACCESS_ACTIVE_LOCALITY)) {
+ /* release locality in use top-downwards */
+ for (l = 4; l >= 0; l--)
+ writeb(TIS_REG(l, TIS_REG_ACCESS),
+ TIS_ACCESS_ACTIVE_LOCALITY);
+ }
+
+ /* request access to locality */
+ writeb(TIS_REG(locty, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+ acc = readb(TIS_REG(locty, TIS_REG_ACCESS));
+ if ((acc & TIS_ACCESS_ACTIVE_LOCALITY)) {
+ writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+ rc = tis_wait_sts(locty, 1000,
+ TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
+ }
+
+ return rc;
+}
+
+static u32 tis_find_active_locality(void)
+{
+ u8 locty;
+
+ for (locty = 0; locty <= 4; locty++) {
+ if ((readb(TIS_REG(locty, TIS_REG_ACCESS)) &
+ TIS_ACCESS_ACTIVE_LOCALITY))
+ return locty;
+ }
+
+ tis_activate(0);
+
+ return 0;
+}
+
+static u32 tis_ready(void)
+{
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+
+ writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+ rc = tis_wait_sts(locty, 1000,
+ TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
+
+ return rc;
+}
+
+static u32 tis_senddata(const u8 *const data, u32 len)
+{
+ u32 rc = 0;
+ u32 offset = 0;
+ u32 end = 0;
+ u16 burst = 0;
+ u32 ctr = 0;
+ u8 locty = tis_find_active_locality();
+
+ do {
+ while (burst == 0 && ctr < 2000) {
+ burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
+ if (burst == 0) {
+ msleep(1);
+ ctr++;
+ }
+ }
+
+ if (burst == 0) {
+ rc = TCG_RESPONSE_TIMEOUT;
+ break;
+ }
+
+ while (1) {
+ writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), data[offset++]);
+ burst--;
+
+ if (burst == 0 || offset == len)
+ break;
+ }
+
+ if (offset == len)
+ end = 1;
+ } while (end == 0);
+
+ return rc;
+}
+
+static u32 tis_readresp(u8 *buffer, u32 *len)
+{
+ u32 rc = 0;
+ u32 offset = 0;
+ u32 sts;
+ u8 locty = tis_find_active_locality();
+
+ while (offset < *len) {
+ buffer[offset] = readb(TIS_REG(locty, TIS_REG_DATA_FIFO));
+ offset++;
+ sts = readb(TIS_REG(locty, TIS_REG_STS));
+ /* data left ? */
+ if ((sts & TIS_STS_DATA_AVAILABLE) == 0)
+ break;
+ }
+
+ *len = offset;
+
+ return rc;
+}
+
+
+static u32 tis_waitdatavalid(void)
+{
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+
+ if (tis_wait_sts(locty, 1000, TIS_STS_VALID, TIS_STS_VALID) != 0)
+ rc = TCG_NO_RESPONSE;
+
+ return rc;
+}
+
+static u32 tis_waitrespready(u32 timeout)
+{
+ u32 rc = 0;
+ u8 locty = tis_find_active_locality();
+
+ writeb(TIS_REG(locty ,TIS_REG_STS), TIS_STS_TPM_GO);
+
+ if (tis_wait_sts(locty, timeout,
+ TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE) != 0)
+ rc = TCG_NO_RESPONSE;
+
+ return rc;
+}
+
+struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = {
+ {
+ .probe = tis_probe,
+ .init = tis_init,
+ .activate = tis_activate,
+ .ready = tis_ready,
+ .senddata = tis_senddata,
+ .readresp = tis_readresp,
+ .waitdatavalid = tis_waitdatavalid,
+ .waitrespready = tis_waitrespready,
+ .sha1threshold = 100 * 1024,
+ },
+};
Index: seabios/src/tpm_drivers.h
===================================================================
--- /dev/null
+++ seabios/src/tpm_drivers.h
@@ -0,0 +1,58 @@
+#ifndef TPM_DRIVERS_H
+
+#include "types.h" // u32
+
+/* low level driver implementation */
+struct tpm_driver {
+ u32 (*probe)(void);
+ u32 (*init)(void);
+ u32 (*activate)(u8 locty);
+ u32 (*ready)(void);
+ u32 (*senddata)(const u8 *const data, u32 len);
+ u32 (*readresp)(u8 *buffer, u32 *len);
+ u32 (*waitdatavalid)(void);
+ u32 (*waitrespready)(u32 timeout);
+ /* the TPM will be used for buffers of sizes below the sha1threshold
+ for calculating the hash */
+ u32 sha1threshold;
+};
+
+#define TPM_NUM_DRIVERS 1
+
+#define TPM_INVALID_DRIVER -1
+
+/* TIS driver */
+/* address of locality 0 (TIS) */
+#define TPM_TIS_BASE_ADDRESS 0xfed40000
+
+#define TIS_REG(LOCTY, REG) \
+ (void *)(TPM_TIS_BASE_ADDRESS + (LOCTY << 12) + REG)
+
+/* hardware registers */
+#define TIS_REG_ACCESS 0x0
+#define TIS_REG_INT_ENABLE 0x8
+#define TIS_REG_INT_VECTOR 0xc
+#define TIS_REG_INT_STATUS 0x10
+#define TIS_REG_INTF_CAPABILITY 0x14
+#define TIS_REG_STS 0x18
+#define TIS_REG_DATA_FIFO 0x24
+#define TIS_REG_DID_VID 0xf00
+#define TIS_REG_RID 0xf04
+
+#define TIS_STS_VALID (1 << 7) /* 0x80 */
+#define TIS_STS_COMMAND_READY (1 << 6) /* 0x40 */
+#define TIS_STS_TPM_GO (1 << 5) /* 0x20 */
+#define TIS_STS_DATA_AVAILABLE (1 << 4) /* 0x10 */
+#define TIS_STS_EXPECT (1 << 3) /* 0x08 */
+#define TIS_STS_RESPONSE_RETRY (1 << 1) /* 0x02 */
+
+#define TIS_ACCESS_TPM_REG_VALID_STS (1 << 7) /* 0x80 */
+#define TIS_ACCESS_ACTIVE_LOCALITY (1 << 5) /* 0x20 */
+#define TIS_ACCESS_BEEN_SEIZED (1 << 4) /* 0x10 */
+#define TIS_ACCESS_SEIZE (1 << 3) /* 0x08 */
+#define TIS_ACCESS_PENDING_REQUEST (1 << 2) /* 0x04 */
+#define TIS_ACCESS_REQUEST_USE (1 << 1) /* 0x02 */
+#define TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0) /* 0x01 */
+
+
+#endif /* TPM_DRIVERS_H */
next prev parent reply other threads:[~2011-07-06 16:56 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-07-06 16:31 [Qemu-devel] [PATCH V5 0/9] Add TPM support to SeaBIOS Stefan Berger
2011-07-06 16:31 ` Stefan Berger [this message]
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 2/9] Provide ACPI SSDT table for TPM device + S3 resume support Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 3/9] Add public get_rsdp function Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 4/9] Implementation of the TCG BIOS extensions Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 5/9] Support for BIOS interrupt handler Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 6/9] Add measurement code to the BIOS Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 7/9] Add a menu for TPM control Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 8/9] Support for Qemu-provided measurements Stefan Berger
2011-07-06 16:32 ` [Qemu-devel] [PATCH V5 9/9] Optional tests for the TIS interface Stefan Berger
2011-07-06 22:58 ` [Qemu-devel] [SeaBIOS] [PATCH V5 0/9] Add TPM support to SeaBIOS Kevin O'Connor
2011-07-07 11:48 ` Stefan Berger
2011-07-07 12:43 ` Kevin O'Connor
2011-07-07 15:22 ` Stefan Berger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110706163232.471254631@linux.vnet.ibm.com \
--to=stefanb@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
--cc=seabios@seabios.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).