From patchwork Wed Jul 6 16:31:59 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 103562 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 36C24B6F6B for ; Thu, 7 Jul 2011 04:11:28 +1000 (EST) Received: from localhost ([::1]:52151 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QeWZI-0004Mr-AS for incoming@patchwork.ozlabs.org; Wed, 06 Jul 2011 14:11:24 -0400 Received: from eggs.gnu.org ([140.186.70.92]:55375) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QeVP4-0001vO-IZ for qemu-devel@nongnu.org; Wed, 06 Jul 2011 12:56:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QeVOx-00040L-O8 for qemu-devel@nongnu.org; Wed, 06 Jul 2011 12:56:46 -0400 Received: from e6.ny.us.ibm.com ([32.97.182.146]:45233) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QeVOx-00040H-1K for qemu-devel@nongnu.org; Wed, 06 Jul 2011 12:56:39 -0400 Received: from d01relay04.pok.ibm.com (d01relay04.pok.ibm.com [9.56.227.236]) by e6.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p66GWVk5019800 for ; Wed, 6 Jul 2011 12:32:31 -0400 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d01relay04.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p66GuZNp122682 for ; Wed, 6 Jul 2011 12:56:37 -0400 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p66AtbdP029111 for ; Wed, 6 Jul 2011 04:55:37 -0600 Received: from localhost.localdomain (d941e-10.watson.ibm.com [9.59.241.154]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p66AtUOR028399 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 6 Jul 2011 04:55:34 -0600 Received: from localhost.localdomain (d941e-10 [127.0.0.1]) by localhost.localdomain (8.14.4/8.14.3) with ESMTP id p66GWWMD025641; Wed, 6 Jul 2011 12:32:32 -0400 Received: (from root@localhost) by localhost.localdomain (8.14.4/8.14.4/Submit) id p66GWWYO025640; Wed, 6 Jul 2011 12:32:32 -0400 Message-Id: <20110706163232.471254631@linux.vnet.ibm.com> User-Agent: quilt/0.48-1 Date: Wed, 06 Jul 2011 12:31:59 -0400 From: Stefan Berger To: stefanb@linux.vnet.ibm.com, seabios@seabios.org References: <20110706163158.459850865@linux.vnet.ibm.com> Content-Disposition: inline; filename=tcgbios_tpm_drivers.diff X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.182.146 Cc: qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH V5 1/9] Add an implementation of a TPM TIS driver X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 +// +// 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 */