All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS
@ 2011-03-30 17:55 Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 1/8] Add an implementation for a TPM TIS driver Stefan Berger
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

The following set of patches add TPM and Trusted Computing support to SeaBIOS.
In particular the patches add:

- a TPM driver for the Qemu's TPM TIS emulation (not yet in Qemu git)
- ACPI support for the TPM device (SSDT table)
- ACPI support for measurement logging (TCPA table)
- Support for initialzation of the TPM
- Support for the TCG BIOS extensions (1ah handler [ah = 0xbb])
  (used by trusted grub; http://trousers.sourceforge.net/grub.html)
- Static Root of Trusted for Measurement (SRTM) support
- Support for S3 resume (sends command to TPM upon resume)
- TPM-specific menu for controlling aspects of the TPM
- [An optional test suite for the TIS interface]

All implementations necessarily follow specifications.

Regards,
 Stefan

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 1/8] Add an implementation for a TPM TIS driver
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support Stefan Berger
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios_tpm_drivers.diff --]
[-- Type: text/plain, Size: 8524 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.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 src/tpm_drivers.c |  215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tpm_drivers.h |   55 +++++++++++++
 2 files changed, 270 insertions(+)

Index: seabios/src/tpm_drivers.c
===================================================================
--- /dev/null
+++ seabios/src/tpm_drivers.c
@@ -0,0 +1,215 @@
+/*
+ *  Implementation of the TCG BIOS extension according to the specification
+ *  described in
+ *  https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006, 2010, 2011
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+
+#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;
+        }
+        mssleep(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) {
+                mssleep(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,
+    },
+};
Index: seabios/src/tpm_drivers.h
===================================================================
--- /dev/null
+++ seabios/src/tpm_drivers.h
@@ -0,0 +1,55 @@
+#ifndef TPM_DRIVERS_H
+
+#include "types.h"
+
+/* 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);
+};
+
+#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 */

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 1/8] Add an implementation for a TPM TIS driver Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-04-04  4:17   ` Kevin O'Connor
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions Stefan Berger
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios_acpi.diff --]
[-- Type: text/plain, Size: 7719 bytes --]

This patch provides ACPI support for the TPM device. It probes for the TPM
device and only if a TPM device is found then the TPM's SSDT and TCPA table
are created. This patch also connects them to the RSDT.

Since the logging area in the TCPA table requires 64kb, the memory reserved
for ACPI tables (config.h) is increased to 96kb in case CONFIG_TCGBIOS
is enabled.

This patch requires the subsequent patch for it to compile and work.

The IRQ description in the TPM's SSDT is commented since it will be
'safer' to run the TPM in polling mode - the Linux TPM TIS driver for example
has too many issues when run in interrupt mode.

The description of the TCPA (client) table can be found here:

http://www.trustedcomputinggroup.org/resources/server_work_group_acpi_general_specification_version_10

The compiled SSDT description is also part of this patch.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 Makefile              |    9 ++++++++-
 src/acpi-tpm-ssdt.dsl |   22 ++++++++++++++++++++++
 src/acpi-tpm-ssdt.hex |   34 ++++++++++++++++++++++++++++++++++
 src/acpi.c            |   41 +++++++++++++++++++++++++++++++++++++++++
 src/acpi.h            |   20 ++++++++++++++++++++
 src/config.h          |    6 +++++-
 6 files changed, 130 insertions(+), 2 deletions(-)

Index: seabios/src/acpi-tpm-ssdt.dsl
===================================================================
--- /dev/null
+++ seabios/src/acpi-tpm-ssdt.dsl
@@ -0,0 +1,22 @@
+DefinitionBlock (
+    "acpi-tpm-ssdt.aml",// Output Filename
+    "SSDT",             // Signature
+    0x01,               // SSDT Compliance Revision
+    "BXPC",             // OEMID
+    "BXSSDT",           // TABLE ID
+    0x1                 // OEM Revision
+    )
+{
+    /* TPM with emulated TPM TIS interface */
+    Device (TPM) {
+        Name (_HID, EisaID ("PNP0C31"))
+        Name (_CRS, ResourceTemplate ()
+        {
+                Memory32Fixed (ReadWrite, 0xFED40000, 0x00005000)
+                //IRQNoFlags () {11}
+        })
+        Method (_STA, 0, NotSerialized) {
+            Return (0x0F)
+        }
+    }
+}
Index: seabios/src/acpi-tpm-ssdt.hex
===================================================================
--- /dev/null
+++ seabios/src/acpi-tpm-ssdt.hex
@@ -0,0 +1,34 @@
+/*
+ * 
+ * Intel ACPI Component Architecture
+ * ASL Optimizing Compiler version 20101013-64 [Nov 21 2010]
+ * Copyright (c) 2000 - 2010 Intel Corporation
+ * 
+ * Compilation of "out/.dsl.i" - Sun Mar 13 20:44:32 2011
+ * 
+ * C source code output
+ * AML code block contains 0x93 bytes
+ *
+ */
+unsigned char AmlCode_TPM[] =
+{
+    0x53,0x53,0x44,0x54,0x93,0x00,0x00,0x00,  /* 00000000    "SSDT...." */
+    0x01,0xC3,0x42,0x58,0x50,0x43,0x00,0x00,  /* 00000008    "..BXPC.." */
+    0x42,0x58,0x53,0x53,0x44,0x54,0x00,0x00,  /* 00000010    "BXSSDT.." */
+    0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C,  /* 00000018    "....INTL" */
+    0x13,0x10,0x10,0x20,0x5B,0x82,0x4D,0x06,  /* 00000020    "... [.M." */
+    0x54,0x50,0x4D,0x5F,0x08,0x5F,0x48,0x49,  /* 00000028    "TPM_._HI" */
+    0x44,0x0C,0x41,0xD0,0x0C,0x31,0x08,0x5F,  /* 00000030    "D.A..1._" */
+    0x53,0x54,0x52,0x11,0x33,0x0A,0x30,0x45,  /* 00000038    "STR.3.0E" */
+    0x00,0x6D,0x00,0x75,0x00,0x6C,0x00,0x61,  /* 00000040    ".m.u.l.a" */
+    0x00,0x74,0x00,0x65,0x00,0x64,0x00,0x20,  /* 00000048    ".t.e.d. " */
+    0x00,0x54,0x00,0x50,0x00,0x4D,0x00,0x20,  /* 00000050    ".T.P.M. " */
+    0x00,0x54,0x00,0x49,0x00,0x53,0x00,0x20,  /* 00000058    ".T.I.S. " */
+    0x00,0x64,0x00,0x65,0x00,0x76,0x00,0x69,  /* 00000060    ".d.e.v.i" */
+    0x00,0x63,0x00,0x65,0x00,0x00,0x00,0x08,  /* 00000068    ".c.e...." */
+    0x5F,0x43,0x52,0x53,0x11,0x14,0x0A,0x11,  /* 00000070    "_CRS...." */
+    0x86,0x09,0x00,0x01,0x00,0x00,0xD4,0xFE,  /* 00000078    "........" */
+    0x00,0x50,0x00,0x00,0x22,0x00,0x08,0x79,  /* 00000080    ".P.."..y" */
+    0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00,  /* 00000088    "..._STA." */
+    0xA4,0x0A,0x0F                            /* 00000090    "..."      */
+};
Index: seabios/Makefile
===================================================================
--- seabios.orig/Makefile
+++ seabios/Makefile
@@ -192,13 +192,20 @@ $(OUT)vgabios.bin: $(OUT)vgabios.bin.raw
 	$(Q)./tools/buildrom.py $< $@
 
 ####### dsdt build rules
+src/acpi-tpm-ssdt.hex: src/acpi-tpm-ssdt.dsl
+	@echo "Compiling TPM SSDT"
+	$(Q)cpp -P $< > $(OUT)$*.dsl.i
+	$(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i
+	$(Q)cp $(OUT)$*.hex $@
+	$(Q)sed -i 's/AmlCode/AmlCode_TPM/' $@
+
 src/%.hex: src/%.dsl
 	@echo "Compiling DSDT"
 	$(Q)cpp -P $< > $(OUT)$*.dsl.i
 	$(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i
 	$(Q)cp $(OUT)$*.hex $@
 
-$(OUT)ccode32flat.o: src/acpi-dsdt.hex
+$(OUT)ccode32flat.o: src/acpi-dsdt.hex src/acpi-tpm-ssdt.hex
 
 ####### Kconfig rules
 export HOSTCC             := $(CC)
Index: seabios/src/acpi.c
===================================================================
--- seabios.orig/src/acpi.c
+++ seabios/src/acpi.c
@@ -13,6 +13,8 @@
 #include "pci_regs.h" // PCI_INTERRUPT_LINE
 #include "paravirt.h"
 #include "dev-i440fx.h" // piix4_fadt_init
+#include "acpi-tpm-ssdt.hex"
+#include "tcgbios.h" // has_working_tpm
 
 /****************************************************/
 /* ACPI tables init */
@@ -586,6 +588,39 @@ static const struct pci_device_id acpi_f
     PCI_DEVICE_END,
 };
 
+
+static u32 add_tpm_device(void **tpm_addr, void **tcpa_addr)
+{
+    struct tcpa_descriptor_rev2 *tcpa;
+
+    *tpm_addr = NULL;
+    *tcpa_addr = NULL;
+
+    if (has_working_tpm()) {
+        u32 laml = 64 * 1024;
+        *tpm_addr = malloc_high(sizeof(AmlCode_TPM));
+
+        tcpa = malloc_high(sizeof(*tcpa) + laml);
+        if (!tcpa || !*tpm_addr) {
+            warn_noalloc();
+            return 1;
+        }
+
+        if (*tpm_addr)
+            memcpy(*tpm_addr, AmlCode_TPM, sizeof(AmlCode_TPM));
+
+        memset(tcpa, 0x0, sizeof(*tcpa) + laml);
+        u64 lasa = (u32)tcpa + sizeof(*tcpa);
+
+        tcpa->laml = laml;
+        tcpa->lasa = lasa;
+        build_header((void*)tcpa, TCPA_SIGNATURE, sizeof(*tcpa), 2);
+
+        *tcpa_addr = tcpa;
+    }
+    return 0;
+}
+
 struct rsdp_descriptor *RsdpAddr;
 
 #define MAX_ACPI_TABLES 20
@@ -642,6 +677,12 @@ acpi_bios_init(void)
         }
     }
 
+    void *tcpa, *tpm;
+    if (add_tpm_device(&tpm, &tcpa))
+        return;
+    ACPI_INIT_TABLE(tpm);
+    ACPI_INIT_TABLE(tcpa);
+
     struct rsdt_descriptor_rev1 *rsdt;
     size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx;
     rsdt = malloc_high(rsdt_len);
Index: seabios/src/acpi.h
===================================================================
--- seabios.orig/src/acpi.h
+++ seabios/src/acpi.h
@@ -98,4 +98,24 @@ struct fadt_descriptor_rev1
 #endif
 } PACKED;
 
+
+struct rsdt_descriptor {
+    ACPI_TABLE_HEADER_DEF
+    u32 entry[1];
+} PACKED;
+
+#define TCPA_SIGNATURE 0x41504354
+struct tcpa_descriptor_rev2
+{
+    ACPI_TABLE_HEADER_DEF
+    u16  platform_class;
+    u32  laml;
+    u64  lasa;
+} PACKED;
+
+/* TCPA ACPI definitions */
+#define TCPA_ACPI_CLASS_CLIENT          0
+#define TCPA_ACPI_CLASS_SERVER          1
+
+
 #endif // acpi.h
Index: seabios/src/config.h
===================================================================
--- seabios.orig/src/config.h
+++ seabios/src/config.h
@@ -26,7 +26,11 @@
 // Space to reserve in f-segment for dynamic allocations
 #define CONFIG_MAX_BIOSTABLE 2048
 // Space to reserve in high-memory for tables
-#define CONFIG_MAX_HIGHTABLE (64*1024)
+#if CONFIG_TCGBIOS
+# define CONFIG_MAX_HIGHTABLE (96*1024)
+#else
+# define CONFIG_MAX_HIGHTABLE (64*1024)
+#endif
 // Largest supported externaly facing drive id
 #define CONFIG_MAX_EXTDRIVE 16
 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 1/8] Add an implementation for a TPM TIS driver Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-04-04  4:14   ` Kevin O'Connor
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 4/8] Build the TCG BIOS extensions and TPM drivers Stefan Berger
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios.diff --]
[-- Type: text/plain, Size: 26943 bytes --]

This patch implements the main part of the TCG BIOS extensions. It provides
the following functionality:

- initialization of the TCPA ACPI table used for logging of measurements
- initialization of the TPM by sending a sequence of commands to it
- proper setup of the TPM once the BIOS hands over control to the bootloader
- support for S3 resume; BIOS sends TPM_Startup(ST_STATE) to TPM
- a utility function called mssleep is added. It waits for a number
  of milliseconds before it returns. I had tried to build a function
  like that based on calc_future_time() and check_timer(), but those
  didn't work once in an S3 resume.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 src/boot.c    |    2 
 src/post.c    |    5 
 src/resume.c  |    2 
 src/tcgbios.c |  525 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tcgbios.h |  386 ++++++++++++++++++++++++++++++++++++++++++
 src/util.c    |   18 +
 src/util.h    |    5 
 7 files changed, 943 insertions(+)

