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.
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_genera...
The compiled SSDT description is also part of this patch.
v6: - following Andreas Niederl's suggestion: enclosing Device(TPM) in Scope(_SB) { ... } to have Linux 2.6.33 recognize the device properly; seems to work fine with 3.0.0
v2: - Increasing the CONFIG_MAX_HIGHTABLE to 96kb - Adding cut-down tcgbios.c|h to keep SeaBIOS compiling - Build tpm_drivers.c and tcgbios.c -> TPM's SSDT and TCPA tables are now visible in Linux
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- Makefile | 12 +++++-- src/fw/acpi-tpm-ssdt.dsl | 24 ++++++++++++++ src/fw/acpi-tpm-ssdt.hex | 27 ++++++++++++++++ src/fw/acpi.c | 41 ++++++++++++++++++++++++ src/std/acpi.h | 20 ++++++++++++ src/tcgbios.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tcgbios.h | 57 ++++++++++++++++++++++++++++++++++ 7 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 src/fw/acpi-tpm-ssdt.dsl create mode 100644 src/fw/acpi-tpm-ssdt.hex create mode 100644 src/tcgbios.c create mode 100644 src/tcgbios.h
diff --git a/Makefile b/Makefile index 78b598e..08b05c0 100644 --- a/Makefile +++ b/Makefile @@ -38,11 +38,12 @@ SRCBOTH=misc.c stacks.c output.c string.c x86.c block.c cdrom.c mouse.c kbd.c \ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c SRC16=$(SRCBOTH) system.c disk.c font.c SRC32FLAT=$(SRCBOTH) post.c memmap.c malloc.c pmm.c romfile.c optionroms.c \ - boot.c bootsplash.c jpeg.c bmp.c \ + boot.c bootsplash.c jpeg.c bmp.c tcgbios.c \ hw/ahci.c hw/pvscsi.c hw/usb-xhci.c hw/usb-hub.c \ fw/coreboot.c fw/lzmadecode.c fw/csm.c fw/biostables.c \ fw/paravirt.c fw/shadow.c fw/pciinit.c fw/smm.c fw/mtrr.c fw/xen.c \ - fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c + fw/acpi.c fw/mptable.c fw/pirtable.c fw/smbios.c fw/romfile_loader.c \ + hw/tpm_drivers.c SRC32SEG=string.c output.c pcibios.c apm.c stacks.c hw/pci.c hw/serialio.c DIRS=src src/hw src/fw vgasrc
@@ -241,6 +242,13 @@ $(OUT)vgabios.bin: $(OUT)vgabios.bin.raw scripts/buildrom.py iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \ ; then echo "$(2)"; else echo "$(3)"; fi ;)
+src/fw/acpi-tpm-ssdt.hex: src/fw/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/' $@ + $(OUT)%.hex: %.dsl ./scripts/acpi_extract_preprocess.py ./scripts/acpi_extract.py @echo " Compiling IASL $@" $(Q)$(CPP) $(CPPFLAGS) $< -o $(OUT)$*.dsl.i.orig diff --git a/src/fw/acpi-tpm-ssdt.dsl b/src/fw/acpi-tpm-ssdt.dsl new file mode 100644 index 0000000..080bae4 --- /dev/null +++ b/src/fw/acpi-tpm-ssdt.dsl @@ -0,0 +1,24 @@ +DefinitionBlock ( + "acpi-tpm-ssdt.aml",// Output Filename + "SSDT", // Signature + 0x01, // SSDT Compliance Revision + "BXPC", // OEMID + "BXSSDT", // TABLE ID + 0x1 // OEM Revision + ) +{ + Scope(_SB) { + /* TPM with emulated TPM TIS interface */ + Device (TPM) { + Name (_HID, EisaID ("PNP0C31")) + Name (_CRS, ResourceTemplate () + { + Memory32Fixed (ReadWrite, 0xFED40000, 0x00005000) + //IRQNoFlags () {5} + }) + Method (_STA, 0, NotSerialized) { + Return (0x0F) + } + } + } +} diff --git a/src/fw/acpi-tpm-ssdt.hex b/src/fw/acpi-tpm-ssdt.hex new file mode 100644 index 0000000..acbb78f --- /dev/null +++ b/src/fw/acpi-tpm-ssdt.hex @@ -0,0 +1,27 @@ +/* + * + * Intel ACPI Component Architecture + * ASL Optimizing Compiler version 20101013-64 [Nov 21 2010] + * Copyright (c) 2000 - 2010 Intel Corporation + * + * Compilation of "out/.dsl.i" - Mon Jan 30 16:03:18 2012 + * + * C source code output + * AML code block contains 0x5D bytes + * + */ +unsigned char AmlCode_TPM[] = +{ + 0x53,0x53,0x44,0x54,0x5D,0x00,0x00,0x00, /* 00000000 "SSDT]..." */ + 0x01,0x15,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,0x10,0x38,0x5C,0x5F, /* 00000020 "... .8_" */ + 0x53,0x42,0x5F,0x5B,0x82,0x30,0x54,0x50, /* 00000028 "SB_[.0TP" */ + 0x4D,0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C, /* 00000030 "M_._HID." */ + 0x41,0xD0,0x0C,0x31,0x08,0x5F,0x43,0x52, /* 00000038 "A..1._CR" */ + 0x53,0x11,0x11,0x0A,0x0E,0x86,0x09,0x00, /* 00000040 "S......." */ + 0x01,0x00,0x00,0xD4,0xFE,0x00,0x50,0x00, /* 00000048 "......P." */ + 0x00,0x79,0x00,0x14,0x09,0x5F,0x53,0x54, /* 00000050 ".y..._ST" */ + 0x41,0x00,0xA4,0x0A,0x0F /* 00000058 "A...." */ +}; diff --git a/src/fw/acpi.c b/src/fw/acpi.c index 733ca4d..a6c63a7 100644 --- a/src/fw/acpi.c +++ b/src/fw/acpi.c @@ -20,8 +20,10 @@ #include "string.h" // memset #include "util.h" // MaxCountCPUs #include "x86.h" // readl +#include "tcgbios.h" // detected_tpm
#include "src/fw/acpi-dsdt.hex" +#include "acpi-tpm-ssdt.hex"
static void build_header(struct acpi_table_header *h, u32 sig, int len, u8 rev) @@ -590,6 +592,39 @@ static const struct pci_device_id acpi_find_tbl[] = { 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 (detected_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; +} + #define MAX_ACPI_TABLES 20 void acpi_setup(void) @@ -664,6 +699,12 @@ acpi_setup(void) build_header(dsdt, DSDT_SIGNATURE, sizeof(AmlCode), 1); }
+ void *tcpa, *tpm; + if (add_tpm_device(&tpm, &tcpa)) + return; + ACPI_INIT_TABLE(tpm); + ACPI_INIT_TABLE(tcpa); + // Build final rsdt table struct rsdt_descriptor_rev1 *rsdt; size_t rsdt_len = sizeof(*rsdt) + sizeof(u32) * tbl_idx; diff --git a/src/std/acpi.h b/src/std/acpi.h index fad6ac2..813e9ad 100644 --- a/src/std/acpi.h +++ b/src/std/acpi.h @@ -269,4 +269,24 @@ struct acpi_table_mcfg { struct acpi_mcfg_allocation allocation[0]; } 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 diff --git a/src/tcgbios.c b/src/tcgbios.c new file mode 100644 index 0000000..e4f0d46 --- /dev/null +++ b/src/tcgbios.c @@ -0,0 +1,81 @@ +// Implementation of the TCG BIOS extension according to the specification +// described in +// https://www.trustedcomputinggroup.org/specs/PCClient/TCG_PCClientImplementat... +// +// Copyright (C) 2006-2011 IBM Corporation +// +// Authors: +// Stefan Berger stefanb@linux.vnet.ibm.com +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + + +#include "config.h" + +#include "types.h" +#include "hw/tpm_drivers.h" // tpm_drivers[] + + +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, +}; + + +/******************************************************** + 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; +} + +static void +probe_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; + } +} + +int +detected_tpm(void) +{ + probe_tpm(); + + return tcpa_state.tpm_found; +} + +static int +has_working_tpm(void) +{ + probe_tpm(); + + return tcpa_state.tpm_working; +} diff --git a/src/tcgbios.h b/src/tcgbios.h new file mode 100644 index 0000000..ed3f781 --- /dev/null +++ b/src/tcgbios.h @@ -0,0 +1,57 @@ +#ifndef TCGBIOS_H +#define TCGBIOS_H + + +#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 + + +int detected_tpm(void); + + +#endif /* TCGBIOS_H */