Index: seabios/src/tcgbios.c
===================================================================
--- /dev/null
+++ seabios/src/tcgbios.c
@@ -0,0 +1,525 @@
+/*
+ *  Implementation of the TCG BIOS extension according to the specification
+ *  described in
+ *  https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006,2010,2011
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+
+#include "config.h"
+
+#if CONFIG_TCGBIOS
+
+#include "types.h"
+#include "tpm_drivers.h" // tpm_drivers[]
+#include "util.h" // printf, get_keystroke
+#include "tcgbios.h"// tcpa_*, prototypes
+#include "acpi.h"  // RSDP_SIGNATURE, rsdt_descriptor
+#include "smbios.h" // smbios_entry_point
+
+
+//#define DEBUG_TCGBIOS
+
+static const u8 Startup_ST_CLEAR[2] = { 0x00, TPM_ST_CLEAR };
+static const u8 Startup_ST_STATE[2] = { 0x00, TPM_ST_STATE };
+
+static const u8 PhysicalPresence_CMD_ENABLE[2]  = { 0x00, 0x20 };
+static const u8 PhysicalPresence_CMD_DISABLE[2] = { 0x01, 0x00 };
+static const u8 PhysicalPresence_PRESENT[2]     = { 0x00, 0x08 };
+static const u8 PhysicalPresence_NOT_PRESENT[2] = { 0x00, 0x10 };
+static const u8 PhysicalPresence_LOCK[2]        = { 0x00, 0x04 };
+
+static const u8 CommandFlag_FALSE[1] = { 0x00 };
+static const u8 CommandFlag_TRUE[1]  = { 0x01 };
+
+static const u8 GetCapability_Permanent_Flags[12] = {
+    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04,
+    0x00, 0x00, 0x01, 0x08
+};
+
+static const u8 GetCapability_OwnerAuth[12] = {
+    0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04,
+    0x00, 0x00, 0x01, 0x11
+};
+
+
+#define RSDP_CAST(ptr)   ((struct rsdp_descriptor *)ptr)
+
+
+/* helper functions */
+
+static inline void *input_buf32(struct bregs *regs)
+{
+    return MAKE_FLATPTR(regs->es, regs->di);
+}
+
+static inline void *output_buf32(struct bregs *regs)
+{
+    return MAKE_FLATPTR(regs->ds, regs->si);
+}
+
+
+typedef struct {
+    u8            tpm_probed:1;
+    u8            tpm_found:1;
+    u8            tpm_working:1;
+    u8            if_shutdown:1;
+    u8            tpm_driver_to_use:4;
+} tcpa_state_t;
+
+
+static tcpa_state_t tcpa_state = {
+    .tpm_driver_to_use = TPM_INVALID_DRIVER,
+};
+
+extern struct tpm_driver tpm_drivers[];
+
+
+/********************************************************
+  Extensions for TCG-enabled BIOS
+ *******************************************************/
+
+
+static u32
+is_tpm_present(void)
+{
+    u32 rc = 0;
+    unsigned int i;
+
+    for (i = 0; i < TPM_NUM_DRIVERS; i++) {
+        struct tpm_driver *td = &tpm_drivers[i];
+        if (td->probe() != 0) {
+            td->init();
+            tcpa_state.tpm_driver_to_use = i;
+            rc = 1;
+            break;
+        }
+    }
+
+    return rc;
+}
+
+
+int
+has_working_tpm(void)
+{
+    if (!tcpa_state.tpm_probed) {
+        tcpa_state.tpm_probed = 1;
+        tcpa_state.tpm_found = (is_tpm_present() != 0);
+        tcpa_state.tpm_working = 1;
+    }
+    if (!tcpa_state.tpm_working)
+        return 0;
+
+    return tcpa_state.tpm_found;
+}
+
+
+static u8
+calc_checksum(const u8 *addr, u32 length)
+{
+    u8 sum = 0;
+    u32 ctr;
+
+    for (ctr = 0; ctr < length; ctr++)
+        sum += addr[ctr];
+
+    return sum;
+}
+
+
+/*
+ * Search for the RSDP ACPI table in the memory starting at addr and
+ * ending at addr + len - 1.
+ */
+static struct rsdp_descriptor *
+find_rsdp(u8 *start, unsigned int len)
+{
+    u8 *end = start + len;
+
+    /* scan memory in steps of 16 bytes */
+    while (start < end) {
+        /* check for expected string */
+        if (RSDP_CAST(start)->signature == RSDP_SIGNATURE &&
+            calc_checksum(start,
+                          sizeof(struct rsdp_descriptor)) == 0)
+            return RSDP_CAST(start);
+        start += 0x10;
+    }
+
+    return 0;
+}
+
+
+
+
+static struct tcpa_descriptor_rev2 *
+find_tcpa_by_rsdp(struct rsdp_descriptor *rsdp)
+{
+    u32 ctr = 0;
+    struct tcpa_descriptor_rev2 *tcpa = NULL;
+    struct rsdt_descriptor *rsdt;
+    u32 length;
+    u16 off;
+
+    rsdt   = (struct rsdt_descriptor *)rsdp->rsdt_physical_address;
+    if (!rsdt)
+        return NULL;
+
+    length = rsdt->length;
+    off = offsetof(struct rsdt_descriptor, entry);
+
+    while ((off + sizeof(rsdt->entry[0])) <= length) {
+        /* try all pointers to structures */
+        tcpa = (struct tcpa_descriptor_rev2 *)(int)rsdt->entry[ctr];
+
+        /* valid TCPA ACPI table ? */
+        if (tcpa->signature == TCPA_SIGNATURE &&
+            calc_checksum((u8 *)tcpa, tcpa->length) == 0)
+            break;
+
+        tcpa = NULL;
+        off += sizeof(rsdt->entry[0]);
+        ctr++;
+    }
+
+    return tcpa;
+}
+
+
+static struct tcpa_descriptor_rev2 *
+find_tcpa_table(void)
+{
+    struct tcpa_descriptor_rev2 *tcpa = NULL;
+    struct rsdp_descriptor *rsdp;
+    u16 ebda_seg;
+
+    /* RSDP in EBDA? */
+    ebda_seg = *(u16 *)MAKE_FLATPTR(0x40, 0xe);
+    rsdp = find_rsdp(MAKE_FLATPTR(ebda_seg, 0), 1024);
+
+    if (rsdp)
+        tcpa = find_tcpa_by_rsdp(rsdp);
+
+    if (!tcpa) {
+        rsdp = find_rsdp((u8 *)0xE0000, 0x20000);
+        if (rsdp)
+            tcpa = find_tcpa_by_rsdp(rsdp);
+    }
+
+    if (!rsdp)
+        tcpa_state.if_shutdown = 1;
+
+#ifdef DEBUG_TCGBIOS
+    if (! rsdp )
+        dprintf(1, "TCGBIOS: RSDP was NOT found! -- Disabling interface.\n");
+    else if ( !tcpa )
+        dprintf(1, "TCGBIOS: TCPA ACPI was NOT found!\n");
+#endif
+
+    return tcpa;
+}
+
+
+static u8 *
+get_lasa_base_ptr(u32 *laml)
+{
+    u8 *lasa = 0;
+    struct tcpa_descriptor_rev2 *tcpa = find_tcpa_table();
+
+    if (tcpa) {
+        lasa = (u8 *)(long)tcpa->lasa;
+        if (laml)
+            *laml = tcpa->laml;
+    }
+
+    return lasa;
+}
+
+
+/* clear the ACPI log */
+static void
+reset_acpi_log(void)
+{
+    u32 laml;
+    u8 *lasa = get_lasa_base_ptr(&laml);
+
+    if (lasa)
+        memset(lasa, 0x0, laml);
+}
+
+
+/*
+   initialize the TCPA ACPI subsystem; find the ACPI tables and determine
+   where the TCPA table is.
+ */
+void
+tcpa_acpi_init(void)
+{
+    tcpa_state.if_shutdown = 0;
+    tcpa_state.tpm_probed = 0;
+    tcpa_state.tpm_found = 0;
+    tcpa_state.tpm_working = 0;
+
+    if (!has_working_tpm()) {
+        tcpa_state.if_shutdown = 1;
+        return;
+    }
+
+    reset_acpi_log();
+}
+
+
+static u32
+transmit(u8 locty, const struct iovec iovec[],
+         u8 *respbuffer, u32 *respbufferlen)
+{
+    u32 rc = 0;
+    u32 irc;
+    struct tpm_driver *td;
+    unsigned int i;
+
+    if (tcpa_state.tpm_driver_to_use == TPM_INVALID_DRIVER)
+        return TCG_FATAL_COM_ERROR;
+
+    td = &tpm_drivers[tcpa_state.tpm_driver_to_use];
+
+    irc = td->activate(locty);
+    if (irc != 0) {
+        /* tpm could not be activated */
+        return TCG_FATAL_COM_ERROR;
+    }
+
+    for (i = 0; iovec[i].length; i++) {
+        irc = td->senddata(iovec[i].data,
+                           iovec[i].length);
+        if (irc != 0)
+            return TCG_FATAL_COM_ERROR;
+    }
+
+    irc = td->waitdatavalid();
+    if (irc != 0)
+        return TCG_FATAL_COM_ERROR;
+
+    irc = td->waitrespready(10000);
+    if (irc != 0)
+        return TCG_FATAL_COM_ERROR;
+
+    irc = td->readresp(respbuffer,
+                       respbufferlen);
+    if (irc != 0)
+        return TCG_FATAL_COM_ERROR;
+
+    td->ready();
+
+    return rc;
+}
+
+
+/*
+ * Send a TPM command with the given ordinal. Append the given buffer
+ * containing all data in network byte order to the command (this is
+ * the custom part per command) and expect a response of the given size.
+ * If a buffer is provided, the response will be copied into it.
+ */
+static u32
+build_and_send_cmd_od(u32 ordinal, const u8 *append, u32 append_size,
+                      u8 *resbuffer, u32 return_size, u32 *returnCode,
+                      const u8 *otherdata, u32 otherdata_size)
+{
+#define MAX_APPEND_SIZE   12
+#define MAX_RESPONSE_SIZE sizeof(struct tpm_res_getcap_perm_flags)
+    u32 rc;
+    u8 ibuffer[TPM_REQ_HEADER_SIZE + MAX_APPEND_SIZE];
+    u8 obuffer[MAX_RESPONSE_SIZE];
+    struct tpm_req_header *trqh = (struct tpm_req_header *)ibuffer;
+    struct tpm_rsp_header *trsh = (struct tpm_rsp_header *)obuffer;
+    u8 locty = 0;
+    struct iovec iovec[3];
+    u32 obuffer_len = sizeof(obuffer);
+    u32 idx = 1;
+
+    if (append_size > MAX_APPEND_SIZE ||
+        return_size > MAX_RESPONSE_SIZE) {
+#ifdef DEBUG_TCGBIOS
+        dprintf(1, "TCGBIOS: size of requested buffers too big.");
+#endif
+        return TCG_FIRMWARE_ERROR;
+    }
+
+    iovec[0].data   = trqh;
+    iovec[0].length = TPM_REQ_HEADER_SIZE + append_size;
+
+    if (otherdata) {
+        iovec[1].data   = (void *)otherdata;
+        iovec[1].length = otherdata_size;
+        idx = 2;
+    }
+
+    iovec[idx].data   = NULL;
+    iovec[idx].length = 0;
+
+    memset(ibuffer, 0x0, sizeof(ibuffer));
+    memset(obuffer, 0x0, sizeof(obuffer));
+
+    trqh->tag     = htons(0xc1);
+    trqh->totlen  = htonl(TPM_REQ_HEADER_SIZE + append_size + otherdata_size);
+    trqh->ordinal = htonl(ordinal);
+
+    if (append_size)
+        memcpy((char *)trqh + sizeof(*trqh),
+               append, append_size);
+
+    rc = transmit(locty, iovec, obuffer, &obuffer_len);
+    if (rc)
+        return rc;
+
+    *returnCode = ntohl(trsh->errcode);
+
+    if (resbuffer)
+        memcpy(resbuffer, trsh, return_size);
+
+    return 0;
+}
+
+
+static u32
+build_and_send_cmd(u32 ordinal, const u8 *append, u32 append_size,
+                   u8 *resbuffer, u32 return_size, u32 *returnCode)
+{
+    return build_and_send_cmd_od(ordinal, append, append_size,
+                                 resbuffer, return_size, returnCode,
+                                 NULL, 0);
+}
+
+
+u32
+tcpa_startup(void)
+{
+    u32 rc = 0;
+    u32 returnCode;
+
+    if (!has_working_tpm())
+        return 0;
+
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: Starting with TPM_Startup(ST_CLEAR)\n");
+#endif
+    rc = build_and_send_cmd(TPM_ORD_Startup,
+                            Startup_ST_CLEAR, sizeof(Startup_ST_CLEAR),
+                            NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"Return code from TPM_Startup = 0x%08x\n",
+              returnCode);
+#endif
+    if (rc && returnCode)
+        goto err_exit;
+
+    rc = build_and_send_cmd(TPM_ORD_SelfTestFull, NULL, 0,
+                            NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"Return code from TPM_SelfTestFull = 0x%08x\n",
+              returnCode);
+#endif
+    if (rc || returnCode)
+        goto err_exit;
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+u32
+tcpa_leave_bios(void)
+{
+    u32 rc = 0;
+    u32 returnCode;
+
+    if (!has_working_tpm())
+        return 0;
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+                            PhysicalPresence_CMD_ENABLE,
+                            sizeof(PhysicalPresence_CMD_ENABLE),
+                            NULL, 10, &returnCode);
+    if (rc || returnCode)
+        goto err_exit;
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+                            PhysicalPresence_NOT_PRESENT,
+                            sizeof(PhysicalPresence_NOT_PRESENT),
+                            NULL, 10, &returnCode);
+    if (rc || returnCode)
+        goto err_exit;
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+u32
+tcpa_s3_resume(void)
+{
+    u32 rc = 0;
+    u32 returnCode;
+
+    if (has_working_tpm()) {
+        rc = build_and_send_cmd(TPM_ORD_Startup,
+                                Startup_ST_STATE,
+                                sizeof(Startup_ST_STATE),
+                                NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+        dprintf(1,"TCGBIOS: Resuming with TPM_Startup(ST_STATE)\n");
+        dprintf(1,"TCGBIOS: ReturnCode from TPM_Startup = 0x%08x\n",
+                  returnCode);
+#endif
+        if (rc || returnCode)
+            goto err_exit;
+    }
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+#endif /* CONFIG_TCGBIOS */
Index: seabios/src/tcgbios.h
===================================================================
--- /dev/null
+++ seabios/src/tcgbios.h
@@ -0,0 +1,386 @@
+#ifndef TCGBIOS_H
+#define TCGBIOS_H
+
+#include "types.h"
+#include "bregs.h" /* struct bregs */
+
+#define TCG_MAGIC 0x41504354L
+
+/* Define for section 12.3 */
+#define TCG_PC_OK                       0x0
+#define TCG_PC_TPMERROR                 0x1
+#define TCG_PC_LOGOVERFLOW              0x2
+#define TCG_PC_UNSUPPORTED              0x3
+
+#define TPM_ALG_SHA                     0x4
+
+#define TCG_MAGIC                       0x41504354L
+#define TCG_VERSION_MAJOR               1
+#define TCG_VERSION_MINOR               2
+
+#define TPM_OK                          0x0
+#define TPM_RET_BASE                    0x1
+#define TCG_GENERAL_ERROR               (TPM_RET_BASE + 0x0)
+#define TCG_TPM_IS_LOCKED               (TPM_RET_BASE + 0x1)
+#define TCG_NO_RESPONSE                 (TPM_RET_BASE + 0x2)
+#define TCG_INVALID_RESPONSE            (TPM_RET_BASE + 0x3)
+#define TCG_INVALID_ACCESS_REQUEST      (TPM_RET_BASE + 0x4)
+#define TCG_FIRMWARE_ERROR              (TPM_RET_BASE + 0x5)
+#define TCG_INTEGRITY_CHECK_FAILED      (TPM_RET_BASE + 0x6)
+#define TCG_INVALID_DEVICE_ID           (TPM_RET_BASE + 0x7)
+#define TCG_INVALID_VENDOR_ID           (TPM_RET_BASE + 0x8)
+#define TCG_UNABLE_TO_OPEN              (TPM_RET_BASE + 0x9)
+#define TCG_UNABLE_TO_CLOSE             (TPM_RET_BASE + 0xa)
+#define TCG_RESPONSE_TIMEOUT            (TPM_RET_BASE + 0xb)
+#define TCG_INVALID_COM_REQUEST         (TPM_RET_BASE + 0xc)
+#define TCG_INVALID_ADR_REQUEST         (TPM_RET_BASE + 0xd)
+#define TCG_WRITE_BYTE_ERROR            (TPM_RET_BASE + 0xe)
+#define TCG_READ_BYTE_ERROR             (TPM_RET_BASE + 0xf)
+#define TCG_BLOCK_WRITE_TIMEOUT         (TPM_RET_BASE + 0x10)
+#define TCG_CHAR_WRITE_TIMEOUT          (TPM_RET_BASE + 0x11)
+#define TCG_CHAR_READ_TIMEOUT           (TPM_RET_BASE + 0x12)
+#define TCG_BLOCK_READ_TIMEOUT          (TPM_RET_BASE + 0x13)
+#define TCG_TRANSFER_ABORT              (TPM_RET_BASE + 0x14)
+#define TCG_INVALID_DRV_FUNCTION        (TPM_RET_BASE + 0x15)
+#define TCG_OUTPUT_BUFFER_TOO_SHORT     (TPM_RET_BASE + 0x16)
+#define TCG_FATAL_COM_ERROR             (TPM_RET_BASE + 0x17)
+#define TCG_INVALID_INPUT_PARA          (TPM_RET_BASE + 0x18)
+#define TCG_TCG_COMMAND_ERROR           (TPM_RET_BASE + 0x19)
+#define TCG_INTERFACE_SHUTDOWN          (TPM_RET_BASE + 0x20)
+//define TCG_PC_UNSUPPORTED             (TPM_RET_BASE + 0x21)
+#define TCG_PC_TPM_NOT_PRESENT          (TPM_RET_BASE + 0x22)
+#define TCG_PC_TPM_DEACTIVATED          (TPM_RET_BASE + 0x23)
+
+
+#define TPM_INVALID_ADR_REQUEST          TCG_INVALID_ADR_REQUEST
+#define TPM_IS_LOCKED                    TCG_TPM_IS_LOCKED
+#define TPM_INVALID_DEVICE_ID            TCG_INVALID_DEVICE_ID
+#define TPM_INVALID_VENDOR_ID            TCG_INVALID_VENDOR_ID
+//define TPM_RESERVED_REG_INVALID
+#define TPM_FIRMWARE_ERROR               TCG_FIRMWARE_ERROR
+#define TPM_UNABLE_TO_OPEN               TCG_UNABLE_TO_OPEN
+#define TPM_UNABLE_TO_CLOSE              TCG_UNABLE_TO_CLOSE
+#define TPM_INVALID_RESPONSE             TCG_INVALID_RESPONSE
+#define TPM_RESPONSE_TIMEOUT             TCG_RESPONSE_TIMEOUT
+#define TPM_INVALID_ACCESS_REQUEST       TCG_INVALID_ACCESS_REQUEST
+#define TPM_TRANSFER_ABORT               TCG_TRANSFER_ABORT
+#define TPM_GENERAL_ERROR                TCG_GENERAL_ERROR
+
+
+#define TPM_ORD_SelfTestFull             0x00000050
+#define TPM_ORD_ForceClear               0x0000005d
+#define TPM_ORD_GetCapability            0x00000065
+#define TPM_ORD_PhysicalEnable           0x0000006f
+#define TPM_ORD_PhysicalDisable          0x00000070
+#define TPM_ORD_SetOwnerInstall          0x00000071
+#define TPM_ORD_PhysicalSetDeactivated   0x00000072
+#define TPM_ORD_Startup                  0x00000099
+#define TPM_ORD_PhysicalPresence         0x4000000a
+#define TPM_ORD_Extend                   0x00000014
+#define TPM_ORD_SHA1Start                0x000000a0
+#define TPM_ORD_SHA1Update               0x000000a1
+#define TPM_ORD_SHA1Complete             0x000000a2
+
+
+#define TPM_ST_CLEAR                     0x1
+#define TPM_ST_STATE                     0x2
+#define TPM_ST_DEACTIVATED               0x3
+
+
+/* interrupt identifiers (al register) */
+enum irq_ids {
+    TCG_StatusCheck = 0,
+    TCG_HashLogExtendEvent = 1,
+    TCG_PassThroughToTPM = 2,
+    TCG_ShutdownPreBootInterface = 3,
+    TCG_HashLogEvent = 4,
+    TCG_HashAll = 5,
+    TCG_TSS = 6,
+    TCG_CompactHashLogExtendEvent = 7,
+};
+
+/* event types: 10.4.1 / table 11 */
+#define EV_POST_CODE             1
+#define EV_SEPARATOR             4
+#define EV_ACTION                5
+#define EV_EVENT_TAG             6
+#define EV_COMPACT_HASH         12
+#define EV_IPL                  13
+#define EV_IPL_PARTITION_DATA   14
+
+
+#define STATUS_FLAG_SHUTDOWN        (1 << 0)
+
+#define SHA1_BUFSIZE                20
+
+
+struct iovec
+{
+    size_t length;
+    void   *data;
+};
+
+
+/* Input and Output blocks for the TCG BIOS commands */
+
+struct hleei_short
+{
+    u16   ipblength;
+    u16   reserved;
+    const void *hashdataptr;
+    u32   hashdatalen;
+    u32   pcrindex;
+    const void *logdataptr;
+    u32   logdatalen;
+} PACKED;
+
+
+struct hleei_long
+{
+    u16   ipblength;
+    u16   reserved;
+    void *hashdataptr;
+    u32   hashdatalen;
+    u32   pcrindex;
+    u32   reserved2;
+    void *logdataptr;
+    u32   logdatalen;
+} PACKED;
+
+
+struct hleeo
+{
+    u16    opblength;
+    u16    reserved;
+    u32    eventnumber;
+    u8     digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct pttti
+{
+    u16    ipblength;
+    u16    reserved;
+    u16    opblength;
+    u16    reserved2;
+    u8     tpmopin[0];
+} PACKED;
+
+
+struct pttto
+{
+    u16    opblength;
+    u16    reserved;
+    u8     tpmopout[0];
+};
+
+
+struct hlei
+{
+    u16    ipblength;
+    u16    reserved;
+    const void  *hashdataptr;
+    u32    hashdatalen;
+    u32    pcrindex;
+    u32    logeventtype;
+    const void  *logdataptr;
+    u32    logdatalen;
+} PACKED;
+
+
+struct hleo
+{
+    u16    opblength;
+    u16    reserved;
+    u32    eventnumber;
+} PACKED;
+
+
+struct hai
+{
+    u16    ipblength;
+    u16    reserved;
+    const void  *hashdataptr;
+    u32    hashdatalen;
+    u32    algorithmid;
+} PACKED;
+
+
+struct ti
+{
+    u16    ipblength;
+    u16    reserved;
+    u16    opblength;
+    u16    reserved2;
+    u8     tssoperandin[0];
+} PACKED;
+
+
+struct to
+{
+    u16    opblength;
+    u16    reserved;
+    u8     tssoperandout[0];
+} PACKED;
+
+
+struct pcpes
+{
+    u32    pcrindex;
+    u32    eventtype;
+    u8     digest[SHA1_BUFSIZE];
+    u32    eventdatasize;
+    u32    event;
+} PACKED;
+
+
+/* 10.4.2.1 */
+struct pcctes
+{
+    u32 eventid;
+    u32 eventdatasize;
+    u8  digest[SHA1_BUFSIZE];
+} PACKED;
+
+/* 10.4.2.1 w/ 10.4.2.2.1 embedded */
+struct pcctes_romex
+{
+    u32 eventid;
+    u32 eventdatasize;
+    u16 reserved;
+    u16 pfa;
+    u8  digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+#define TPM_REQ_HEADER \
+    u16    tag; \
+    u32    totlen; \
+    u32    ordinal;
+
+#define TPM_REQ_HEADER_SIZE  (sizeof(u16) + sizeof(u32) + sizeof(u32))
+
+#define TPM_RSP_HEADER \
+    u16    tag; \
+    u32    totlen; \
+    u32    errcode;
+
+#define TPM_RSP_HEADER_SIZE  (sizeof(u16) + sizeof(u32) + sizeof(u32))
+
+struct tpm_req_header {
+    TPM_REQ_HEADER;
+} PACKED;
+
+
+struct tpm_rsp_header {
+    TPM_RSP_HEADER;
+} PACKED;
+
+
+struct tpm_req_extend {
+    TPM_REQ_HEADER
+    u32    pcrindex;
+    u8     digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct tpm_rsp_extend {
+    TPM_RSP_HEADER
+    u8     digest[SHA1_BUFSIZE];
+} PACKED;
+
+
+struct tpm_req_getcap_perm_flags {
+    TPM_REQ_HEADER
+    u32    capArea;
+    u32    subCapSize;
+    u32    subCap;
+} PACKED;
+
+
+struct tpm_permanent_flags {
+    u16    tag;
+    u8     flags[20];
+} PACKED;
+
+
+enum permFlagsIndex {
+    PERM_FLAG_IDX_DISABLE = 0,
+    PERM_FLAG_IDX_OWNERSHIP,
+    PERM_FLAG_IDX_DEACTIVATED,
+    PERM_FLAG_IDX_READPUBEK,
+    PERM_FLAG_IDX_DISABLEOWNERCLEAR,
+    PERM_FLAG_IDX_ALLOW_MAINTENANCE,
+    PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK,
+    PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE,
+};
+
+
+struct tpm_res_getcap_perm_flags {
+    TPM_RSP_HEADER
+    u32    size;
+    struct tpm_permanent_flags perm_flags;
+} PACKED;
+
+
+struct tpm_res_getcap_ownerauth {
+    TPM_RSP_HEADER
+    u32    size;
+    u8     flag;
+} PACKED;
+
+
+struct tpm_res_sha1start {
+    TPM_RSP_HEADER
+    u32    max_num_bytes;
+} PACKED;
+
+
+struct tpm_res_sha1complete {
+    TPM_RSP_HEADER
+    u8     hash[20];
+} PACKED;
+
+struct pttti_extend {
+    struct pttti pttti;
+    struct tpm_req_extend req;
+} PACKED;
+
+
+struct pttto_extend {
+    struct pttto pttto;
+    struct tpm_rsp_extend rsp;
+} PACKED;
+
+
+enum ipltype {
+    IPL_BCV = 0,
+    IPL_EL_TORITO_1,
+    IPL_EL_TORITO_2
+};
+
+#if CONFIG_TCGBIOS
+void tcpa_acpi_init(void);
+int has_working_tpm(void);
+u32 tcpa_startup(void);
+u32 tcpa_leave_bios(void);
+u32 tcpa_s3_resume(void);
+#else
+static inline void tcpa_acpi_init(void) {
+}
+static inline int has_working_tpm(void) {
+    return 0;
+}
+static inline u32 tcpa_startup(void) {
+    return 0;
+}
+static inline u32 tcpa_leave_bios(void) {
+    return 0;
+}
+static inline u32 tcpa_s3_resume(void) {
+    return 0;
+}
+#endif
+void tcpa_menu(void);
+
+#endif /* TCGBIOS_H */
Index: seabios/src/util.c
===================================================================
--- seabios.orig/src/util.c
+++ seabios/src/util.c
@@ -322,3 +322,21 @@ get_keystroke(int msec)
         wait_irq();
     }
 }
+
+
+// wait a given time
+// this function also works in case of a resume
+void
+mssleep(u32 msec)
+{
+    u32 i;
+    u8 x, y = inb(0x61) & 0x10;
+
+    /* Poll the DRAM refresh timer: I/O port 61h, bit 4 toggles every 15us. */
+    msec *= (1000/15); /* Convert milliseconds to multiples of 15us. */
+    for ( i = 0; i < msec; i++ ) {
+        while ( (x = inb(0x61) & 0x10) == y )
+            continue;
+        y = x;
+    }
+}
Index: seabios/src/util.h
===================================================================
--- seabios.orig/src/util.h
+++ seabios/src/util.h
@@ -497,4 +497,9 @@ extern u8 BiosChecksum;
 // version (auto generated file out/version.c)
 extern const char VERSION[];
 
+
+void mssleep(u32 time);
+
+void tcpa_interrupt_handler16(struct bregs *regs);
+
 #endif // util.h
Index: seabios/src/post.c
===================================================================
--- seabios.orig/src/post.c
+++ seabios/src/post.c
@@ -25,6 +25,7 @@
 #include "paravirt.h" // qemu_cfg_port_probe
 #include "ps2port.h" // ps2port_setup
 #include "virtio-blk.h" // virtio_blk_setup
+#include "tcgbios.h" // tcpa_*
 
 
 /****************************************************************
@@ -238,6 +239,10 @@ maininit(void)
     mouse_setup();
     init_bios_tables();
 
+    // Initialize tpm (after acpi tables were written)
+    tcpa_acpi_init();
+    tcpa_startup();
+
     // Run vga option rom
     vga_setup();
 
Index: seabios/src/boot.c
===================================================================
--- seabios.orig/src/boot.c
+++ seabios/src/boot.c
@@ -14,6 +14,7 @@
 #include "cmos.h" // inb_cmos
 #include "paravirt.h" // romfile_loadfile
 #include "pci.h" //pci_bdf_to_*
+#include "tcgbios.h" // tcpa_*
 
 
 /****************************************************************
@@ -449,6 +450,7 @@ boot_prep(void)
     // Allow user to modify BCV/IPL order.
     interactive_bootmenu();
     wait_threads();
+    tcpa_leave_bios();
 
     // Map drives and populate BEV list
     struct bootentry_s *pos = BootList;
Index: seabios/src/resume.c
===================================================================
--- seabios.orig/src/resume.c
+++ seabios/src/resume.c
@@ -10,6 +10,7 @@
 #include "biosvar.h" // struct bios_data_area_s
 #include "bregs.h" // struct bregs
 #include "acpi.h" // find_resume_vector
+#include "tcgbios.h" // tcpa_s3_resume
 
 // Reset DMA controller
 void
@@ -116,6 +117,7 @@ s3_resume(void)
     if (s3_resume_vector) {
         dprintf(1, "Jump to resume vector (%x)\n", s3_resume_vector);
         br.code = FLATPTR_TO_SEGOFF((void*)s3_resume_vector);
+        tcpa_s3_resume();
     } else {
         dprintf(1, "No resume vector set!\n");
         // Jump to the post vector to restart with a normal boot.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 4/8] Build the TCG BIOS extensions and TPM drivers.
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
                   ` (2 preceding siblings ...)
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler Stefan Berger
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios_build.diff --]
[-- Type: text/plain, Size: 1515 bytes --]

This patch allows to configure the TCGBIOS extensions to be built
into SeaBIOS, depending on not COREBOOT being selected.

All TCG BIOS extensions are activated with CONFIG_TCGBIOS.

Add the two new code files (tcgbios.c, tpm_drivers.c) to be built.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 Makefile    |    2 +-
 src/Kconfig |    8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

Index: seabios/Makefile
===================================================================
--- seabios.orig/Makefile
+++ seabios/Makefile
@@ -20,7 +20,7 @@ SRC16=$(SRCBOTH) system.c disk.c font.c
 SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
       lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c dev-i440fx.c \
-      pci_region.c
+      pci_region.c tcgbios.c tpm_drivers.c
 SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
 
 cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
Index: seabios/src/Kconfig
===================================================================
--- seabios.orig/src/Kconfig
+++ seabios/src/Kconfig
@@ -314,6 +314,14 @@ menu "BIOS interfaces"
         default n
         help
             Disable A20 on 16bit boot.
+
+    config TCGBIOS
+        depends on !COREBOOT
+        bool "TPM support and TCG BIOS extensions"
+        default y
+        help
+            Provide TPM support along with TCG BIOS extensions
+
 endmenu
 
 menu "BIOS Tables"

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
                   ` (3 preceding siblings ...)
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 4/8] Build the TCG BIOS extensions and TPM drivers Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-04-04  4:30   ` Kevin O'Connor
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS Stefan Berger
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios_inthandler.diff --]
[-- Type: text/plain, Size: 21006 bytes --]

This patch implements the TCG BIOS interrupt handler 1ah. It is for
example used by trusted grub.

This patch adds an implementation of SHA1 (following NIST specs., IETF RFC 3147
and Wikipedia) for speeding up measurements of code. Trusted Grub for example
makes use of this interface and measures (calculates SHA1) of the Linux kernel
and initrd. Those files can be rather large and hunting their bytes through
the TIS interface as part of the int handler commands invoked by trusted grub
does take quite some time due to the many vmexits the interface is creating
(one per byte).

There is also a threshold for the size of data to hash (100k) below which
the TPM is used and above the internal faster SHA1 algorithm is used.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 src/Kconfig   |    8 
 src/clock.c   |    9 
 src/stacks.c  |   14 +
 src/tcgbios.c |  714 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tcgbios.h |    3 
 5 files changed, 748 insertions(+)

Index: seabios/src/tcgbios.c
===================================================================
--- seabios.orig/src/tcgbios.c
+++ seabios/src/tcgbios.c
@@ -62,6 +62,9 @@ static const u8 GetCapability_OwnerAuth[
 #define RSDP_CAST(ptr)   ((struct rsdp_descriptor *)ptr)
 
 
+static u32 sha1(const u8 *data, u32 length, u8 *hash);
+
+
 /* helper functions */
 
 static inline void *input_buf32(struct bregs *regs)
@@ -522,4 +525,715 @@ err_exit:
 }
 
 
+static int
+isValidPcpes(struct pcpes *pcpes)
+{
+    return (pcpes->eventtype != 0);
+}
+
+
+static u8 *
+get_lasa_last_ptr(u16 *entry_count, u8 **lasa_next)
+{
+    struct pcpes *pcpes;
+    u32 laml;
+    u8 *lasa_base = get_lasa_base_ptr(&laml);
+    u8 *lasa_last = NULL;
+    u8 *end = lasa_base + laml;
+    u32 size;
+
+    if (entry_count)
+        *entry_count = 0;
+
+    if (!lasa_base)
+        return NULL;
+
+    while (lasa_base < end) {
+        pcpes = (struct pcpes *)lasa_base;
+        if (!isValidPcpes(pcpes))
+            break;
+        if (entry_count)
+            (*entry_count)++;
+        size = pcpes->eventdatasize + offsetof(struct pcpes, event);
+        lasa_last = lasa_base;
+        lasa_base += size;
+    }
+
+    if (lasa_next)
+        *lasa_next = lasa_base;
+
+    return lasa_last;
+}
+
+
+/*******************************************************************
+  Calculation of SHA1 in SW
+
+  See: http://www.itl.nist.gov/fipspubs/fip180-1.htm
+       RFC3174, Wikipedia's SHA1 alogrithm description
+ ******************************************************************/
+typedef struct _sha1_ctx {
+    u32 h[5];
+} sha1_ctx;
+
+
+static inline u32 rol(u32 val, u16 rol)
+{
+    u32 res;
+
+    __asm__ __volatile__ ("rol %%cl, %%eax"
+                          : "=a" (res)
+                          : "a" (val), "c" (rol));
+
+    return res;
+}
+
+
+static inline u64 bswap_64(u64 val)
+{
+    u32 hi = (u32)(val >> 32);
+    u32 lo = (u32)val;
+
+    __asm__ __volatile__ ("bswap %%eax"
+                          : "=a" (lo)
+                          : "a" (lo));
+
+    __asm__ __volatile__ ("bswap %%eax"
+                          : "=a" (hi)
+                          : "a" (hi));
+
+    return ((u64)lo << 32 | hi);
+}
+
+
+static const u32 sha_ko[4] = { 0x5a827999,
+                               0x6ed9eba1,
+                               0x8f1bbcdc,
+                               0xca62c1d6 };
+
+
+static void
+sha1_block(u32 *w, sha1_ctx *ctx)
+{
+    u32 i;
+    u32 a,b,c,d,e,f;
+    u32 tmp;
+    u32 idx;
+
+    /* change endianess of given data */
+    for (i = 0; i < 16; i++)
+        w[i] = htonl(w[i]);
+
+    for (i = 16; i <= 79; i++) {
+        tmp = w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16];
+        w[i] = rol(tmp,1);
+    }
+
+    a = ctx->h[0];
+    b = ctx->h[1];
+    c = ctx->h[2];
+    d = ctx->h[3];
+    e = ctx->h[4];
+
+    for (i = 0; i <= 79; i++) {
+        if (i <= 19) {
+            f = (b & c) | ((b ^ 0xffffffff) & d);
+            idx = 0;
+        } else if (i <= 39) {
+            f = b ^ c ^ d;
+            idx = 1;
+        } else if (i <= 59) {
+            f = (b & c) | (b & d) | (c & d);
+            idx = 2;
+        } else {
+            f = b ^ c ^ d;
+            idx = 3;
+        }
+
+        tmp = rol(a, 5) +
+              f +
+              e +
+              sha_ko[idx] +
+              w[i];
+        e = d;
+        d = c;
+        c = rol(b, 30);
+        b = a;
+        a = tmp;
+    }
+
+    ctx->h[0] += a;
+    ctx->h[1] += b;
+    ctx->h[2] += c;
+    ctx->h[3] += d;
+    ctx->h[4] += e;
+}
+
+
+static void
+sha1_do(sha1_ctx *ctx, const u8 *data32, u32 length)
+{
+    u32 offset;
+    u16 num;
+    u32 bits = 0;
+    u32 w[80];
+    u64 tmp;
+
+    /* treat data in 64-byte chunks */
+    for (offset = 0; length - offset >= 64; offset += 64) {
+        memcpy(w, data32 + offset, 64);
+        sha1_block((u32 *)w, ctx);
+        bits += (64 * 8);
+    }
+
+    /* last block with less than 64 bytes */
+    num = length - offset;
+    bits += (num << 3);
+
+    memcpy(w, data32 + offset, num);
+    ((u8 *)w)[num] = 0x80;
+    if (64 - (num + 1) > 0)
+        memset( &((u8 *)w)[num + 1], 0x0, 64 - (num + 1));
+
+    if (num >= 56) {
+        /* cannot append number of bits here */
+        sha1_block((u32 *)w, ctx);
+        memset(w, 0x0, 60);
+    }
+
+    /* write number of bits to end of block */
+    tmp = bswap_64(bits);
+    memcpy(&w[14], &tmp, 8);
+
+    sha1_block(w, ctx);
+
+    /* need to switch result's endianess */
+    for (num = 0; num < 5; num++)
+        ctx->h[num] = htonl(ctx->h[num]);
+}
+
+
+static u32
+sha1_fast(const u8 *data, u32 length, u8 *hash)
+{
+    sha1_ctx ctx = {
+        .h[0] = 0x67452301,
+        .h[1] = 0xefcdab89,
+        .h[2] = 0x98badcfe,
+        .h[3] = 0x10325476,
+        .h[4] = 0xc3d2e1f0,
+    };
+
+    sha1_do(&ctx, data, length);
+    memcpy(hash, &ctx.h[0], 20);
+
+    return 0;
+}
+
+
+
+
+#if CONFIG_TPM_FOR_SHA1
+
+static u32
+sha1(const u8 *data, u32 length, u8 *hash)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_res_sha1start start;
+    struct tpm_res_sha1complete complete;
+    u32 blocks = length / 64;
+    u32 rest = length % 0x3f;
+    u32 numbytes, numbytes_no;
+    u32 offset = 0;
+
+    if (length > 100 * 1024)
+        return sha1_fast(data, length, hash);
+
+    rc = build_and_send_cmd(TPM_ORD_SHA1Start,
+                            NULL, 0,
+                            (u8 *)&start,
+                            sizeof(struct tpm_res_sha1start),
+                            &returnCode);
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    while (blocks > 0) {
+
+        numbytes = ntohl(start.max_num_bytes);
+        if (numbytes > blocks * 64)
+             numbytes = blocks * 64;
+
+        numbytes_no = htonl(numbytes);
+
+        rc = build_and_send_cmd_od(TPM_ORD_SHA1Update,
+                                   (u8 *)&numbytes_no, sizeof(numbytes_no),
+                                   NULL, 0, &returnCode,
+                                   &data[offset], numbytes);
+
+        if (rc || returnCode)
+            goto err_exit;
+
+        offset += numbytes;
+        blocks -= (numbytes / 64);
+    }
+
+    numbytes_no = htonl(rest);
+
+    rc = build_and_send_cmd_od(TPM_ORD_SHA1Complete,
+                              (u8 *)&numbytes_no, sizeof(numbytes_no),
+                              (u8 *)&complete,
+                              sizeof(struct tpm_res_sha1complete),
+                              &returnCode,
+                              &data[offset], rest);
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    memcpy(hash, complete.hash, sizeof(complete.hash));
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM SHA1 malfunctioning.\n");
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+#else
+
+static u32
+sha1(const u8 *data, u32 length, u8 *hash)
+{
+    return sha1_fast(data, length, hash);
+}
+
+#endif
+/*
+ * Extend the ACPI log with the given entry by copying the
+ * entry data into the log.
+ * Input
+ *  Pointer to the structure to be copied into the log
+ *
+ * Output:
+ *  lower 16 bits of return code contain entry number
+ *  if entry number is '0', then upper 16 bits contain error code.
+ */
+static u32
+tcpa_extend_acpi_log(void *entry_ptr, u16 *entry_count)
+{
+    u32 laml, size;
+    u8 *lasa_base = get_lasa_base_ptr(&laml), *lasa_next;
+    struct pcpes *pcpes = (struct pcpes *)entry_ptr;
+
+    get_lasa_last_ptr(entry_count, &lasa_next);
+
+#ifdef DEBUG_TCGBIOS
+    dprintf(1, "TCGBIOS: LASA_BASE = %p, LASA_NEXT = %p\n",lasa_base, lasa_next);
+#endif
+
+    if (lasa_next == NULL || laml == 0)
+        return TCG_PC_LOGOVERFLOW;
+
+    size = pcpes->eventdatasize + offsetof(struct pcpes, event);
+
+    if ((lasa_next + size - lasa_base) > laml) {
+#ifdef DEBUG_TCGBIOS
+    dprintf(1, "TCGBIOS: LOG OVERFLOW: size = %d\n", size);
+#endif
+        return TCG_PC_LOGOVERFLOW;
+    }
+
+    memcpy(lasa_next, entry_ptr, size);
+
+    (*entry_count)++;
+
+    return 0;
+}
+
+
+static u32
+is_preboot_if_shutdown(void)
+{
+    return tcpa_state.if_shutdown;
+}
+
+
+static u32
+shutdown_preboot_interface(void)
+{
+    u32 rc = 0;
+
+    if (!is_preboot_if_shutdown()) {
+        tcpa_state.if_shutdown = 1;
+    } else {
+        rc = TCG_INTERFACE_SHUTDOWN;
+    }
+
+    return rc;
+}
+
+
+static void
+tcpa_shutdown(void)
+{
+    reset_acpi_log();
+    shutdown_preboot_interface();
+}
+
+
+static u32
+pass_through_to_tpm(struct pttti *pttti, struct pttto *pttto)
+{
+    u32 rc = 0;
+    u32 resbuflen = 0;
+    struct tpm_req_header *trh;
+    u8 locty = 0;
+    struct iovec iovec[2];
+    const u32 *tmp;
+
+    if (is_preboot_if_shutdown()) {
+        rc = TCG_INTERFACE_SHUTDOWN;
+        goto err_exit;
+    }
+
+    trh = (struct tpm_req_header *)pttti->tpmopin;
+
+    if (pttti->ipblength < sizeof(struct pttti) + TPM_REQ_HEADER_SIZE ||
+        pttti->opblength < sizeof(struct pttto) ||
+        ntohl(trh->totlen)  + sizeof(struct pttti) > pttti->ipblength ) {
+        rc = TCG_INVALID_INPUT_PARA;
+        goto err_exit;
+    }
+
+    resbuflen = pttti->opblength - offsetof(struct pttto, tpmopout);
+
+    iovec[0].data   = pttti->tpmopin;
+    tmp = (const u32 *)&((u8 *)iovec[0].data)[2];
+    iovec[0].length = htonl(*tmp);
+
+    iovec[1].data   = NULL;
+    iovec[1].length = 0;
+
+    rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen);
+    if (rc)
+        goto err_exit;
+
+    pttto->opblength = offsetof(struct pttto, tpmopout) + resbuflen;
+    pttto->reserved  = 0;
+
+err_exit:
+    if (rc != 0) {
+        pttto->opblength = 4;
+        pttto->reserved = 0;
+    }
+
+    return rc;
+}
+
+
+static u32
+tpm_extend(u8 *hash, u32 pcrindex)
+{
+    u32 rc;
+    struct pttto_extend pttto;
+    struct pttti_extend pttti = {
+        .pttti = {
+            .ipblength = sizeof(struct pttti_extend),
+            .opblength = sizeof(struct pttto_extend),
+        },
+        .req = {
+            .tag      = htons(0xc1),
+            .totlen   = htonl(sizeof(pttti.req)),
+            .ordinal  = htonl(TPM_ORD_Extend),
+            .pcrindex = htonl(pcrindex),
+        },
+    };
+
+    memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
+
+    rc = pass_through_to_tpm(&pttti.pttti, &pttto.pttto);
+
+    if (rc == 0) {
+        if (pttto.pttto.opblength < TPM_RSP_HEADER_SIZE ||
+            pttto.pttto.opblength !=
+                sizeof(struct pttto) + ntohl(pttto.rsp.totlen) ||
+            ntohs(pttto.rsp.tag) != 0xc4) {
+            rc = TCG_FATAL_COM_ERROR;
+        }
+    }
+
+    if (rc)
+        tcpa_shutdown();
+
+    return rc;
+}
+
+
+static u32
+hash_all(const struct hai *hai, u8 *hash)
+{
+    if (is_preboot_if_shutdown() != 0)
+        return TCG_INTERFACE_SHUTDOWN;
+
+    if (hai->ipblength != sizeof(struct hai) ||
+        hai->hashdataptr == 0 ||
+        hai->hashdatalen == 0 ||
+        hai->algorithmid != TPM_ALG_SHA)
+        return TCG_INVALID_INPUT_PARA;
+
+    return sha1((const u8 *)hai->hashdataptr, hai->hashdatalen, hash);
+}
+
+
+static u32
+hash_log_event(const struct hlei *hlei, struct hleo *hleo)
+{
+    u32 rc = 0;
+    u16 size;
+    struct pcpes *pcpes;
+    u16 entry_count;
+
+    if (is_preboot_if_shutdown() != 0) {
+        rc = TCG_INTERFACE_SHUTDOWN;
+        goto err_exit;
+    }
+
+    size = hlei->ipblength;
+    if (size != sizeof(*hlei)) {
+        rc = TCG_INVALID_INPUT_PARA;
+        goto err_exit;
+    }
+
+    pcpes = (struct pcpes *)hlei->logdataptr;
+
+    if (pcpes->pcrindex >= 24 ||
+        pcpes->pcrindex  != hlei->pcrindex ||
+        pcpes->eventtype != hlei->logeventtype) {
+        rc = TCG_INVALID_INPUT_PARA;
+        goto err_exit;
+    }
+
+    if ((hlei->hashdataptr != 0) && (hlei->hashdatalen != 0)) {
+        rc = sha1((const u8 *)hlei->hashdataptr,
+                  hlei->hashdatalen, pcpes->digest);
+        if (rc)
+            return rc;
+    }
+
+    rc = tcpa_extend_acpi_log((void *)hlei->logdataptr, &entry_count);
+    if (rc)
+        goto err_exit;
+
+    /* updating the log was fine */
+    hleo->opblength = sizeof(struct hleo);
+    hleo->reserved  = 0;
+    hleo->eventnumber = entry_count;
+
+err_exit:
+    if (rc != 0) {
+        hleo->opblength = 2;
+        hleo->reserved = 0;
+    }
+
+    return rc;
+}
+
+
+static u32
+hash_log_extend_event(const struct hleei_short *hleei_s, struct hleeo *hleeo)
+{
+    u32 rc = 0;
+    struct hleo hleo;
+    struct hleei_long *hleei_l = (struct hleei_long *)hleei_s;
+    const void *logdataptr;
+    u32 logdatalen;
+    struct pcpes *pcpes;
+
+    /* short or long version? */
+    switch (hleei_s->ipblength) {
+    case sizeof(struct hleei_short):
+        /* short */
+        logdataptr = hleei_s->logdataptr;
+        logdatalen = hleei_s->logdatalen;
+    break;
+
+    case sizeof(struct hleei_long):
+        /* long */
+        logdataptr = hleei_l->logdataptr;
+        logdatalen = hleei_l->logdatalen;
+    break;
+
+    default:
+        /* bad input block */
+        rc = TCG_INVALID_INPUT_PARA;
+        goto err_exit;
+    }
+
+    pcpes = (struct pcpes *)logdataptr;
+
+    struct hlei hlei = {
+        .ipblength   = sizeof(hlei),
+        .hashdataptr = hleei_s->hashdataptr,
+        .hashdatalen = hleei_s->hashdatalen,
+        .pcrindex    = hleei_s->pcrindex,
+        .logeventtype= pcpes->eventtype,
+        .logdataptr  = logdataptr,
+        .logdatalen  = logdatalen,
+    };
+
+    rc = hash_log_event(&hlei, &hleo);
+    if (rc)
+        goto err_exit;
+
+    hleeo->opblength = sizeof(struct hleeo);
+    hleeo->reserved  = 0;
+    hleeo->eventnumber = hleo.eventnumber;
+
+    rc = tpm_extend(pcpes->digest, hleei_s->pcrindex);
+
+err_exit:
+    if (rc != 0) {
+        hleeo->opblength = 4;
+        hleeo->reserved  = 0;
+    }
+
+    return rc;
+
+}
+
+
+static u32
+tss(struct ti *ti, struct to *to)
+{
+    u32 rc = 0;
+
+    if (is_preboot_if_shutdown() == 0) {
+        rc = TCG_PC_UNSUPPORTED;
+    } else {
+        rc = TCG_INTERFACE_SHUTDOWN;
+    }
+
+    to->opblength = sizeof(struct to);
+    to->reserved  = 0;
+
+    return rc;
+}
+
+
+static u32
+compact_hash_log_extend_event(u8 *buffer,
+                              u32 info,
+                              u32 length,
+                              u32 pcrindex,
+                              u32 *edx_ptr)
+{
+    u32 rc = 0;
+    struct hleeo hleeo;
+    struct pcpes pcpes = {
+        .pcrindex      = pcrindex,
+        .eventtype     = EV_COMPACT_HASH,
+        .eventdatasize = sizeof(info),
+        .event         = info,
+    };
+    struct hleei_short hleei = {
+        .ipblength   = sizeof(hleei),
+        .hashdataptr = buffer,
+        .hashdatalen = length,
+        .pcrindex    = pcrindex,
+        .logdataptr  = &pcpes,
+        .logdatalen  = sizeof(pcpes),
+    };
+
+    rc = hash_log_extend_event(&hleei, &hleeo);
+    if (rc == 0)
+        *edx_ptr = hleeo.eventnumber;
+
+    return rc;
+}
+
+
+void VISIBLE32FLAT
+tcpa_interrupt_handler32(struct bregs *regs)
+{
+    switch ((enum irq_ids)regs->al) {
+    case TCG_StatusCheck:
+        if (is_tpm_present() == 0) {
+            /* no TPM available */
+            regs->eax = TCG_PC_TPM_NOT_PRESENT;
+        } else {
+            regs->eax = 0;
+            regs->ebx = TCG_MAGIC;
+            regs->ch = TCG_VERSION_MAJOR;
+            regs->cl = TCG_VERSION_MINOR;
+            regs->edx = 0x0;
+            regs->esi = (u32)get_lasa_base_ptr(NULL);
+            regs->edi =
+                  (u32)get_lasa_last_ptr(NULL, NULL);
+            set_cf(regs, 0);;
+        }
+        break;
+
+    case TCG_HashLogExtendEvent:
+        regs->eax =
+            hash_log_extend_event(
+                  (struct hleei_short *)input_buf32(regs),
+                  (struct hleeo *)output_buf32(regs));
+        set_cf(regs, 0);
+        break;
+
+    case TCG_PassThroughToTPM:
+        regs->eax =
+            pass_through_to_tpm((struct pttti *)input_buf32(regs),
+                                (struct pttto *)output_buf32(regs));
+        set_cf(regs, 0);
+        break;
+
+    case TCG_ShutdownPreBootInterface:
+        regs->eax = shutdown_preboot_interface();
+        set_cf(regs, 0);
+        break;
+
+    case TCG_HashLogEvent:
+        regs->eax = hash_log_event((struct hlei*)input_buf32(regs),
+                                   (struct hleo*)output_buf32(regs));
+        set_cf(regs, 0);
+        break;
+
+    case TCG_HashAll:
+        regs->eax =
+            hash_all((struct hai*)input_buf32(regs),
+                     (u8 *)output_buf32(regs));
+        set_cf(regs, 0);
+        break;
+
+    case TCG_TSS:
+        regs->eax = tss((struct ti*)input_buf32(regs),
+                    (struct to*)output_buf32(regs));
+        set_cf(regs, 0);
+        break;
+
+    case TCG_CompactHashLogExtendEvent:
+        regs->eax =
+          compact_hash_log_extend_event((u8 *)input_buf32(regs),
+                                        regs->esi,
+                                        regs->ecx,
+                                        regs->edx,
+                                        &regs->edx);
+        set_cf(regs, 0);
+        break;
+
+    default:
+        set_cf(regs, 1);
+    }
+
+    return;
+}
+
+
 #endif /* CONFIG_TCGBIOS */
Index: seabios/src/stacks.c
===================================================================
--- seabios.orig/src/stacks.c
+++ seabios/src/stacks.c
@@ -7,6 +7,7 @@
 #include "biosvar.h" // get_ebda_seg
 #include "util.h" // dprintf
 #include "bregs.h" // CR0_PE
+#include "tcgbios.h"
 
 // Thread info - stored at bottom of each thread stack - don't change
 // without also updating the inline assembler below.
@@ -393,3 +394,16 @@ check_preempt(void)
     extern void _cfunc32flat_yield_preempt(void);
     call32(_cfunc32flat_yield_preempt, 0, 0);
 }
+
+
+#ifdef CONFIG_TCGBIOS
+void tcpa_interrupt_handler16(struct bregs *regs)
+{
+    if (MODESEGMENT) {
+        dprintf(3, "16: Calling tcpa_interrupt_handler\n");
+        call32(_cfunc32flat_tcpa_interrupt_handler32, (u32)regs, 0);
+    } else {
+        _cfunc32flat_tcpa_interrupt_handler32(regs);
+    }
+}
+#endif /* CONFIG_TCGBIOS */
Index: seabios/src/clock.c
===================================================================
--- seabios.orig/src/clock.c
+++ seabios/src/clock.c
@@ -434,6 +434,14 @@ handle_1a07(struct bregs *regs)
     set_success(regs);
 }
 
+static void
+handle_1abb(struct bregs *regs)
+{
+#if CONFIG_TCGBIOS
+    tcpa_interrupt_handler16(regs);
+#endif
+}
+
 // Unsupported
 static void
 handle_1aXX(struct bregs *regs)
@@ -456,6 +464,7 @@ handle_1a(struct bregs *regs)
     case 0x06: handle_1a06(regs); break;
     case 0x07: handle_1a07(regs); break;
     case 0xb1: handle_1ab1(regs); break;
+    case 0xbb: handle_1abb(regs); break;
     default:   handle_1aXX(regs); break;
     }
 }
Index: seabios/src/tcgbios.h
===================================================================
--- seabios.orig/src/tcgbios.h
+++ seabios/src/tcgbios.h
@@ -359,6 +359,9 @@ enum ipltype {
     IPL_EL_TORITO_2
 };
 
+void tcpa_interrupt_handler32(struct bregs *regs);
+void _cfunc32flat_tcpa_interrupt_handler32(struct bregs *regs);
+
 #if CONFIG_TCGBIOS
 void tcpa_acpi_init(void);
 int has_working_tpm(void);
Index: seabios/src/Kconfig
===================================================================
--- seabios.orig/src/Kconfig
+++ seabios/src/Kconfig
@@ -322,6 +322,14 @@ menu "BIOS interfaces"
         help
             Provide TPM support along with TCG BIOS extensions
 
+    config TPM_FOR_SHA1
+        depends on TCGBIOS
+        bool "Use the TPM for SHA1 calculations"
+        default y
+        help
+            Either you may use the TPM for SHA1 calculations or
+            use the internal sha1 algorithm to do it (faster).
+
 endmenu
 
 menu "BIOS Tables"

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
                   ` (4 preceding siblings ...)
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-04-04  4:57   ` Kevin O'Connor
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 7/8] Add a menu for TPM control Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 8/8] Optional tests for the TIS interface Stefan Berger
  7 siblings, 1 reply; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios_measure.diff --]
[-- Type: text/plain, Size: 18525 bytes --]

This patch adds invocactions of functions that measure various parts of the
code and data through various parts of the BIOS code. It follows TCG
specifications on what needs to be measured. It also adds the implementation
of the called functions.

Reference for what needs to be measured can be found in section 3.2.2++ in

http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios_specification_version_12


The first measurements are done once the ACPI tables have been initialized.
The whole 0xe and 0xf segment are measure for measuring the 'POST'.

Once booted into Linux, the current measurements produce the following logs
which can be found in /sys/kernel/security/tpm0/ascii_bios_measurements.
The below log also shows measurements from trusted grub.

 0 0f9a2ad992c04a24e081b2a49b984616c4358386 01 [POST CODE]
 1 3fb240d2a04085a4e84f81e4398e070ed5a18163 06 [SMBIOS]
 2 cc812353fc277c1fab99e0b721752a1392984566 06 [Option ROM]
 2 9dbd87163112e5670378abe4510491259a61f411 05 [Start Option ROM Scan]
 2 6f74e357331b8dee11bbad85f27bc66cb873106c 06 [Option ROM]
 2 5626eb7ac05c7231e46d7461e7d3839b03ae9fad 06 [Option ROM]
 4 c1e25c3f6b0dc78d57296aa2870ca6f782ccf80f 05 [Calling INT 19h]
 0 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 1 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 2 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 3 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 4 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 5 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 6 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 7 d9be6524a5f5047db5866813acf3277892a7a30a 04 []
 4 8cf2fe6c87d4d0b2998a43da630292e6d85ee8b6 05 [Booting BCV device 80h (HDD)]
 4 5dff94459a3e2d13a433ef94afdc306144565bf7 0d [IPL]
 5 d1b33afde65ad47502332af957c60f20c84c1edc 0e [IPL Partition Data]
 4 487ce764b527ccad17f1d04243d0136fa981e6c4 0d [IPL]
 4 91d285e4dead566324c8938a3cc75803f462d9a1 0d [IPL]
 4 8ba79ac98bb491524fef29defc724daaf6263d35 0d [IPL]
 4 c591c15b82e4ff30e7383a4ff1ef3b41b38521ac 06 []
 4 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator]
 5 8cdc27ec545eda33fbba1e8b8dae4da5c7206972 04 [Grub Event Separator]
 5 e8673b9e14b02dc12d8ccfd0176bca7a3de7fc3c 0e [IPL Partition Data]
 5 0163e375a0af7525c5dac1a8e74b277359e40d1d 1105 []
 8 4be30f67c3d48ab7f04d9c0fd07f06d4c68379be 1205 []
 8 54c83965978de9708d026016ecb0e70660e04388 1305 []
 5 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator]
 8 2431ed60130faeaf3a045f21963f71cacd46a029 04 [OS Event Separator]
 8 f3973cae05d6e2055062119d6e6e1e077b7df876 1005 []


Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 src/boot.c       |    5 
 src/cdrom.c      |   10 +
 src/optionroms.c |    4 
 src/post.c       |    5 
 src/tcgbios.c    |  397 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tcgbios.h    |   36 ++++
 6 files changed, 457 insertions(+)

Index: seabios/src/post.c
===================================================================
--- seabios.orig/src/post.c
+++ seabios/src/post.c
@@ -190,6 +190,9 @@ init_hw(void)
 void VISIBLE32FLAT
 startBoot(void)
 {
+    tcpa_calling_int19h();
+    tcpa_add_event_separators();
+
     // Clear low-memory allocations (required by PMM spec).
     memset((void*)BUILD_STACK_ADDR, 0, BUILD_EBDA_MINIMUM - BUILD_STACK_ADDR);
 
@@ -242,6 +245,8 @@ maininit(void)
     // Initialize tpm (after acpi tables were written)
     tcpa_acpi_init();
     tcpa_startup();
+    tcpa_measure_post((void *)0xE0000, (void *)0xFFFFF);
+    tcpa_smbios_measure();
 
     // Run vga option rom
     vga_setup();
Index: seabios/src/optionroms.c
===================================================================
--- seabios.orig/src/optionroms.c
+++ seabios/src/optionroms.c
@@ -14,6 +14,7 @@
 #include "pci_ids.h" // PCI_CLASS_DISPLAY_VGA
 #include "boot.h" // IPL
 #include "paravirt.h" // qemu_cfg_*
+#include "tcgbios.h" // tcpa_*
 
 
 /****************************************************************
@@ -134,6 +135,7 @@ is_valid_rom(struct rom_header *rom)
         if (CONFIG_OPTIONROMS_CHECKSUM)
             return 0;
     }
+    tcpa_option_rom(FLATPTR_TO_SEG(rom), len);
     return 1;
 }
 
@@ -385,6 +387,8 @@ optionrom_setup(void)
     memset(sources, 0, sizeof(sources));
     u32 post_vga = RomEnd;
 
+    tcpa_start_option_rom_scan();
+
     if (CONFIG_OPTIONROMS_DEPLOYED) {
         // Option roms are already deployed on the system.
         u32 pos = RomEnd;
Index: seabios/src/boot.c
===================================================================
--- seabios.orig/src/boot.c
+++ seabios/src/boot.c
@@ -533,6 +533,9 @@ boot_disk(u8 bootdrv, int checksig)
         }
     }
 
+    tcpa_add_bootdevice(0, bootdrv);
+    tcpa_ipl(IPL_BCV, bootseg, 0, 512); /* specs: 8.2.3 steps 4 and 5 */
+
     /* Canonicalize bootseg:bootip */
     u16 bootip = (bootseg & 0x0fff) << 4;
     bootseg &= 0xf000;
@@ -620,6 +623,8 @@ do_boot(u16 seq_nr)
         break;
     }
 
+    tcpa_returned_via_int18h();
+
     // Boot failed: invoke the boot recovery function
     struct bregs br;
     memset(&br, 0, sizeof(br));
Index: seabios/src/cdrom.c
===================================================================
--- seabios.orig/src/cdrom.c
+++ seabios/src/cdrom.c
@@ -11,6 +11,7 @@
 #include "biosvar.h" // GET_EBDA
 #include "ata.h" // ATA_CMD_REQUEST_SENSE
 #include "blockcmd.h" // CDB_CMD_REQUEST_SENSE
+#include "tcgbios.h" // tcpa_*
 
 
 /****************************************************************
@@ -293,6 +294,11 @@ cdrom_boot(struct drive_s *drive_g)
     if (buffer[0x20] != 0x88)
         return 11; // Bootable
 
+    /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
+    /* measure 2048 bytes (one sector) */
+    tcpa_add_bootdevice(1, 0);
+    tcpa_ipl(IPL_EL_TORITO_2, GET_SEG(SS), (u32)buffer, 2048);
+
     u16 ebda_seg = get_ebda_seg();
     u8 media = buffer[0x21];
     SET_EBDA2(ebda_seg, cdemu.media, media);
@@ -319,6 +325,10 @@ cdrom_boot(struct drive_s *drive_g)
     if (ret)
         return 12;
 
+    /* specs: 8.2.3 step 4 and 8.2.5.6, measure El Torito boot image */
+    /* measure 1st 512 bytes */
+    tcpa_ipl(IPL_EL_TORITO_1, boot_segment, 0, 512);
+
     if (media == 0) {
         // No emulation requested - return success.
         SET_EBDA2(ebda_seg, cdemu.emulated_extdrive, EXTSTART_CD + cdid);
Index: seabios/src/tcgbios.c
===================================================================
--- seabios.orig/src/tcgbios.c
+++ seabios/src/tcgbios.c
@@ -58,6 +58,8 @@ static const u8 GetCapability_OwnerAuth[
     0x00, 0x00, 0x01, 0x11
 };
 
+static u8 evt_separator[] = {0xff,0xff,0xff,0xff};
+
 
 #define RSDP_CAST(ptr)   ((struct rsdp_descriptor *)ptr)
 
@@ -1236,4 +1238,399 @@ tcpa_interrupt_handler32(struct bregs *r
 }
 
 
+/*
+ * Add a measurement to the log; the data at data_seg:data/length are
+ * appended to the TCG_PCClientPCREventStruct
+ *
+ * Input parameters:
+ *  pcrIndex   : which PCR to extend
+ *  event_type : type of event; specs 10.4.1
+ *  data       : pointer to the data (i.e., string) to be added to the log
+ *  length     : length of the data
+ */
+static u32
+tcpa_add_measurement_to_log(u32 pcrIndex,
+                            u32 event_type,
+                            const char *data, u32 length)
+{
+    u32 rc = 0;
+    struct hleeo hleeo;
+    u8 _pcpes[offsetof(struct pcpes, event) + 400];
+    struct pcpes *pcpes = (struct pcpes *)_pcpes;
+
+    if (length < sizeof(_pcpes) - offsetof(struct pcpes, event)) {
+
+        pcpes->pcrindex      = pcrIndex;
+        pcpes->eventtype     = event_type;
+        memset(&pcpes->digest, 0x0, sizeof(pcpes->digest));
+        pcpes->eventdatasize = length;
+        memcpy(&pcpes->event, data, length);
+
+        struct hleei_short hleei = {
+            .ipblength   = sizeof(hleei),
+            .hashdataptr = &pcpes->event,
+            .hashdatalen = length,
+            .pcrindex    = pcrIndex,
+            .logdataptr  = _pcpes,
+            .logdatalen  = length + offsetof(struct pcpes, event),
+        };
+
+        rc = hash_log_extend_event(&hleei, &hleeo);
+    } else {
+        rc = TCG_GENERAL_ERROR;
+    }
+
+    return rc;
+}
+
+
+static u32
+tcpa_add_pcpes_to_log(const struct pcpes *pcpes)
+{
+    struct hleeo hleeo;
+    struct hleei_short hleei = {
+        .ipblength   = sizeof(hleei),
+        .pcrindex    = pcpes->pcrindex,
+        .logdataptr  = pcpes,
+        .logdatalen  = sizeof(pcpes),
+    };
+
+    return hash_log_extend_event(&hleei, &hleeo);
+}
+
+
+/*
+ * Add a measurement to the log; further description of the data
+ * that are to be hashed are NOT appended to the TCG_PCClientPCREventStruc.
+ * Input parameters:
+ *  pcrIndex   : PCR to extend
+ *  event_type : type of event; specs 10.4.1
+ *  ptr        : 32 bit pointer to the data to be hashed
+ *  length     : length of the data to be hashed
+ *
+ * Returns lower 16 bit of return code of TCG_HashLogExtendEvent. '0' means
+ * success, otherwise an error is indicated.
+ */
+static u32
+tcpa_add_measurement_to_log_simple(u32 pcrIndex,
+                                   u16 event_type,
+                                   u8 *ptr, u32 length)
+{
+    struct hleeo hleeo;
+    struct pcpes pcpes = {
+        .pcrindex = pcrIndex,
+        .eventtype = event_type,
+        /* specs: 10.4.1, EV_IPL eventfield should not contain the code.*/
+        .eventdatasize = 0,
+        .event = 0,
+    };
+    struct hleei_short hleei = {
+        .ipblength   = sizeof(hleei),
+        .hashdataptr = ptr,
+        .hashdatalen = length,
+        .pcrindex    = pcrIndex,
+        .logdataptr  = &pcpes,
+        .logdatalen  = offsetof(struct pcpes, event),
+    };
+
+    return hash_log_extend_event(&hleei, &hleeo);
+}
+
+
+/*
+ * Add a measurement to the list of measurements
+ * pcrIndex   : PCR to be extended
+ * event_type : type of event; specs 10.4.1
+ * data       : additional parameter; used as parameter for 10.4.3
+ *              'action index'
+ */
+static u32
+tcpa_add_measurement(u32 pcrIndex,
+                     u16 event_type,
+                     const char *string)
+{
+    u32 rc;
+
+    switch (event_type) {
+    case EV_SEPARATOR:
+        rc = tcpa_add_measurement_to_log_simple(pcrIndex,
+                                                event_type,
+                                                (u8 *)evt_separator,
+                                                4);
+        break;
+
+    case EV_ACTION:
+        rc = tcpa_add_measurement_to_log(pcrIndex,
+                                         event_type,
+                                         string,
+                                         strlen(string));
+        break;
+
+    default:
+        rc = TCG_INVALID_INPUT_PARA;
+    }
+
+    return rc;
+}
+
+
+u32
+tcpa_calling_int19h(void)
+{
+    if (!has_working_tpm())
+        return 0;
+
+    return tcpa_add_measurement(4, EV_ACTION,
+                                "Calling INT 19h");
+}
+
+
+u32
+tcpa_returned_via_int18h(void)
+{
+    if (!has_working_tpm())
+        return 0;
+
+    return tcpa_add_measurement(4, EV_ACTION,
+                                "Return via INT 18h");
+}
+
+
+/*
+ * Add event separators for PCRs 0 to 7; specs 8.2.3
+ */
+u32
+tcpa_add_event_separators(void)
+{
+    u32 rc;
+    u32 pcrIndex = 0;
+
+    if (!has_working_tpm())
+        return 0;
+
+    while (pcrIndex <= 7) {
+        rc = tcpa_add_measurement(pcrIndex, EV_SEPARATOR, NULL);
+        if (rc)
+            break;
+        pcrIndex ++;
+    }
+
+    return rc;
+}
+
+
+/*
+ * Add a measurement regarding the boot device (CDRom, Floppy, HDD) to
+ * the list of measurements.
+ */
+u32
+tcpa_add_bootdevice(u32 bootcd, u32 bootdrv)
+{
+    const char *string;
+
+    if (!has_working_tpm())
+        return 0;
+
+    switch (bootcd) {
+    case 0:
+        switch (bootdrv) {
+        case 0:
+            string = "Booting BCV device 00h (Floppy)";
+            break;
+
+        case 0x80:
+            string = "Booting BCV device 80h (HDD)";
+            break;
+
+        default:
+            string = "Booting unknown device";
+            break;
+        }
+
+        break;
+
+    default:
+        string = "Booting from CD ROM device";
+    }
+
+    return tcpa_add_measurement_to_log(4, EV_ACTION,
+                                       string, strlen(string));
+}
+
+
+/*
+ * Add measurement to the log about option rom scan
+ * 10.4.3 : action 14
+ */
+u32
+tcpa_start_option_rom_scan(void)
+{
+    if (!has_working_tpm())
+        return 0;
+
+    return tcpa_add_measurement(2, EV_ACTION,
+                                "Start Option ROM Scan");
+}
+
+
+/*
+ * Add measurement to the log about an option rom
+ */
+u32
+tcpa_option_rom(u16 seg, u32 len)
+{
+    u32 rc;
+    struct pcctes_romex pcctes = {
+        .eventid = 7, /* 10.4.2.3.7 */
+        .eventdatasize = sizeof(u16) + sizeof(u16) + SHA1_BUFSIZE,
+    };
+
+    if (!has_working_tpm())
+        return 0;
+
+    rc = sha1((const u8 *)MAKE_FLATPTR(seg, 0), len, pcctes.digest);
+    if (rc)
+        return rc;
+
+    return tcpa_add_measurement_to_log(2,
+                                       EV_EVENT_TAG,
+                                       (const char *)&pcctes,
+                                       sizeof(pcctes));
+}
+
+
+static struct smbios_entry_point *
+find_smbios_entry_point(void)
+{
+    void *smbios = (void *)0xf0000;
+
+    while (smbios <(void *) 0x100000) {
+        if (memcmp(smbios, "_SM_", 4) == 0 &&
+            calc_checksum(smbios,
+                          sizeof(struct smbios_entry_point)) == 0)
+            return smbios;
+        smbios += 0x10;
+    }
+
+    return NULL;
+}
+
+
+u32
+tcpa_smbios_measure(void)
+{
+    u32 rc;
+    struct pcctes pcctes = {
+        .eventid = 1, /* 10.4.2.3.1 */
+        .eventdatasize = SHA1_BUFSIZE,
+    };
+    struct smbios_entry_point *sep = find_smbios_entry_point();
+
+    if (!has_working_tpm())
+        return 0;
+
+#ifdef DEBUG_TCGBIOS
+    dprintf(1, "TCGBIOS: SMBIOS at %p\n", sep);
+#endif
+    if (!sep)
+        return 0;
+
+    rc = sha1((const u8 *)sep->structure_table_address,
+              sep->structure_table_length, pcctes.digest);
+    if (rc)
+        return rc;
+
+    return tcpa_add_measurement_to_log(1,
+                                       EV_EVENT_TAG,
+                                       (const char *)&pcctes,
+                                       sizeof(pcctes));
+}
+
+
+/*
+ * Add a measurement to the log in support of 8.2.5.3
+ * Creates two log entries
+ *
+ * Input parameter:
+ *  bootcd : 0: MBR of hdd, 1: boot image, 2: boot catalog of El Torito
+ *  seg    : segment where the IPL data are located
+ *  off    : offset where the IPL data are located
+ *  count  : length in bytes
+ */
+u32
+tcpa_ipl(enum ipltype bootcd, u16 seg, u16 off, u32 count)
+{
+    u32 rc;
+    u8 *addr = (u8 *)MAKE_FLATPTR(seg, off);
+
+    if (!has_working_tpm())
+        return 0;
+
+    switch (bootcd) {
+    case IPL_EL_TORITO_1:
+        /* specs: 8.2.5.6 El Torito */
+        rc = tcpa_add_measurement_to_log_simple(4,
+                                                EV_IPL,
+                                                addr,
+                                                count);
+        break;
+
+    case IPL_EL_TORITO_2:
+        /* specs: 8.2.5.6 El Torito */
+        rc = tcpa_add_measurement_to_log_simple(5,
+                                                EV_IPL_PARTITION_DATA,
+                                                addr,
+                                                count);
+        break;
+
+    default:
+        /* specs: 8.2.5.3 */
+        /* equivalent to: dd if=/dev/hda ibs=1 count=440 | sha1sum */
+        rc = tcpa_add_measurement_to_log_simple(4,
+                                                EV_IPL,
+                                                addr,
+                                                0x1b8);
+
+        if (rc)
+            break;
+
+        /* equivalent to: dd if=/dev/hda ibs=1 count=72 skip=440 | sha1sum */
+        rc = tcpa_add_measurement_to_log_simple(5,
+                                                EV_IPL_PARTITION_DATA,
+                                                addr + 0x1b8,
+                                                0x48);
+    }
+
+    return rc;
+}
+
+
+u32
+tcpa_measure_post(void *from, void *to)
+{
+    u32 rc = 0;
+    int len = to - from;
+    struct pcpes pcpes = {
+        .eventtype = EV_POST_CODE,
+        .eventdatasize = 0,
+        .pcrindex = 0,
+    };
+
+    if (!has_working_tpm())
+        return 0;
+
+    if (len > 0) {
+        rc = sha1((u8 *)from, to - from + 1, pcpes.digest);
+        if (rc)
+            return rc;
+
+        rc = tcpa_add_pcpes_to_log(&pcpes);
+    } else {
+        rc = TCG_FIRMWARE_ERROR;
+    }
+
+    return rc;
+}
+
+
 #endif /* CONFIG_TCGBIOS */
Index: seabios/src/tcgbios.h
===================================================================
--- seabios.orig/src/tcgbios.h
+++ seabios/src/tcgbios.h
@@ -368,6 +368,15 @@ int has_working_tpm(void);
 u32 tcpa_startup(void);
 u32 tcpa_leave_bios(void);
 u32 tcpa_s3_resume(void);
+u32 tcpa_calling_int19h(void);
+u32 tcpa_returned_via_int18h(void);
+u32 tcpa_add_bootdevice(u32 bootcd, u32 bootdrv);
+u32 tcpa_add_event_separators(void);
+u32 tcpa_ipl(enum ipltype bootcd, u16 seg, u16 off, u32 count);
+u32 tcpa_start_option_rom_scan(void);
+u32 tcpa_option_rom(u16 seg, u32 len);
+u32 tcpa_smbios_measure(void);
+u32 tcpa_measure_post(void *from, void *to);
 #else
 static inline void tcpa_acpi_init(void) {
 }
@@ -383,6 +392,33 @@ static inline u32 tcpa_leave_bios(void) 
 static inline u32 tcpa_s3_resume(void) {
     return 0;
 }
+static inline u32 tcpa_calling_int19h(void) {
+    return 0;
+}
+static inline u32 tcpa_returned_via_int18h(void) {
+    return 0;
+}
+static inline u32 tcpa_add_bootdevice(u32 bootcd, u32 bootdrv) {
+    return 0;
+}
+static inline u32 tcpa_add_event_separators(void) {
+    return 0;
+}
+static inline u32 tcpa_ipl(enum ipltype bootcd, u16 seg, u16 off, u32 count) {
+    return 0;
+}
+static inline u32 tcpa_start_option_rom_scan(void) {
+    return 0;
+}
+static inline u32 tcpa_option_rom(u16 seg, u32 len) {
+    return 0;
+}
+static inline u32 tcpa_smbios_measure(void) {
+    return 0;
+}
+static inline u32 tcpa_measure_post(void *from, void *to) {
+    return 0;
+}
 #endif
 void tcpa_menu(void);
 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 7/8] Add a menu for TPM control
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
                   ` (5 preceding siblings ...)
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 8/8] Optional tests for the TIS interface Stefan Berger
  7 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tcgbios_menu.diff --]
[-- Type: text/plain, Size: 15902 bytes --]

This patch provides an addtional menu entry that enables the user to control
certain aspects of the TPM.

If a working TPM has been detected, the top level BIOS menu
will look like this:

Press F12 for boot menu.
Press F11 to TPM menu.

Upon pressing F11 the TPM menu will be shown:

1. Enable TPM
2. Disable TPM
3. Activate TPM
4. Deactivate TPM
5. Clear ownership
6. Allow installation of owner
7. Prevent installation of owner
Escape for previous menu.
TPM is enabled, active, does not have an owner but one can be installed.

The code for the above 7 menu items is part of this patch.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>


---
 src/boot.c    |   10 -
 src/tcgbios.c |  576 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 584 insertions(+), 2 deletions(-)

Index: seabios/src/tcgbios.c
===================================================================
--- seabios.orig/src/tcgbios.c
+++ seabios/src/tcgbios.c
@@ -1,4 +1,4 @@
-/*
+;/*
  *  Implementation of the TCG BIOS extension according to the specification
  *  described in
  *  https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
@@ -95,6 +95,11 @@ static tcpa_state_t tcpa_state = {
 
 extern struct tpm_driver tpm_drivers[];
 
+typedef struct {
+    u16 revision;
+    u8  op;
+} tpm_bios_cfg_t;
+
 
 /********************************************************
   Extensions for TCG-enabled BIOS
@@ -1633,4 +1638,573 @@ tcpa_measure_post(void *from, void *to)
 }
 
 
+
+static u32
+assert_physical_presence(void)
+{
+    u32 rc = 0;
+    u32 returnCode;
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+                            PhysicalPresence_CMD_ENABLE,
+                            sizeof(PhysicalPresence_CMD_ENABLE),
+                            NULL, 10, &returnCode);
+
+#ifdef DEBUG_TCGBIOS
+    printf("Return code from TSC_PhysicalPresence(CMD_ENABLE) = 0x%08x\n",
+           returnCode);
+#endif
+    if (rc || returnCode)
+        goto err_exit;
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalPresence,
+                            PhysicalPresence_PRESENT,
+                            sizeof(PhysicalPresence_PRESENT),
+                            NULL, 10, &returnCode);
+
+#ifdef DEBUG_TCGBIOS
+    printf("Return code from TSC_PhysicalPresence(PRESENT) = 0x%08x\n",
+           returnCode);
+#endif
+    if (rc || returnCode)
+        goto err_exit;
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+read_permanent_flags(char *buf, int buf_len)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_res_getcap_perm_flags pf;
+
+    memset(buf, 0x0, buf_len);
+
+    rc = build_and_send_cmd(TPM_ORD_GetCapability,
+                            GetCapability_Permanent_Flags,
+                            sizeof(GetCapability_Permanent_Flags),
+                            (u8 *)&pf,
+                            sizeof(struct tpm_res_getcap_perm_flags),
+                            &returnCode);
+
+#ifdef DEBUG_TCGBIOS
+    dprintf(1, "TCGBIOS: Return code from TPM_GetCapability() = 0x%08x\n",
+        returnCode);
+#endif
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    memcpy(buf, &pf.perm_flags, buf_len);
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+read_has_owner(u8 *has_owner)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_res_getcap_ownerauth oauth;
+
+    rc = build_and_send_cmd(TPM_ORD_GetCapability,
+                            GetCapability_OwnerAuth,
+                            sizeof(GetCapability_OwnerAuth),
+                            (u8 *)&oauth,
+                            sizeof(struct tpm_res_getcap_ownerauth),
+                            &returnCode);
+
+#ifdef DEBUG_TCGBIOS
+    dprintf(1, "TCGBIOS: Return code from TPM_GetCapability() = 0x%08x\n",
+        returnCode);
+#endif
+
+    if (rc || returnCode)
+        goto err_exit;
+
+    *has_owner = oauth.flag;
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+disable_tpm(int disable, int verbose)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_permanent_flags pf;
+
+    rc = read_permanent_flags((char *)&pf, sizeof(pf));
+    if (rc)
+        return rc;
+
+    if (!!pf.flags[PERM_FLAG_IDX_DISABLE] == !!disable) {
+        if (verbose)
+            printf("TPM is already %s.\n,",
+                   disable ? "disabled" : "enabled");
+        return 0;
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+#ifdef DEBUG_TCGBIOS
+        dprintf(1, "TCGBIOS: Asserting physical presence "
+                   "failed.\n");
+#endif
+        return rc;
+    }
+
+    rc = build_and_send_cmd(disable ? TPM_ORD_PhysicalDisable
+                                    : TPM_ORD_PhysicalEnable,
+                            NULL, 0, NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+    printf("Return code from TPM_Physical%sable = 0x%08x\n",
+           disable ? "Dis" : "En", returnCode);
+#endif
+    if (rc || returnCode)
+            goto err_exit;
+
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1, "TCGBIOS: %sabling the TPM failed.\n",
+            disable ? "Dis" : "En");
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+deactivate_tpm(int deactivate, int allow_reset, int verbose)
+{
+    u32 rc;
+    u32 returnCode;
+    struct tpm_permanent_flags pf;
+
+    rc = read_permanent_flags((char *)&pf, sizeof(pf));
+    if (rc)
+        return rc;
+
+    if (!!pf.flags[PERM_FLAG_IDX_DEACTIVATED] == !!deactivate) {
+        if (verbose)
+            printf("TPM is already %s.\n",
+                   deactivate ? "deactivated" : "activated");
+        return 0;
+    }
+
+    if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
+        if (verbose)
+            printf("TPM must first be enabled.\n");
+        return 0;
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+#ifdef DEBUG_TCGBIOS
+        dprintf(1, "TCGBIOS: Asserting physical presence "
+                   "failed.\n");
+#endif
+        return rc;
+    }
+
+    rc = build_and_send_cmd(TPM_ORD_PhysicalSetDeactivated,
+                            deactivate ? CommandFlag_TRUE
+                                       : CommandFlag_FALSE,
+                            deactivate ? sizeof(CommandFlag_TRUE)
+                                       : sizeof(CommandFlag_FALSE),
+                            NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+    printf("Return code from PhysicalSetDeactivated(%d) = 0x%08x\n",
+           deactivate ? 1 : 0, returnCode);
+#endif
+    if (rc || returnCode)
+        goto err_exit;
+
+    if (!deactivate && allow_reset) {
+        if (verbose) {
+            printf("Requiring a reboot to activate the TPM.\n");
+
+            msleep(2000);
+        }
+        reset_vector();
+    }
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+enable_activate(int allow_reset, int verbose)
+{
+    u32 rc;
+
+    rc = disable_tpm(0, verbose);
+    if (rc)
+        return rc;
+
+    rc = deactivate_tpm(0, allow_reset, verbose);
+
+    return rc;
+}
+
+
+static u32
+force_clear(int enable_activate_before, int enable_activate_after, int verbose)
+{
+    u32 rc;
+    u32 returnCode;
+    u8 has_owner;
+
+    rc = read_has_owner(&has_owner);
+    if (rc)
+        return rc;
+    if (!has_owner) {
+        if (verbose)
+            printf("TPM does not have an owner.\n");
+        return 0;
+    }
+
+    if (enable_activate_before) {
+        rc = enable_activate(0, verbose);
+        if (rc) {
+#ifdef DEBUG_TCGBIOS
+            dprintf(1, "TCGBIOS: Enabling/activating the TPM "
+                       "failed.\n");
+#endif
+            return rc;
+        }
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+#ifdef DEBUG_TCGBIOS
+        dprintf(1, "TCGBIOS: Asserting physical presence "
+                   "failed.\n");
+#endif
+        return rc;
+    }
+
+    rc = build_and_send_cmd(TPM_ORD_ForceClear,
+                            NULL, 0, NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+    printf("Return code from TPM_ForceClear() = 0x%08x\n", returnCode);
+#endif
+    if (rc || returnCode)
+        goto err_exit;
+
+    if (!enable_activate_after) {
+        if (verbose)
+            printf("Owner successfully cleared.\n"
+                   "You will need to enable/activate the TPM again.\n\n");
+        return 0;
+    }
+
+    enable_activate(1, verbose);
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static u32
+set_owner_install(int allow, int verbose)
+{
+    u32 rc, returnCode;
+    u8 has_owner;
+    struct tpm_permanent_flags pf;
+
+    rc = read_has_owner(&has_owner);
+    if (rc)
+        return rc;
+    if (has_owner) {
+        if (verbose)
+            printf("Must first remove owner.\n");
+        return 0;
+    }
+
+    rc = read_permanent_flags((char *)&pf, sizeof(pf));
+    if (rc)
+        return rc;
+
+    if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
+        if (verbose)
+            printf("TPM must first be enable.\n");
+        return 0;
+    }
+
+    rc = assert_physical_presence();
+    if (rc) {
+#ifdef DEBUG_TCGBIOS
+        dprintf(1, "TCGBIOS: Asserting physical presence failed.\n");
+#endif
+        return rc;
+    }
+
+    rc = build_and_send_cmd(TPM_ORD_SetOwnerInstall,
+                            (allow) ? CommandFlag_TRUE :
+                                      CommandFlag_FALSE,
+                            sizeof(CommandFlag_TRUE),
+                            NULL, 10, &returnCode);
+#ifdef DEBUG_TCGBIOS
+    printf("Return code from TPM_SetOwnerInstall() = 0x%08x\n",
+           returnCode);
+#endif
+    if (rc || returnCode)
+        goto err_exit;
+
+    if (verbose)
+        printf("Installation of owner %s.\n", allow ? "enabled" : "disabled");
+
+    return 0;
+
+err_exit:
+#ifdef DEBUG_TCGBIOS
+    dprintf(1,"TCGBIOS: TPM malfunctioning (line %d).\n", __LINE__);
+#endif
+    tcpa_state.tpm_working = 0;
+    if (rc)
+        return rc;
+    return TCG_TCG_COMMAND_ERROR;
+}
+
+
+static void
+show_tpm_state(void)
+{
+    struct tpm_permanent_flags pf;
+    u8 has_owner;
+
+    if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
+        read_has_owner(&has_owner))
+        return;
+
+    printf("TPM is ");
+
+    if (pf.flags[PERM_FLAG_IDX_DISABLE])
+        printf("disabled");
+    else
+        printf("enabled");
+
+    if (pf.flags[PERM_FLAG_IDX_DEACTIVATED])
+        printf(", deactivated");
+    else
+        printf(", active");
+
+    if (has_owner)
+        printf(" and has an owner.\n");
+    else {
+        printf(", does not have an owner ");
+        if (pf.flags[PERM_FLAG_IDX_OWNERSHIP])
+            printf("but one can be installed.\n");
+        else
+            printf("and an owner cannot be installed.\n");
+    }
+
+}
+
+
+static u32
+tcpa_process_cfg(const tpm_bios_cfg_t *cfg, int verbose)
+{
+    u32 rc = 0;
+
+#ifdef DEBUG_TCGBIOS
+    printf("TCGBIOS: cfg rev = %d, op = %d\n", cfg->revision, cfg->op);
+#endif
+    if (cfg->revision < 1)
+        return 0;
+
+    switch (cfg->op) {
+        case 0: /* no-op */
+            break;
+
+        case 1:
+            rc = disable_tpm(0, verbose);
+            break;
+
+        case 2:
+            rc = disable_tpm(1, verbose);
+            break;
+
+        case 3:
+            rc = deactivate_tpm(0, 1, verbose);
+            break;
+
+        case 4:
+            rc = deactivate_tpm(1, 1, verbose);
+            break;
+
+        case 5:
+            rc = force_clear(0, 0, verbose);
+            break;
+
+        case 6:
+            rc = enable_activate(1, verbose);
+            break;
+
+        case 7:
+            rc = deactivate_tpm(1, 1, verbose);
+            if (!rc)
+                rc = disable_tpm(1, verbose);
+            break;
+
+        case 8:
+            rc = set_owner_install(1, verbose);
+            break;
+
+        case 9:
+            rc = set_owner_install(0, verbose);
+            break;
+
+        case 10:
+            rc = enable_activate(1, verbose);
+            if (!rc)
+                rc = set_owner_install(1, verbose);
+            break;
+
+        case 11:
+            rc = set_owner_install(0, verbose);
+            if (!rc) {
+                rc = deactivate_tpm(1, 1, verbose);
+                if (!rc)
+                    rc = disable_tpm(1, verbose);
+            }
+            break;
+
+        case 14:
+            rc = force_clear(0, 1, verbose);
+            break;
+
+        case 21:
+            rc = force_clear(1, 0, verbose);
+            break;
+
+        case 22:
+            rc = force_clear(1, 1, verbose);
+            break;
+
+        default:
+            break;
+    }
+
+    if (rc)
+        printf("Op %d: An error occurred: 0x%x\n", cfg->op, rc);
+
+    return rc;
+}
+
+
+void
+tcpa_menu(void)
+{
+    int show_menu = 1;
+    int scan_code;
+    u32 rc;
+    tpm_bios_cfg_t cfg = {
+        .revision = 1,
+        .op  = 0,
+    };
+
+    while (get_keystroke(0) >= 0)
+        ;
+    wait_threads();
+
+    for (;;) {
+        if (show_menu) {
+            printf("1. Enable TPM\n"
+                   "2. Disable TPM\n"
+                   "3. Activate TPM\n"
+                   "4. Deactivate TPM\n"
+                   "5. Clear ownership\n"
+                   "6. Allow installation of owner\n"
+                   "7. Prevent installation of owner\n"
+                   "Escape for previous menu.\n");
+            show_menu = 0;
+            show_tpm_state();
+        }
+
+        cfg.op = 0;
+
+        scan_code = get_keystroke(1000);
+
+        switch (scan_code) {
+        case 1:
+            // ESC
+            return;
+        case 2 ... 5:
+            cfg.op = scan_code - 1;
+            break;
+        case 6: /* force clear */
+            cfg.op = 21;
+            break;
+        case 7 ... 8:
+            cfg.op = scan_code + 1;
+            break;
+        default:
+            continue;
+        }
+
+        rc = tcpa_process_cfg(&cfg, 1);
+
+        if (rc)
+            printf("An error occurred: 0x%x\n", rc);
+
+        show_menu = 1;
+    }
+}
+
 #endif /* CONFIG_TCGBIOS */
Index: seabios/src/boot.c
===================================================================
--- seabios.orig/src/boot.c
+++ seabios/src/boot.c
@@ -364,11 +364,19 @@ interactive_bootmenu(void)
     while (get_keystroke(0) >= 0)
         ;
 
-    printf("Press F12 for boot menu.\n\n");
+again:
+    printf("Press F12 for boot menu.\n");
+    if (has_working_tpm())
+        printf("Press F11 to TPM menu.\n");
+    printf("\n");
 
     enable_bootsplash();
     int scan_code = get_keystroke(CONFIG_BOOTMENU_WAIT);
     disable_bootsplash();
+    if (has_working_tpm() && scan_code == 0x85) {
+         tcpa_menu();
+         goto again;
+    }
     if (scan_code != 0x86)
         /* not F12 */
         return;

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [Qemu-devel] [PATCH V1 8/8] Optional tests for the TIS interface
  2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
                   ` (6 preceding siblings ...)
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 7/8] Add a menu for TPM control Stefan Berger
@ 2011-03-30 17:55 ` Stefan Berger
  7 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-03-30 17:55 UTC (permalink / raw)
  To: stefanb, seabios; +Cc: qemu-devel

[-- Attachment #1: tis_test.diff --]
[-- Type: text/plain, Size: 33068 bytes --]

This patch adds an optional test suite (CONFIG_TIS_TEST) for the TIS interface
to SeaBIOS. If compiled into the BIOS, it can be invoked through the
TPM-specific menu item 8.

1. Enable TPM
2. Disable TPM
3. Activate TPM
4. Deactivate TPM
5. Clear ownership
6. Allow installation of owner
7. Prevent installation of owner
8. TIS test

I would like to see this code become part of the SeaBIOS code base
but I understand that a test suite in a BIOS is not the right place...
Nevertheless, for testing the TIS emulation in Qemu, I am posting it here.
The test suite fills up the available BIOS space from 92.6% at the previous
patch to 98.4%.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---
 Makefile       |    2 
 src/Kconfig    |    7 
 src/tcgbios.c  |   34 +-
 src/tis_test.c |  846 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/tis_test.h |   52 +++
 5 files changed, 932 insertions(+), 9 deletions(-)

Index: seabios/Makefile
===================================================================
--- seabios.orig/Makefile
+++ seabios/Makefile
@@ -20,7 +20,7 @@ SRC16=$(SRCBOTH) system.c disk.c font.c
 SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
       acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
       lzmadecode.c bootsplash.c jpeg.c usb-hub.c paravirt.c dev-i440fx.c \
-      pci_region.c tcgbios.c tpm_drivers.c
+      pci_region.c tcgbios.c tpm_drivers.c tis_test.c
 SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c
 
 cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \
Index: seabios/src/tcgbios.c
===================================================================
--- seabios.orig/src/tcgbios.c
+++ seabios/src/tcgbios.c
@@ -33,6 +33,9 @@
 #include "acpi.h"  // RSDP_SIGNATURE, rsdt_descriptor
 #include "smbios.h" // smbios_entry_point
 
+#ifdef CONFIG_TIS_TEST
+#include "tis_test.h"
+#endif
 
 //#define DEBUG_TCGBIOS
 
@@ -927,6 +930,10 @@ pass_through_to_tpm(struct pttti *pttti,
     iovec[1].data   = NULL;
     iovec[1].length = 0;
 
+#ifdef CONFIG_TIS_TEST
+    locty = pttti->reserved;
+#endif
+
     rc = transmit(locty, iovec, pttto->tpmopout, &resbuflen);
     if (rc)
         goto err_exit;
@@ -2022,26 +2029,29 @@ err_exit:
 }
 
 
-static void
+static int
 show_tpm_state(void)
 {
+    int state = 0;
     struct tpm_permanent_flags pf;
     u8 has_owner;
 
     if (read_permanent_flags((char *)&pf, sizeof(pf)) ||
         read_has_owner(&has_owner))
-        return;
+        return ~0;
 
     printf("TPM is ");
 
-    if (pf.flags[PERM_FLAG_IDX_DISABLE])
+    if (pf.flags[PERM_FLAG_IDX_DISABLE]) {
         printf("disabled");
-    else
+        state |= 1 << PERM_FLAG_IDX_DISABLE;
+    } else
         printf("enabled");
 
-    if (pf.flags[PERM_FLAG_IDX_DEACTIVATED])
+    if (pf.flags[PERM_FLAG_IDX_DEACTIVATED]) {
         printf(", deactivated");
-    else
+        state |= 1 << PERM_FLAG_IDX_DEACTIVATED;
+    } else
         printf(", active");
 
     if (has_owner)
@@ -2054,6 +2064,7 @@ show_tpm_state(void)
             printf("and an owner cannot be installed.\n");
     }
 
+    return state;
 }
 
 
@@ -2152,7 +2163,7 @@ void
 tcpa_menu(void)
 {
     int show_menu = 1;
-    int scan_code;
+    int scan_code, state;
     u32 rc;
     tpm_bios_cfg_t cfg = {
         .revision = 1,
@@ -2172,9 +2183,12 @@ tcpa_menu(void)
                    "5. Clear ownership\n"
                    "6. Allow installation of owner\n"
                    "7. Prevent installation of owner\n"
+#ifdef CONFIG_TIS_TEST
+                   "8. TIS test\n"
+#endif
                    "Escape for previous menu.\n");
             show_menu = 0;
-            show_tpm_state();
+            state = show_tpm_state();
         }
 
         cfg.op = 0;
@@ -2194,6 +2208,10 @@ tcpa_menu(void)
         case 7 ... 8:
             cfg.op = scan_code + 1;
             break;
+#ifdef CONFIG_TIS_TEST
+        case 9:
+            tis_test(state);
+#endif
         default:
             continue;
         }
Index: seabios/src/tis_test.c
===================================================================
--- /dev/null
+++ seabios/src/tis_test.c
@@ -0,0 +1,846 @@
+/*
+ *  TIS interface tests
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2006,2011
+ *
+ * Author: Stefan Berger <stefanb@us.ibm.com>
+ */
+#include "config.h"
+
+#include "types.h"
+#include "util.h" /* read{b,l}, write{b,l} */
+#include "tcgbios.h"
+#include "tpm_drivers.h"
+#include "tis_test.h"
+
+#ifdef CONFIG_TIS_TEST
+
+static int
+tis_check_reg(u32 reg, u8 locty, u32 mask, u32 exp, u32 timeout)
+{
+    u32 val;
+    u32 now = 0;
+
+    while (now <= timeout) {
+        val = readl(TIS_REG(locty, reg));
+
+        if ((val & mask) == exp)
+            return 0;
+
+        mssleep(10);
+
+        now += 10;
+    }
+
+    return 1;
+}
+
+static int
+tis_check_status(u8 locty, u32 mask, u32 exp, u32 timeout)
+{
+    return tis_check_reg(TIS_REG_STS, locty, mask, exp, timeout);
+}
+
+static int
+tis_check_access(u8 locty, u32 mask, u32 exp, u32 timeout)
+{
+    return tis_check_reg(TIS_REG_ACCESS, locty, mask, exp, timeout);
+}
+
+static void
+wait_for_keystroke(void)
+{
+    printf("Press escape to continue.\n");
+    while (1) {
+        switch (get_keystroke(1000)) {
+        case 1:
+            return;
+        }
+    }
+}
+
+static void
+check_access(u8 locty, u8 mask, u8 exp,
+             const char *succ_msg,
+             const char *fail_msg)
+{
+    u8 acc = readb(TIS_REG(locty, TIS_REG_ACCESS));
+    u8 res = acc & mask;
+
+    if (res == exp)
+        printf("%s  -- access reg : %02x\n", succ_msg, acc);
+    else {
+        printf("ERROR: %s\n"
+               "value = %02x, mask = %02x, exp = %02x, actual = %02x, "
+               "bad = %02x\n",
+               fail_msg, acc, mask, exp, res, res ^ exp );
+        wait_for_keystroke();
+    }
+}
+
+static void
+tis_activate_locality(u8 new_locty)
+{
+    int locty;
+
+    /* release locality in use top-downwards */
+    for (locty = 4; locty >= 0; locty--)
+        writeb(TIS_REG(locty, TIS_REG_ACCESS),
+               TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_BEEN_SEIZED);
+
+    printf("Requesting access to locality %d\n", new_locty);
+
+    writeb(TIS_REG(new_locty, TIS_REG_ACCESS),
+           TIS_ACCESS_REQUEST_USE);
+
+    check_access(new_locty,
+                 TIS_ACCESS_ACTIVE_LOCALITY,
+                 TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Switch to the locality",
+                 "Could not get the locality");
+}
+
+/*
+ * Test getting access to localities using the
+ * TIS_ACCESS_ACTIVATE_LOCALITY flag
+ * The test ends with locality 0 being active.
+ */
+static void
+test_active_locality_flag(void)
+{
+    printf("Requesting access to locality 0\n");
+
+    writeb(TIS_REG(0, TIS_REG_ACCESS),
+           TIS_ACCESS_REQUEST_USE|TIS_ACCESS_BEEN_SEIZED);
+
+    check_access(0,
+                 TIS_ACCESS_TPM_ESTABLISHMENT,
+                 TIS_ACCESS_TPM_ESTABLISHMENT,
+                 "Valid TPM Establishment flag in locality 0",
+                 "Invalid TPM Establishment flag in locality 0");
+
+    check_access(0,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY | TIS_ACCESS_BEEN_SEIZED,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Got locality 0",
+                 "Could not get locality 0");
+
+    printf("Giving up locality 0\n");
+    writeb(TIS_REG(0, TIS_REG_ACCESS), TIS_ACCESS_ACTIVE_LOCALITY);
+
+    check_access(0,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80,
+                 "Successfully released locality 0",
+                 "Still have locality 0");
+
+    printf("Requesting access to locality 1\n");
+
+    writeb(TIS_REG(1, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+    check_access(1,
+                 TIS_ACCESS_ACTIVE_LOCALITY,
+                 TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Got locality 1",
+                 "Could not get locality 1");
+
+    printf("Requesting access to locality 2; seizing locality.\n");
+
+    writeb(TIS_REG(2, TIS_REG_ACCESS), TIS_ACCESS_SEIZE);
+
+    check_access(1,
+                 0x80 | TIS_ACCESS_BEEN_SEIZED | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_BEEN_SEIZED,
+                 "Access to locality 1 has been seized",
+                 "Access to locality 1 has not been properly seized");
+
+    check_access(2,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Got locality 2",
+                 "Could not get locality 2");
+
+    printf("Setting request to use by locality 1\n");
+
+    writeb(TIS_REG(1, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+    check_access(2,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY| TIS_ACCESS_PENDING_REQUEST,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY| TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 2 sees pending request by locality 1",
+                 "Locality 2 does not see pending request by locality 1");
+
+    check_access(1,
+                 0x80 | TIS_ACCESS_REQUEST_USE | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_REQUEST_USE,
+                 "Locality 1 has request pending",
+                 "Locality 1 does not have request pending");
+
+    printf("Setting request to use by locality 0\n");
+
+    writeb(TIS_REG(0, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+    check_access(0,
+                 0x80 | TIS_ACCESS_REQUEST_USE | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_REQUEST_USE,
+                 "Locality 0 has request pending",
+                 "Locality 0 does not have request pending");
+
+    check_access(2,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 2 sees pending request by locality 1",
+                 "Locality 2 does not see pending request by locality 1");
+
+    printf("Setting request to use by locality 3\n");
+
+    writeb(TIS_REG(3, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+    check_access(3,
+                 0x80 | TIS_ACCESS_REQUEST_USE | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_REQUEST_USE,
+                 "Locality 3 has request pending",
+                 "Locality 3 does not have request pending");
+
+    check_access(2,
+                 0x80|TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80|TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 2 sees pending request by localities 0, 1 & 3",
+                 "Locality 2 does not see pending request by localities "
+                 "0, 1 & 3");
+
+    printf("Releasing use by locality 2\n");
+
+    writeb(TIS_REG(2, TIS_REG_ACCESS), TIS_ACCESS_ACTIVE_LOCALITY);
+
+    check_access(2,
+                 0x80 | TIS_ACCESS_PENDING_REQUEST|TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 2 successfully relased usage",
+                 "Locality 2 did not completely release usage");
+
+    check_access(3,
+                 0x80|TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80|TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 3 is active and sees pending request by localities "
+                 "0 & 1",
+                 "Locality 3 does not see proper flags");
+
+    check_access(0,
+                 0x80|TIS_ACCESS_REQUEST_USE|TIS_ACCESS_PENDING_REQUEST|
+                      TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80|TIS_ACCESS_REQUEST_USE|TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 0 has request pending and sees other pending request",
+                 "Locality 0 does not have request pending");
+
+    printf("Locality 1 drops request\n");
+
+    writeb(TIS_REG(1, TIS_REG_ACCESS), TIS_ACCESS_ACTIVE_LOCALITY);
+
+    printf("Releasing use by locality 3\n");
+
+    writeb(TIS_REG(3, TIS_REG_ACCESS), TIS_ACCESS_ACTIVE_LOCALITY);
+
+    check_access(3,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80,
+                 "Locality 3 successfully relased usage",
+                 "Locality 3 did not completely release usage");
+
+    check_access(1,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80,
+                 "Locality 1 successfully relased usage",
+                 "Locality 1 did not completely release usage");
+
+    check_access(0,
+                 0x80|TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80|TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Locality 0 is active",
+                 "Locality 0 is not avtive");
+}
+
+/*
+ * Test the seize flag. It is assumed that locality 0 is active.
+ * The test ends with locality 2 being active
+ */
+static void
+test_seize_locality_flag(void)
+{
+    printf("Requesting use by locality 1 using the SEIZE bit\n");
+
+    writeb(TIS_REG(1, TIS_REG_ACCESS), TIS_ACCESS_SEIZE);
+
+    check_access(0,
+                 0x80 | TIS_ACCESS_BEEN_SEIZED|TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_BEEN_SEIZED,
+                 "Access to locality 0 has been seized",
+                 "Access to locality 0 has not been properly seized");
+
+    check_access(1,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Locality 1 successfully seized usage",
+                 "Locality 1 did not seize usage");
+
+    printf("Requesting use by locality 2 using the SEIZE bit\n");
+
+    writeb(TIS_REG(2, TIS_REG_ACCESS), TIS_ACCESS_SEIZE);
+
+    check_access(1,
+                 0x80 | TIS_ACCESS_BEEN_SEIZED | TIS_ACCESS_ACTIVE_LOCALITY,
+                 0x80 | TIS_ACCESS_BEEN_SEIZED,
+                 "Access to locality 1 has been seized",
+                 "Access to locality 1 has not been properly seized");
+
+    check_access(2,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 0x80 | TIS_ACCESS_ACTIVE_LOCALITY,
+                 "Locality 2 successfully seized usage",
+                 "Locality 1 did not seize usage");
+}
+
+#define ENABLED(L4,L3,L2,L1,L0) \
+  ((L4) << 4 | (L3) << 3 | (L2) << 2 | (L1) << 1 | (L0))
+
+static const u8 pcr_resets[] = {
+     ENABLED(1,1,1,1,1), /* PCR 16 */
+     ENABLED(1,0,0,0,0),
+     ENABLED(1,0,0,0,0),
+     ENABLED(1,0,0,0,0),
+     ENABLED(1,0,1,0,0),
+     ENABLED(0,0,1,0,0),
+     ENABLED(0,0,1,0,0),
+     ENABLED(1,1,1,1,1),
+};
+
+static const u8 pcr_extends[] = {
+     ENABLED(1,1,1,1,1), /* PCR 16 */
+     ENABLED(1,1,1,0,0),
+     ENABLED(1,1,1,0,0),
+     ENABLED(0,1,1,0,0),
+     ENABLED(0,1,1,1,0),
+     ENABLED(0,0,1,0,0),
+     ENABLED(0,0,1,0,0),
+     ENABLED(1,1,1,1,1),
+};
+
+
+static u32
+do_pcr_read(u32 pcrindex, u8 *result, u8 locty)
+{
+    u32 rc;
+
+    struct pttto_pcrread pttto;
+    struct pttti_pcrread pttti = {
+        .pttti = {
+            .reserved = locty,
+            .ipblength = sizeof(struct pttti_pcrread),
+            .opblength = sizeof(struct pttto_pcrread),
+        },
+        .req = {
+            .tag      = htons(0xc1),
+            .totlen   = htonl(sizeof(pttti.req)),
+            .ordinal  = htonl(TPM_ORD_PcrRead),
+            .pcrindex = htonl(pcrindex),
+        },
+    };
+    struct bregs regs;
+    regs.es  = FLATPTR_TO_SEG   (&pttti);
+    regs.edi = FLATPTR_TO_OFFSET(&pttti);
+    regs.ds  = FLATPTR_TO_SEG   (&pttto);
+    regs.esi = FLATPTR_TO_OFFSET(&pttto);
+    regs.eax = TCG_PassThroughToTPM;
+
+    tcpa_interrupt_handler32(&regs);
+
+    rc = regs.eax;
+
+    if (rc == 0) {
+        if ((pttto.pttto.opblength < TPM_RSP_HEADER_SIZE) ||
+            ntohs(pttto.rsp.tag) != 0xc4) {
+            rc = TCG_FATAL_COM_ERROR;
+        }
+    }
+
+    if (rc == 0)
+       memcpy(result, pttto.rsp.digest, sizeof(pttto.rsp.digest));
+
+    return rc;
+}
+
+
+static u32
+do_pcr_extend(u8 *hash, u32 pcrindex, u8 locty)
+{
+    u32 rc;
+
+    struct pttto_extend pttto;
+    struct pttti_extend pttti = {
+        .pttti = {
+            .reserved = locty,
+            .ipblength = sizeof(struct pttti_extend),
+            .opblength = sizeof(struct pttto_extend),
+        },
+        .req = {
+            .tag      = htons(0xc1),
+            .totlen   = htonl(sizeof(pttti.req)),
+            .ordinal  = htonl(TPM_ORD_Extend),
+            .pcrindex = htonl(pcrindex),
+        },
+    };
+    struct bregs regs;
+    regs.es  = FLATPTR_TO_SEG(&pttti);
+    regs.edi = FLATPTR_TO_OFFSET(&pttti);
+    regs.ds  = FLATPTR_TO_SEG(&pttto);
+    regs.esi = FLATPTR_TO_OFFSET(&pttto);
+    regs.eax = TCG_PassThroughToTPM;
+
+    memcpy(pttti.req.digest, hash, sizeof(pttti.req.digest));
+
+    tcpa_interrupt_handler32(&regs);
+
+    rc = regs.eax;
+
+    if (rc == 0) {
+        if ((pttto.pttto.opblength < TPM_RSP_HEADER_SIZE) ||
+            ntohs(pttto.rsp.tag) != 0xc4) {
+            rc = TCG_FATAL_COM_ERROR;
+        }
+    }
+
+    return rc;
+}
+
+
+static u32
+do_pcr_reset(u32 pcrindex, u8 locty)
+{
+    u32 rc;
+
+    struct pttto_pcrreset pttto;
+    struct pttti_pcrreset pttti = {
+        .pttti = {
+            .reserved  = locty,
+            .ipblength = sizeof(struct pttti_pcrreset),
+            .opblength = sizeof(struct pttto_pcrreset),
+        },
+        .req = {
+            .tag          = htons(0xc1),
+            .totlen       = htonl(sizeof(pttti.req)),
+            .ordinal      = htonl(TPM_ORD_PCR_Reset),
+            .sizeOfSelect = htons(3),
+        },
+    };
+    struct bregs regs;
+    regs.es  = FLATPTR_TO_SEG(&pttti);
+    regs.edi = FLATPTR_TO_OFFSET(&pttti);
+    regs.ds  = FLATPTR_TO_SEG(&pttto);
+    regs.esi = FLATPTR_TO_OFFSET(&pttto);
+    regs.eax = TCG_PassThroughToTPM;
+
+    pttti.req.pcrSelect[pcrindex >> 3] = 1 << (pcrindex & 0x7);
+
+    tcpa_interrupt_handler32(&regs);
+
+    rc = regs.eax;
+
+    if (rc == 0) {
+        if ((pttto.pttto.opblength < TPM_RSP_HEADER_SIZE) ||
+            ntohs(pttto.rsp.tag) != 0xc4) {
+            rc = TCG_FATAL_COM_ERROR;
+        }
+    }
+
+    return rc;
+}
+
+
+static void
+test_pcr_test(void)
+{
+    u32 pcr_num, res;
+    u8 locty;
+    u8 value_a[20], value_b[20], value_c[20];
+    u8 reset_pcr_0s[20] = { /* all PCRs; 17-22 if TOSPresent = true */
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    };
+    u8 reset_pcr_1s[20] = { /* 17-22 if TOSPresent = false */
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+    };
+    u8 value_ext[20] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
+    int extended;
+    int tos_present = !readb(TIS_REG(0, TIS_REG_ACCESS)) &
+                            TIS_ACCESS_TPM_ESTABLISHMENT;
+
+    printf("Testing PCR Extend and Reset\n");
+
+    for (pcr_num = 16; pcr_num <= 23; pcr_num++) {
+
+        printf("PCR %d: ",pcr_num);
+
+        for (locty = 0; locty <= 4; locty++) {
+            if ((res = do_pcr_read(pcr_num, value_a, locty))) {
+                printf("!F0[%d] = 0x%08x", locty, res);
+                continue;
+            }
+            if ((res = do_pcr_extend(value_ext, pcr_num, locty))) {
+                printf("!F1[%d] = 0x%08x", locty, res);
+                continue;
+            }
+            if ((res = do_pcr_read(pcr_num, value_b, locty))) {
+                printf("!F2[%d] = 0x%08x", locty, res);
+                continue;
+            }
+            /* did the PCR change? */
+            if (memcmp(value_a, value_b, sizeof(value_a)) != 0) {
+                /* extend worked */
+                extended = 1;
+                if ((pcr_extends[pcr_num-16] & (1 << locty)) == 0)
+                    printf("!F3[%d] ", locty);
+                else
+                    printf(" P1[%d] ", locty);
+            } else {
+                extended = 0;
+                /* extend did not work */
+                if (pcr_extends[pcr_num-16] & (1 << locty))
+                    printf("!F4[%d] ", locty);
+                else
+                    printf(" P2[%d] ", locty);
+            }
+
+            if (!extended) {
+                /* Need to extend using locality 2; this always works */
+                if ((res = do_pcr_extend(value_ext, pcr_num, 2))) {
+                    printf("!F5[%d] = 0x%08x", locty, res);
+                    continue;
+                }
+            }
+
+            if ((res = do_pcr_reset(pcr_num, locty))) {
+                printf("!F6[%d] = 0x%08x", locty, res);
+                continue;
+            }
+            if (do_pcr_read(pcr_num, value_c, locty)) {
+                printf("!F7[%d] = 0x%08x", locty, res);
+                continue;
+            }
+            /* did reset work? */
+            if ((( pcr_num <= 16 ||
+                   pcr_num == 23 ||
+                  (pcr_num >= 17 && pcr_num <= 22 && tos_present)
+                 ) &&
+                  memcmp(value_c, reset_pcr_0s, sizeof(value_c)) == 0
+                ) ||
+                ( pcr_num >= 17 && pcr_num <= 22 && !tos_present &&
+                  memcmp(value_c, reset_pcr_1s, sizeof(value_c)) == 0
+                )
+               ) {
+                /* reset worked */
+                if ((pcr_resets[pcr_num-16] & (1 << locty)) == 0)
+                    printf("!F8[%d] ", locty);
+                else
+                    printf(" P3[%d] ", locty);
+            } else {
+                /* reset did not work */
+                if ((pcr_resets[pcr_num-16] & (1 << locty)))
+                    printf("!F9[%d] ", locty);
+                else
+                    printf(" P4[%d] ", locty);
+            }
+        }
+        printf("\n");
+    }
+}
+
+
+/* send a command to the TPM without waiting for the response;
+   the caller must have activate the given locality */
+static int
+send_command(u8 locty, const unsigned char *command, u32 cmd_length)
+{
+    u32 c;
+    u32 burst;
+
+    writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+
+    if (tis_check_status(locty,
+                         TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY, 1000)) {
+        printf("Error: Could not bring the TPM "
+               "into ready state in locality %d\n", locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    burst = readl(TIS_REG(locty, TIS_REG_STS)) >> 8;
+
+    for (c = 0; c < cmd_length && burst > 0; c++) {
+        writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), command[c]);
+        burst--;
+    }
+
+    if (c != cmd_length) {
+        printf("Error: Could not write data into locality %d FIFO\n", locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_TPM_GO);
+
+    return 0;
+}
+
+
+unsigned char pcr_read_cmd[] = {
+    0x00, 0xc1, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00,
+    0x00, 0x15, 0x00, 0x00, 0x00, 0x0a
+};
+
+static void
+test_cmd_aborts(void)
+{
+    printf("Testing command aborts\n");
+
+    /* abort using COMMAND_READY flag */
+
+    tis_activate_locality(0);
+
+    if (send_command(0, pcr_read_cmd, sizeof(pcr_read_cmd))) {
+        printf("Error: Sending command did not work.\n");
+        wait_for_keystroke();
+    } else {
+        writeb(TIS_REG(0, TIS_REG_STS), TIS_STS_COMMAND_READY);
+
+        if (tis_check_status(0,
+                             TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY,
+                             1000)) {
+            printf("After abort, locality %d did not become ready in time.\n",
+                   0);
+        }
+    }
+
+    /* abort using the Seize flag by a higher locality */
+
+    writeb(TIS_REG(0, TIS_REG_ACCESS), TIS_ACCESS_BEEN_SEIZED);
+
+    if (send_command(0, pcr_read_cmd, sizeof(pcr_read_cmd))) {
+        printf("Error: Sending command did not work.\n");
+        wait_for_keystroke();
+    } else {
+        writeb(TIS_REG(1, TIS_REG_ACCESS), TIS_ACCESS_SEIZE);
+
+        if (tis_check_access(1,
+                             TIS_ACCESS_ACTIVE_LOCALITY,
+                             TIS_ACCESS_ACTIVE_LOCALITY,
+                             1000)) {
+            printf("Error: Aborting of locality %d command by locality %d "
+                   "using the SEIZE flag did not work.\n",
+                   0, 1);
+            wait_for_keystroke();
+        } else {
+            check_access(0,
+                         TIS_ACCESS_BEEN_SEIZED|TIS_ACCESS_ACTIVE_LOCALITY,
+                         TIS_ACCESS_BEEN_SEIZED,
+                         "Access to locality 0 has been seized",
+                         "Access to locality 0 has not been properly seized");
+
+            check_access(1,
+                         TIS_ACCESS_ACTIVE_LOCALITY,
+                         TIS_ACCESS_ACTIVE_LOCALITY,
+                         "Got locality 1",
+                         "Could not get locality 1");
+        }
+    }
+
+    /* abort using ACTIVE_LOCALITY flag */
+    tis_activate_locality(1);
+
+    /* put in request by locality 0 */
+    writeb(TIS_REG(0, TIS_REG_ACCESS), TIS_ACCESS_REQUEST_USE);
+
+    check_access(1,
+                 TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 TIS_ACCESS_ACTIVE_LOCALITY|TIS_ACCESS_PENDING_REQUEST,
+                 "Locality 1 sees pending request",
+                 "Locality 1 does not see pending request");
+
+    if (send_command(1, pcr_read_cmd, sizeof(pcr_read_cmd))) {
+        printf("Error: Sending command did not work.\n");
+        wait_for_keystroke();
+    } else {
+        writeb(TIS_REG(1, TIS_REG_ACCESS), TIS_ACCESS_ACTIVE_LOCALITY);
+
+        if (tis_check_access(0,
+                             TIS_ACCESS_ACTIVE_LOCALITY,
+                             TIS_ACCESS_ACTIVE_LOCALITY,
+                             1000)) {
+            printf("Error: Aborting of locality %d command "
+                   "using the ACTIVE_LOCALITY flag did not work.\n",
+                   1);
+            printf("access[0] : %02x\n", readb(TIS_REG(0, TIS_REG_ACCESS)));
+            printf("access[1] : %02x\n", readb(TIS_REG(1, TIS_REG_ACCESS)));
+            wait_for_keystroke();
+        } else {
+            check_access(1,
+                         TIS_ACCESS_ACTIVE_LOCALITY,
+                         0,
+                         "Access to locality 1 relinquished",
+                         "Access to locality 1 not relinquished");
+
+            check_access(0,
+                         TIS_ACCESS_ACTIVE_LOCALITY,
+                         TIS_ACCESS_ACTIVE_LOCALITY,
+                         "Got locality 0",
+                         "Could not get locality 0");
+        }
+    }
+}
+
+
+int
+test_various(u8 locty)
+{
+    int i;
+
+    tis_activate_locality(locty);
+
+    printf("Putting locality %d in ready state.\n", locty);
+
+    writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+
+    if (tis_check_status(locty,
+                         TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY, 1000)) {
+        printf("Error: Could not bring the TPM "
+               "into ready state in locality %d\n",locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    printf("Reading data from FIFO. Expecting 0xff.\n");
+
+    if (readb(TIS_REG(locty, TIS_REG_DATA_FIFO)) != 0xff) {
+        printf("Error: Expected to 0xff from FIFO\n");
+        wait_for_keystroke();
+    }
+
+    printf("Writing a byte into the FIFO.\n");
+
+    writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), pcr_read_cmd[0]);
+
+    if (tis_check_status(locty,
+                         TIS_STS_EXPECT, TIS_STS_EXPECT, 0)) {
+        printf("Error: TIS is not expecting data in locality %d\n",locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    printf("Sending single byte to be processed.\n");
+
+    /* tpm will process the single byte */
+    writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_TPM_GO);
+
+    if (tis_check_status(locty,
+                         TIS_STS_EXPECT, 0, 0)) {
+        printf("Error: TIS is still expecting data in locality %d [2nd]\n",
+               locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    printf("Checking for result.\n");
+
+    if (tis_check_status(locty,
+                         TIS_STS_DATA_AVAILABLE, TIS_STS_DATA_AVAILABLE,
+                         1000)) {
+        printf("Error: No data available in locality %d [2nd]\n",
+               locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    printf("Putting locality %d in ready state.\n", locty);
+
+    writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+
+    printf("Writing TPM_PcrRead command into FIFO.\n");
+
+    for (i = 0; i < sizeof(pcr_read_cmd); i++) {
+        if (i > 0 && tis_check_status(0, TIS_STS_EXPECT, TIS_STS_EXPECT, 0)) {
+            printf("Error: TIS is not expecting data anymore [%d/%d].\n",
+                   i,sizeof(pcr_read_cmd)-1);
+            readb(TIS_REG(locty, 0xf90));
+            wait_for_keystroke();
+        }
+        writeb(TIS_REG(locty, TIS_REG_DATA_FIFO), pcr_read_cmd[i]);
+    }
+
+    printf("Checking whether the TPM is still expecting data. "
+           "It should not.\n");
+
+    if (tis_check_status(locty,
+                         TIS_STS_EXPECT, 0, 0)) {
+        printf("Error: TIS is still expecting data in locality %d\n",
+               locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    printf("Sending command to put locality %d into ready state.\n", locty);
+
+    writeb(TIS_REG(locty, TIS_REG_STS), TIS_STS_COMMAND_READY);
+
+    printf("Checking that locality %d is in ready state.\n", locty);
+
+    if (tis_check_status(locty,
+                         TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY, 1000)) {
+        printf("Error: Could not bring the TPM "
+               "into ready state in locality %d [2nd]\n", locty);
+        wait_for_keystroke();
+        return 1;
+    }
+
+    return 0;
+}
+
+
+void
+tis_test(int tpm_state)
+{
+    test_active_locality_flag();
+
+    /* locality 0 is active */
+
+    test_seize_locality_flag();
+
+    /* locality 2 is active */
+
+    if (tpm_state == 0)
+        test_pcr_test();
+
+    test_cmd_aborts();
+
+    test_various(0);
+
+    tis_activate_locality(0);
+
+    printf("END OF TEST.\n");
+    wait_for_keystroke();
+}
+
+#endif /* CONFIG_TIS_TEST */
Index: seabios/src/tis_test.h
===================================================================
--- /dev/null
+++ seabios/src/tis_test.h
@@ -0,0 +1,52 @@
+#ifndef TIS_TEST
+#define TIS_TEST
+
+#include "tcgbios.h"
+
+#define TPM_ORD_PCR_Reset       0x000000c8
+#define TPM_ORD_PcrRead         0x00000015
+
+void tis_test(int tpm_state);
+
+struct tpm_req_pcrread {
+    TPM_REQ_HEADER
+    u32    pcrindex;
+} PACKED;
+
+struct tpm_rsp_pcrread {
+    TPM_RSP_HEADER
+    u8     digest[SHA1_BUFSIZE];
+} PACKED;
+
+struct pttti_pcrread {
+    struct pttti pttti;
+    struct tpm_req_pcrread req;
+} PACKED;
+
+struct pttto_pcrread {
+    struct pttto pttto;
+    struct tpm_rsp_pcrread rsp;
+} PACKED;
+
+
+struct tpm_req_pcrreset {
+    TPM_REQ_HEADER
+    u16     sizeOfSelect;
+    u8      pcrSelect[3];
+} PACKED;
+
+struct tpm_rsp_pcrreset {
+    TPM_RSP_HEADER
+} PACKED;
+
+struct pttti_pcrreset {
+    struct pttti pttti;
+    struct tpm_req_pcrreset req;
+} PACKED;
+
+struct pttto_pcrreset {
+    struct pttto pttto;
+    struct tpm_rsp_pcrreset rsp;
+} PACKED;
+
+#endif /* TIS_TEST */
Index: seabios/src/Kconfig
===================================================================
--- seabios.orig/src/Kconfig
+++ seabios/src/Kconfig
@@ -330,6 +330,13 @@ menu "BIOS interfaces"
             Either you may use the TPM for SHA1 calculations or
             use the internal sha1 algorithm to do it (faster).
 
+    config TIS_TEST
+        depends on TCGBIOS
+        bool "TPM TIS test"
+        default n
+        help
+            Test cases for the TPM TIS interface
+
 endmenu
 
 menu "BIOS Tables"

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions Stefan Berger
@ 2011-04-04  4:14   ` Kevin O'Connor
  2011-04-04 14:49     ` Stefan Berger
  0 siblings, 1 reply; 17+ messages in thread
From: Kevin O'Connor @ 2011-04-04  4:14 UTC (permalink / raw)
  To: Stefan Berger; +Cc: seabios, qemu-devel

Hi Stefan,

I haven't had a chance to fully review, but I do have some comments.

On Wed, Mar 30, 2011 at 01:55:37PM -0400, Stefan Berger wrote:
[...]
> - a utility function called mssleep is added. It waits for a number
>   of milliseconds before it returns. I had tried to build a function
>   like that based on calc_future_time() and check_timer(), but those
>   didn't work once in an S3 resume.

There is already msleep() for this.  The inb(0x61) thing doesn't
actually work anywhere but on bochs.  If msleep() isn't working for
you, try rerunning calibrate_tsc() after S3 resume.

[...]
> +/*
> + *  Implementation of the TCG BIOS extension according to the specification
> + *  described in
> + *  https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2 of the License, or (at your option) any later version.

SeaBIOS is LGPLv3.  Also, I'm not a big fan of these big copyright
notices on the top of every file - is it necessary?

[...]
> +#if CONFIG_TCGBIOS

I'd prefer to avoid ifdefs in the code.  Everything should be setup to
have the compiler/linker automatically drop anything unused.  (So, a
simple "if (!CONFIG_TCGBIOS) return;" should drop any function and all
variables/functions only reachable from it.)

[...]
> +//#define DEBUG_TCGBIOS

Same here.  Can you use just set DEBUG_tcg to a value in config.h and
replace all the dprintf(1, ...) with dprintf(DEBUG_tcg, ...)?

> +static u8
> +calc_checksum(const u8 *addr, u32 length)

util.c:checksum()

> +static struct rsdp_descriptor *
> +find_rsdp(u8 *start, unsigned int len)

Should be unneeded - see how acpi.c:find_resume_vector() works.

-Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support Stefan Berger
@ 2011-04-04  4:17   ` Kevin O'Connor
  2011-04-04 14:52     ` Stefan Berger
  0 siblings, 1 reply; 17+ messages in thread
From: Kevin O'Connor @ 2011-04-04  4:17 UTC (permalink / raw)
  To: Stefan Berger; +Cc: seabios, qemu-devel

On Wed, Mar 30, 2011 at 01:55:36PM -0400, Stefan Berger wrote:
> This patch provides ACPI support for the TPM device. It probes for the TPM
> device and only if a TPM device is found then the TPM's SSDT and TCPA table
> are created. This patch also connects them to the RSDT.
[...]
>  // Space to reserve in high-memory for tables
> -#define CONFIG_MAX_HIGHTABLE (64*1024)
> +#if CONFIG_TCGBIOS
> +# define CONFIG_MAX_HIGHTABLE (96*1024)
> +#else
> +# define CONFIG_MAX_HIGHTABLE (64*1024)
> +#endif

I'm a bit confused on patch ordering - it seems CONFIG_TCGBIOS is
defined in patch 4 but used in patch 2.

Also, I'd prefer to avoid ifdefs - just up the size to 96 always, or
do something like:

#define CONFIG_MAX_HIGHTABLE ((64*1024) + CONFIG_TCGBIOS*(32*1024))

-Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler Stefan Berger
@ 2011-04-04  4:30   ` Kevin O'Connor
  2011-04-04 14:54     ` Stefan Berger
  0 siblings, 1 reply; 17+ messages in thread
From: Kevin O'Connor @ 2011-04-04  4:30 UTC (permalink / raw)
  To: Stefan Berger; +Cc: seabios, qemu-devel

On Wed, Mar 30, 2011 at 01:55:39PM -0400, Stefan Berger wrote:
> This patch implements the TCG BIOS interrupt handler 1ah. It is for
> example used by trusted grub.
[...]
> +/*******************************************************************
> +  Calculation of SHA1 in SW
> +
> +  See: http://www.itl.nist.gov/fipspubs/fip180-1.htm
> +       RFC3174, Wikipedia's SHA1 alogrithm description
> + ******************************************************************/

Looks like tcgbios.c is awfully big - can we move the sha1 code to
it's own file (eg, sha1.c)?

[...]
> +static inline u32 rol(u32 val, u16 rol)

Should move to util.h.

> +static inline u64 bswap_64(u64 val)

Same.

[...]
> +++ seabios/src/stacks.c
[...]
> +#ifdef CONFIG_TCGBIOS
> +void tcpa_interrupt_handler16(struct bregs *regs)
> +{
> +    if (MODESEGMENT) {

I'm a bit confused here - MODESEGMENT will always be true.  Also, this
code doesn't need to be in stacks.c - just invoke call32() directly
from handle_1abb().

Also, as before, just do "if (!CONFIG_TCGBIOS) return;" instead of the
#ifdef.

-Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS
  2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS Stefan Berger
@ 2011-04-04  4:57   ` Kevin O'Connor
  2011-04-04 16:38     ` Stefan Berger
  0 siblings, 1 reply; 17+ messages in thread
From: Kevin O'Connor @ 2011-04-04  4:57 UTC (permalink / raw)
  To: Stefan Berger; +Cc: seabios, qemu-devel

On Wed, Mar 30, 2011 at 01:55:40PM -0400, Stefan Berger wrote:
> This patch adds invocactions of functions that measure various parts of the
> code and data through various parts of the BIOS code. It follows TCG
> specifications on what needs to be measured. It also adds the implementation
> of the called functions.
[...]
>  void VISIBLE32FLAT
>  startBoot(void)
>  {
> +    tcpa_calling_int19h();
> +    tcpa_add_event_separators();

Why add two functions here, instead of just one function that does
both actions?

[...]
>      // Initialize tpm (after acpi tables were written)
>      tcpa_acpi_init();
>      tcpa_startup();
> +    tcpa_measure_post((void *)0xE0000, (void *)0xFFFFF);
> +    tcpa_smbios_measure();

Same here.  Also, I'm not sure I understand why you're measuring
0xE0000-0xFFFFF - if the intent is to measure the code, then it's a
bit more complicated as the init code has already been relocated by
this point.

[...]
> +    tcpa_option_rom(FLATPTR_TO_SEG(rom), len);

You're better off just defining tcpa_option_rom() to take a regular
pointer.

[...]
> +    /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
> +    /* measure 2048 bytes (one sector) */
> +    tcpa_add_bootdevice(1, 0);
> +    tcpa_ipl(IPL_EL_TORITO_2, GET_SEG(SS), (u32)buffer, 2048);

Same here for tcpa_ipl().  GET_SEG() always returns 0 in 32bit mode
and this code is only run in 32bit mode.

[...]
> +static struct smbios_entry_point *
> +find_smbios_entry_point(void)
> +{

The smbios table is built in smbios.c:smbios_entry_point_init() -
instead of scanning for the table, just record where the table is in a
global variable.

[...]
> +u32
> +tcpa_smbios_measure(void)
> +{
> +    u32 rc;
> +    struct pcctes pcctes = {
> +        .eventid = 1, /* 10.4.2.3.1 */
> +        .eventdatasize = SHA1_BUFSIZE,
> +    };
> +    struct smbios_entry_point *sep = find_smbios_entry_point();
> +
> +    if (!has_working_tpm())
> +        return 0;

BTW - SeaBIOS uses C99, so it's fine to move "if (!has_working_tpm())"
above the variable declarations.

-Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions
  2011-04-04  4:14   ` Kevin O'Connor
@ 2011-04-04 14:49     ` Stefan Berger
  0 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-04-04 14:49 UTC (permalink / raw)
  To: Kevin O'Connor; +Cc: seabios, qemu-devel

On 04/04/2011 12:14 AM, Kevin O'Connor wrote:
> Hi Stefan,
>
> I haven't had a chance to fully review, but I do have some comments.
Thanks. I can post a v2 as a followup to your changes.
> On Wed, Mar 30, 2011 at 01:55:37PM -0400, Stefan Berger wrote:
> [...]
>> - a utility function called mssleep is added. It waits for a number
>>    of milliseconds before it returns. I had tried to build a function
>>    like that based on calc_future_time() and check_timer(), but those
>>    didn't work once in an S3 resume.
> There is already msleep() for this.  The inb(0x61) thing doesn't
> actually work anywhere but on bochs.  If msleep() isn't working for
> you, try rerunning calibrate_tsc() after S3 resume.
Using that one now.
> [...]
>> +/*
>> + *  Implementation of the TCG BIOS extension according to the specification
>> + *  described in
>> + *  https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementationforBIOS_1-20_1-00.pdf
>> + *
>> + *  This library is free software; you can redistribute it and/or
>> + *  modify it under the terms of the GNU Lesser General Public
>> + *  License as published by the Free Software Foundation; either
>> + *  version 2 of the License, or (at your option) any later version.
> SeaBIOS is LGPLv3.  Also, I'm not a big fan of these big copyright
> notices on the top of every file - is it necessary?
I will change it to look like the other files.
> [...]
>> +#if CONFIG_TCGBIOS
> I'd prefer to avoid ifdefs in the code.  Everything should be setup to
> have the compiler/linker automatically drop anything unused.  (So, a
> simple "if (!CONFIG_TCGBIOS) return;" should drop any function and all
> variables/functions only reachable from it.)
Ok, I will adapt it to that.
> [...]
>> +//#define DEBUG_TCGBIOS
> Same here.  Can you use just set DEBUG_tcg to a value in config.h and
> replace all the dprintf(1, ...) with dprintf(DEBUG_tcg, ...)?

Did that now.
>> +static u8
>> +calc_checksum(const u8 *addr, u32 length)
> util.c:checksum()
Using that one.
>> +static struct rsdp_descriptor *
>> +find_rsdp(u8 *start, unsigned int len)
> Should be unneeded - see how acpi.c:find_resume_vector() works.
I was going to keep the function find_rsdp but change its implementation 
to the test you are doing in find_resume_vector() regarding rsdp signature.

    Stefan

> -Kevin
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support
  2011-04-04  4:17   ` Kevin O'Connor
@ 2011-04-04 14:52     ` Stefan Berger
  0 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-04-04 14:52 UTC (permalink / raw)
  To: Kevin O'Connor; +Cc: seabios, qemu-devel

On 04/04/2011 12:17 AM, Kevin O'Connor wrote:
> On Wed, Mar 30, 2011 at 01:55:36PM -0400, Stefan Berger wrote:
>> This patch provides ACPI support for the TPM device. It probes for the TPM
>> device and only if a TPM device is found then the TPM's SSDT and TCPA table
>> are created. This patch also connects them to the RSDT.
> [...]
>>   // Space to reserve in high-memory for tables
>> -#define CONFIG_MAX_HIGHTABLE (64*1024)
>> +#if CONFIG_TCGBIOS
>> +# define CONFIG_MAX_HIGHTABLE (96*1024)
>> +#else
>> +# define CONFIG_MAX_HIGHTABLE (64*1024)
>> +#endif
> I'm a bit confused on patch ordering - it seems CONFIG_TCGBIOS is
> defined in patch 4 but used in patch 2.
I had it in patch 2 since there I am allocating 64kb in the high memory...
I'll move it to patch 4.
> Also, I'd prefer to avoid ifdefs - just up the size to 96 always, or
> do something like:
>
> #define CONFIG_MAX_HIGHTABLE ((64*1024) + CONFIG_TCGBIOS*(32*1024))
>
Done that.

    Stefan
> -Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler
  2011-04-04  4:30   ` Kevin O'Connor
@ 2011-04-04 14:54     ` Stefan Berger
  0 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-04-04 14:54 UTC (permalink / raw)
  To: Kevin O'Connor; +Cc: seabios, qemu-devel

On 04/04/2011 12:30 AM, Kevin O'Connor wrote:
> On Wed, Mar 30, 2011 at 01:55:39PM -0400, Stefan Berger wrote:
>> This patch implements the TCG BIOS interrupt handler 1ah. It is for
>> example used by trusted grub.
> [...]
>> +/*******************************************************************
>> +  Calculation of SHA1 in SW
>> +
>> +  See: http://www.itl.nist.gov/fipspubs/fip180-1.htm
>> +       RFC3174, Wikipedia's SHA1 alogrithm description
>> + ******************************************************************/
> Looks like tcgbios.c is awfully big - can we move the sha1 code to
> it's own file (eg, sha1.c)?
Done.
> [...]
>> +static inline u32 rol(u32 val, u16 rol)
> Should move to util.h.
Done.
>> +static inline u64 bswap_64(u64 val)
> Same.
Done.
> [...]
>> +++ seabios/src/stacks.c
> [...]
>> +#ifdef CONFIG_TCGBIOS
>> +void tcpa_interrupt_handler16(struct bregs *regs)
>> +{
>> +    if (MODESEGMENT) {
> I'm a bit confused here - MODESEGMENT will always be true.  Also, this
> code doesn't need to be in stacks.c - just invoke call32() directly
> from handle_1abb().
>
Will adapt it to that.
Other code was checking the MODESEGMENT and so I thought I better do 
that, too.
> Also, as before, just do "if (!CONFIG_TCGBIOS) return;" instead of the
> #ifdef.
>
Did that.

    Stefan

> -Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS
  2011-04-04  4:57   ` Kevin O'Connor
@ 2011-04-04 16:38     ` Stefan Berger
  0 siblings, 0 replies; 17+ messages in thread
From: Stefan Berger @ 2011-04-04 16:38 UTC (permalink / raw)
  To: Kevin O'Connor; +Cc: seabios, qemu-devel

On 04/04/2011 12:57 AM, Kevin O'Connor wrote:
> On Wed, Mar 30, 2011 at 01:55:40PM -0400, Stefan Berger wrote:
>> This patch adds invocactions of functions that measure various parts of the
>> code and data through various parts of the BIOS code. It follows TCG
>> specifications on what needs to be measured. It also adds the implementation
>> of the called functions.
> [...]
>>   void VISIBLE32FLAT
>>   startBoot(void)
>>   {
>> +    tcpa_calling_int19h();
>> +    tcpa_add_event_separators();
> Why add two functions here, instead of just one function that does
> both actions?
I kept them separate since they're two different 'events', which would 
allow to put another call in between, if another event was to be 
measured - currently there is none. I'll combine the calls.
> [...]
>>       // Initialize tpm (after acpi tables were written)
>>       tcpa_acpi_init();
>>       tcpa_startup();
>> +    tcpa_measure_post((void *)0xE0000, (void *)0xFFFFF);
>> +    tcpa_smbios_measure();
> Same here.  Also, I'm not sure I understand why you're measuring
> 0xE0000-0xFFFFF - if the intent is to measure the code, then it's a
> bit more complicated as the init code has already been relocated by
> this point.
Basically, I wanted to start the measuring as early as possible, ideally 
measuring layers or functions sequentially, which turns out to be quite 
'tricky'. So this was the brute force compromise. I'll drop it and will 
start with the smbios measurement for now.
> [...]
>> +    tcpa_option_rom(FLATPTR_TO_SEG(rom), len);
> You're better off just defining tcpa_option_rom() to take a regular
> pointer.
Done.
> [...]
>> +    /* specs: 8.2.3 step 5 and 8.2.5.6, measure El Torito boot catalog */
>> +    /* measure 2048 bytes (one sector) */
>> +    tcpa_add_bootdevice(1, 0);
>> +    tcpa_ipl(IPL_EL_TORITO_2, GET_SEG(SS), (u32)buffer, 2048);
> Same here for tcpa_ipl().  GET_SEG() always returns 0 in 32bit mode
> and this code is only run in 32bit mode.
>
Done.
> [...]
>> +static struct smbios_entry_point *
>> +find_smbios_entry_point(void)
>> +{
> The smbios table is built in smbios.c:smbios_entry_point_init() -
> instead of scanning for the table, just record where the table is in a
> global variable.
Done.
> [...]
>> +u32
>> +tcpa_smbios_measure(void)
>> +{
>> +    u32 rc;
>> +    struct pcctes pcctes = {
>> +        .eventid = 1, /* 10.4.2.3.1 */
>> +        .eventdatasize = SHA1_BUFSIZE,
>> +    };
>> +    struct smbios_entry_point *sep = find_smbios_entry_point();
>> +
>> +    if (!has_working_tpm())
>> +        return 0;
> BTW - SeaBIOS uses C99, so it's fine to move "if (!has_working_tpm())"
> above the variable declarations.
>
I am moving all these checks above the var decls.

   Stefan
> -Kevin

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2011-04-04 16:38 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-03-30 17:55 [Qemu-devel] [PATCH V1 0/8] Add TPM support to SeaBIOS Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 1/8] Add an implementation for a TPM TIS driver Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 2/8] Provide ACPI SSDT table for TPM device + S3 resume support Stefan Berger
2011-04-04  4:17   ` Kevin O'Connor
2011-04-04 14:52     ` Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 3/8] Implementation of the TCG BIOS extensions Stefan Berger
2011-04-04  4:14   ` Kevin O'Connor
2011-04-04 14:49     ` Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 4/8] Build the TCG BIOS extensions and TPM drivers Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 5/8] Support for BIOS interrupt handler Stefan Berger
2011-04-04  4:30   ` Kevin O'Connor
2011-04-04 14:54     ` Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 6/8] Add measurement code to the BIOS Stefan Berger
2011-04-04  4:57   ` Kevin O'Connor
2011-04-04 16:38     ` Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 7/8] Add a menu for TPM control Stefan Berger
2011-03-30 17:55 ` [Qemu-devel] [PATCH V1 8/8] Optional tests for the TIS interface Stefan Berger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.