Philipp Deppenwiese (zaolin@das-labor.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10542
-gerrit
commit 145a5f11f5714fb1e408a27bfe0580fe478e57e3 Author: Philipp Deppenwiese zaolin@das-labor.org Date: Sat Jun 13 23:35:37 2015 +0200
TPM: Merge of two TPM API's into one API.
Currently coreboot includes two TPM software implementations.
Following changes are done:
+ Splited LPC/I2C tpm driver implementation into two directories in src/drivers/tpm/ . + Moved pc80/tpm to tpm directory because it's not pc80 specific. + Use Google's lib/tlcl.* small tpm software stack as the main one. + Remove the old one drivers/pc80/tpm/romstage.c which can't be used for vboot2.
+ Split & Merge implementations into TSS and TSPI. -> Rename tlcl* files into tss which is the common name. -> Move init_tpm(void) function from drivers/pc80/tpm/romstage.c into the lib/tpm/tspi.c which is also the common name for highlevel tpm functions based on tss. -> Put the tss and tspi files into tpm folders in lib/ and include/ . -> Change header includes so that tpm.h can be found in include/pc80/ and software stack related stuff in include/tpm.
+ Revert pragma once statements from previous commit.
Compile:
VBOOT2 Feature = yes Coreboot TPM Feature = yes
Run:
VBOOT2 Feature = not tested Coreboot TPM Feature = yes
Change-Id: I8cbcd723d83ffcc0c1c47c58438dccdb16bb7cf7 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org --- src/cpu/intel/haswell/romstage.c | 2 +- src/drivers/i2c/tpm/Kconfig | 13 - src/drivers/i2c/tpm/Makefile.inc | 4 - src/drivers/i2c/tpm/tis.c | 201 ------ src/drivers/i2c/tpm/tpm.c | 558 --------------- src/drivers/i2c/tpm/tpm.h | 136 ---- src/drivers/pc80/Kconfig | 2 - src/drivers/pc80/Makefile.inc | 2 +- src/drivers/pc80/tpm/Kconfig | 46 -- src/drivers/pc80/tpm/Makefile.inc | 3 - src/drivers/pc80/tpm/acpi/tpm.asl | 196 ------ src/drivers/pc80/tpm/chip.h | 35 - src/drivers/pc80/tpm/romstage.c | 255 ------- src/drivers/pc80/tpm/tpm.c | 778 --------------------- src/drivers/tpm/Kconfig | 24 + src/drivers/tpm/Makefile.inc | 1 + src/drivers/tpm/acpi/tpm.asl | 196 ++++++ src/drivers/tpm/i2c/Kconfig | 13 + src/drivers/tpm/i2c/Makefile.inc | 4 + src/drivers/tpm/i2c/chip.h | 98 +++ src/drivers/tpm/i2c/tpm.c | 729 +++++++++++++++++++ src/drivers/tpm/lpc/Kconfig | 24 + src/drivers/tpm/lpc/Makefile.inc | 4 + src/drivers/tpm/lpc/chip.h | 35 + src/drivers/tpm/lpc/tpm.c | 778 +++++++++++++++++++++ src/include/antirollback.h | 2 +- src/include/tpm.h | 71 -- src/include/tpm/tpm.h | 75 ++ src/include/tpm/tspi.h | 29 + src/include/tpm/tss.h | 136 ++++ src/include/tpm/tss_constants.h | 98 +++ src/include/tpm_lite/tlcl.h | 137 ---- src/include/tpm_lite/tss_constants.h | 96 --- src/lib/Makefile.inc | 8 +- src/lib/mocked_tlcl.c | 136 ---- src/lib/tlcl.c | 327 --------- src/lib/tlcl_internal.h | 61 -- src/lib/tlcl_structures.h | 138 ---- src/lib/tpm/Makefile.inc | 13 + src/lib/tpm/mocked_tss.c | 136 ++++ src/lib/tpm/tspi.c | 95 +++ src/lib/tpm/tss.c | 331 +++++++++ src/lib/tpm/tss_internal.h | 61 ++ src/lib/tpm/tss_structures.h | 138 ++++ src/mainboard/google/auron/acpi/mainboard.asl | 2 +- src/mainboard/google/auron/devicetree.cb | 2 +- src/mainboard/google/cyan/acpi/mainboard.asl | 2 +- src/mainboard/google/cyan/devicetree.cb | 2 +- src/mainboard/google/glados/acpi/mainboard.asl | 2 +- src/mainboard/google/glados/devicetree.cb | 2 +- src/mainboard/google/jecht/acpi/mainboard.asl | 2 +- src/mainboard/google/link/romstage.c | 2 +- src/mainboard/google/parrot/romstage.c | 2 +- src/mainboard/google/samus/acpi/mainboard.asl | 2 +- src/mainboard/google/samus/devicetree.cb | 2 +- src/mainboard/google/stout/romstage.c | 2 +- src/mainboard/intel/emeraldlake2/romstage.c | 2 +- src/mainboard/intel/kunimitsu/acpi/mainboard.asl | 2 +- src/mainboard/intel/sklrvp/acpi/mainboard.asl | 2 +- src/mainboard/intel/strago/acpi/mainboard.asl | 2 +- src/mainboard/intel/strago/devicetree.cb | 2 +- src/mainboard/lenovo/t420s/devicetree.cb | 2 +- src/mainboard/lenovo/t420s/dsdt.asl | 2 +- src/mainboard/lenovo/t430s/devicetree.cb | 2 +- src/mainboard/lenovo/t430s/dsdt.asl | 2 +- src/mainboard/lenovo/t520/devicetree.cb | 2 +- src/mainboard/lenovo/t520/dsdt.asl | 2 +- src/mainboard/lenovo/t530/devicetree.cb | 2 +- src/mainboard/lenovo/t530/dsdt.asl | 2 +- src/mainboard/lenovo/x201/devicetree.cb | 2 +- src/mainboard/lenovo/x201/dsdt.asl | 2 +- src/mainboard/lenovo/x201/romstage.c | 2 +- src/mainboard/lenovo/x220/devicetree.cb | 2 +- src/mainboard/lenovo/x220/dsdt.asl | 2 +- src/mainboard/lenovo/x230/devicetree.cb | 2 +- src/mainboard/lenovo/x230/dsdt.asl | 2 +- src/mainboard/samsung/lumpy/romstage.c | 2 +- src/mainboard/samsung/stumpy/romstage.c | 2 +- .../intel/sandybridge/romstage_native.c | 2 +- src/soc/intel/baytrail/romstage/romstage.c | 2 +- src/soc/intel/braswell/romstage/romstage.c | 2 +- src/soc/intel/broadwell/romstage/romstage.c | 2 +- src/soc/intel/common/romstage.c | 2 +- .../google/chromeos/vboot2/antirollback.c | 4 +- 84 files changed, 3063 insertions(+), 3244 deletions(-)
diff --git a/src/cpu/intel/haswell/romstage.c b/src/cpu/intel/haswell/romstage.c index 6adb8be..c24883b 100644 --- a/src/cpu/intel/haswell/romstage.c +++ b/src/cpu/intel/haswell/romstage.c @@ -44,7 +44,7 @@ #include "northbridge/intel/haswell/raminit.h" #include "southbridge/intel/lynxpoint/pch.h" #include "southbridge/intel/lynxpoint/me.h" -#include <tpm.h> +#include <tpm/tspi.h>
static inline void reset_system(void) { diff --git a/src/drivers/i2c/tpm/Kconfig b/src/drivers/i2c/tpm/Kconfig deleted file mode 100644 index f2b969f..0000000 --- a/src/drivers/i2c/tpm/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config I2C_TPM - bool "I2C TPM" - depends on !PC80_SYSTEM # for now - -config DRIVER_TPM_I2C_BUS - hex "I2C TPM chip bus" - default 9 # FIXME, workaround for Kconfig BS - depends on I2C_TPM - -config DRIVER_TPM_I2C_ADDR - hex "I2C TPM chip address" - default 2 # FIXME, workaround for Kconfig BS - depends on I2C_TPM diff --git a/src/drivers/i2c/tpm/Makefile.inc b/src/drivers/i2c/tpm/Makefile.inc deleted file mode 100644 index 4f5913f..0000000 --- a/src/drivers/i2c/tpm/Makefile.inc +++ /dev/null @@ -1,4 +0,0 @@ -ramstage-$(CONFIG_I2C_TPM) += tis.c tpm.c -romstage-$(CONFIG_I2C_TPM) += tis.c tpm.c -verstage-$(CONFIG_I2C_TPM) += tis.c tpm.c -bootblock-$(CONFIG_I2C_TPM) += tis.c tpm.c diff --git a/src/drivers/i2c/tpm/tis.c b/src/drivers/i2c/tpm/tis.c deleted file mode 100644 index fca4316..0000000 --- a/src/drivers/i2c/tpm/tis.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2011 Infineon Technologies - * Copyright 2013 Google Inc. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include <stdint.h> -#include <string.h> -#include <assert.h> -#include <delay.h> -#include <device/i2c.h> -#include <endian.h> -#include <tpm.h> -#include "tpm.h" -#include <timer.h> - -#include <console/console.h> - -/* global structure for tpm chip data */ -struct tpm_chip g_chip; - -#define TPM_CMD_COUNT_BYTE 2 -#define TPM_CMD_ORDINAL_BYTE 6 -#define TPM_VALID_STATUS (1 << 7) - -int tis_open(void) -{ - int rc; - - if (g_chip.is_open) { - printk(BIOS_DEBUG, "tis_open() called twice.\n"); - return -1; - } - - rc = tpm_vendor_init(CONFIG_DRIVER_TPM_I2C_BUS, - CONFIG_DRIVER_TPM_I2C_ADDR); - - if (rc < 0) - g_chip.is_open = 0; - - if (rc) { - return -1; - } - - return 0; -} - -int tis_close(void) -{ - if (g_chip.is_open) { - tpm_vendor_cleanup(&g_chip); - g_chip.is_open = 0; - } - - return 0; -} - -int tis_init(void) -{ - int bus = CONFIG_DRIVER_TPM_I2C_BUS; - int chip = CONFIG_DRIVER_TPM_I2C_ADDR; - struct stopwatch sw; - uint8_t buf = 0; - int ret; - long sw_run_duration = 750; - - /* - * Probe TPM. Check if the TPM_ACCESS register's ValidSts bit is set(1) - * If the bit remains clear(0) then claim that init has failed. - */ - stopwatch_init_msecs_expire(&sw, sw_run_duration); - do { - ret = i2c_readb(bus, chip, 0, &buf); - if (!ret && (buf & TPM_VALID_STATUS)) { - sw_run_duration = stopwatch_duration_msecs(&sw); - break; - } - } while (!stopwatch_expired(&sw)); - - printk(BIOS_INFO, - "%s: ValidSts bit %s(%d) in TPM_ACCESS register after %ld ms\n", - __func__, (buf & TPM_VALID_STATUS) ? "set" : "clear", - (buf & TPM_VALID_STATUS) >> 7, sw_run_duration); - - /* - * Claim failure if the ValidSts (bit 7) is clear. - */ - if (!(buf & TPM_VALID_STATUS)) - return -1; - - return 0; -} - -static ssize_t tpm_transmit(const uint8_t *buf, size_t bufsiz) -{ - int rc; - uint32_t count, ordinal; - - struct tpm_chip *chip = &g_chip; - - memcpy(&count, buf + TPM_CMD_COUNT_BYTE, sizeof(count)); - count = be32_to_cpu(count); - memcpy(&ordinal, buf + TPM_CMD_ORDINAL_BYTE, sizeof(ordinal)); - ordinal = be32_to_cpu(ordinal); - - if (count == 0) { - printk(BIOS_DEBUG, "tpm_transmit: no data\n"); - return -1; - } - if (count > bufsiz) { - printk(BIOS_DEBUG, "tpm_transmit: invalid count value %x %zx\n", - count, bufsiz); - return -1; - } - - ASSERT(chip->vendor.send); - rc = chip->vendor.send(chip, (uint8_t *) buf, count); - if (rc < 0) { - printk(BIOS_DEBUG, "tpm_transmit: tpm_send error\n"); - goto out; - } - - if (chip->vendor.irq) - goto out_recv; - - int timeout = 2 * 60 * 1000; /* two minutes timeout */ - while (timeout) { - ASSERT(chip->vendor.status); - uint8_t status = chip->vendor.status(chip); - if ((status & chip->vendor.req_complete_mask) == - chip->vendor.req_complete_val) { - goto out_recv; - } - - if ((status == chip->vendor.req_canceled)) { - printk(BIOS_DEBUG, "tpm_transmit: Operation Canceled\n"); - rc = -1; - goto out; - } - mdelay(TPM_TIMEOUT); - timeout--; - } - - ASSERT(chip->vendor.cancel); - chip->vendor.cancel(chip); - printk(BIOS_DEBUG, "tpm_transmit: Operation Timed out\n"); - rc = -1; //ETIME; - goto out; - -out_recv: - - rc = chip->vendor.recv(chip, (uint8_t *) buf, TPM_BUFSIZE); - if (rc < 0) - printk(BIOS_DEBUG, "tpm_transmit: tpm_recv: error %d\n", rc); -out: - return rc; -} - -int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, - uint8_t *recvbuf, size_t *rbuf_len) -{ - uint8_t buf[TPM_BUFSIZE]; - - if (sizeof(buf) < sbuf_size) - return -1; - - memcpy(buf, sendbuf, sbuf_size); - - int len = tpm_transmit(buf, sbuf_size); - - if (len < 10) { - *rbuf_len = 0; - return -1; - } - - if (len > *rbuf_len) { - *rbuf_len = len; - return -1; - } - - memcpy(recvbuf, buf, len); - *rbuf_len = len; - - return 0; -} diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c deleted file mode 100644 index 160b391..0000000 --- a/src/drivers/i2c/tpm/tpm.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) 2011 Infineon Technologies - * - * Authors: - * Peter Huewe huewe.external@infineon.com - * - * Description: - * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org - * - * This device driver implements the TPM interface as defined in - * the TCG TPM Interface Spec version 1.2, revision 1.0 and the - * Infineon I2C Protocol Stack Specification v0.20. - * - * It is based on the Linux kernel driver tpm.c from Leendert van - * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. - * - * Version: 2.1.1 - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include <stdint.h> -#include <string.h> -#include <types.h> -#include <delay.h> -#include <console/console.h> -#include <device/i2c.h> -#include <endian.h> -#include "tpm.h" - -/* Address of the TPM on the I2C bus */ -#define TPM_I2C_ADDR 0x20 - -/* max. number of iterations after I2C NAK */ -#define MAX_COUNT 3 - -#define SLEEP_DURATION 60 /* in usec */ - -/* max. number of iterations after I2C NAK for 'long' commands - * we need this especially for sending TPM_READY, since the cleanup after the - * transtion to the ready state may take some time, but it is unpredictable - * how long it will take. - */ -#define MAX_COUNT_LONG 50 - -#define SLEEP_DURATION_LONG 210 /* in usec */ - -/* expected value for DIDVID register */ -#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L -#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L - -enum i2c_chip_type { - SLB9635, - SLB9645, - UNKNOWN, -}; - -static const char * const chip_name[] = { - [SLB9635] = "slb9635tt", - [SLB9645] = "slb9645tt", - [UNKNOWN] = "unknown/fallback to slb9635", -}; - -/* Structure to store I2C TPM specific stuff */ -struct tpm_inf_dev { - int bus; - unsigned int addr; - uint8_t buf[TPM_BUFSIZE + sizeof(uint8_t)]; // max. buffer size + addr - enum i2c_chip_type chip_type; -}; - -static struct tpm_inf_dev tpm_dev = { - .bus = -1, - .addr = TPM_I2C_ADDR -}; - -/* - * iic_tpm_read() - read from TPM register - * @addr: register address to read from - * @buffer: provided by caller - * @len: number of bytes to read - * - * Read len bytes from TPM register and put them into - * buffer (little-endian format, i.e. first byte is put into buffer[0]). - * - * NOTE: TPM is big-endian for multi-byte values. Multi-byte - * values have to be swapped. - * - * Return -1 on error, 0 on success. - */ -static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) -{ - int rc; - int count; - - if (tpm_dev.bus < 0) - return -1; - if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { - /* slb9635 protocol should work in both cases */ - for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, &addr, 1); - if (rc == 0) - break; /* success, break to skip sleep */ - - udelay(SLEEP_DURATION); - } - - if (rc) - return -1; - - /* After the TPM has successfully received the register address - * it needs some time, thus we're sleeping here again, before - * retrieving the data - */ - for (count = 0; count < MAX_COUNT; count++) { - udelay(SLEEP_DURATION); - rc = i2c_read_raw(tpm_dev.bus, tpm_dev.addr, - buffer, len); - if (rc == 0) - break; /* success, break to skip sleep */ - - } - } else { - /* use a combined read for newer chips - * unfortunately the smbus functions are not suitable due to - * the 32 byte limit of the smbus. - * retries should usually not be needed, but are kept just to - * be safe on the safe side. - */ - struct i2c_seg aseg = { .read = 0, .chip = tpm_dev.addr, - .buf = &addr, .len = 1 }; - struct i2c_seg dseg = { .read = 1, .chip = tpm_dev.addr, - .buf = buffer, .len = len }; - for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_transfer(tpm_dev.bus, &aseg, 1) || - i2c_transfer(tpm_dev.bus, &dseg, 1); - if (rc == 0) - break; /* break here to skip sleep */ - udelay(SLEEP_DURATION); - } - } - - /* take care of 'guard time' */ - udelay(SLEEP_DURATION); - if (rc) - return -1; - - return 0; -} - -static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, - unsigned int sleep_time, - uint8_t max_count) -{ - int rc = 0; - int count; - - if (len > TPM_BUFSIZE) { - printk(BIOS_DEBUG, "%s: Length %zd is too large\n", __func__, len); - return -1; - } - - /* prepare send buffer */ - tpm_dev.buf[0] = addr; - memcpy(&(tpm_dev.buf[1]), buffer, len); - - if (tpm_dev.bus < 0) - return -1; - for (count = 0; count < max_count; count++) { - rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, - tpm_dev.buf, len + 1); - if (rc == 0) - break; /* success, break to skip sleep */ - - udelay(sleep_time); - } - - /* take care of 'guard time' */ - udelay(SLEEP_DURATION); - if (rc) - return -1; - - return 0; -} - -/* - * iic_tpm_write() - write to TPM register - * @addr: register address to write to - * @buffer: containing data to be written - * @len: number of bytes to write - * - * Write len bytes from provided buffer to TPM register (little - * endian format, i.e. buffer[0] is written as first byte). - * - * NOTE: TPM is big-endian for multi-byte values. Multi-byte - * values have to be swapped. - * - * NOTE: use this function instead of the iic_tpm_write_generic function. - * - * Return -EIO on error, 0 on success - */ -static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len) -{ - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION, - MAX_COUNT); -} - -/* - * This function is needed especially for the cleanup situation after - * sending TPM_READY - * */ -static int iic_tpm_write_long(uint8_t addr, uint8_t *buffer, size_t len) -{ - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, - MAX_COUNT_LONG); -} - -#define TPM_HEADER_SIZE 10 - -enum tis_access { - TPM_ACCESS_VALID = 0x80, - TPM_ACCESS_ACTIVE_LOCALITY = 0x20, - TPM_ACCESS_REQUEST_PENDING = 0x04, - TPM_ACCESS_REQUEST_USE = 0x02, -}; - -enum tis_status { - TPM_STS_VALID = 0x80, - TPM_STS_COMMAND_READY = 0x40, - TPM_STS_GO = 0x20, - TPM_STS_DATA_AVAIL = 0x10, - TPM_STS_DATA_EXPECT = 0x08, -}; - -#define TPM_ACCESS(l) (0x0000 | ((l) << 4)) -#define TPM_STS(l) (0x0001 | ((l) << 4)) -#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) -#define TPM_DID_VID(l) (0x0006 | ((l) << 4)) - -static int check_locality(struct tpm_chip *chip, int loc) -{ - uint8_t buf; - - if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) - return -1; - - if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { - chip->vendor.locality = loc; - return loc; - } - - return -1; -} - -static void release_locality(struct tpm_chip *chip, int loc, int force) -{ - uint8_t buf; - if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) - return; - - if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == - (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { - buf = TPM_ACCESS_ACTIVE_LOCALITY; - iic_tpm_write(TPM_ACCESS(loc), &buf, 1); - } -} - -static int request_locality(struct tpm_chip *chip, int loc) -{ - uint8_t buf = TPM_ACCESS_REQUEST_USE; - - if (check_locality(chip, loc) >= 0) - return loc; /* we already have the locality */ - - iic_tpm_write(TPM_ACCESS(loc), &buf, 1); - - /* wait for burstcount */ - int timeout = 2 * 1000; /* 2s timeout */ - while (timeout) { - if (check_locality(chip, loc) >= 0) - return loc; - mdelay(TPM_TIMEOUT); - timeout--; - } - - return -1; -} - -static uint8_t tpm_tis_i2c_status(struct tpm_chip *chip) -{ - /* NOTE: Since I2C read may fail, return 0 in this case --> time-out */ - uint8_t buf; - if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) - return 0; - else - return buf; -} - -static void tpm_tis_i2c_ready(struct tpm_chip *chip) -{ - /* this causes the current command to be aborted */ - uint8_t buf = TPM_STS_COMMAND_READY; - iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); -} - -static ssize_t get_burstcount(struct tpm_chip *chip) -{ - ssize_t burstcnt; - uint8_t buf[3]; - - /* wait for burstcount */ - int timeout = 2 * 1000; /* 2s timeout */ - while (timeout) { - /* Note: STS is little endian */ - if (iic_tpm_read(TPM_STS(chip->vendor.locality) + 1, buf, 3) < 0) - burstcnt = 0; - else - burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; - - if (burstcnt) - return burstcnt; - mdelay(TPM_TIMEOUT); - timeout--; - } - return -1; -} - -static int wait_for_stat(struct tpm_chip *chip, uint8_t mask, int *status) -{ - unsigned long timeout = 2 * 1024; - while (timeout) { - *status = tpm_tis_i2c_status(chip); - if ((*status & mask) == mask) - return 0; - mdelay(TPM_TIMEOUT); - timeout--; - } - - return -1; -} - -static int recv_data(struct tpm_chip *chip, uint8_t *buf, size_t count) -{ - size_t size = 0; - - while (size < count) { - ssize_t burstcnt = get_burstcount(chip); - int rc; - - /* burstcount < 0 = TPM is busy */ - if (burstcnt < 0) - return burstcnt; - - /* limit received data to max. left */ - if (burstcnt > (count - size)) - burstcnt = count - size; - - rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), - &(buf[size]), - burstcnt); - if (rc == 0) - size += burstcnt; - - } - return size; -} - -static int tpm_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf, size_t count) -{ - int size = 0; - uint32_t expected; - int status; - - if (count < TPM_HEADER_SIZE) { - size = -1; - goto out; - } - - /* read first 10 bytes, including tag, paramsize, and result */ - size = recv_data(chip, buf, TPM_HEADER_SIZE); - if (size < TPM_HEADER_SIZE) { - printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Unable to read header\n"); - goto out; - } - - memcpy(&expected, buf + TPM_RSP_SIZE_BYTE, sizeof(expected)); - expected = be32_to_cpu(expected); - if ((size_t)expected > count) { - size = -1; - goto out; - } - - size += recv_data(chip, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); - if (size < expected) { - printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Unable to " - "read remainder of result\n"); - size = -1; - goto out; - } - - wait_for_stat(chip, TPM_STS_VALID, &status); - if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Error left over data\n"); - size = -1; - goto out; - } - -out: - tpm_tis_i2c_ready(chip); - - return size; -} - -static int tpm_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len) -{ - int status; - size_t count = 0; - uint8_t sts = TPM_STS_GO; - - if (len > TPM_BUFSIZE) - return -1; /* command is too long for our TPM, sorry */ - - status = tpm_tis_i2c_status(chip); - if ((status & TPM_STS_COMMAND_READY) == 0) { - tpm_tis_i2c_ready(chip); - if (wait_for_stat(chip, TPM_STS_COMMAND_READY, &status) < 0) - goto out_err; - } - - while (count < len - 1) { - ssize_t burstcnt = get_burstcount(chip); - - /* burstcount < 0 = TPM is busy */ - if (burstcnt < 0) - return burstcnt; - - if (burstcnt > (len-1-count)) - burstcnt = len-1-count; - -#ifdef CONFIG_TPM_I2C_BURST_LIMITATION - if (burstcnt > CONFIG_TPM_I2C_BURST_LIMITATION) - burstcnt = CONFIG_TPM_I2C_BURST_LIMITATION; -#endif /* CONFIG_TPM_I2C_BURST_LIMITATION */ - - if (iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), - &(buf[count]), burstcnt) == 0) - count += burstcnt; - - wait_for_stat(chip, TPM_STS_VALID, &status); - if ((status & TPM_STS_DATA_EXPECT) == 0) - goto out_err; - } - - /* write last byte */ - iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); - - wait_for_stat(chip, TPM_STS_VALID, &status); - if ((status & TPM_STS_DATA_EXPECT) != 0) - goto out_err; - - /* go and do it */ - iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); - - return len; - -out_err: - tpm_tis_i2c_ready(chip); - - return -1; -} - -static struct tpm_vendor_specific tpm_tis_i2c = { - .status = tpm_tis_i2c_status, - .recv = tpm_tis_i2c_recv, - .send = tpm_tis_i2c_send, - .cancel = tpm_tis_i2c_ready, - .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = TPM_STS_COMMAND_READY, -}; - -/* Initialization of I2C TPM */ - -int tpm_vendor_init(unsigned bus, uint32_t dev_addr) -{ - uint32_t vendor; - unsigned int old_addr; - struct tpm_chip *chip; - extern struct tpm_chip g_chip; - - old_addr = tpm_dev.addr; - if (dev_addr != 0) - tpm_dev.addr = dev_addr; - tpm_dev.bus = bus; - - chip = &g_chip; - memcpy(&chip->vendor, &tpm_tis_i2c, sizeof(struct tpm_vendor_specific)); - chip->is_open = 1; - - /* Disable interrupts (not supported) */ - chip->vendor.irq = 0; - - if (request_locality(chip, 0) != 0) - goto out_err; - - /* Read four bytes from DID_VID register */ - if (iic_tpm_read(TPM_DID_VID(0), (uint8_t *)&vendor, 4) < 0) - goto out_release; - - if (vendor == TPM_TIS_I2C_DID_VID_9645) { - tpm_dev.chip_type = SLB9645; - } else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) { - tpm_dev.chip_type = SLB9635; - } else { - printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor); - goto out_release; - } - - printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", - chip_name[tpm_dev.chip_type], vendor >> 16); - - /* - * A timeout query to TPM can be placed here. - * Standard timeout values are used so far - */ - - return 0; - -out_release: - release_locality(chip, 0, 1); - -out_err: - tpm_dev.addr = old_addr; - return -1; -} - -void tpm_vendor_cleanup(struct tpm_chip *chip) -{ - release_locality(chip, chip->vendor.locality, 1); -} diff --git a/src/drivers/i2c/tpm/tpm.h b/src/drivers/i2c/tpm/tpm.h deleted file mode 100644 index 35285c0..0000000 --- a/src/drivers/i2c/tpm/tpm.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2011 Infineon Technologies - * - * Authors: - * Peter Huewe huewe.external@infineon.com - * - * Version: 2.1.1 - * - * Description: - * Device driver for TCG/TCPA TPM (trusted platform module). - * Specifications at www.trustedcomputinggroup.org - * - * It is based on the Linux kernel driver tpm.c from Leendert van - * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. - * - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#ifndef __DRIVERS_TPM_SLB9635_I2C_TPM_H__ -#define __DRIVERS_TPM_SLB9635_I2C_TPM_H__ - -#include <stdint.h> - -enum tpm_timeout { - TPM_TIMEOUT = 1, /* msecs */ -}; - -/* Size of external transmit buffer (used for stack buffer in tpm_sendrecv) */ -#define TPM_BUFSIZE 1260 - -/* Index of fields in TPM command buffer */ -#define TPM_CMD_SIZE_BYTE 2 -#define TPM_CMD_ORDINAL_BYTE 6 - -/* Index of Count field in TPM response buffer */ -#define TPM_RSP_SIZE_BYTE 2 -#define TPM_RSP_RC_BYTE 6 - -struct tpm_chip; - -struct tpm_vendor_specific { - const uint8_t req_complete_mask; - const uint8_t req_complete_val; - const uint8_t req_canceled; - int irq; - int (*recv)(struct tpm_chip *, uint8_t *, size_t); - int (*send)(struct tpm_chip *, uint8_t *, size_t); - void (*cancel)(struct tpm_chip *); - uint8_t(*status)(struct tpm_chip *); - int locality; -}; - -struct tpm_chip { - int is_open; - struct tpm_vendor_specific vendor; -}; - -struct tpm_input_header { - uint16_t tag; - uint32_t length; - uint32_t ordinal; -} __attribute__ ((packed)); - -struct tpm_output_header { - uint16_t tag; - uint32_t length; - uint32_t return_code; -} __attribute__ ((packed)); - -struct timeout_t { - uint32_t a; - uint32_t b; - uint32_t c; - uint32_t d; -} __attribute__ ((packed)); - -struct duration_t { - uint32_t tpm_short; - uint32_t tpm_medium; - uint32_t tpm_long; -} __attribute__ ((packed)); - -typedef union { - struct timeout_t timeout; - struct duration_t duration; -} cap_t; - -struct tpm_getcap_params_in { - uint32_t cap; - uint32_t subcap_size; - uint32_t subcap; -} __attribute__ ((packed)); - -struct tpm_getcap_params_out { - uint32_t cap_size; - cap_t cap; -} __attribute__ ((packed)); - -typedef union { - struct tpm_input_header in; - struct tpm_output_header out; -} tpm_cmd_header; - -typedef union { - struct tpm_getcap_params_out getcap_out; - struct tpm_getcap_params_in getcap_in; -} tpm_cmd_params; - -struct tpm_cmd_t { - tpm_cmd_header header; - tpm_cmd_params params; -} __attribute__ ((packed)); - -/* ---------- Interface for TPM vendor ------------ */ - -int tpm_vendor_init(unsigned bus, uint32_t dev_addr); - -void tpm_vendor_cleanup(struct tpm_chip *chip); - -#endif /* __DRIVERS_TPM_SLB9635_I2C_TPM_H__ */ diff --git a/src/drivers/pc80/Kconfig b/src/drivers/pc80/Kconfig index 0ed1ecf..808de17 100644 --- a/src/drivers/pc80/Kconfig +++ b/src/drivers/pc80/Kconfig @@ -22,6 +22,4 @@ config DRIVERS_MC146818 default y if ARCH_X86 select RTC
-source src/drivers/pc80/tpm/Kconfig - endif diff --git a/src/drivers/pc80/Makefile.inc b/src/drivers/pc80/Makefile.inc index 0788cc7..838f336 100644 --- a/src/drivers/pc80/Makefile.inc +++ b/src/drivers/pc80/Makefile.inc @@ -13,7 +13,7 @@ romstage-$(CONFIG_DRIVERS_MC146818) += mc146818rtc_early.c
romstage-$(CONFIG_SPKMODEM) += spkmodem.c
-subdirs-y += tpm vga +subdirs-y += vga
cbfs-files-$(CONFIG_HAVE_CMOS_DEFAULT) += cmos.default cmos.default-file = $(CONFIG_CMOS_DEFAULT_FILE):nvramtool diff --git a/src/drivers/pc80/tpm/Kconfig b/src/drivers/pc80/tpm/Kconfig deleted file mode 100644 index f6a7948..0000000 --- a/src/drivers/pc80/tpm/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -config MAINBOARD_HAS_LPC_TPM - bool - default n - help - Board has TPM support - -config LPC_TPM - bool "Enable TPM support" - depends on MAINBOARD_HAS_LPC_TPM - default n - help - Enable this option to enable LPC TPM support in coreboot. - - If unsure, say N. - -config TPM_TIS_BASE_ADDRESS - hex - default 0xfed40000 - depends on LPC_TPM - help - This can be used to adjust the TPM memory base address. - The default is specified by the TCG PC Client Specific TPM - Interface Specification 1.2 and should not be changed unless - the TPM being used does not conform to TPM TIS 1.2. - -config TPM_INIT_FAILURE_IS_FATAL - bool - default n - depends on LPC_TPM - help - What to do if TPM init failed. If true, force a hard reset, - otherwise just log error message to console. - -config SKIP_TPM_STARTUP_ON_NORMAL_BOOT - bool - default n - depends on LPC_TPM - help - Skip TPM init on normal boot. Useful if payload does TPM init. - -config TPM_DEACTIVATE - bool "Deactivate TPM" - default n - depends on LPC_TPM - help - Deactivate TPM by issuing deactivate command. diff --git a/src/drivers/pc80/tpm/Makefile.inc b/src/drivers/pc80/tpm/Makefile.inc deleted file mode 100644 index 089d067..0000000 --- a/src/drivers/pc80/tpm/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -romstage-$(CONFIG_LPC_TPM) += tpm.c -ramstage-$(CONFIG_LPC_TPM) += tpm.c -romstage-$(CONFIG_LPC_TPM) += romstage.c diff --git a/src/drivers/pc80/tpm/acpi/tpm.asl b/src/drivers/pc80/tpm/acpi/tpm.asl deleted file mode 100644 index ece63e2..0000000 --- a/src/drivers/pc80/tpm/acpi/tpm.asl +++ /dev/null @@ -1,196 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2014 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -/* Trusted Platform Module */ - -Device (TPM) -{ - Name (_HID, EISAID ("PNP0C31")) - Name (_CID, 0x310cd041) - Name (_UID, 1) - - Method (_STA, 0) - { -#if CONFIG_LPC_TPM && !CONFIG_TPM_DEACTIVATE - Return (0xf) -#else - Return (0x0) -#endif - } - - Name (IBUF, ResourceTemplate () - { - /* Updated based on TPM interrupt for Locality 0 */ - Interrupt (ResourceConsumer, Edge, ActiveHigh, - Exclusive, , , TIRQ) { 0 } - }) - - Name (RBUF, ResourceTemplate () - { - IO (Decode16, 0x2e, 0x2e, 0x01, 0x02) - Memory32Fixed (ReadWrite, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000) - }) - - Method (_CRS, 0, NotSerialized) - { - OperationRegion (TREG, SystemMemory, - CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000) - Field (TREG, ByteAcc, NoLock, Preserve) - { - /* TPM_INT_ENABLE_0 */ - Offset (0x0008), - , 3, - ITPL, 2, /* Interrupt type and polarity */ - - /* TPM_INT_VECTOR_0 */ - Offset (0x000C), - IVEC, 4, /* SERIRQ vector */ - } - - If (LGreater (IVEC, 0)) { - /* Update interrupt vector */ - CreateField (^IBUF, ^TIRQ._INT, 32, TVEC) - Store (IVEC, TVEC) - - /* Update interrupt type and polarity */ - CreateBitField (^IBUF, ^TIRQ._HE, TTYP) - CreateBitField (^IBUF, ^TIRQ._LL, TPOL) - CreateBitField (^IBUF, ^TIRQ._SHR, TSHR) - - If (LEqual (ITPL, 0x0)) { - /* Active-High Level-Triggered Shared */ - Store (Zero, TPOL) - Store (Zero, TTYP) - Store (One, TSHR) - } ElseIf (LEqual (ITPL, 0x1)) { - /* Active-Low Level-Triggered Shared */ - Store (One, TPOL) - Store (Zero, TTYP) - Store (One, TSHR) - } ElseIf (LEqual (ITPL, 0x2)) { - /* Active-High Edge-Triggered Exclusive */ - Store (Zero, TPOL) - Store (One, TTYP) - Store (Zero, TSHR) - } ElseIf (LEqual (ITPL, 0x3)) { - /* Active-Low Edge-Triggered Exclusive */ - Store (One, TPOL) - Store (One, TTYP) - Store (Zero, TSHR) - } - - /* Merge IRQ with base address */ - Return (ConcatenateResTemplate (RBUF, IBUF)) - } Else { - Return (RBUF) - } - } - - /* Dummy _DSM to make Bitlocker work. */ - Method (_DSM, 4, Serialized) - { - /* Physical presence interface. - This is used to submit commands like "Clear TPM" to - be run at next reboot provided that user confirms them. - Spec allows user to cancel all commands and/or - configure BIOS to reject commands. So we pretend that - user did just this: cancelled everything. If user - really wants to clear TPM the only option now is to do it manually - in payload. - */ - If (LEqual (Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) - { - If (LEqual (Arg2, 0)) - { - /* Functions 1-8. */ - Return (Buffer (2) { 0xFF, 0x01 }) - } - - /* Interface version: 1.2 */ - If (LEqual (Arg2, 1)) - { - Return ("1.2") - } - - /* Submit operations: drop on the floor and return success. */ - If (LEqual (Arg2, 2)) - { - Return (0x00) - } - - /* Pending operation: none. */ - If (LEqual (Arg2, 3)) - { - Return (Package (2) { 0, 0 }) - } - - /* Pre-OS transition method: reboot. */ - If (LEqual (Arg2, 4)) - { - Return (2) - } - - /* Operation response: no operation executed. */ - If (LEqual (Arg2, 5)) - { - Return (Package (3) { 0, 0, 0 }) - } - - /* Set preffered user language: deprecated and must return 3 aka "not implemented". */ - If (LEqual (Arg2, 6)) - { - Return (3) - } - - /* Submit operations: deny. */ - If (LEqual (Arg2, 7)) - { - Return (3) - } - - /* All actions are forbidden. */ - If (LEqual (Arg2, 8)) - { - Return (1) - } - - Return (1) - } - - /* Memory clearing on boot: just a dummy. */ - If (LEqual (Arg0, ToUUID("376054ed-cc13-4675-901c-4756d7f2d45d"))) - { - If (LEqual (Arg2, 0)) - { - /* Function 1. */ - Return (Buffer (1) { 3 }) - } - - /* Just return success. */ - If (LEqual (Arg2, 1)) - { - Return (0) - } - - Return (1) - } - - Return (Buffer (1) { 0 }) - } -} diff --git a/src/drivers/pc80/tpm/chip.h b/src/drivers/pc80/tpm/chip.h deleted file mode 100644 index 1a63b98..0000000 --- a/src/drivers/pc80/tpm/chip.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2014 Google Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#ifndef DRIVERS_PC80_TPM_CHIP_H -#define DRIVERS_PC80_TPM_CHIP_H - -typedef struct drivers_pc80_tpm_config { - /* - * TPM Interrupt polarity: - * - * High Level 0 - * Low Level 1 - * Rising Edge 2 - * Falling Edge 3 - */ - u8 irq_polarity; -} tpm_config_t; - -#endif /* DRIVERS_PC80_TPM_CHIP_H */ diff --git a/src/drivers/pc80/tpm/romstage.c b/src/drivers/pc80/tpm/romstage.c deleted file mode 100644 index 96760e2..0000000 --- a/src/drivers/pc80/tpm/romstage.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011 The ChromiumOS Authors. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include <types.h> -#include <console/cbmem_console.h> -#include <console/console.h> -#include <arch/acpi.h> -#include <tpm.h> -#include <reset.h> - -//#define EXTRA_LOGGING - -#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */ - -#define TPM_SUCCESS ((u32)0x00000000) - -#define TPM_E_IOERROR ((u32)0x0000001f) -#define TPM_E_COMMUNICATION_ERROR ((u32)0x00005004) -#define TPM_E_NON_FATAL ((u32)0x00000800) -#define TPM_E_INVALID_POSTINIT ((u32)0x00000026) - -#define TPM_E_NEEDS_SELFTEST ((u32)(TPM_E_NON_FATAL + 1)) -#define TPM_E_DOING_SELFTEST ((u32)(TPM_E_NON_FATAL + 2)) - -static const struct { - u8 buffer[12]; -} tpm_resume_cmd = { - { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x2 } -}; - -static const struct { - u8 buffer[12]; -} tpm_startup_cmd = { - {0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x1 } -}; - -static const struct { - u8 buffer[12]; -} tpm_deactivate_cmd = { - {0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x3 } -}; - -static const struct { - u8 buffer[10]; -} tpm_continueselftest_cmd = { - { 0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53 } -}; - -static inline void FromTpmUint32(const u8 * buffer, u32 * x) -{ - *x = ((buffer[0] << 24) | - (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); -} - -static inline int TpmCommandSize(const u8 * buffer) -{ - u32 size; - FromTpmUint32(buffer + sizeof(u16), &size); - return (int)size; -} - -/* Gets the code field of a TPM command. */ -static inline int TpmCommandCode(const u8 * buffer) -{ - u32 code; - FromTpmUint32(buffer + sizeof(u16) + sizeof(u32), &code); - return code; -} - -/* Gets the return code field of a TPM result. */ -static inline int TpmReturnCode(const u8 * buffer) -{ - return TpmCommandCode(buffer); -} - -/* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or - * DOING_SELFTEST errors are returned. - */ -static u32 TlclSendReceiveNoRetry(const u8 * request, - u8 * response, int max_length) -{ - size_t response_length = max_length; - u32 result; - -#ifdef EXTRA_LOGGING - printk(BIOS_DEBUG, "TPM: command: %x%x %x%x%x%x %x%x%x%x\n", - request[0], request[1], - request[2], request[3], request[4], request[5], - request[6], request[7], request[8], request[9]); -#endif - - result = TPM_SUCCESS; - if (tis_sendrecv - (request, TpmCommandSize(request), response, &response_length)) - result = TPM_E_IOERROR; - - if (0 != result) { - /* Communication with TPM failed, so response is garbage */ - printk(BIOS_DEBUG, - "TPM: command 0x%x send/receive failed: 0x%x\n", - TpmCommandCode(request), result); - return TPM_E_COMMUNICATION_ERROR; - } - /* Otherwise, use the result code from the response */ - result = TpmReturnCode(response); - -/* TODO: add paranoia about returned response_length vs. max_length - * (and possibly expected length from the response header). See - * crosbug.com/17017 */ - -#ifdef EXTRA_LOGGING - printk(BIOS_DEBUG, "TPM: response: %x%x %x%x%x%x %x%x%x%x\n", - response[0], response[1], - response[2], response[3], response[4], response[5], - response[6], response[7], response[8], response[9]); -#endif - - printk(BIOS_DEBUG, "TPM: command 0x%x returned 0x%x\n", - TpmCommandCode(request), result); - - return result; -} - -static inline u32 TlclContinueSelfTest(void) -{ - u8 response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - printk(BIOS_DEBUG, "TPM: Continue self test\n"); - /* Call the No Retry version of SendReceive to avoid recursion. */ - return TlclSendReceiveNoRetry(tpm_continueselftest_cmd.buffer, - response, sizeof(response)); -} - -/* Sends a TPM command and gets a response. Returns 0 if success or the TPM - * error code if error. In the firmware, waits for the self test to complete - * if needed. In the host, reports the first error without retries. */ -static u32 TlclSendReceive(const u8 * request, u8 * response, int max_length) -{ - u32 result = TlclSendReceiveNoRetry(request, response, max_length); - /* When compiling for the firmware, hide command failures due to the self - * test not having run or completed. */ - /* If the command fails because the self test has not completed, try it - * again after attempting to ensure that the self test has completed. */ - if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) { - result = TlclContinueSelfTest(); - if (result != TPM_SUCCESS) { - return result; - } -#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE) - /* Retry only once */ - result = TlclSendReceiveNoRetry(request, response, max_length); -#else - /* This needs serious testing. The TPM specification says: - * "iii. The caller MUST wait for the actions of - * TPM_ContinueSelfTest to complete before reissuing the - * command C1." But, if ContinueSelfTest is non-blocking, how - * do we know that the actions have completed other than trying - * again? */ - do { - result = - TlclSendReceiveNoRetry(request, response, - max_length); - } while (result == TPM_E_DOING_SELFTEST); -#endif - } - - return result; -} - -void init_tpm(int s3resume) -{ - u32 result; - u8 response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - - if (CONFIG_TPM_DEACTIVATE) { - printk(BIOS_SPEW, "TPM: Deactivate\n"); - result = TlclSendReceive(tpm_deactivate_cmd.buffer, - response, sizeof(response)); - if (result == TPM_SUCCESS) { - printk(BIOS_SPEW, "TPM: OK.\n"); - return; - } - - printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); - return; - } - - /* Doing TPM startup when we're not coming in on the S3 resume path - * saves us roughly 20ms in boot time only. This does not seem to - * be worth an API change to vboot_reference-firmware right now, so - * let's keep the code around, but just bail out early: - */ - if (s3resume ? CONFIG_NO_TPM_RESUME - : CONFIG_SKIP_TPM_STARTUP_ON_NORMAL_BOOT) - return; - - printk(BIOS_DEBUG, "TPM initialization.\n"); - - printk(BIOS_SPEW, "TPM: Init\n"); - if (tis_init()) - return; - - printk(BIOS_SPEW, "TPM: Open\n"); - if (tis_open()) - return; - - - if (s3resume) { - /* S3 Resume */ - printk(BIOS_SPEW, "TPM: Resume\n"); - result = TlclSendReceive(tpm_resume_cmd.buffer, - response, sizeof(response)); - if (result == TPM_E_INVALID_POSTINIT) { - /* We're on a platform where the TPM maintains power - * in S3, so it's already initialized. - */ - printk(BIOS_DEBUG, "TPM: Already initialized.\n"); - return; - } - } else { - printk(BIOS_SPEW, "TPM: Startup\n"); - result = TlclSendReceive(tpm_startup_cmd.buffer, - response, sizeof(response)); - } - - if (result == TPM_SUCCESS) { - printk(BIOS_SPEW, "TPM: OK.\n"); - return; - } - - printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); - - if (CONFIG_TPM_INIT_FAILURE_IS_FATAL) { - printk(BIOS_ERR, "Hard reset!\n"); - post_code(POST_TPM_FAILURE); - if (IS_ENABLED(CONFIG_CONSOLE_CBMEM_DUMP_TO_UART)) - cbmem_dump_console(); - hard_reset(); - } -} diff --git a/src/drivers/pc80/tpm/tpm.c b/src/drivers/pc80/tpm/tpm.c deleted file mode 100644 index ba2561d..0000000 --- a/src/drivers/pc80/tpm/tpm.c +++ /dev/null @@ -1,778 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -/* - * The code in this file has been heavily based on the article "Writing a TPM - * Device Driver" published on http://ptgmedia.pearsoncmg.com and the - * submission by Stefan Berger on Qemu-devel mailing list. - * - * One principal difference is that in the simplest config the other than 0 - * TPM localities do not get mapped by some devices (for instance, by - * Infineon slb9635), so this driver provides access to locality 0 only. - */ - -#include <stdlib.h> -#include <string.h> -#include <delay.h> -#include <arch/io.h> -#include <console/console.h> -#include <tpm.h> -#include <arch/early_variables.h> -#include <device/pnp.h> -#include "chip.h" - -#define PREFIX "lpc_tpm: " - -/* coreboot wrapper for TPM driver (start) */ -#define TPM_DEBUG(fmt, args...) \ - if (CONFIG_DEBUG_TPM) { \ - printk(BIOS_DEBUG, PREFIX); \ - printk(BIOS_DEBUG, fmt , ##args); \ - } -#define TPM_DEBUG_IO_READ(reg_, val_) \ - TPM_DEBUG("Read reg 0x%x returns 0x%x\n", (reg_), (val_)) -#define TPM_DEBUG_IO_WRITE(reg_, val_) \ - TPM_DEBUG("Write reg 0x%x with 0x%x\n", (reg_), (val_)) -#define printf(x...) printk(BIOS_ERR, x) - -/* coreboot wrapper for TPM driver (end) */ - -#ifndef CONFIG_TPM_TIS_BASE_ADDRESS -/* Base TPM address standard for x86 systems */ -#define CONFIG_TPM_TIS_BASE_ADDRESS 0xfed40000 -#endif - -/* the macro accepts the locality value, but only locality 0 is operational */ -#define TIS_REG(LOCALITY, REG) \ - (void *)(CONFIG_TPM_TIS_BASE_ADDRESS + (LOCALITY << 12) + REG) - -/* hardware registers' offsets */ -#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_BURST_COUNT 0x19 -#define TIS_REG_DATA_FIFO 0x24 -#define TIS_REG_DID_VID 0xf00 -#define TIS_REG_RID 0xf04 - -/* Some registers' bit field definitions */ -#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 */ - -/* - * Error value returned if a tpm register does not enter the expected state - * after continuous polling. No actual TPM register reading ever returns ~0, - * so this value is a safe error indication to be mixed with possible status - * register values. - */ -#define TPM_TIMEOUT_ERR (~0) - -/* Error value returned on various TPM driver errors */ -#define TPM_DRIVER_ERR (~0) - - /* 1 second is plenty for anything TPM does.*/ -#define MAX_DELAY_US (1000 * 1000) - -/* - * Structures defined below allow creating descriptions of TPM vendor/device - * ID information for run time discovery. The only device the system knows - * about at this time is Infineon slb9635 - */ -struct device_name { - u16 dev_id; - const char * const dev_name; -}; - -struct vendor_name { - u16 vendor_id; - const char * vendor_name; - const struct device_name* dev_names; -}; - -static const struct device_name atmel_devices[] = { - {0x3204, "AT97SC3204"}, - {0xffff} -}; - -static const struct device_name infineon_devices[] = { - {0x000b, "SLB9635 TT 1.2"}, - {0x001a, "SLB9660 TT 1.2"}, - {0x001b, "SLB9670 TT 1.2"}, - {0xffff} -}; - -static const struct device_name nuvoton_devices[] = { - {0x00fe, "NPCT420AA V2"}, - {0xffff} -}; - -static const struct device_name stmicro_devices[] = { - {0x0000, "ST33ZP24" }, - {0xffff} -}; - -static const struct vendor_name vendor_names[] = { - {0x1114, "Atmel", atmel_devices}, - {0x15d1, "Infineon", infineon_devices}, - {0x1050, "Nuvoton", nuvoton_devices}, - {0x104a, "ST Microelectronics", stmicro_devices}, -}; - -/* - * Cached vendor/device ID pair to indicate that the device has been already - * discovered - */ -static u32 vendor_dev_id CAR_GLOBAL; - -static inline u8 tpm_read_status(int locality) -{ - u8 value = read8(TIS_REG(locality, TIS_REG_STS)); - TPM_DEBUG_IO_READ(TIS_REG_STS, value); - return value; -} - -static inline void tpm_write_status(u8 sts, int locality) -{ - TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts); - write8(TIS_REG(locality, TIS_REG_STS), sts); -} - -static inline u8 tpm_read_data(int locality) -{ - u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO)); - TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value); - return value; -} - -static inline void tpm_write_data(u8 data, int locality) -{ - TPM_DEBUG_IO_WRITE(TIS_REG_STS, data); - write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data); -} - -static inline u16 tpm_read_burst_count(int locality) -{ - u16 count; - count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT)); - count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8; - TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count); - return count; -} - -static inline u8 tpm_read_access(int locality) -{ - u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS)); - TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value); - return value; -} - -static inline void tpm_write_access(u8 data, int locality) -{ - TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data); - write8(TIS_REG(locality, TIS_REG_ACCESS), data); -} - -static inline u32 tpm_read_did_vid(int locality) -{ - u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID)); - TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value); - return value; -} - -static inline void tpm_write_int_vector(int vector, int locality) -{ - TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector); - write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf); -} - -static inline void tpm_write_int_polarity(int polarity, int locality) -{ - /* Set polarity and leave all other bits at 0 */ - u32 value = (polarity & 0x3) << 3; - TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value); - write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value); -} - -/* - * tis_wait_sts() - * - * Wait for at least a second for a status to change its state to match the - * expected state. Normally the transition happens within microseconds. - * - * @locality - locality - * @mask - bitmask for the bitfield(s) to watch - * @expected - value the field(s) are supposed to be set to - * - * Returns 0 on success or TPM_TIMEOUT_ERR on timeout. - */ -static int tis_wait_sts(int locality, u8 mask, u8 expected) -{ - u32 time_us = MAX_DELAY_US; - while (time_us > 0) { - u8 value = tpm_read_status(locality); - if ((value & mask) == expected) - return 0; - udelay(1); /* 1 us */ - time_us--; - } - return TPM_TIMEOUT_ERR; -} - -static inline int tis_wait_ready(int locality) -{ - return tis_wait_sts(locality, TIS_STS_COMMAND_READY, - TIS_STS_COMMAND_READY); -} - -static inline int tis_wait_valid(int locality) -{ - return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID); -} - -static inline int tis_wait_valid_data(int locality) -{ - const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; - return tis_wait_sts(locality, has_data, has_data); -} - -static inline int tis_has_valid_data(int locality) -{ - const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; - return (tpm_read_status(locality) & has_data) == has_data; -} - -static inline int tis_expect_data(int locality) -{ - return !!(tpm_read_status(locality) & TIS_STS_EXPECT); -} - -/* - * tis_wait_access() - * - * Wait for at least a second for a access to change its state to match the - * expected state. Normally the transition happens within microseconds. - * - * @locality - locality - * @mask - bitmask for the bitfield(s) to watch - * @expected - value the field(s) are supposed to be set to - * - * Returns 0 on success or TPM_TIMEOUT_ERR on timeout. - */ -static int tis_wait_access(int locality, u8 mask, u8 expected) -{ - u32 time_us = MAX_DELAY_US; - while (time_us > 0) { - u8 value = tpm_read_access(locality); - if ((value & mask) == expected) - return 0; - udelay(1); /* 1 us */ - time_us--; - } - return TPM_TIMEOUT_ERR; -} - -static inline int tis_wait_dropped_access(int locality) -{ - return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, 0); -} - -static inline int tis_wait_received_access(int locality) -{ - return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, - TIS_ACCESS_ACTIVE_LOCALITY); -} - -static inline int tis_has_access(int locality) -{ - return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY); -} - -static inline void tis_request_access(int locality) -{ - tpm_write_access(TIS_ACCESS_REQUEST_USE, locality); -} - -static inline void tis_drop_access(int locality) -{ - tpm_write_access(TIS_ACCESS_ACTIVE_LOCALITY, locality); -} - -/* - * PC Client Specific TPM Interface Specification section 11.2.12: - * - * Software must be prepared to send two writes of a "1" to command ready - * field: the first to indicate successful read of all the data, thus - * clearing the data from the ReadFIFO and freeing the TPM's resources, - * and the second to indicate to the TPM it is about to send a new command. - * - * In practice not all TPMs behave the same so it is necessary to be - * flexible when trying to set command ready. - * - * Returns 0 on success if the TPM is ready for transactions. - * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set. - */ -static int tis_command_ready(u8 locality) -{ - u32 status; - - /* 1st attempt to set command ready */ - tpm_write_status(TIS_STS_COMMAND_READY, locality); - - /* Wait for response */ - status = tpm_read_status(locality); - - /* Check if command ready is set yet */ - if (status & TIS_STS_COMMAND_READY) - return 0; - - /* 2nd attempt to set command ready */ - tpm_write_status(TIS_STS_COMMAND_READY, locality); - - return tis_wait_ready(locality); -} - -/* - * Probe the TPM device and try determining its manufacturer/device name. - * - * Returns 0 on success (the device is found or was found during an earlier - * invocation) or TPM_DRIVER_ERR if the device is not found. - */ -static u32 tis_probe(void) -{ - const char *device_name = "unknown"; - const char *vendor_name = device_name; - const struct device_name *dev; - u32 didvid; - u16 vid, did; - int i; - - if (car_get_var(vendor_dev_id)) - return 0; /* Already probed. */ - - didvid = tpm_read_did_vid(0); - if (!didvid || (didvid == 0xffffffff)) { - printf("%s: No TPM device found\n", __FUNCTION__); - return TPM_DRIVER_ERR; - } - - car_set_var(vendor_dev_id, didvid); - - vid = didvid & 0xffff; - did = (didvid >> 16) & 0xffff; - for (i = 0; i < ARRAY_SIZE(vendor_names); i++) { - int j = 0; - u16 known_did; - if (vid == vendor_names[i].vendor_id) { - vendor_name = vendor_names[i].vendor_name; - } else { - continue; - } - dev = &vendor_names[i].dev_names[j]; - while ((known_did = dev->dev_id) != 0xffff) { - if (known_did == did) { - device_name = dev->dev_name; - break; - } - j++; - dev = &vendor_names[i].dev_names[j]; - } - break; - } - /* this will have to be converted into debug printout */ - printf("Found TPM %s by %s\n", device_name, vendor_name); - return 0; -} - -/* - * tis_senddata() - * - * send the passed in data to the TPM device. - * - * @data - address of the data to send, byte by byte - * @len - length of the data to send - * - * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does - * not accept the entire command). - */ -static u32 tis_senddata(const u8 * const data, u32 len) -{ - u32 offset = 0; - u16 burst = 0; - u32 max_cycles = 0; - u8 locality = 0; - - if (tis_wait_ready(locality)) { - printf("%s:%d - failed to get 'command_ready' status\n", - __FILE__, __LINE__); - return TPM_DRIVER_ERR; - } - burst = tpm_read_burst_count(locality); - - while (1) { - unsigned count; - - /* Wait till the device is ready to accept more data. */ - while (!burst) { - if (max_cycles++ == MAX_DELAY_US) { - printf("%s:%d failed to feed %d bytes of %d\n", - __FILE__, __LINE__, len - offset, len); - return TPM_DRIVER_ERR; - } - udelay(1); - burst = tpm_read_burst_count(locality); - } - - max_cycles = 0; - - /* - * Calculate number of bytes the TPM is ready to accept in one - * shot. - * - * We want to send the last byte outside of the loop (hence - * the -1 below) to make sure that the 'expected' status bit - * changes to zero exactly after the last byte is fed into the - * FIFO. - */ - count = min(burst, len - offset - 1); - while (count--) - tpm_write_data(data[offset++], locality); - - if (tis_wait_valid(locality) || !tis_expect_data(locality)) { - printf("%s:%d TPM command feed overflow\n", - __FILE__, __LINE__); - return TPM_DRIVER_ERR; - } - - burst = tpm_read_burst_count(locality); - if ((offset == (len - 1)) && burst) - /* - * We need to be able to send the last byte to the - * device, so burst size must be nonzero before we - * break out. - */ - break; - } - - /* Send the last byte. */ - tpm_write_data(data[offset++], locality); - - /* - * Verify that TPM does not expect any more data as part of this - * command. - */ - if (tis_wait_valid(locality) || tis_expect_data(locality)) { - printf("%s:%d unexpected TPM status 0x%x\n", - __FILE__, __LINE__, tpm_read_status(locality)); - return TPM_DRIVER_ERR; - } - - /* OK, sitting pretty, let's start the command execution. */ - tpm_write_status(TIS_STS_TPM_GO, locality); - - return 0; -} - -/* - * tis_readresponse() - * - * read the TPM device response after a command was issued. - * - * @buffer - address where to read the response, byte by byte. - * @len - pointer to the size of buffer - * - * On success stores the number of received bytes to len and returns 0. On - * errors (misformatted TPM data or synchronization problems) returns - * TPM_DRIVER_ERR. - */ -static u32 tis_readresponse(u8 *buffer, size_t *len) -{ - u16 burst_count; - u32 offset = 0; - u8 locality = 0; - u32 expected_count = *len; - int max_cycles = 0; - - /* Wait for the TPM to process the command */ - if (tis_wait_valid_data(locality)) { - printf("%s:%d failed processing command\n", __FILE__, __LINE__); - return TPM_DRIVER_ERR; - } - - do { - while ((burst_count = tpm_read_burst_count(locality)) == 0) { - if (max_cycles++ == MAX_DELAY_US) { - printf("%s:%d TPM stuck on read\n", - __FILE__, __LINE__); - return TPM_DRIVER_ERR; - } - udelay(1); - } - - max_cycles = 0; - - while (burst_count-- && (offset < expected_count)) { - buffer[offset++] = tpm_read_data(locality); - if (offset == 6) { - /* - * We got the first six bytes of the reply, - * let's figure out how many bytes to expect - * total - it is stored as a 4 byte number in - * network order, starting with offset 2 into - * the body of the reply. - */ - u32 real_length; - memcpy(&real_length, - buffer + 2, - sizeof(real_length)); - expected_count = be32_to_cpu(real_length); - - if ((expected_count < offset) || - (expected_count > *len)) { - printf("%s:%d bad response size %d\n", - __FILE__, __LINE__, - expected_count); - return TPM_DRIVER_ERR; - } - } - } - - /* Wait for the next portion */ - if (tis_wait_valid(locality)) { - printf("%s:%d failed to read response\n", - __FILE__, __LINE__); - return TPM_DRIVER_ERR; - } - - if (offset == expected_count) - break; /* We got all we need */ - - } while (tis_has_valid_data(locality)); - - /* * Make sure we indeed read all there was. */ - if (tis_has_valid_data(locality)) { - printf("%s:%d wrong receive status: %x %d bytes left\n", - __FILE__, __LINE__, tpm_read_status(locality), - tpm_read_burst_count(locality)); - return TPM_DRIVER_ERR; - } - - /* Tell the TPM that we are done. */ - if (tis_command_ready(locality) == TPM_TIMEOUT_ERR) - return TPM_DRIVER_ERR; - - *len = offset; - return 0; -} - -/* - * tis_init() - * - * Initialize the TPM device. Returns 0 on success or TPM_DRIVER_ERR on - * failure (in case device probing did not succeed). - */ -int tis_init(void) -{ - if (tis_probe()) - return TPM_DRIVER_ERR; - return 0; -} - -/* - * tis_open() - * - * Requests access to locality 0 for the caller. After all commands have been - * completed the caller is supposed to call tis_close(). - * - * Returns 0 on success, TPM_DRIVER_ERR on failure. - */ -int tis_open(void) -{ - u8 locality = 0; /* we use locality zero for everything */ - - if (tis_close()) - return TPM_DRIVER_ERR; - - /* now request access to locality */ - tis_request_access(locality); - - /* did we get a lock? */ - if (tis_wait_received_access(locality)) { - printf("%s:%d - failed to lock locality %d\n", - __FILE__, __LINE__, locality); - return TPM_DRIVER_ERR; - } - - /* Certain TPMs seem to need some delay here or they hang... */ - udelay(10); - - if (tis_command_ready(locality) == TPM_TIMEOUT_ERR) - return TPM_DRIVER_ERR; - - return 0; -} - -/* - * tis_close() - * - * terminate the current session with the TPM by releasing the locked - * locality. Returns 0 on success of TPM_DRIVER_ERR on failure (in case lock - * removal did not succeed). - */ -int tis_close(void) -{ - u8 locality = 0; - if (tis_has_access(locality)) { - tis_drop_access(locality); - if (tis_wait_dropped_access(locality)) { - printf("%s:%d - failed to release locality %d\n", - __FILE__, __LINE__, locality); - return TPM_DRIVER_ERR; - } - } - return 0; -} - -/* - * tis_sendrecv() - * - * Send the requested data to the TPM and then try to get its response - * - * @sendbuf - buffer of the data to send - * @send_size size of the data to send - * @recvbuf - memory to save the response to - * @recv_len - pointer to the size of the response buffer - * - * Returns 0 on success (and places the number of response bytes at recv_len) - * or TPM_DRIVER_ERR on failure. - */ -int tis_sendrecv(const uint8_t *sendbuf, size_t send_size, - uint8_t *recvbuf, size_t *recv_len) -{ - if (tis_senddata(sendbuf, send_size)) { - printf("%s:%d failed sending data to TPM\n", - __FILE__, __LINE__); - return TPM_DRIVER_ERR; - } - - return tis_readresponse(recvbuf, recv_len); -} - -#ifdef __RAMSTAGE__ - -/* - * tis_setup_interrupt() - * - * Set up the interrupt vector and polarity for locality 0 and - * disable all interrupts so they are unused in firmware but can - * be enabled by the OS. - * - * The values used here must match what is passed in the TPM ACPI - * device if ACPI is used on the platform. - * - * @vector - TPM interrupt vector - * @polarity - TPM interrupt polarity - * - * Returns 0 on success, TPM_DRIVER_ERR on failure. - */ -static int tis_setup_interrupt(int vector, int polarity) -{ - u8 locality = 0; - int has_access = tis_has_access(locality); - - /* Open connection and request access if not already granted */ - if (!has_access && tis_open() < 0) - return TPM_DRIVER_ERR; - - /* Set TPM interrupt vector */ - tpm_write_int_vector(vector, locality); - - /* Set TPM interupt polarity and disable interrupts */ - tpm_write_int_polarity(polarity, locality); - - /* Close connection if it was opened */ - if (!has_access && tis_close() < 0) - return TPM_DRIVER_ERR; - - return 0; -} - -static void lpc_tpm_read_resources(struct device *dev) -{ - /* Static 5K memory region specified in Kconfig */ - mmio_resource(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10); -} - -static void lpc_tpm_set_resources(struct device *dev) -{ - tpm_config_t *config = (tpm_config_t *)dev->chip_info; - struct resource *res; - - for (res = dev->resource_list; res; res = res->next) { - if (!(res->flags & IORESOURCE_ASSIGNED)) - continue; - - if (res->flags & IORESOURCE_IRQ) { - /* Set interrupt vector */ - tis_setup_interrupt((int)res->base, - config->irq_polarity); - } else { - continue; - } - - res->flags |= IORESOURCE_STORED; - report_resource_stored(dev, res, " <tpm>"); - } -} - -static struct device_operations lpc_tpm_ops = { - .read_resources = &lpc_tpm_read_resources, - .set_resources = &lpc_tpm_set_resources, -}; - -static struct pnp_info pnp_dev_info[] = { - { .flags = PNP_IRQ0 } -}; - -static void enable_dev(struct device *dev) -{ - pnp_enable_devices(dev, &lpc_tpm_ops, - ARRAY_SIZE(pnp_dev_info), pnp_dev_info); -} - -struct chip_operations drivers_pc80_tpm_ops = { - CHIP_NAME("LPC TPM") - .enable_dev = enable_dev -}; - -#endif /* __RAMSTAGE__ */ diff --git a/src/drivers/tpm/Kconfig b/src/drivers/tpm/Kconfig new file mode 100644 index 0000000..5e8df7b --- /dev/null +++ b/src/drivers/tpm/Kconfig @@ -0,0 +1,24 @@ +source src/drivers/tpm/lpc/Kconfig +source src/drivers/tpm/i2c/Kconfig + +config TPM_INIT_FAILURE_IS_FATAL + bool + default n + depends on LPC_TPM || I2C_TPM + help + What to do if TPM init failed. If true, force a hard reset, + otherwise just log error message to console. + +config SKIP_TPM_STARTUP_ON_NORMAL_BOOT + bool + default n + depends on LPC_TPM || I2C_TPM + help + Skip TPM init on normal boot. Useful if payload does TPM init. + +config TPM_DEACTIVATE + bool "Deactivate TPM" + default n + depends on LPC_TPM || I2C_TPM + help + Deactivate TPM by issuing deactivate command. diff --git a/src/drivers/tpm/Makefile.inc b/src/drivers/tpm/Makefile.inc new file mode 100644 index 0000000..a7fad64 --- /dev/null +++ b/src/drivers/tpm/Makefile.inc @@ -0,0 +1 @@ +subdirs-y = i2c lpc \ No newline at end of file diff --git a/src/drivers/tpm/acpi/tpm.asl b/src/drivers/tpm/acpi/tpm.asl new file mode 100644 index 0000000..ece63e2 --- /dev/null +++ b/src/drivers/tpm/acpi/tpm.asl @@ -0,0 +1,196 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2014 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +/* Trusted Platform Module */ + +Device (TPM) +{ + Name (_HID, EISAID ("PNP0C31")) + Name (_CID, 0x310cd041) + Name (_UID, 1) + + Method (_STA, 0) + { +#if CONFIG_LPC_TPM && !CONFIG_TPM_DEACTIVATE + Return (0xf) +#else + Return (0x0) +#endif + } + + Name (IBUF, ResourceTemplate () + { + /* Updated based on TPM interrupt for Locality 0 */ + Interrupt (ResourceConsumer, Edge, ActiveHigh, + Exclusive, , , TIRQ) { 0 } + }) + + Name (RBUF, ResourceTemplate () + { + IO (Decode16, 0x2e, 0x2e, 0x01, 0x02) + Memory32Fixed (ReadWrite, CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000) + }) + + Method (_CRS, 0, NotSerialized) + { + OperationRegion (TREG, SystemMemory, + CONFIG_TPM_TIS_BASE_ADDRESS, 0x5000) + Field (TREG, ByteAcc, NoLock, Preserve) + { + /* TPM_INT_ENABLE_0 */ + Offset (0x0008), + , 3, + ITPL, 2, /* Interrupt type and polarity */ + + /* TPM_INT_VECTOR_0 */ + Offset (0x000C), + IVEC, 4, /* SERIRQ vector */ + } + + If (LGreater (IVEC, 0)) { + /* Update interrupt vector */ + CreateField (^IBUF, ^TIRQ._INT, 32, TVEC) + Store (IVEC, TVEC) + + /* Update interrupt type and polarity */ + CreateBitField (^IBUF, ^TIRQ._HE, TTYP) + CreateBitField (^IBUF, ^TIRQ._LL, TPOL) + CreateBitField (^IBUF, ^TIRQ._SHR, TSHR) + + If (LEqual (ITPL, 0x0)) { + /* Active-High Level-Triggered Shared */ + Store (Zero, TPOL) + Store (Zero, TTYP) + Store (One, TSHR) + } ElseIf (LEqual (ITPL, 0x1)) { + /* Active-Low Level-Triggered Shared */ + Store (One, TPOL) + Store (Zero, TTYP) + Store (One, TSHR) + } ElseIf (LEqual (ITPL, 0x2)) { + /* Active-High Edge-Triggered Exclusive */ + Store (Zero, TPOL) + Store (One, TTYP) + Store (Zero, TSHR) + } ElseIf (LEqual (ITPL, 0x3)) { + /* Active-Low Edge-Triggered Exclusive */ + Store (One, TPOL) + Store (One, TTYP) + Store (Zero, TSHR) + } + + /* Merge IRQ with base address */ + Return (ConcatenateResTemplate (RBUF, IBUF)) + } Else { + Return (RBUF) + } + } + + /* Dummy _DSM to make Bitlocker work. */ + Method (_DSM, 4, Serialized) + { + /* Physical presence interface. + This is used to submit commands like "Clear TPM" to + be run at next reboot provided that user confirms them. + Spec allows user to cancel all commands and/or + configure BIOS to reject commands. So we pretend that + user did just this: cancelled everything. If user + really wants to clear TPM the only option now is to do it manually + in payload. + */ + If (LEqual (Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + If (LEqual (Arg2, 0)) + { + /* Functions 1-8. */ + Return (Buffer (2) { 0xFF, 0x01 }) + } + + /* Interface version: 1.2 */ + If (LEqual (Arg2, 1)) + { + Return ("1.2") + } + + /* Submit operations: drop on the floor and return success. */ + If (LEqual (Arg2, 2)) + { + Return (0x00) + } + + /* Pending operation: none. */ + If (LEqual (Arg2, 3)) + { + Return (Package (2) { 0, 0 }) + } + + /* Pre-OS transition method: reboot. */ + If (LEqual (Arg2, 4)) + { + Return (2) + } + + /* Operation response: no operation executed. */ + If (LEqual (Arg2, 5)) + { + Return (Package (3) { 0, 0, 0 }) + } + + /* Set preffered user language: deprecated and must return 3 aka "not implemented". */ + If (LEqual (Arg2, 6)) + { + Return (3) + } + + /* Submit operations: deny. */ + If (LEqual (Arg2, 7)) + { + Return (3) + } + + /* All actions are forbidden. */ + If (LEqual (Arg2, 8)) + { + Return (1) + } + + Return (1) + } + + /* Memory clearing on boot: just a dummy. */ + If (LEqual (Arg0, ToUUID("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + If (LEqual (Arg2, 0)) + { + /* Function 1. */ + Return (Buffer (1) { 3 }) + } + + /* Just return success. */ + If (LEqual (Arg2, 1)) + { + Return (0) + } + + Return (1) + } + + Return (Buffer (1) { 0 }) + } +} diff --git a/src/drivers/tpm/i2c/Kconfig b/src/drivers/tpm/i2c/Kconfig new file mode 100644 index 0000000..82317d7 --- /dev/null +++ b/src/drivers/tpm/i2c/Kconfig @@ -0,0 +1,13 @@ +config I2C_TPM + bool "Enable TPM support" + depends on !PC80_SYSTEM # for now + +config DRIVER_TPM_I2C_BUS + hex "I2C TPM chip bus" + default 9 # FIXME, workaround for Kconfig BS + depends on I2C_TPM + +config DRIVER_TPM_I2C_ADDR + hex "I2C TPM chip address" + default 2 # FIXME, workaround for Kconfig BS + depends on I2C_TPM diff --git a/src/drivers/tpm/i2c/Makefile.inc b/src/drivers/tpm/i2c/Makefile.inc new file mode 100644 index 0000000..b415478 --- /dev/null +++ b/src/drivers/tpm/i2c/Makefile.inc @@ -0,0 +1,4 @@ +ramstage-$(CONFIG_I2C_TPM) += tpm.c +romstage-$(CONFIG_I2C_TPM) += tpm.c +verstage-$(CONFIG_I2C_TPM) += tpm.c +bootblock-$(CONFIG_I2C_TPM) += tpm.c diff --git a/src/drivers/tpm/i2c/chip.h b/src/drivers/tpm/i2c/chip.h new file mode 100644 index 0000000..9ab688e --- /dev/null +++ b/src/drivers/tpm/i2c/chip.h @@ -0,0 +1,98 @@ +#include <stddef.h> +#include <stdint.h> + +#ifndef DRIVERS_TPM_I2C_CHIP_H +#define DRIVERS_TPM_I2C_CHIP_H + + +enum tpm_timeout { + TPM_TIMEOUT = 1, /* msecs */ +}; + +/* Size of external transmit buffer (used for stack buffer in tpm_sendrecv) */ +#define TPM_BUFSIZE 1260 + +/* Index of fields in TPM command buffer */ +#define TPM_CMD_SIZE_BYTE 2 +#define TPM_CMD_ORDINAL_BYTE 6 + +/* Index of Count field in TPM response buffer */ +#define TPM_RSP_SIZE_BYTE 2 +#define TPM_RSP_RC_BYTE 6 + +struct tpm_chip; + +struct tpm_vendor_specific { + const uint8_t req_complete_mask; + const uint8_t req_complete_val; + const uint8_t req_canceled; + int irq; + int (*recv)(struct tpm_chip *, uint8_t *, size_t); + int (*send)(struct tpm_chip *, uint8_t *, size_t); + void (*cancel)(struct tpm_chip *); + uint8_t(*status)(struct tpm_chip *); + int locality; +}; + +struct tpm_chip { + int is_open; + struct tpm_vendor_specific vendor; +}; + +struct tpm_input_header { + uint16_t tag; + uint32_t length; + uint32_t ordinal; +} __attribute__ ((packed)); + +struct tpm_output_header { + uint16_t tag; + uint32_t length; + uint32_t return_code; +} __attribute__ ((packed)); + +struct timeout_t { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; +} __attribute__ ((packed)); + +struct duration_t { + uint32_t tpm_short; + uint32_t tpm_medium; + uint32_t tpm_long; +} __attribute__ ((packed)); + +typedef union { + struct timeout_t timeout; + struct duration_t duration; +} cap_t; + +struct tpm_getcap_params_in { + uint32_t cap; + uint32_t subcap_size; + uint32_t subcap; +} __attribute__ ((packed)); + +struct tpm_getcap_params_out { + uint32_t cap_size; + cap_t cap; +} __attribute__ ((packed)); + +typedef union { + struct tpm_input_header in; + struct tpm_output_header out; +} tpm_cmd_header; + +typedef union { + struct tpm_getcap_params_out getcap_out; + struct tpm_getcap_params_in getcap_in; +} tpm_cmd_params; + +struct tpm_cmd_t { + tpm_cmd_header header; + tpm_cmd_params params; +} __attribute__ ((packed)); + +#endif \ No newline at end of file diff --git a/src/drivers/tpm/i2c/tpm.c b/src/drivers/tpm/i2c/tpm.c new file mode 100644 index 0000000..bde5852 --- /dev/null +++ b/src/drivers/tpm/i2c/tpm.c @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2011 Infineon Technologies + * + * Authors: + * Peter Huewe huewe.external@infineon.com + * + * Description: + * Device driver for TCG/TCPA TPM (trusted platform module). + * Specifications at www.trustedcomputinggroup.org + * + * This device driver implements the TPM interface as defined in + * the TCG TPM Interface Spec version 1.2, revision 1.0 and the + * Infineon I2C Protocol Stack Specification v0.20. + * + * It is based on the Linux kernel driver tpm.c from Leendert van + * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. + * + * Version: 2.1.1 + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <stdint.h> +#include <string.h> +#include <types.h> +#include <delay.h> +#include <console/console.h> +#include <device/i2c.h> +#include <endian.h> +#include <timer.h> +#include <assert.h> +#include "chip.h" +#include <tpm/tpm.h> + +/* Address of the TPM on the I2C bus */ +#define TPM_I2C_ADDR 0x20 + +/* max. number of iterations after I2C NAK */ +#define MAX_COUNT 3 + +#define SLEEP_DURATION 60 /* in usec */ + +/* max. number of iterations after I2C NAK for 'long' commands + * we need this especially for sending TPM_READY, since the cleanup after the + * transtion to the ready state may take some time, but it is unpredictable + * how long it will take. + */ +#define MAX_COUNT_LONG 50 + +#define SLEEP_DURATION_LONG 210 /* in usec */ + +/* expected value for DIDVID register */ +#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L +#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L + +#define TPM_CMD_COUNT_BYTE 2 +#define TPM_CMD_ORDINAL_BYTE 6 +#define TPM_VALID_STATUS (1 << 7) + +/* global structure for tpm chip data */ +struct tpm_chip g_chip; + +enum i2c_chip_type { + SLB9635, + SLB9645, + UNKNOWN, +}; + +static const char * const chip_name[] = { + [SLB9635] = "slb9635tt", + [SLB9645] = "slb9645tt", + [UNKNOWN] = "unknown/fallback to slb9635", +}; + +/* Structure to store I2C TPM specific stuff */ +struct tpm_inf_dev { + int bus; + unsigned int addr; + uint8_t buf[TPM_BUFSIZE + sizeof(uint8_t)]; // max. buffer size + addr + enum i2c_chip_type chip_type; +}; + +static struct tpm_inf_dev tpm_dev = { + .bus = -1, + .addr = TPM_I2C_ADDR +}; + +/* + * iic_tpm_read() - read from TPM register + * @addr: register address to read from + * @buffer: provided by caller + * @len: number of bytes to read + * + * Read len bytes from TPM register and put them into + * buffer (little-endian format, i.e. first byte is put into buffer[0]). + * + * NOTE: TPM is big-endian for multi-byte values. Multi-byte + * values have to be swapped. + * + * Return -1 on error, 0 on success. + */ +static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) +{ + int rc; + int count; + + if (tpm_dev.bus < 0) + return -1; + if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { + /* slb9635 protocol should work in both cases */ + for (count = 0; count < MAX_COUNT; count++) { + rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, &addr, 1); + if (rc == 0) + break; /* success, break to skip sleep */ + + udelay(SLEEP_DURATION); + } + + if (rc) + return -1; + + /* After the TPM has successfully received the register address + * it needs some time, thus we're sleeping here again, before + * retrieving the data + */ + for (count = 0; count < MAX_COUNT; count++) { + udelay(SLEEP_DURATION); + rc = i2c_read_raw(tpm_dev.bus, tpm_dev.addr, + buffer, len); + if (rc == 0) + break; /* success, break to skip sleep */ + + } + } else { + /* use a combined read for newer chips + * unfortunately the smbus functions are not suitable due to + * the 32 byte limit of the smbus. + * retries should usually not be needed, but are kept just to + * be safe on the safe side. + */ + struct i2c_seg aseg = { .read = 0, .chip = tpm_dev.addr, + .buf = &addr, .len = 1 }; + struct i2c_seg dseg = { .read = 1, .chip = tpm_dev.addr, + .buf = buffer, .len = len }; + for (count = 0; count < MAX_COUNT; count++) { + rc = i2c_transfer(tpm_dev.bus, &aseg, 1) || + i2c_transfer(tpm_dev.bus, &dseg, 1); + if (rc == 0) + break; /* break here to skip sleep */ + udelay(SLEEP_DURATION); + } + } + + /* take care of 'guard time' */ + udelay(SLEEP_DURATION); + if (rc) + return -1; + + return 0; +} + +static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, + unsigned int sleep_time, + uint8_t max_count) +{ + int rc = 0; + int count; + + if (len > TPM_BUFSIZE) { + printk(BIOS_DEBUG, "%s: Length %zd is too large\n", __func__, len); + return -1; + } + + /* prepare send buffer */ + tpm_dev.buf[0] = addr; + memcpy(&(tpm_dev.buf[1]), buffer, len); + + if (tpm_dev.bus < 0) + return -1; + for (count = 0; count < max_count; count++) { + rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, + tpm_dev.buf, len + 1); + if (rc == 0) + break; /* success, break to skip sleep */ + + udelay(sleep_time); + } + + /* take care of 'guard time' */ + udelay(SLEEP_DURATION); + if (rc) + return -1; + + return 0; +} + +/* + * iic_tpm_write() - write to TPM register + * @addr: register address to write to + * @buffer: containing data to be written + * @len: number of bytes to write + * + * Write len bytes from provided buffer to TPM register (little + * endian format, i.e. buffer[0] is written as first byte). + * + * NOTE: TPM is big-endian for multi-byte values. Multi-byte + * values have to be swapped. + * + * NOTE: use this function instead of the iic_tpm_write_generic function. + * + * Return -EIO on error, 0 on success + */ +static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len) +{ + return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION, + MAX_COUNT); +} + +/* + * This function is needed especially for the cleanup situation after + * sending TPM_READY + * */ +static int iic_tpm_write_long(uint8_t addr, uint8_t *buffer, size_t len) +{ + return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, + MAX_COUNT_LONG); +} + +#define TPM_HEADER_SIZE 10 + +enum tis_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum tis_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +#define TPM_ACCESS(l) (0x0000 | ((l) << 4)) +#define TPM_STS(l) (0x0001 | ((l) << 4)) +#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) +#define TPM_DID_VID(l) (0x0006 | ((l) << 4)) + +static int check_locality(struct tpm_chip *chip, int loc) +{ + uint8_t buf; + + if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) + return -1; + + if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == + (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { + chip->vendor.locality = loc; + return loc; + } + + return -1; +} + +static void release_locality(struct tpm_chip *chip, int loc, int force) +{ + uint8_t buf; + if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) + return; + + if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == + (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { + buf = TPM_ACCESS_ACTIVE_LOCALITY; + iic_tpm_write(TPM_ACCESS(loc), &buf, 1); + } +} + +static int request_locality(struct tpm_chip *chip, int loc) +{ + uint8_t buf = TPM_ACCESS_REQUEST_USE; + + if (check_locality(chip, loc) >= 0) + return loc; /* we already have the locality */ + + iic_tpm_write(TPM_ACCESS(loc), &buf, 1); + + /* wait for burstcount */ + int timeout = 2 * 1000; /* 2s timeout */ + while (timeout) { + if (check_locality(chip, loc) >= 0) + return loc; + mdelay(TPM_TIMEOUT); + timeout--; + } + + return -1; +} + +static uint8_t tpm_tis_i2c_status(struct tpm_chip *chip) +{ + /* NOTE: Since I2C read may fail, return 0 in this case --> time-out */ + uint8_t buf; + if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) + return 0; + else + return buf; +} + +static void tpm_tis_i2c_ready(struct tpm_chip *chip) +{ + /* this causes the current command to be aborted */ + uint8_t buf = TPM_STS_COMMAND_READY; + iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); +} + +static ssize_t get_burstcount(struct tpm_chip *chip) +{ + ssize_t burstcnt; + uint8_t buf[3]; + + /* wait for burstcount */ + int timeout = 2 * 1000; /* 2s timeout */ + while (timeout) { + /* Note: STS is little endian */ + if (iic_tpm_read(TPM_STS(chip->vendor.locality) + 1, buf, 3) < 0) + burstcnt = 0; + else + burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; + + if (burstcnt) + return burstcnt; + mdelay(TPM_TIMEOUT); + timeout--; + } + return -1; +} + +static int wait_for_stat(struct tpm_chip *chip, uint8_t mask, int *status) +{ + unsigned long timeout = 2 * 1024; + while (timeout) { + *status = tpm_tis_i2c_status(chip); + if ((*status & mask) == mask) + return 0; + mdelay(TPM_TIMEOUT); + timeout--; + } + + return -1; +} + +static int recv_data(struct tpm_chip *chip, uint8_t *buf, size_t count) +{ + size_t size = 0; + + while (size < count) { + ssize_t burstcnt = get_burstcount(chip); + int rc; + + /* burstcount < 0 = TPM is busy */ + if (burstcnt < 0) + return burstcnt; + + /* limit received data to max. left */ + if (burstcnt > (count - size)) + burstcnt = count - size; + + rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), + &(buf[size]), + burstcnt); + if (rc == 0) + size += burstcnt; + + } + return size; +} + +static int tpm_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf, size_t count) +{ + int size = 0; + uint32_t expected; + int status; + + if (count < TPM_HEADER_SIZE) { + size = -1; + goto out; + } + + /* read first 10 bytes, including tag, paramsize, and result */ + size = recv_data(chip, buf, TPM_HEADER_SIZE); + if (size < TPM_HEADER_SIZE) { + printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Unable to read header\n"); + goto out; + } + + memcpy(&expected, buf + TPM_RSP_SIZE_BYTE, sizeof(expected)); + expected = be32_to_cpu(expected); + if ((size_t)expected > count) { + size = -1; + goto out; + } + + size += recv_data(chip, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE); + if (size < expected) { + printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Unable to " + "read remainder of result\n"); + size = -1; + goto out; + } + + wait_for_stat(chip, TPM_STS_VALID, &status); + if (status & TPM_STS_DATA_AVAIL) { /* retry? */ + printk(BIOS_DEBUG, "tpm_tis_i2c_recv: Error left over data\n"); + size = -1; + goto out; + } + +out: + tpm_tis_i2c_ready(chip); + + return size; +} + +static int tpm_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len) +{ + int status; + size_t count = 0; + uint8_t sts = TPM_STS_GO; + + if (len > TPM_BUFSIZE) + return -1; /* command is too long for our TPM, sorry */ + + status = tpm_tis_i2c_status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) { + tpm_tis_i2c_ready(chip); + if (wait_for_stat(chip, TPM_STS_COMMAND_READY, &status) < 0) + goto out_err; + } + + while (count < len - 1) { + ssize_t burstcnt = get_burstcount(chip); + + /* burstcount < 0 = TPM is busy */ + if (burstcnt < 0) + return burstcnt; + + if (burstcnt > (len-1-count)) + burstcnt = len-1-count; + +#ifdef CONFIG_TPM_I2C_BURST_LIMITATION + if (burstcnt > CONFIG_TPM_I2C_BURST_LIMITATION) + burstcnt = CONFIG_TPM_I2C_BURST_LIMITATION; +#endif /* CONFIG_TPM_I2C_BURST_LIMITATION */ + + if (iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), + &(buf[count]), burstcnt) == 0) + count += burstcnt; + + wait_for_stat(chip, TPM_STS_VALID, &status); + if ((status & TPM_STS_DATA_EXPECT) == 0) + goto out_err; + } + + /* write last byte */ + iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); + + wait_for_stat(chip, TPM_STS_VALID, &status); + if ((status & TPM_STS_DATA_EXPECT) != 0) + goto out_err; + + /* go and do it */ + iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); + + return len; + +out_err: + tpm_tis_i2c_ready(chip); + + return -1; +} + +static struct tpm_vendor_specific tpm_tis_i2c = { + .status = tpm_tis_i2c_status, + .recv = tpm_tis_i2c_recv, + .send = tpm_tis_i2c_send, + .cancel = tpm_tis_i2c_ready, + .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, + .req_canceled = TPM_STS_COMMAND_READY, +}; + +int tis_open(void) +{ + int rc; + + if (g_chip.is_open) { + printk(BIOS_DEBUG, "tis_open() called twice.\n"); + return -1; + } + + rc = tpm_vendor_init(CONFIG_DRIVER_TPM_I2C_BUS, + CONFIG_DRIVER_TPM_I2C_ADDR); + + if (rc < 0) + g_chip.is_open = 0; + + if (rc) { + return -1; + } + + return 0; +} + +int tis_close(void) +{ + if (g_chip.is_open) { + tpm_vendor_cleanup(&g_chip); + g_chip.is_open = 0; + } + + return 0; +} + +int tis_init(void) +{ + int bus = CONFIG_DRIVER_TPM_I2C_BUS; + int chip = CONFIG_DRIVER_TPM_I2C_ADDR; + struct stopwatch sw; + uint8_t buf = 0; + int ret; + long sw_run_duration = 750; + + /* + * Probe TPM. Check if the TPM_ACCESS register's ValidSts bit is set(1) + * If the bit remains clear(0) then claim that init has failed. + */ + stopwatch_init_msecs_expire(&sw, sw_run_duration); + do { + ret = i2c_readb(bus, chip, 0, &buf); + if (!ret && (buf & TPM_VALID_STATUS)) { + sw_run_duration = stopwatch_duration_msecs(&sw); + break; + } + } while (!stopwatch_expired(&sw)); + + printk(BIOS_INFO, + "%s: ValidSts bit %s(%d) in TPM_ACCESS register after %ld ms\n", + __func__, (buf & TPM_VALID_STATUS) ? "set" : "clear", + (buf & TPM_VALID_STATUS) >> 7, sw_run_duration); + + /* + * Claim failure if the ValidSts (bit 7) is clear. + */ + if (!(buf & TPM_VALID_STATUS)) + return -1; + + return 0; +} + +static ssize_t tpm_transmit(const uint8_t *buf, size_t bufsiz) +{ + int rc; + uint32_t count, ordinal; + + struct tpm_chip *chip = &g_chip; + + memcpy(&count, buf + TPM_CMD_COUNT_BYTE, sizeof(count)); + count = be32_to_cpu(count); + memcpy(&ordinal, buf + TPM_CMD_ORDINAL_BYTE, sizeof(ordinal)); + ordinal = be32_to_cpu(ordinal); + + if (count == 0) { + printk(BIOS_DEBUG, "tpm_transmit: no data\n"); + return -1; + } + if (count > bufsiz) { + printk(BIOS_DEBUG, "tpm_transmit: invalid count value %x %zx\n", + count, bufsiz); + return -1; + } + + ASSERT(chip->vendor.send); + rc = chip->vendor.send(chip, (uint8_t *) buf, count); + if (rc < 0) { + printk(BIOS_DEBUG, "tpm_transmit: tpm_send error\n"); + goto out; + } + + if (chip->vendor.irq) + goto out_recv; + + int timeout = 2 * 60 * 1000; /* two minutes timeout */ + while (timeout) { + ASSERT(chip->vendor.status); + uint8_t status = chip->vendor.status(chip); + if ((status & chip->vendor.req_complete_mask) == + chip->vendor.req_complete_val) { + goto out_recv; + } + + if ((status == chip->vendor.req_canceled)) { + printk(BIOS_DEBUG, "tpm_transmit: Operation Canceled\n"); + rc = -1; + goto out; + } + mdelay(TPM_TIMEOUT); + timeout--; + } + + ASSERT(chip->vendor.cancel); + chip->vendor.cancel(chip); + printk(BIOS_DEBUG, "tpm_transmit: Operation Timed out\n"); + rc = -1; //ETIME; + goto out; + +out_recv: + + rc = chip->vendor.recv(chip, (uint8_t *) buf, TPM_BUFSIZE); + if (rc < 0) + printk(BIOS_DEBUG, "tpm_transmit: tpm_recv: error %d\n", rc); +out: + return rc; +} + +int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, + uint8_t *recvbuf, size_t *rbuf_len) +{ + uint8_t buf[TPM_BUFSIZE]; + + if (sizeof(buf) < sbuf_size) + return -1; + + memcpy(buf, sendbuf, sbuf_size); + + int len = tpm_transmit(buf, sbuf_size); + + if (len < 10) { + *rbuf_len = 0; + return -1; + } + + if (len > *rbuf_len) { + *rbuf_len = len; + return -1; + } + + memcpy(recvbuf, buf, len); + *rbuf_len = len; + + return 0; +} + +/* Initialization of I2C TPM */ + +int tpm_vendor_init(unsigned bus, uint32_t dev_addr) +{ + uint32_t vendor; + unsigned int old_addr; + struct tpm_chip *chip; + extern struct tpm_chip g_chip; + + old_addr = tpm_dev.addr; + if (dev_addr != 0) + tpm_dev.addr = dev_addr; + tpm_dev.bus = bus; + + chip = &g_chip; + memcpy(&chip->vendor, &tpm_tis_i2c, sizeof(struct tpm_vendor_specific)); + chip->is_open = 1; + + /* Disable interrupts (not supported) */ + chip->vendor.irq = 0; + + if (request_locality(chip, 0) != 0) + goto out_err; + + /* Read four bytes from DID_VID register */ + if (iic_tpm_read(TPM_DID_VID(0), (uint8_t *)&vendor, 4) < 0) + goto out_release; + + if (vendor == TPM_TIS_I2C_DID_VID_9645) { + tpm_dev.chip_type = SLB9645; + } else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) { + tpm_dev.chip_type = SLB9635; + } else { + printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor); + goto out_release; + } + + printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", + chip_name[tpm_dev.chip_type], vendor >> 16); + + /* + * A timeout query to TPM can be placed here. + * Standard timeout values are used so far + */ + + return 0; + +out_release: + release_locality(chip, 0, 1); + +out_err: + tpm_dev.addr = old_addr; + return -1; +} + +void tpm_vendor_cleanup(struct tpm_chip *chip) +{ + release_locality(chip, chip->vendor.locality, 1); +} diff --git a/src/drivers/tpm/lpc/Kconfig b/src/drivers/tpm/lpc/Kconfig new file mode 100644 index 0000000..1e842d2 --- /dev/null +++ b/src/drivers/tpm/lpc/Kconfig @@ -0,0 +1,24 @@ +config MAINBOARD_HAS_LPC_TPM + bool + default n + help + Board has TPM support + +config LPC_TPM + bool "Enable TPM support" + depends on MAINBOARD_HAS_LPC_TPM + default n + help + Enable this option to enable LPC TPM support in coreboot. + + If unsure, say N. + +config TPM_TIS_BASE_ADDRESS + hex + default 0xfed40000 + depends on LPC_TPM + help + This can be used to adjust the TPM memory base address. + The default is specified by the TCG PC Client Specific TPM + Interface Specification 1.2 and should not be changed unless + the TPM being used does not conform to TPM TIS 1.2. diff --git a/src/drivers/tpm/lpc/Makefile.inc b/src/drivers/tpm/lpc/Makefile.inc new file mode 100644 index 0000000..a592639 --- /dev/null +++ b/src/drivers/tpm/lpc/Makefile.inc @@ -0,0 +1,4 @@ +ramstage-$(CONFIG_LPC_TPM) += tpm.c +romstage-$(CONFIG_LPC_TPM) += tpm.c +verstage-$(CONFIG_LPC_TPM) += tpm.c +bootblock-$(CONFIG_LPC_TPM) += tpm.c diff --git a/src/drivers/tpm/lpc/chip.h b/src/drivers/tpm/lpc/chip.h new file mode 100644 index 0000000..9370ecf --- /dev/null +++ b/src/drivers/tpm/lpc/chip.h @@ -0,0 +1,35 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2014 Google Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#ifndef DRIVERS_TPM_LPC_CHIP_H +#define DRIVERS_TPM_LPC_CHIP_H + +typedef struct drivers_tpm_config { + /* + * TPM Interrupt polarity: + * + * High Level 0 + * Low Level 1 + * Rising Edge 2 + * Falling Edge 3 + */ + u8 irq_polarity; +} tpm_config_t; + +#endif /* DRIVERS_TPM_LPC_CHIP_H */ diff --git a/src/drivers/tpm/lpc/tpm.c b/src/drivers/tpm/lpc/tpm.c new file mode 100644 index 0000000..1a87dc9 --- /dev/null +++ b/src/drivers/tpm/lpc/tpm.c @@ -0,0 +1,778 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2011 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +/* + * The code in this file has been heavily based on the article "Writing a TPM + * Device Driver" published on http://ptgmedia.pearsoncmg.com and the + * submission by Stefan Berger on Qemu-devel mailing list. + * + * One principal difference is that in the simplest config the other than 0 + * TPM localities do not get mapped by some devices (for instance, by + * Infineon slb9635), so this driver provides access to locality 0 only. + */ + +#include <stdlib.h> +#include <string.h> +#include <delay.h> +#include <arch/io.h> +#include <console/console.h> +#include <tpm/tpm.h> +#include <arch/early_variables.h> +#include <device/pnp.h> +#include "chip.h" + +#define PREFIX "lpc_tpm: " + +/* coreboot wrapper for TPM driver (start) */ +#define TPM_DEBUG(fmt, args...) \ + if (CONFIG_DEBUG_TPM) { \ + printk(BIOS_DEBUG, PREFIX); \ + printk(BIOS_DEBUG, fmt , ##args); \ + } +#define TPM_DEBUG_IO_READ(reg_, val_) \ + TPM_DEBUG("Read reg 0x%x returns 0x%x\n", (reg_), (val_)) +#define TPM_DEBUG_IO_WRITE(reg_, val_) \ + TPM_DEBUG("Write reg 0x%x with 0x%x\n", (reg_), (val_)) +#define printf(x...) printk(BIOS_ERR, x) + +/* coreboot wrapper for TPM driver (end) */ + +#ifndef CONFIG_TPM_TIS_BASE_ADDRESS +/* Base TPM address standard for x86 systems */ +#define CONFIG_TPM_TIS_BASE_ADDRESS 0xfed40000 +#endif + +/* the macro accepts the locality value, but only locality 0 is operational */ +#define TIS_REG(LOCALITY, REG) \ + (void *)(CONFIG_TPM_TIS_BASE_ADDRESS + (LOCALITY << 12) + REG) + +/* hardware registers' offsets */ +#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_BURST_COUNT 0x19 +#define TIS_REG_DATA_FIFO 0x24 +#define TIS_REG_DID_VID 0xf00 +#define TIS_REG_RID 0xf04 + +/* Some registers' bit field definitions */ +#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 */ + +/* + * Error value returned if a tpm register does not enter the expected state + * after continuous polling. No actual TPM register reading ever returns ~0, + * so this value is a safe error indication to be mixed with possible status + * register values. + */ +#define TPM_TIMEOUT_ERR (~0) + +/* Error value returned on various TPM driver errors */ +#define TPM_DRIVER_ERR (~0) + + /* 1 second is plenty for anything TPM does.*/ +#define MAX_DELAY_US (1000 * 1000) + +/* + * Structures defined below allow creating descriptions of TPM vendor/device + * ID information for run time discovery. The only device the system knows + * about at this time is Infineon slb9635 + */ +struct device_name { + u16 dev_id; + const char * const dev_name; +}; + +struct vendor_name { + u16 vendor_id; + const char * vendor_name; + const struct device_name* dev_names; +}; + +static const struct device_name atmel_devices[] = { + {0x3204, "AT97SC3204"}, + {0xffff} +}; + +static const struct device_name infineon_devices[] = { + {0x000b, "SLB9635 TT 1.2"}, + {0x001a, "SLB9660 TT 1.2"}, + {0x001b, "SLB9670 TT 1.2"}, + {0xffff} +}; + +static const struct device_name nuvoton_devices[] = { + {0x00fe, "NPCT420AA V2"}, + {0xffff} +}; + +static const struct device_name stmicro_devices[] = { + {0x0000, "ST33ZP24" }, + {0xffff} +}; + +static const struct vendor_name vendor_names[] = { + {0x1114, "Atmel", atmel_devices}, + {0x15d1, "Infineon", infineon_devices}, + {0x1050, "Nuvoton", nuvoton_devices}, + {0x104a, "ST Microelectronics", stmicro_devices}, +}; + +/* + * Cached vendor/device ID pair to indicate that the device has been already + * discovered + */ +static u32 vendor_dev_id CAR_GLOBAL; + +static inline u8 tpm_read_status(int locality) +{ + u8 value = read8(TIS_REG(locality, TIS_REG_STS)); + TPM_DEBUG_IO_READ(TIS_REG_STS, value); + return value; +} + +static inline void tpm_write_status(u8 sts, int locality) +{ + TPM_DEBUG_IO_WRITE(TIS_REG_STS, sts); + write8(TIS_REG(locality, TIS_REG_STS), sts); +} + +static inline u8 tpm_read_data(int locality) +{ + u8 value = read8(TIS_REG(locality, TIS_REG_DATA_FIFO)); + TPM_DEBUG_IO_READ(TIS_REG_DATA_FIFO, value); + return value; +} + +static inline void tpm_write_data(u8 data, int locality) +{ + TPM_DEBUG_IO_WRITE(TIS_REG_STS, data); + write8(TIS_REG(locality, TIS_REG_DATA_FIFO), data); +} + +static inline u16 tpm_read_burst_count(int locality) +{ + u16 count; + count = read8(TIS_REG(locality, TIS_REG_BURST_COUNT)); + count |= read8(TIS_REG(locality, TIS_REG_BURST_COUNT + 1)) << 8; + TPM_DEBUG_IO_READ(TIS_REG_BURST_COUNT, count); + return count; +} + +static inline u8 tpm_read_access(int locality) +{ + u8 value = read8(TIS_REG(locality, TIS_REG_ACCESS)); + TPM_DEBUG_IO_READ(TIS_REG_ACCESS, value); + return value; +} + +static inline void tpm_write_access(u8 data, int locality) +{ + TPM_DEBUG_IO_WRITE(TIS_REG_ACCESS, data); + write8(TIS_REG(locality, TIS_REG_ACCESS), data); +} + +static inline u32 tpm_read_did_vid(int locality) +{ + u32 value = read32(TIS_REG(locality, TIS_REG_DID_VID)); + TPM_DEBUG_IO_READ(TIS_REG_DID_VID, value); + return value; +} + +static inline void tpm_write_int_vector(int vector, int locality) +{ + TPM_DEBUG_IO_WRITE(TIS_REG_INT_VECTOR, vector); + write8(TIS_REG(locality, TIS_REG_INT_VECTOR), vector & 0xf); +} + +static inline void tpm_write_int_polarity(int polarity, int locality) +{ + /* Set polarity and leave all other bits at 0 */ + u32 value = (polarity & 0x3) << 3; + TPM_DEBUG_IO_WRITE(TIS_REG_INT_ENABLE, value); + write32(TIS_REG(locality, TIS_REG_INT_ENABLE), value); +} + +/* + * tis_wait_sts() + * + * Wait for at least a second for a status to change its state to match the + * expected state. Normally the transition happens within microseconds. + * + * @locality - locality + * @mask - bitmask for the bitfield(s) to watch + * @expected - value the field(s) are supposed to be set to + * + * Returns 0 on success or TPM_TIMEOUT_ERR on timeout. + */ +static int tis_wait_sts(int locality, u8 mask, u8 expected) +{ + u32 time_us = MAX_DELAY_US; + while (time_us > 0) { + u8 value = tpm_read_status(locality); + if ((value & mask) == expected) + return 0; + udelay(1); /* 1 us */ + time_us--; + } + return TPM_TIMEOUT_ERR; +} + +static inline int tis_wait_ready(int locality) +{ + return tis_wait_sts(locality, TIS_STS_COMMAND_READY, + TIS_STS_COMMAND_READY); +} + +static inline int tis_wait_valid(int locality) +{ + return tis_wait_sts(locality, TIS_STS_VALID, TIS_STS_VALID); +} + +static inline int tis_wait_valid_data(int locality) +{ + const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; + return tis_wait_sts(locality, has_data, has_data); +} + +static inline int tis_has_valid_data(int locality) +{ + const u8 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID; + return (tpm_read_status(locality) & has_data) == has_data; +} + +static inline int tis_expect_data(int locality) +{ + return !!(tpm_read_status(locality) & TIS_STS_EXPECT); +} + +/* + * tis_wait_access() + * + * Wait for at least a second for a access to change its state to match the + * expected state. Normally the transition happens within microseconds. + * + * @locality - locality + * @mask - bitmask for the bitfield(s) to watch + * @expected - value the field(s) are supposed to be set to + * + * Returns 0 on success or TPM_TIMEOUT_ERR on timeout. + */ +static int tis_wait_access(int locality, u8 mask, u8 expected) +{ + u32 time_us = MAX_DELAY_US; + while (time_us > 0) { + u8 value = tpm_read_access(locality); + if ((value & mask) == expected) + return 0; + udelay(1); /* 1 us */ + time_us--; + } + return TPM_TIMEOUT_ERR; +} + +static inline int tis_wait_dropped_access(int locality) +{ + return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, 0); +} + +static inline int tis_wait_received_access(int locality) +{ + return tis_wait_access(locality, TIS_ACCESS_ACTIVE_LOCALITY, + TIS_ACCESS_ACTIVE_LOCALITY); +} + +static inline int tis_has_access(int locality) +{ + return !!(tpm_read_access(locality) & TIS_ACCESS_ACTIVE_LOCALITY); +} + +static inline void tis_request_access(int locality) +{ + tpm_write_access(TIS_ACCESS_REQUEST_USE, locality); +} + +static inline void tis_drop_access(int locality) +{ + tpm_write_access(TIS_ACCESS_ACTIVE_LOCALITY, locality); +} + +/* + * PC Client Specific TPM Interface Specification section 11.2.12: + * + * Software must be prepared to send two writes of a "1" to command ready + * field: the first to indicate successful read of all the data, thus + * clearing the data from the ReadFIFO and freeing the TPM's resources, + * and the second to indicate to the TPM it is about to send a new command. + * + * In practice not all TPMs behave the same so it is necessary to be + * flexible when trying to set command ready. + * + * Returns 0 on success if the TPM is ready for transactions. + * Returns TPM_TIMEOUT_ERR if the command ready bit does not get set. + */ +static int tis_command_ready(u8 locality) +{ + u32 status; + + /* 1st attempt to set command ready */ + tpm_write_status(TIS_STS_COMMAND_READY, locality); + + /* Wait for response */ + status = tpm_read_status(locality); + + /* Check if command ready is set yet */ + if (status & TIS_STS_COMMAND_READY) + return 0; + + /* 2nd attempt to set command ready */ + tpm_write_status(TIS_STS_COMMAND_READY, locality); + + return tis_wait_ready(locality); +} + +/* + * Probe the TPM device and try determining its manufacturer/device name. + * + * Returns 0 on success (the device is found or was found during an earlier + * invocation) or TPM_DRIVER_ERR if the device is not found. + */ +static u32 tis_probe(void) +{ + const char *device_name = "unknown"; + const char *vendor_name = device_name; + const struct device_name *dev; + u32 didvid; + u16 vid, did; + int i; + + if (car_get_var(vendor_dev_id)) + return 0; /* Already probed. */ + + didvid = tpm_read_did_vid(0); + if (!didvid || (didvid == 0xffffffff)) { + printf("%s: No TPM device found\n", __FUNCTION__); + return TPM_DRIVER_ERR; + } + + car_set_var(vendor_dev_id, didvid); + + vid = didvid & 0xffff; + did = (didvid >> 16) & 0xffff; + for (i = 0; i < ARRAY_SIZE(vendor_names); i++) { + int j = 0; + u16 known_did; + if (vid == vendor_names[i].vendor_id) { + vendor_name = vendor_names[i].vendor_name; + } else { + continue; + } + dev = &vendor_names[i].dev_names[j]; + while ((known_did = dev->dev_id) != 0xffff) { + if (known_did == did) { + device_name = dev->dev_name; + break; + } + j++; + dev = &vendor_names[i].dev_names[j]; + } + break; + } + /* this will have to be converted into debug printout */ + printf("Found TPM %s by %s\n", device_name, vendor_name); + return 0; +} + +/* + * tis_senddata() + * + * send the passed in data to the TPM device. + * + * @data - address of the data to send, byte by byte + * @len - length of the data to send + * + * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does + * not accept the entire command). + */ +static u32 tis_senddata(const u8 * const data, u32 len) +{ + u32 offset = 0; + u16 burst = 0; + u32 max_cycles = 0; + u8 locality = 0; + + if (tis_wait_ready(locality)) { + printf("%s:%d - failed to get 'command_ready' status\n", + __FILE__, __LINE__); + return TPM_DRIVER_ERR; + } + burst = tpm_read_burst_count(locality); + + while (1) { + unsigned count; + + /* Wait till the device is ready to accept more data. */ + while (!burst) { + if (max_cycles++ == MAX_DELAY_US) { + printf("%s:%d failed to feed %d bytes of %d\n", + __FILE__, __LINE__, len - offset, len); + return TPM_DRIVER_ERR; + } + udelay(1); + burst = tpm_read_burst_count(locality); + } + + max_cycles = 0; + + /* + * Calculate number of bytes the TPM is ready to accept in one + * shot. + * + * We want to send the last byte outside of the loop (hence + * the -1 below) to make sure that the 'expected' status bit + * changes to zero exactly after the last byte is fed into the + * FIFO. + */ + count = min(burst, len - offset - 1); + while (count--) + tpm_write_data(data[offset++], locality); + + if (tis_wait_valid(locality) || !tis_expect_data(locality)) { + printf("%s:%d TPM command feed overflow\n", + __FILE__, __LINE__); + return TPM_DRIVER_ERR; + } + + burst = tpm_read_burst_count(locality); + if ((offset == (len - 1)) && burst) + /* + * We need to be able to send the last byte to the + * device, so burst size must be nonzero before we + * break out. + */ + break; + } + + /* Send the last byte. */ + tpm_write_data(data[offset++], locality); + + /* + * Verify that TPM does not expect any more data as part of this + * command. + */ + if (tis_wait_valid(locality) || tis_expect_data(locality)) { + printf("%s:%d unexpected TPM status 0x%x\n", + __FILE__, __LINE__, tpm_read_status(locality)); + return TPM_DRIVER_ERR; + } + + /* OK, sitting pretty, let's start the command execution. */ + tpm_write_status(TIS_STS_TPM_GO, locality); + + return 0; +} + +/* + * tis_readresponse() + * + * read the TPM device response after a command was issued. + * + * @buffer - address where to read the response, byte by byte. + * @len - pointer to the size of buffer + * + * On success stores the number of received bytes to len and returns 0. On + * errors (misformatted TPM data or synchronization problems) returns + * TPM_DRIVER_ERR. + */ +static u32 tis_readresponse(u8 *buffer, size_t *len) +{ + u16 burst_count; + u32 offset = 0; + u8 locality = 0; + u32 expected_count = *len; + int max_cycles = 0; + + /* Wait for the TPM to process the command */ + if (tis_wait_valid_data(locality)) { + printf("%s:%d failed processing command\n", __FILE__, __LINE__); + return TPM_DRIVER_ERR; + } + + do { + while ((burst_count = tpm_read_burst_count(locality)) == 0) { + if (max_cycles++ == MAX_DELAY_US) { + printf("%s:%d TPM stuck on read\n", + __FILE__, __LINE__); + return TPM_DRIVER_ERR; + } + udelay(1); + } + + max_cycles = 0; + + while (burst_count-- && (offset < expected_count)) { + buffer[offset++] = tpm_read_data(locality); + if (offset == 6) { + /* + * We got the first six bytes of the reply, + * let's figure out how many bytes to expect + * total - it is stored as a 4 byte number in + * network order, starting with offset 2 into + * the body of the reply. + */ + u32 real_length; + memcpy(&real_length, + buffer + 2, + sizeof(real_length)); + expected_count = be32_to_cpu(real_length); + + if ((expected_count < offset) || + (expected_count > *len)) { + printf("%s:%d bad response size %d\n", + __FILE__, __LINE__, + expected_count); + return TPM_DRIVER_ERR; + } + } + } + + /* Wait for the next portion */ + if (tis_wait_valid(locality)) { + printf("%s:%d failed to read response\n", + __FILE__, __LINE__); + return TPM_DRIVER_ERR; + } + + if (offset == expected_count) + break; /* We got all we need */ + + } while (tis_has_valid_data(locality)); + + /* * Make sure we indeed read all there was. */ + if (tis_has_valid_data(locality)) { + printf("%s:%d wrong receive status: %x %d bytes left\n", + __FILE__, __LINE__, tpm_read_status(locality), + tpm_read_burst_count(locality)); + return TPM_DRIVER_ERR; + } + + /* Tell the TPM that we are done. */ + if (tis_command_ready(locality) == TPM_TIMEOUT_ERR) + return TPM_DRIVER_ERR; + + *len = offset; + return 0; +} + +/* + * tis_init() + * + * Initialize the TPM device. Returns 0 on success or TPM_DRIVER_ERR on + * failure (in case device probing did not succeed). + */ +int tis_init(void) +{ + if (tis_probe()) + return TPM_DRIVER_ERR; + return 0; +} + +/* + * tis_open() + * + * Requests access to locality 0 for the caller. After all commands have been + * completed the caller is supposed to call tis_close(). + * + * Returns 0 on success, TPM_DRIVER_ERR on failure. + */ +int tis_open(void) +{ + u8 locality = 0; /* we use locality zero for everything */ + + if (tis_close()) + return TPM_DRIVER_ERR; + + /* now request access to locality */ + tis_request_access(locality); + + /* did we get a lock? */ + if (tis_wait_received_access(locality)) { + printf("%s:%d - failed to lock locality %d\n", + __FILE__, __LINE__, locality); + return TPM_DRIVER_ERR; + } + + /* Certain TPMs seem to need some delay here or they hang... */ + udelay(10); + + if (tis_command_ready(locality) == TPM_TIMEOUT_ERR) + return TPM_DRIVER_ERR; + + return 0; +} + +/* + * tis_close() + * + * terminate the current session with the TPM by releasing the locked + * locality. Returns 0 on success of TPM_DRIVER_ERR on failure (in case lock + * removal did not succeed). + */ +int tis_close(void) +{ + u8 locality = 0; + if (tis_has_access(locality)) { + tis_drop_access(locality); + if (tis_wait_dropped_access(locality)) { + printf("%s:%d - failed to release locality %d\n", + __FILE__, __LINE__, locality); + return TPM_DRIVER_ERR; + } + } + return 0; +} + +/* + * tis_sendrecv() + * + * Send the requested data to the TPM and then try to get its response + * + * @sendbuf - buffer of the data to send + * @send_size size of the data to send + * @recvbuf - memory to save the response to + * @recv_len - pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at recv_len) + * or TPM_DRIVER_ERR on failure. + */ +int tis_sendrecv(const uint8_t *sendbuf, size_t send_size, + uint8_t *recvbuf, size_t *recv_len) +{ + if (tis_senddata(sendbuf, send_size)) { + printf("%s:%d failed sending data to TPM\n", + __FILE__, __LINE__); + return TPM_DRIVER_ERR; + } + + return tis_readresponse(recvbuf, recv_len); +} + +#ifdef __RAMSTAGE__ + +/* + * tis_setup_interrupt() + * + * Set up the interrupt vector and polarity for locality 0 and + * disable all interrupts so they are unused in firmware but can + * be enabled by the OS. + * + * The values used here must match what is passed in the TPM ACPI + * device if ACPI is used on the platform. + * + * @vector - TPM interrupt vector + * @polarity - TPM interrupt polarity + * + * Returns 0 on success, TPM_DRIVER_ERR on failure. + */ +static int tis_setup_interrupt(int vector, int polarity) +{ + u8 locality = 0; + int has_access = tis_has_access(locality); + + /* Open connection and request access if not already granted */ + if (!has_access && tis_open() < 0) + return TPM_DRIVER_ERR; + + /* Set TPM interrupt vector */ + tpm_write_int_vector(vector, locality); + + /* Set TPM interupt polarity and disable interrupts */ + tpm_write_int_polarity(polarity, locality); + + /* Close connection if it was opened */ + if (!has_access && tis_close() < 0) + return TPM_DRIVER_ERR; + + return 0; +} + +static void lpc_tpm_read_resources(struct device *dev) +{ + /* Static 5K memory region specified in Kconfig */ + mmio_resource(dev, 0, CONFIG_TPM_TIS_BASE_ADDRESS >> 10, 0x5000 >> 10); +} + +static void lpc_tpm_set_resources(struct device *dev) +{ + tpm_config_t *config = (tpm_config_t *)dev->chip_info; + struct resource *res; + + for (res = dev->resource_list; res; res = res->next) { + if (!(res->flags & IORESOURCE_ASSIGNED)) + continue; + + if (res->flags & IORESOURCE_IRQ) { + /* Set interrupt vector */ + tis_setup_interrupt((int)res->base, + config->irq_polarity); + } else { + continue; + } + + res->flags |= IORESOURCE_STORED; + report_resource_stored(dev, res, " <tpm>"); + } +} + +static struct device_operations lpc_tpm_ops = { + .read_resources = &lpc_tpm_read_resources, + .set_resources = &lpc_tpm_set_resources, +}; + +static struct pnp_info pnp_dev_info[] = { + { .flags = PNP_IRQ0 } +}; + +static void enable_dev(struct device *dev) +{ + pnp_enable_devices(dev, &lpc_tpm_ops, + ARRAY_SIZE(pnp_dev_info), pnp_dev_info); +} + +struct chip_operations drivers_tpm_ops = { + CHIP_NAME("LPC TPM") + .enable_dev = enable_dev +}; + +#endif /* __RAMSTAGE__ */ diff --git a/src/include/antirollback.h b/src/include/antirollback.h index 5ba36f7..9d3c3fd 100644 --- a/src/include/antirollback.h +++ b/src/include/antirollback.h @@ -9,7 +9,7 @@ #ifndef ANTIROLLBACK_H_ #define ANTIROLLBACK_H_
-#include "tpm_lite/tss_constants.h" +#include <tpm/tss_constants.h>
struct vb2_context; enum vb2_pcr_digest; diff --git a/src/include/tpm.h b/src/include/tpm.h deleted file mode 100644 index 9b4db4a..0000000 --- a/src/include/tpm.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright 2011 Google Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#ifndef TPM_H_ -#define TPM_H_ - -#include <stddef.h> -#include <stdint.h> - -/* - * tis_init() - * - * Initialize the TPM device. Returns 0 on success or -1 on - * failure (in case device probing did not succeed). - */ -int tis_init(void); - -/* - * tis_open() - * - * Requests access to locality 0 for the caller. After all commands have been - * completed the caller is supposed to call tis_close(). - * - * Returns 0 on success, -1 on failure. - */ -int tis_open(void); - -/* - * tis_close() - * - * terminate the currect session with the TPM by releasing the locked - * locality. Returns 0 on success of -1 on failure (in case lock - * removal did not succeed). - */ -int tis_close(void); - -/* - * tis_sendrecv() - * - * Send the requested data to the TPM and then try to get its response - * - * @sendbuf - buffer of the data to send - * @send_size size of the data to send - * @recvbuf - memory to save the response to - * @recv_len - pointer to the size of the response buffer - * - * Returns 0 on success (and places the number of response bytes at recv_len) - * or -1 on failure. - */ -int tis_sendrecv(const u8 *sendbuf, size_t send_size, u8 *recvbuf, - size_t *recv_len); - -void init_tpm(int s3resume); - -#endif /* TPM_H_ */ diff --git a/src/include/tpm/tpm.h b/src/include/tpm/tpm.h new file mode 100644 index 0000000..4f05797 --- /dev/null +++ b/src/include/tpm/tpm.h @@ -0,0 +1,75 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2011 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#ifndef TPM_TPM_H +#define TPM_TPM_H + +#include <stddef.h> +#include <stdint.h> + +struct tpm_chip; + +/* + * tis_init() + * + * Initialize the TPM device. Returns 0 on success or -1 on + * failure (in case device probing did not succeed). + */ +int tis_init(void); + +/* + * tis_open() + * + * Requests access to locality 0 for the caller. After all commands have been + * completed the caller is supposed to call tis_close(). + * + * Returns 0 on success, -1 on failure. + */ +int tis_open(void); + +/* + * tis_close() + * + * terminate the currect session with the TPM by releasing the locked + * locality. Returns 0 on success of -1 on failure (in case lock + * removal did not succeed). + */ +int tis_close(void); + +/* + * tis_sendrecv() + * + * Send the requested data to the TPM and then try to get its response + * + * @sendbuf - buffer of the data to send + * @send_size size of the data to send + * @recvbuf - memory to save the response to + * @recv_len - pointer to the size of the response buffer + * + * Returns 0 on success (and places the number of response bytes at recv_len) + * or -1 on failure. + */ +int tis_sendrecv(const u8 *sendbuf, size_t send_size, u8 *recvbuf, + size_t *recv_len); + +int tpm_vendor_init(unsigned bus, uint32_t dev_addr); + +void tpm_vendor_cleanup(struct tpm_chip *chip); + +#endif /* PC80_TPM_H */ diff --git a/src/include/tpm/tspi.h b/src/include/tpm/tspi.h new file mode 100644 index 0000000..8e1b5f0 --- /dev/null +++ b/src/include/tpm/tspi.h @@ -0,0 +1,29 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#ifndef TPM_TSPI_H +#define TPM_TSPI_H + +/** + * TSPI Implementation for coreboot without vboot2 + */ +void init_tpm(int s3resume); + + +#endif /* TPM_TSPI_H */ \ No newline at end of file diff --git a/src/include/tpm/tss.h b/src/include/tpm/tss.h new file mode 100644 index 0000000..c6c4b1a --- /dev/null +++ b/src/include/tpm/tss.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * TPM Lightweight Command Library. + * + * A low-level library for interfacing to TPM hardware or an emulator. + */ + +#ifndef TPM_TSS_H +#define TPM_TSS_H + +#include "tss_constants.h" + +/*****************************************************************************/ +/* Functions implemented in tlcl.c */ + +/** + * Call this first. Returns 0 if success, nonzero if error. + */ +uint32_t tlcl_lib_init(void); + +/** + * Perform a raw TPM request/response transaction. + */ +uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response, + int max_length); + +/* Commands */ + +/** + * Send a TPM_Startup(ST_CLEAR). The TPM error code is returned (0 for + * success). + */ +uint32_t tlcl_startup(void); + +/** + * Resume by sending a TPM_Startup(ST_STATE). The TPM error code is returned + * (0 for success). + */ +uint32_t tlcl_resume(void); + +/** + * Run the self test. + * + * Note---this is synchronous. To run this in parallel with other firmware, + * use ContinueSelfTest(). The TPM error code is returned. + */ +uint32_t tlcl_self_test_full(void); + +/** + * Run the self test in the background. + */ +uint32_t tlcl_continue_self_test(void); + +/** + * Define a space with permission [perm]. [index] is the index for the space, + * [size] the usable data size. The TPM error code is returned. + */ +uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size); + +/** + * Write [length] bytes of [data] to space at [index]. The TPM error code is + * returned. + */ +uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length); + +/** + * Read [length] bytes from space at [index] into [data]. The TPM error code + * is returned. + */ +uint32_t tlcl_read(uint32_t index, void *data, uint32_t length); + +/** + * Assert physical presence in software. The TPM error code is returned. + */ +uint32_t tlcl_assert_physical_presence(void); + +/** + * Enable the physical presence command. The TPM error code is returned. + */ +uint32_t tlcl_physical_presence_cmd_enable(void); + +/** + * Finalize the physical presence settings: sofware PP is enabled, hardware PP + * is disabled, and the lifetime lock is set. The TPM error code is returned. + */ +uint32_t tlcl_finalize_physical_presence(void); + +/** + * Set the nvLocked bit. The TPM error code is returned. + */ +uint32_t tlcl_set_nv_locked(void); + +/** + * Issue a ForceClear. The TPM error code is returned. + */ +uint32_t tlcl_force_clear(void); + +/** + * Issue a PhysicalEnable. The TPM error code is returned. + */ +uint32_t tlcl_set_enable(void); + +/** + * Issue a SetDeactivated. Pass 0 to activate. Returns result code. + */ +uint32_t tlcl_set_deactivated(uint8_t flag); + +/** + * Get flags of interest. Pointers for flags you aren't interested in may + * be NULL. The TPM error code is returned. + */ +uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated, + uint8_t *nvlocked); + +/** + * Set the bGlobalLock flag, which only a reboot can clear. The TPM error + * code is returned. + */ +uint32_t tlcl_set_global_lock(void); + +/** + * Perform a TPM_Extend. + */ +uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, + uint8_t *out_digest); + +/** + * Get the entire set of permanent flags. + */ +uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags); + +#endif \ No newline at end of file diff --git a/src/include/tpm/tss_constants.h b/src/include/tpm/tss_constants.h new file mode 100644 index 0000000..9cfbe2d --- /dev/null +++ b/src/include/tpm/tss_constants.h @@ -0,0 +1,98 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Some TPM constants and type definitions for standalone compilation for use + * in the firmware + */ + +#ifndef TPM_TSS_CONSTANTS_H +#define TPM_TSS_CONSTANTS_H + +#include <stdint.h> + +#define TPM_MAX_COMMAND_SIZE 4096 +#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */ +#define TPM_PUBEK_SIZE 256 +#define TPM_PCR_DIGEST 20 + +#define TPM_E_NON_FATAL 0x800 + +#define TPM_SUCCESS ((uint32_t)0x00000000) + +#define TPM_E_AREA_LOCKED ((uint32_t)0x0000003c) +#define TPM_E_BADINDEX ((uint32_t)0x00000002) +#define TPM_E_BAD_PRESENCE ((uint32_t)0x0000002d) +#define TPM_E_IOERROR ((uint32_t)0x0000001f) +#define TPM_E_INVALID_POSTINIT ((uint32_t)0x00000026) +#define TPM_E_MAXNVWRITES ((uint32_t)0x00000048) +#define TPM_E_OWNER_SET ((uint32_t)0x00000014) + +#define TPM_E_NEEDS_SELFTEST ((uint32_t)(TPM_E_NON_FATAL + 1)) +#define TPM_E_DOING_SELFTEST ((uint32_t)(TPM_E_NON_FATAL + 2)) + +#define TPM_E_ALREADY_INITIALIZED ((uint32_t)0x00005000) /* vboot local */ +#define TPM_E_INTERNAL_INCONSISTENCY ((uint32_t)0x00005001) /* vboot local */ +#define TPM_E_MUST_REBOOT ((uint32_t)0x00005002) /* vboot local */ +#define TPM_E_CORRUPTED_STATE ((uint32_t)0x00005003) /* vboot local */ +#define TPM_E_COMMUNICATION_ERROR ((uint32_t)0x00005004) /* vboot local */ +#define TPM_E_RESPONSE_TOO_LARGE ((uint32_t)0x00005005) /* vboot local */ +#define TPM_E_NO_DEVICE ((uint32_t)0x00005006) /* vboot local */ +#define TPM_E_INPUT_TOO_SMALL ((uint32_t)0x00005007) /* vboot local */ +#define TPM_E_WRITE_FAILURE ((uint32_t)0x00005008) /* vboot local */ +#define TPM_E_READ_EMPTY ((uint32_t)0x00005009) /* vboot local */ +#define TPM_E_READ_FAILURE ((uint32_t)0x0000500a) /* vboot local */ + +#define TPM_NV_INDEX0 ((uint32_t)0x00000000) +#define TPM_NV_INDEX_LOCK ((uint32_t)0xffffffff) +#define TPM_NV_PER_GLOBALLOCK (((uint32_t)1)<<15) +#define TPM_NV_PER_PPWRITE (((uint32_t)1)<<0) +#define TPM_NV_PER_READ_STCLEAR (((uint32_t)1)<<31) +#define TPM_NV_PER_WRITE_STCLEAR (((uint32_t)1)<<14) + +#define TPM_TAG_RQU_COMMAND ((uint16_t) 0xc1) +#define TPM_TAG_RQU_AUTH1_COMMAND ((uint16_t) 0xc2) +#define TPM_TAG_RQU_AUTH2_COMMAND ((uint16_t) 0xc3) + +#define TPM_TAG_RSP_COMMAND ((uint16_t) 0xc4) +#define TPM_TAG_RSP_AUTH1_COMMAND ((uint16_t) 0xc5) +#define TPM_TAG_RSP_AUTH2_COMMAND ((uint16_t) 0xc6) + +typedef uint8_t TSS_BOOL; +typedef uint16_t TPM_STRUCTURE_TAG; + +typedef struct tdTPM_PERMANENT_FLAGS +{ + TPM_STRUCTURE_TAG tag; + TSS_BOOL disable; + TSS_BOOL ownership; + TSS_BOOL deactivated; + TSS_BOOL readPubek; + TSS_BOOL disableOwnerClear; + TSS_BOOL allowMaintenance; + TSS_BOOL physicalPresenceLifetimeLock; + TSS_BOOL physicalPresenceHWEnable; + TSS_BOOL physicalPresenceCMDEnable; + TSS_BOOL CEKPUsed; + TSS_BOOL TPMpost; + TSS_BOOL TPMpostLock; + TSS_BOOL FIPS; + TSS_BOOL Operator; + TSS_BOOL enableRevokeEK; + TSS_BOOL nvLocked; + TSS_BOOL readSRKPub; + TSS_BOOL tpmEstablished; + TSS_BOOL maintenanceDone; + TSS_BOOL disableFullDALogicInfo; +} TPM_PERMANENT_FLAGS; + +typedef struct tdTPM_STCLEAR_FLAGS{ + TPM_STRUCTURE_TAG tag; + TSS_BOOL deactivated; + TSS_BOOL disableForceClear; + TSS_BOOL physicalPresence; + TSS_BOOL physicalPresenceLock; + TSS_BOOL bGlobalLock; +} TPM_STCLEAR_FLAGS; + +#endif /* TPM_TSS_CONSTANTS_H */ \ No newline at end of file diff --git a/src/include/tpm_lite/tlcl.h b/src/include/tpm_lite/tlcl.h deleted file mode 100644 index 7724592..0000000 --- a/src/include/tpm_lite/tlcl.h +++ /dev/null @@ -1,137 +0,0 @@ -/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * TPM Lightweight Command Library. - * - * A low-level library for interfacing to TPM hardware or an emulator. - */ - -#ifndef TPM_LITE_TLCL_H_ -#define TPM_LITE_TLCL_H_ -#include <stdint.h> - -#include "tss_constants.h" - -/*****************************************************************************/ -/* Functions implemented in tlcl.c */ - -/** - * Call this first. Returns 0 if success, nonzero if error. - */ -uint32_t tlcl_lib_init(void); - -/** - * Perform a raw TPM request/response transaction. - */ -uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response, - int max_length); - -/* Commands */ - -/** - * Send a TPM_Startup(ST_CLEAR). The TPM error code is returned (0 for - * success). - */ -uint32_t tlcl_startup(void); - -/** - * Resume by sending a TPM_Startup(ST_STATE). The TPM error code is returned - * (0 for success). - */ -uint32_t tlcl_resume(void); - -/** - * Run the self test. - * - * Note---this is synchronous. To run this in parallel with other firmware, - * use ContinueSelfTest(). The TPM error code is returned. - */ -uint32_t tlcl_self_test_full(void); - -/** - * Run the self test in the background. - */ -uint32_t tlcl_continue_self_test(void); - -/** - * Define a space with permission [perm]. [index] is the index for the space, - * [size] the usable data size. The TPM error code is returned. - */ -uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size); - -/** - * Write [length] bytes of [data] to space at [index]. The TPM error code is - * returned. - */ -uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length); - -/** - * Read [length] bytes from space at [index] into [data]. The TPM error code - * is returned. - */ -uint32_t tlcl_read(uint32_t index, void *data, uint32_t length); - -/** - * Assert physical presence in software. The TPM error code is returned. - */ -uint32_t tlcl_assert_physical_presence(void); - -/** - * Enable the physical presence command. The TPM error code is returned. - */ -uint32_t tlcl_physical_presence_cmd_enable(void); - -/** - * Finalize the physical presence settings: sofware PP is enabled, hardware PP - * is disabled, and the lifetime lock is set. The TPM error code is returned. - */ -uint32_t tlcl_finalize_physical_presence(void); - -/** - * Set the nvLocked bit. The TPM error code is returned. - */ -uint32_t tlcl_set_nv_locked(void); - -/** - * Issue a ForceClear. The TPM error code is returned. - */ -uint32_t tlcl_force_clear(void); - -/** - * Issue a PhysicalEnable. The TPM error code is returned. - */ -uint32_t tlcl_set_enable(void); - -/** - * Issue a SetDeactivated. Pass 0 to activate. Returns result code. - */ -uint32_t tlcl_set_deactivated(uint8_t flag); - -/** - * Get flags of interest. Pointers for flags you aren't interested in may - * be NULL. The TPM error code is returned. - */ -uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated, - uint8_t *nvlocked); - -/** - * Set the bGlobalLock flag, which only a reboot can clear. The TPM error - * code is returned. - */ -uint32_t tlcl_set_global_lock(void); - -/** - * Perform a TPM_Extend. - */ -uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, - uint8_t *out_digest); - -/** - * Get the entire set of permanent flags. - */ -uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags); - -#endif /* TPM_LITE_TLCL_H_ */ diff --git a/src/include/tpm_lite/tss_constants.h b/src/include/tpm_lite/tss_constants.h deleted file mode 100644 index 883a5ad..0000000 --- a/src/include/tpm_lite/tss_constants.h +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Some TPM constants and type definitions for standalone compilation for use - * in the firmware - */ -#ifndef VBOOT_REFERENCE_TSS_CONSTANTS_H_ -#define VBOOT_REFERENCE_TSS_CONSTANTS_H_ -#include <stdint.h> - -#define TPM_MAX_COMMAND_SIZE 4096 -#define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */ -#define TPM_PUBEK_SIZE 256 -#define TPM_PCR_DIGEST 20 - -#define TPM_E_NON_FATAL 0x800 - -#define TPM_SUCCESS ((uint32_t)0x00000000) - -#define TPM_E_AREA_LOCKED ((uint32_t)0x0000003c) -#define TPM_E_BADINDEX ((uint32_t)0x00000002) -#define TPM_E_BAD_PRESENCE ((uint32_t)0x0000002d) -#define TPM_E_IOERROR ((uint32_t)0x0000001f) -#define TPM_E_INVALID_POSTINIT ((uint32_t)0x00000026) -#define TPM_E_MAXNVWRITES ((uint32_t)0x00000048) -#define TPM_E_OWNER_SET ((uint32_t)0x00000014) - -#define TPM_E_NEEDS_SELFTEST ((uint32_t)(TPM_E_NON_FATAL + 1)) -#define TPM_E_DOING_SELFTEST ((uint32_t)(TPM_E_NON_FATAL + 2)) - -#define TPM_E_ALREADY_INITIALIZED ((uint32_t)0x00005000) /* vboot local */ -#define TPM_E_INTERNAL_INCONSISTENCY ((uint32_t)0x00005001) /* vboot local */ -#define TPM_E_MUST_REBOOT ((uint32_t)0x00005002) /* vboot local */ -#define TPM_E_CORRUPTED_STATE ((uint32_t)0x00005003) /* vboot local */ -#define TPM_E_COMMUNICATION_ERROR ((uint32_t)0x00005004) /* vboot local */ -#define TPM_E_RESPONSE_TOO_LARGE ((uint32_t)0x00005005) /* vboot local */ -#define TPM_E_NO_DEVICE ((uint32_t)0x00005006) /* vboot local */ -#define TPM_E_INPUT_TOO_SMALL ((uint32_t)0x00005007) /* vboot local */ -#define TPM_E_WRITE_FAILURE ((uint32_t)0x00005008) /* vboot local */ -#define TPM_E_READ_EMPTY ((uint32_t)0x00005009) /* vboot local */ -#define TPM_E_READ_FAILURE ((uint32_t)0x0000500a) /* vboot local */ - -#define TPM_NV_INDEX0 ((uint32_t)0x00000000) -#define TPM_NV_INDEX_LOCK ((uint32_t)0xffffffff) -#define TPM_NV_PER_GLOBALLOCK (((uint32_t)1)<<15) -#define TPM_NV_PER_PPWRITE (((uint32_t)1)<<0) -#define TPM_NV_PER_READ_STCLEAR (((uint32_t)1)<<31) -#define TPM_NV_PER_WRITE_STCLEAR (((uint32_t)1)<<14) - -#define TPM_TAG_RQU_COMMAND ((uint16_t) 0xc1) -#define TPM_TAG_RQU_AUTH1_COMMAND ((uint16_t) 0xc2) -#define TPM_TAG_RQU_AUTH2_COMMAND ((uint16_t) 0xc3) - -#define TPM_TAG_RSP_COMMAND ((uint16_t) 0xc4) -#define TPM_TAG_RSP_AUTH1_COMMAND ((uint16_t) 0xc5) -#define TPM_TAG_RSP_AUTH2_COMMAND ((uint16_t) 0xc6) - -typedef uint8_t TSS_BOOL; -typedef uint16_t TPM_STRUCTURE_TAG; - -typedef struct tdTPM_PERMANENT_FLAGS -{ - TPM_STRUCTURE_TAG tag; - TSS_BOOL disable; - TSS_BOOL ownership; - TSS_BOOL deactivated; - TSS_BOOL readPubek; - TSS_BOOL disableOwnerClear; - TSS_BOOL allowMaintenance; - TSS_BOOL physicalPresenceLifetimeLock; - TSS_BOOL physicalPresenceHWEnable; - TSS_BOOL physicalPresenceCMDEnable; - TSS_BOOL CEKPUsed; - TSS_BOOL TPMpost; - TSS_BOOL TPMpostLock; - TSS_BOOL FIPS; - TSS_BOOL Operator; - TSS_BOOL enableRevokeEK; - TSS_BOOL nvLocked; - TSS_BOOL readSRKPub; - TSS_BOOL tpmEstablished; - TSS_BOOL maintenanceDone; - TSS_BOOL disableFullDALogicInfo; -} TPM_PERMANENT_FLAGS; - -typedef struct tdTPM_STCLEAR_FLAGS{ - TPM_STRUCTURE_TAG tag; - TSS_BOOL deactivated; - TSS_BOOL disableForceClear; - TSS_BOOL physicalPresence; - TSS_BOOL physicalPresenceLock; - TSS_BOOL bGlobalLock; -} TPM_STCLEAR_FLAGS; - -#endif /* VBOOT_REFERENCE_TSS_CONSTANTS_H_ */ diff --git a/src/lib/Makefile.inc b/src/lib/Makefile.inc index 8597667..140421e 100644 --- a/src/lib/Makefile.inc +++ b/src/lib/Makefile.inc @@ -16,7 +16,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc. # -subdirs-y += loaders +subdirs-y += loaders tpm
bootblock-y += assets.c bootblock-y += prog_loaders.c @@ -54,12 +54,6 @@ verstage-y += boot_device.c verstage-$(CONFIG_CONSOLE_CBMEM) += cbmem_console.c verstage-$(CONFIG_COMMON_CBFS_SPI_WRAPPER) += cbfs_spi.c
-ifeq ($(MOCK_TPM),1) -libverstage-y += mocked_tlcl.c -else -libverstage-y += tlcl.c -endif - verstage-$(CONFIG_GENERIC_UDELAY) += timer.c verstage-$(CONFIG_GENERIC_GPIO_LIB) += gpio.c verstage-y += mem_pool.c diff --git a/src/lib/mocked_tlcl.c b/src/lib/mocked_tlcl.c deleted file mode 100644 index c5c12bf..0000000 --- a/src/lib/mocked_tlcl.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2015 The ChromiumOS Authors. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc. - */ - -#include <tpm_lite/tlcl.h> - -#ifdef FOR_TEST -#include <stdio.h> -#define VBDEBUG(format, args...) printf(format, ## args) -#else -#include <console/console.h> -#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args) -#endif - -uint32_t tlcl_lib_init(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_startup(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_resume(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_self_test_full(void) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_continue_self_test(void) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_write(uint32_t index, const void* data, uint32_t length) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_read(uint32_t index, void* data, uint32_t length) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - - -uint32_t tlcl_assert_physical_presence(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_physical_presence_cmd_enable(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_finalize_physical_presence(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_set_nv_locked(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_force_clear(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_set_enable(void) { - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_set_deactivated(uint8_t flag) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS* pflags) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_get_flags(uint8_t* disable, uint8_t* deactivated, - uint8_t *nvlocked) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_set_global_lock(void) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} - -uint32_t tlcl_extend(int pcr_num, const uint8_t* in_digest, - uint8_t* out_digest) -{ - VBDEBUG("MOCK_TPM: %s\n", __func__); - return TPM_E_NO_DEVICE; -} diff --git a/src/lib/tlcl.c b/src/lib/tlcl.c deleted file mode 100644 index ccf4e80..0000000 --- a/src/lib/tlcl.c +++ /dev/null @@ -1,327 +0,0 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* A lightweight TPM command library. - * - * The general idea is that TPM commands are array of bytes whose - * fields are mostly compile-time constant. The goal is to build much - * of the commands at compile time (or build time) and change some of - * the fields at run time as needed. The code in - * utility/tlcl_generator.c builds structures containing the commands, - * as well as the offsets of the fields that need to be set at run - * time. - */ - -#include <assert.h> -#include <string.h> -#include <tpm_lite/tlcl.h> -#include <tpm.h> -#include <vb2_api.h> -#include "tlcl_internal.h" -#include "tlcl_structures.h" - -#ifdef FOR_TEST -#include <stdio.h> -#define VBDEBUG(format, args...) printf(format, ## args) -#else -#include <console/console.h> -#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args) -#endif - -static int tpm_send_receive(const uint8_t *request, - uint32_t request_length, - uint8_t *response, - uint32_t *response_length) -{ - size_t len = *response_length; - if (tis_sendrecv(request, request_length, response, &len)) - return VB2_ERROR_UNKNOWN; - /* check 64->32bit overflow and (re)check response buffer overflow */ - if (len > *response_length) - return VB2_ERROR_UNKNOWN; - *response_length = len; - return VB2_SUCCESS; -} - -/* Sets the size field of a TPM command. */ -static inline void set_tpm_command_size(uint8_t* buffer, uint32_t size) { - to_tpm_uint32(buffer + sizeof(uint16_t), size); -} - -/* Gets the size field of a TPM command. */ -__attribute__((unused)) -static inline int tpm_command_size(const uint8_t* buffer) { - uint32_t size; - from_tpm_uint32(buffer + sizeof(uint16_t), &size); - return (int) size; -} - -/* Gets the code field of a TPM command. */ -static inline int tpm_command_code(const uint8_t* buffer) { - uint32_t code; - from_tpm_uint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code); - return code; -} - -/* Gets the return code field of a TPM result. */ -static inline int tpm_return_code(const uint8_t* buffer) { - return tpm_command_code(buffer); -} - -/* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or - * DOING_SELFTEST errors are returned. - */ -static uint32_t tlcl_send_receive_no_retry(const uint8_t* request, - uint8_t* response, int max_length) { - uint32_t response_length = max_length; - uint32_t result; - - result = tpm_send_receive(request, tpm_command_size(request), - response, &response_length); - if (0 != result) { - /* Communication with TPM failed, so response is garbage */ - VBDEBUG("TPM: command 0x%x send/receive failed: 0x%x\n", - tpm_command_code(request), result); - return result; - } - /* Otherwise, use the result code from the response */ - result = tpm_return_code(response); - - /* TODO: add paranoia about returned response_length vs. max_length - * (and possibly expected length from the response header). See - * crosbug.com/17017 */ - - VBDEBUG("TPM: command 0x%x returned 0x%x\n", - tpm_command_code(request), result); - -return result; -} - - -/* Sends a TPM command and gets a response. Returns 0 if success or the TPM - * error code if error. Waits for the self test to complete if needed. */ -uint32_t tlcl_send_receive(const uint8_t* request, uint8_t* response, - int max_length) { - uint32_t result = tlcl_send_receive_no_retry(request, response, - max_length); - /* If the command fails because the self test has not completed, try it - * again after attempting to ensure that the self test has completed. */ - if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) { - result = tlcl_continue_self_test(); - if (result != TPM_SUCCESS) - return result; -#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE) - /* Retry only once */ - result = tlcl_send_receive_no_retry(request, response, - max_length); -#else - /* This needs serious testing. The TPM specification says: "iii. - * The caller MUST wait for the actions of TPM_ContinueSelfTest - * to complete before reissuing the command C1." But, if - * ContinueSelfTest is non-blocking, how do we know that the - * actions have completed other than trying again? */ - do { - result = tlcl_send_receive_no_retry(request, response, - max_length); - } while (result == TPM_E_DOING_SELFTEST); -#endif - } - return result; -} - -/* Sends a command and returns the error code. */ -static uint32_t send(const uint8_t* command) { - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - return tlcl_send_receive(command, response, sizeof(response)); -} - -/* Exported functions. */ - -uint32_t tlcl_lib_init(void) { - if (tis_init()) - return VB2_ERROR_UNKNOWN; - if (tis_open()) - return VB2_ERROR_UNKNOWN; - return VB2_SUCCESS; -} - -uint32_t tlcl_startup(void) { - VBDEBUG("TPM: Startup\n"); - return send(tpm_startup_cmd.buffer); -} - -uint32_t tlcl_resume(void) { - VBDEBUG("TPM: Resume\n"); - return send(tpm_resume_cmd.buffer); -} - -uint32_t tlcl_self_test_full(void) -{ - VBDEBUG("TPM: Self test full\n"); - return send(tpm_selftestfull_cmd.buffer); -} - -uint32_t tlcl_continue_self_test(void) -{ - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - VBDEBUG("TPM: Continue self test\n"); - /* Call the No Retry version of SendReceive to avoid recursion. */ - return tlcl_send_receive_no_retry(tpm_continueselftest_cmd.buffer, - response, sizeof(response)); -} - -uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size) -{ - struct s_tpm_nv_definespace_cmd cmd; - VBDEBUG("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size); - memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd)); - to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.index, index); - to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm); - to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.size, size); - return send(cmd.buffer); -} - -uint32_t tlcl_write(uint32_t index, const void* data, uint32_t length) -{ - struct s_tpm_nv_write_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - const int total_length = - kTpmRequestHeaderLength + kWriteInfoLength + length; - - VBDEBUG("TPM: tlcl_write(0x%x, %d)\n", index, length); - memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd)); - assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE); - set_tpm_command_size(cmd.buffer, total_length); - - to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.index, index); - to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.length, length); - memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length); - - return tlcl_send_receive(cmd.buffer, response, sizeof(response)); -} - -uint32_t tlcl_read(uint32_t index, void* data, uint32_t length) -{ - struct s_tpm_nv_read_cmd cmd; - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t result_length; - uint32_t result; - - VBDEBUG("TPM: tlcl_read(0x%x, %d)\n", index, length); - memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd)); - to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.index, index); - to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.length, length); - - result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); - if (result == TPM_SUCCESS && length > 0) { - uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; - from_tpm_uint32(nv_read_cursor, &result_length); - nv_read_cursor += sizeof(uint32_t); - memcpy(data, nv_read_cursor, result_length); - } - - return result; -} - - -uint32_t tlcl_assert_physical_presence(void) { - VBDEBUG("TPM: Asserting physical presence\n"); - return send(tpm_ppassert_cmd.buffer); -} - -uint32_t tlcl_physical_presence_cmd_enable(void) { - VBDEBUG("TPM: Enable the physical presence command\n"); - return send(tpm_ppenable_cmd.buffer); -} - -uint32_t tlcl_finalize_physical_presence(void) { - VBDEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n"); - return send(tpm_finalizepp_cmd.buffer); -} - -uint32_t tlcl_set_nv_locked(void) { - VBDEBUG("TPM: Set NV locked\n"); - return tlcl_define_space(TPM_NV_INDEX_LOCK, 0, 0); -} - -uint32_t tlcl_force_clear(void) { - VBDEBUG("TPM: Force clear\n"); - return send(tpm_forceclear_cmd.buffer); -} - -uint32_t tlcl_set_enable(void) { - VBDEBUG("TPM: Enabling TPM\n"); - return send(tpm_physicalenable_cmd.buffer); -} - -uint32_t tlcl_set_deactivated(uint8_t flag) -{ - struct s_tpm_physicalsetdeactivated_cmd cmd; - VBDEBUG("TPM: SetDeactivated(%d)\n", flag); - memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd)); - *(cmd.buffer + cmd.deactivated) = flag; - return send(cmd.buffer); -} - -uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS* pflags) -{ - uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; - uint32_t size; - uint32_t result = tlcl_send_receive(tpm_getflags_cmd.buffer, response, - sizeof(response)); - if (result != TPM_SUCCESS) - return result; - from_tpm_uint32(response + kTpmResponseHeaderLength, &size); - assert(size == sizeof(TPM_PERMANENT_FLAGS)); - memcpy(pflags, response + kTpmResponseHeaderLength + sizeof(size), - sizeof(TPM_PERMANENT_FLAGS)); - return result; -} - -uint32_t tlcl_get_flags(uint8_t* disable, uint8_t* deactivated, - uint8_t *nvlocked) -{ - TPM_PERMANENT_FLAGS pflags; - uint32_t result = tlcl_get_permanent_flags(&pflags); - if (result == TPM_SUCCESS) { - if (disable) - *disable = pflags.disable; - if (deactivated) - *deactivated = pflags.deactivated; - if (nvlocked) - *nvlocked = pflags.nvLocked; - VBDEBUG("TPM: flags disable=%d, deactivated=%d, nvlocked=%d\n", - pflags.disable, pflags.deactivated, pflags.nvLocked); - } - return result; -} - -uint32_t tlcl_set_global_lock(void) -{ - uint32_t x; - VBDEBUG("TPM: Set global lock\n"); - return tlcl_write(TPM_NV_INDEX0, (uint8_t*) &x, 0); -} - -uint32_t tlcl_extend(int pcr_num, const uint8_t* in_digest, - uint8_t* out_digest) -{ - struct s_tpm_extend_cmd cmd; - uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; - uint32_t result; - - memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); - to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); - memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); - - result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); - if (result != TPM_SUCCESS) - return result; - - if (out_digest) - memcpy(out_digest, response + kTpmResponseHeaderLength, - kPcrDigestLength); - return result; -} diff --git a/src/lib/tlcl_internal.h b/src/lib/tlcl_internal.h deleted file mode 100644 index 8261b0d..0000000 --- a/src/lib/tlcl_internal.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef TPM_LITE_TLCL_INTERNAL_H_ -#define TPM_LITE_TLCL_INTERNAL_H_ - -/* - * These numbers derive from adding the sizes of command fields as shown in the - * TPM commands manual. - */ -#define kTpmRequestHeaderLength 10 -#define kTpmResponseHeaderLength 10 -#define kTpmReadInfoLength 12 -#define kEncAuthLength 20 -#define kPcrDigestLength 20 - - -/* - * Conversion functions. to_tpm_TYPE puts a value of type TYPE into a TPM - * command buffer. from_tpm_TYPE gets a value of type TYPE from a TPM command - * buffer into a variable. - */ -__attribute__((unused)) -static inline void to_tpm_uint32(uint8_t *buffer, uint32_t x) { - buffer[0] = (uint8_t)(x >> 24); - buffer[1] = (uint8_t)((x >> 16) & 0xff); - buffer[2] = (uint8_t)((x >> 8) & 0xff); - buffer[3] = (uint8_t)(x & 0xff); -} - -/* - * See comment for above function. - */ -__attribute__((unused)) -static inline void from_tpm_uint32(const uint8_t *buffer, uint32_t *x) { - *x = ((buffer[0] << 24) | - (buffer[1] << 16) | - (buffer[2] << 8) | - buffer[3]); -} - -/* - * See comment for above function. - */ -__attribute__((unused)) -static inline void to_tpm_uint16(uint8_t *buffer, uint16_t x) { - buffer[0] = (uint8_t)(x >> 8); - buffer[1] = (uint8_t)(x & 0xff); -} - -/* - * See comment for above function. - */ -__attribute__((unused)) -static inline void from_tpm_uint16(const uint8_t *buffer, uint16_t *x) { - *x = (buffer[0] << 8) | buffer[1]; -} - -#endif /* TPM_LITE_TLCL_INTERNAL_H_ */ diff --git a/src/lib/tlcl_structures.h b/src/lib/tlcl_structures.h deleted file mode 100644 index 36c1bb9..0000000 --- a/src/lib/tlcl_structures.h +++ /dev/null @@ -1,138 +0,0 @@ -/* This file is automatically generated */ - -const struct s_tpm_extend_cmd{ - uint8_t buffer[34]; - uint16_t pcrNum; - uint16_t inDigest; -} tpm_extend_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, }, -10, 14, }; - -const struct s_tpm_get_random_cmd{ - uint8_t buffer[14]; - uint16_t bytesRequested; -} tpm_get_random_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x46, }, -10, }; - -const struct s_tpm_getownership_cmd{ - uint8_t buffer[22]; -} tpm_getownership_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x11, }, -}; - -const struct s_tpm_getpermissions_cmd{ - uint8_t buffer[22]; - uint16_t index; -} tpm_getpermissions_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x4, }, -18, }; - -const struct s_tpm_getstclearflags_cmd{ - uint8_t buffer[22]; -} tpm_getstclearflags_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x9, }, -}; - -const struct s_tpm_getflags_cmd{ - uint8_t buffer[22]; -} tpm_getflags_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x8, }, -}; - -const struct s_tpm_physicalsetdeactivated_cmd{ - uint8_t buffer[11]; - uint16_t deactivated; -} tpm_physicalsetdeactivated_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, }, -10, }; - -const struct s_tpm_physicalenable_cmd{ - uint8_t buffer[10]; -} tpm_physicalenable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, }, -}; - -const struct s_tpm_physicaldisable_cmd{ - uint8_t buffer[10]; -} tpm_physicaldisable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, }, -}; - -const struct s_tpm_forceclear_cmd{ - uint8_t buffer[10]; -} tpm_forceclear_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, }, -}; - -const struct s_tpm_readpubek_cmd{ - uint8_t buffer[30]; -} tpm_readpubek_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, }, -}; - -const struct s_tpm_continueselftest_cmd{ - uint8_t buffer[10]; -} tpm_continueselftest_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, }, -}; - -const struct s_tpm_selftestfull_cmd{ - uint8_t buffer[10]; -} tpm_selftestfull_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, }, -}; - -const struct s_tpm_resume_cmd{ - uint8_t buffer[12]; -} tpm_resume_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x2, }, -}; - -const struct s_tpm_savestate_cmd{ - uint8_t buffer[10]; -} tpm_savestate_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x98, }, -}; - -const struct s_tpm_startup_cmd{ - uint8_t buffer[12]; -} tpm_startup_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x1, }, -}; - -const struct s_tpm_finalizepp_cmd{ - uint8_t buffer[12]; -} tpm_finalizepp_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0, }, -}; - -const struct s_tpm_pplock_cmd{ - uint8_t buffer[12]; -} tpm_pplock_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x4, }, -}; - -const struct s_tpm_ppenable_cmd{ - uint8_t buffer[12]; -} tpm_ppenable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x20, }, -}; - -const struct s_tpm_ppassert_cmd{ - uint8_t buffer[12]; -} tpm_ppassert_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x8, }, -}; - -const struct s_tpm_pcr_read_cmd{ - uint8_t buffer[14]; - uint16_t pcrNum; -} tpm_pcr_read_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, }, -10, }; - -const struct s_tpm_nv_read_cmd{ - uint8_t buffer[22]; - uint16_t index; - uint16_t length; -} tpm_nv_read_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, }, -10, 18, }; - -const struct s_tpm_nv_write_cmd{ - uint8_t buffer[256]; - uint16_t index; - uint16_t length; - uint16_t data; -} tpm_nv_write_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, }, -10, 18, 22, }; - -const struct s_tpm_nv_definespace_cmd{ - uint8_t buffer[101]; - uint16_t index; - uint16_t perm; - uint16_t size; -} tpm_nv_definespace_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x18, 0, 0, 0, 0, 0x0, 0x3, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x3, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x17, }, -12, 70, 77, }; - -const int kWriteInfoLength = 12; -const int kNvDataPublicPermissionsOffset = 60; diff --git a/src/lib/tpm/Makefile.inc b/src/lib/tpm/Makefile.inc new file mode 100644 index 0000000..81a3eb9 --- /dev/null +++ b/src/lib/tpm/Makefile.inc @@ -0,0 +1,13 @@ +ifneq ($(CONFIG_CHROMEOS),y) +romstage-$(CONFIG_LPC_TPM) += tss.c tspi.c +ramstage-$(CONFIG_LPC_TPM) += tss.c tspi.c +else +romstage-$(CONFIG_LPC_TPM) += tspi.c +endif + +ifeq ($(MOCK_TPM),1) +libverstage-y += mocked_tss.c +else +libverstage-y += tss.c +endif + diff --git a/src/lib/tpm/mocked_tss.c b/src/lib/tpm/mocked_tss.c new file mode 100644 index 0000000..ce956ad --- /dev/null +++ b/src/lib/tpm/mocked_tss.c @@ -0,0 +1,136 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 The ChromiumOS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <tpm/tss.h> + +#ifdef FOR_TEST +#include <stdio.h> +#define VBDEBUG(format, args...) printf(format, ## args) +#else +#include <console/console.h> +#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args) +#endif + +uint32_t tlcl_lib_init(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_startup(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_resume(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_self_test_full(void) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_continue_self_test(void) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_write(uint32_t index, const void* data, uint32_t length) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_read(uint32_t index, void* data, uint32_t length) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + + +uint32_t tlcl_assert_physical_presence(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_physical_presence_cmd_enable(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_finalize_physical_presence(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_set_nv_locked(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_force_clear(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_set_enable(void) { + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_set_deactivated(uint8_t flag) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS* pflags) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_get_flags(uint8_t* disable, uint8_t* deactivated, + uint8_t *nvlocked) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_set_global_lock(void) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} + +uint32_t tlcl_extend(int pcr_num, const uint8_t* in_digest, + uint8_t* out_digest) +{ + VBDEBUG("MOCK_TPM: %s\n", __func__); + return TPM_E_NO_DEVICE; +} diff --git a/src/lib/tpm/tspi.c b/src/lib/tpm/tspi.c new file mode 100644 index 0000000..00848f1 --- /dev/null +++ b/src/lib/tpm/tspi.c @@ -0,0 +1,95 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2015 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <console/cbmem_console.h> +#include <console/console.h> +#include <reset.h> + +#include <tpm/tss.h> +#include <tpm/tspi.h> + +void init_tpm(int s3resume) +{ + u32 result = 0; + + if (CONFIG_TPM_DEACTIVATE) { + printk(BIOS_SPEW, "TPM: Deactivate\n"); + + result = tlcl_set_deactivated(1); + if(result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); + return; + } + } + + /* Doing TPM startup when we're not coming in on the S3 resume path + * saves us roughly 20ms in boot time only. This does not seem to + * be worth an API change to vboot_reference-firmware right now, so + * let's keep the code around, but just bail out early: + */ + if (s3resume ? CONFIG_NO_TPM_RESUME + : CONFIG_SKIP_TPM_STARTUP_ON_NORMAL_BOOT) + return; + + printk(BIOS_DEBUG, "TPM initialization.\n"); + + if(tlcl_lib_init() != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); + return; + } + + if (s3resume) { + /* S3 Resume */ + printk(BIOS_SPEW, "TPM: Resume\n"); + + result = tlcl_resume(); + if(result == TPM_E_INVALID_POSTINIT) { + /* We're on a platform where the TPM maintains power + * in S3, so it's already initialized. + */ + printk(BIOS_DEBUG, "TPM: Already initialized.\n"); + return; + } else if(result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); + return; + } + } else { + printk(BIOS_SPEW, "TPM: Startup\n"); + result = tlcl_startup(); + if(result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); + return; + } + } + + if (result == TPM_SUCCESS) { + printk(BIOS_SPEW, "TPM: OK.\n"); + return; + } + + printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result); + + if (CONFIG_TPM_INIT_FAILURE_IS_FATAL) { + printk(BIOS_ERR, "Hard reset!\n"); + post_code(POST_TPM_FAILURE); + if (IS_ENABLED(CONFIG_CONSOLE_CBMEM_DUMP_TO_UART)) + cbmem_dump_console(); + hard_reset(); + } +} \ No newline at end of file diff --git a/src/lib/tpm/tss.c b/src/lib/tpm/tss.c new file mode 100644 index 0000000..5ffe991 --- /dev/null +++ b/src/lib/tpm/tss.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* A lightweight TPM command library. + * + * The general idea is that TPM commands are array of bytes whose + * fields are mostly compile-time constant. The goal is to build much + * of the commands at compile time (or build time) and change some of + * the fields at run time as needed. The code in + * utility/tlcl_generator.c builds structures containing the commands, + * as well as the offsets of the fields that need to be set at run + * time. + */ + +#include <assert.h> +#include <string.h> +#include <tpm/tss.h> +#include <tpm/tpm.h> +#include <console/cbmem_console.h> +#include <console/console.h> +#include <reset.h> +#include "tss_internal.h" +#include "tss_structures.h" + +#ifdef FOR_TEST +#include <stdio.h> +#define VBDEBUG(format, args...) printf(format, ## args) +#else +#include <console/console.h> +#define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args) +#endif + +#define UNKNOWN_ERROR 0x10000001 // see VBOOT2 error codes.. + +static int tpm_send_receive(const uint8_t *request, + uint32_t request_length, + uint8_t *response, + uint32_t *response_length) +{ + size_t len = *response_length; + if (tis_sendrecv(request, request_length, response, &len)) + return UNKNOWN_ERROR; + /* check 64->32bit overflow and (re)check response buffer overflow */ + if (len > *response_length) + return UNKNOWN_ERROR; + *response_length = len; + return TPM_SUCCESS; +} + +/* Sets the size field of a TPM command. */ +static inline void set_tpm_command_size(uint8_t* buffer, uint32_t size) { + to_tpm_uint32(buffer + sizeof(uint16_t), size); +} + +/* Gets the size field of a TPM command. */ +__attribute__((unused)) +static inline int tpm_command_size(const uint8_t* buffer) { + uint32_t size; + from_tpm_uint32(buffer + sizeof(uint16_t), &size); + return (int) size; +} + +/* Gets the code field of a TPM command. */ +static inline int tpm_command_code(const uint8_t* buffer) { + uint32_t code; + from_tpm_uint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code); + return code; +} + +/* Gets the return code field of a TPM result. */ +static inline int tpm_return_code(const uint8_t* buffer) { + return tpm_command_code(buffer); +} + +/* Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or + * DOING_SELFTEST errors are returned. + */ +static uint32_t tlcl_send_receive_no_retry(const uint8_t* request, + uint8_t* response, int max_length) { + uint32_t response_length = max_length; + uint32_t result; + + result = tpm_send_receive(request, tpm_command_size(request), + response, &response_length); + if (0 != result) { + /* Communication with TPM failed, so response is garbage */ + VBDEBUG("TPM: command 0x%x send/receive failed: 0x%x\n", + tpm_command_code(request), result); + return result; + } + /* Otherwise, use the result code from the response */ + result = tpm_return_code(response); + + /* TODO: add paranoia about returned response_length vs. max_length + * (and possibly expected length from the response header). See + * crosbug.com/17017 */ + + VBDEBUG("TPM: command 0x%x returned 0x%x\n", + tpm_command_code(request), result); + +return result; +} + + +/* Sends a TPM command and gets a response. Returns 0 if success or the TPM + * error code if error. Waits for the self test to complete if needed. */ +uint32_t tlcl_send_receive(const uint8_t* request, uint8_t* response, + int max_length) { + uint32_t result = tlcl_send_receive_no_retry(request, response, + max_length); + /* If the command fails because the self test has not completed, try it + * again after attempting to ensure that the self test has completed. */ + if (result == TPM_E_NEEDS_SELFTEST || result == TPM_E_DOING_SELFTEST) { + result = tlcl_continue_self_test(); + if (result != TPM_SUCCESS) + return result; +#if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE) + /* Retry only once */ + result = tlcl_send_receive_no_retry(request, response, + max_length); +#else + /* This needs serious testing. The TPM specification says: "iii. + * The caller MUST wait for the actions of TPM_ContinueSelfTest + * to complete before reissuing the command C1." But, if + * ContinueSelfTest is non-blocking, how do we know that the + * actions have completed other than trying again? */ + do { + result = tlcl_send_receive_no_retry(request, response, + max_length); + } while (result == TPM_E_DOING_SELFTEST); +#endif + } + return result; +} + +/* Sends a command and returns the error code. */ +static uint32_t send(const uint8_t* command) { + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + return tlcl_send_receive(command, response, sizeof(response)); +} + +/* Exported functions. */ + +uint32_t tlcl_lib_init(void) { + if (tis_init()) + return UNKNOWN_ERROR; + if (tis_open()) + return UNKNOWN_ERROR; + return TPM_SUCCESS; +} + +uint32_t tlcl_startup(void) { + VBDEBUG("TPM: Startup\n"); + return send(tpm_startup_cmd.buffer); +} + +uint32_t tlcl_resume(void) { + VBDEBUG("TPM: Resume\n"); + return send(tpm_resume_cmd.buffer); +} + +uint32_t tlcl_self_test_full(void) +{ + VBDEBUG("TPM: Self test full\n"); + return send(tpm_selftestfull_cmd.buffer); +} + +uint32_t tlcl_continue_self_test(void) +{ + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + VBDEBUG("TPM: Continue self test\n"); + /* Call the No Retry version of SendReceive to avoid recursion. */ + return tlcl_send_receive_no_retry(tpm_continueselftest_cmd.buffer, + response, sizeof(response)); +} + +uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size) +{ + struct s_tpm_nv_definespace_cmd cmd; + VBDEBUG("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size); + memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd)); + to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.index, index); + to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.perm, perm); + to_tpm_uint32(cmd.buffer + tpm_nv_definespace_cmd.size, size); + return send(cmd.buffer); +} + +uint32_t tlcl_write(uint32_t index, const void* data, uint32_t length) +{ + struct s_tpm_nv_write_cmd cmd; + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + const int total_length = + kTpmRequestHeaderLength + kWriteInfoLength + length; + + VBDEBUG("TPM: tlcl_write(0x%x, %d)\n", index, length); + memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd)); + assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE); + set_tpm_command_size(cmd.buffer, total_length); + + to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.index, index); + to_tpm_uint32(cmd.buffer + tpm_nv_write_cmd.length, length); + memcpy(cmd.buffer + tpm_nv_write_cmd.data, data, length); + + return tlcl_send_receive(cmd.buffer, response, sizeof(response)); +} + +uint32_t tlcl_read(uint32_t index, void* data, uint32_t length) +{ + struct s_tpm_nv_read_cmd cmd; + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + uint32_t result_length; + uint32_t result; + + VBDEBUG("TPM: tlcl_read(0x%x, %d)\n", index, length); + memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd)); + to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.index, index); + to_tpm_uint32(cmd.buffer + tpm_nv_read_cmd.length, length); + + result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); + if (result == TPM_SUCCESS && length > 0) { + uint8_t* nv_read_cursor = response + kTpmResponseHeaderLength; + from_tpm_uint32(nv_read_cursor, &result_length); + nv_read_cursor += sizeof(uint32_t); + memcpy(data, nv_read_cursor, result_length); + } + + return result; +} + + +uint32_t tlcl_assert_physical_presence(void) { + VBDEBUG("TPM: Asserting physical presence\n"); + return send(tpm_ppassert_cmd.buffer); +} + +uint32_t tlcl_physical_presence_cmd_enable(void) { + VBDEBUG("TPM: Enable the physical presence command\n"); + return send(tpm_ppenable_cmd.buffer); +} + +uint32_t tlcl_finalize_physical_presence(void) { + VBDEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n"); + return send(tpm_finalizepp_cmd.buffer); +} + +uint32_t tlcl_set_nv_locked(void) { + VBDEBUG("TPM: Set NV locked\n"); + return tlcl_define_space(TPM_NV_INDEX_LOCK, 0, 0); +} + +uint32_t tlcl_force_clear(void) { + VBDEBUG("TPM: Force clear\n"); + return send(tpm_forceclear_cmd.buffer); +} + +uint32_t tlcl_set_enable(void) { + VBDEBUG("TPM: Enabling TPM\n"); + return send(tpm_physicalenable_cmd.buffer); +} + +uint32_t tlcl_set_deactivated(uint8_t flag) +{ + struct s_tpm_physicalsetdeactivated_cmd cmd; + VBDEBUG("TPM: SetDeactivated(%d)\n", flag); + memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd)); + *(cmd.buffer + cmd.deactivated) = flag; + return send(cmd.buffer); +} + +uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS* pflags) +{ + uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; + uint32_t size; + uint32_t result = tlcl_send_receive(tpm_getflags_cmd.buffer, response, + sizeof(response)); + if (result != TPM_SUCCESS) + return result; + from_tpm_uint32(response + kTpmResponseHeaderLength, &size); + assert(size == sizeof(TPM_PERMANENT_FLAGS)); + memcpy(pflags, response + kTpmResponseHeaderLength + sizeof(size), + sizeof(TPM_PERMANENT_FLAGS)); + return result; +} + +uint32_t tlcl_get_flags(uint8_t* disable, uint8_t* deactivated, + uint8_t *nvlocked) +{ + TPM_PERMANENT_FLAGS pflags; + uint32_t result = tlcl_get_permanent_flags(&pflags); + if (result == TPM_SUCCESS) { + if (disable) + *disable = pflags.disable; + if (deactivated) + *deactivated = pflags.deactivated; + if (nvlocked) + *nvlocked = pflags.nvLocked; + VBDEBUG("TPM: flags disable=%d, deactivated=%d, nvlocked=%d\n", + pflags.disable, pflags.deactivated, pflags.nvLocked); + } + return result; +} + +uint32_t tlcl_set_global_lock(void) +{ + uint32_t x; + VBDEBUG("TPM: Set global lock\n"); + return tlcl_write(TPM_NV_INDEX0, (uint8_t*) &x, 0); +} + +uint32_t tlcl_extend(int pcr_num, const uint8_t* in_digest, + uint8_t* out_digest) +{ + struct s_tpm_extend_cmd cmd; + uint8_t response[kTpmResponseHeaderLength + kPcrDigestLength]; + uint32_t result; + + memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd)); + to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num); + memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength); + + result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); + if (result != TPM_SUCCESS) + return result; + + if (out_digest) + memcpy(out_digest, response + kTpmResponseHeaderLength, + kPcrDigestLength); + return result; +} diff --git a/src/lib/tpm/tss_internal.h b/src/lib/tpm/tss_internal.h new file mode 100644 index 0000000..bc56b12 --- /dev/null +++ b/src/lib/tpm/tss_internal.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef LIB_TPM_TSS_INTERNAL_H +#define LIB_TPM_TSS_INTERNAL_H + +/* + * These numbers derive from adding the sizes of command fields as shown in the + * TPM commands manual. + */ +#define kTpmRequestHeaderLength 10 +#define kTpmResponseHeaderLength 10 +#define kTpmReadInfoLength 12 +#define kEncAuthLength 20 +#define kPcrDigestLength 20 + + +/* + * Conversion functions. to_tpm_TYPE puts a value of type TYPE into a TPM + * command buffer. from_tpm_TYPE gets a value of type TYPE from a TPM command + * buffer into a variable. + */ +__attribute__((unused)) +static inline void to_tpm_uint32(uint8_t *buffer, uint32_t x) { + buffer[0] = (uint8_t)(x >> 24); + buffer[1] = (uint8_t)((x >> 16) & 0xff); + buffer[2] = (uint8_t)((x >> 8) & 0xff); + buffer[3] = (uint8_t)(x & 0xff); +} + +/* + * See comment for above function. + */ +__attribute__((unused)) +static inline void from_tpm_uint32(const uint8_t *buffer, uint32_t *x) { + *x = ((buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]); +} + +/* + * See comment for above function. + */ +__attribute__((unused)) +static inline void to_tpm_uint16(uint8_t *buffer, uint16_t x) { + buffer[0] = (uint8_t)(x >> 8); + buffer[1] = (uint8_t)(x & 0xff); +} + +/* + * See comment for above function. + */ +__attribute__((unused)) +static inline void from_tpm_uint16(const uint8_t *buffer, uint16_t *x) { + *x = (buffer[0] << 8) | buffer[1]; +} + +#endif /* LIB_TPM_TSS_INTERNAL_H */ \ No newline at end of file diff --git a/src/lib/tpm/tss_structures.h b/src/lib/tpm/tss_structures.h new file mode 100644 index 0000000..36c1bb9 --- /dev/null +++ b/src/lib/tpm/tss_structures.h @@ -0,0 +1,138 @@ +/* This file is automatically generated */ + +const struct s_tpm_extend_cmd{ + uint8_t buffer[34]; + uint16_t pcrNum; + uint16_t inDigest; +} tpm_extend_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x22, 0x0, 0x0, 0x0, 0x14, }, +10, 14, }; + +const struct s_tpm_get_random_cmd{ + uint8_t buffer[14]; + uint16_t bytesRequested; +} tpm_get_random_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x46, }, +10, }; + +const struct s_tpm_getownership_cmd{ + uint8_t buffer[22]; +} tpm_getownership_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x11, }, +}; + +const struct s_tpm_getpermissions_cmd{ + uint8_t buffer[22]; + uint16_t index; +} tpm_getpermissions_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x11, 0x0, 0x0, 0x0, 0x4, }, +18, }; + +const struct s_tpm_getstclearflags_cmd{ + uint8_t buffer[22]; +} tpm_getstclearflags_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x9, }, +}; + +const struct s_tpm_getflags_cmd{ + uint8_t buffer[22]; +} tpm_getflags_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x1, 0x8, }, +}; + +const struct s_tpm_physicalsetdeactivated_cmd{ + uint8_t buffer[11]; + uint16_t deactivated; +} tpm_physicalsetdeactivated_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xb, 0x0, 0x0, 0x0, 0x72, }, +10, }; + +const struct s_tpm_physicalenable_cmd{ + uint8_t buffer[10]; +} tpm_physicalenable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x6f, }, +}; + +const struct s_tpm_physicaldisable_cmd{ + uint8_t buffer[10]; +} tpm_physicaldisable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x70, }, +}; + +const struct s_tpm_forceclear_cmd{ + uint8_t buffer[10]; +} tpm_forceclear_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x5d, }, +}; + +const struct s_tpm_readpubek_cmd{ + uint8_t buffer[30]; +} tpm_readpubek_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x1e, 0x0, 0x0, 0x0, 0x7c, }, +}; + +const struct s_tpm_continueselftest_cmd{ + uint8_t buffer[10]; +} tpm_continueselftest_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x53, }, +}; + +const struct s_tpm_selftestfull_cmd{ + uint8_t buffer[10]; +} tpm_selftestfull_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x50, }, +}; + +const struct s_tpm_resume_cmd{ + uint8_t buffer[12]; +} tpm_resume_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x2, }, +}; + +const struct s_tpm_savestate_cmd{ + uint8_t buffer[10]; +} tpm_savestate_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0x98, }, +}; + +const struct s_tpm_startup_cmd{ + uint8_t buffer[12]; +} tpm_startup_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0x99, 0x0, 0x1, }, +}; + +const struct s_tpm_finalizepp_cmd{ + uint8_t buffer[12]; +} tpm_finalizepp_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x2, 0xa0, }, +}; + +const struct s_tpm_pplock_cmd{ + uint8_t buffer[12]; +} tpm_pplock_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x4, }, +}; + +const struct s_tpm_ppenable_cmd{ + uint8_t buffer[12]; +} tpm_ppenable_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x20, }, +}; + +const struct s_tpm_ppassert_cmd{ + uint8_t buffer[12]; +} tpm_ppassert_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xc, 0x40, 0x0, 0x0, 0xa, 0x0, 0x8, }, +}; + +const struct s_tpm_pcr_read_cmd{ + uint8_t buffer[14]; + uint16_t pcrNum; +} tpm_pcr_read_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x15, }, +10, }; + +const struct s_tpm_nv_read_cmd{ + uint8_t buffer[22]; + uint16_t index; + uint16_t length; +} tpm_nv_read_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x16, 0x0, 0x0, 0x0, 0xcf, }, +10, 18, }; + +const struct s_tpm_nv_write_cmd{ + uint8_t buffer[256]; + uint16_t index; + uint16_t length; + uint16_t data; +} tpm_nv_write_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xcd, }, +10, 18, 22, }; + +const struct s_tpm_nv_definespace_cmd{ + uint8_t buffer[101]; + uint16_t index; + uint16_t perm; + uint16_t size; +} tpm_nv_definespace_cmd = {{0x0, 0xc1, 0x0, 0x0, 0x0, 0x65, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x18, 0, 0, 0, 0, 0x0, 0x3, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x3, 0, 0, 0, 0x1f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0, 0x17, }, +12, 70, 77, }; + +const int kWriteInfoLength = 12; +const int kNvDataPublicPermissionsOffset = 60; diff --git a/src/mainboard/google/auron/acpi/mainboard.asl b/src/mainboard/google/auron/acpi/mainboard.asl index 8461a9d..b4b0ba2 100644 --- a/src/mainboard/google/auron/acpi/mainboard.asl +++ b/src/mainboard/google/auron/acpi/mainboard.asl @@ -48,7 +48,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
Scope (_SB.PCI0.I2C0) diff --git a/src/mainboard/google/auron/devicetree.cb b/src/mainboard/google/auron/devicetree.cb index 77e71b8..ea71cf6 100644 --- a/src/mainboard/google/auron/devicetree.cb +++ b/src/mainboard/google/auron/devicetree.cb @@ -90,7 +90,7 @@ chip soc/intel/broadwell device pci 1d.0 on end # USB2 EHCI device pci 1e.0 off end # PCI bridge device pci 1f.0 on - chip drivers/pc80/tpm + chip drivers/tpm # Rising edge interrupt register "irq_polarity" = "2" device pnp 0c31.0 on diff --git a/src/mainboard/google/cyan/acpi/mainboard.asl b/src/mainboard/google/cyan/acpi/mainboard.asl index 9918672..183c4b1 100755 --- a/src/mainboard/google/cyan/acpi/mainboard.asl +++ b/src/mainboard/google/cyan/acpi/mainboard.asl @@ -46,7 +46,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
Scope (_SB.I2C1) diff --git a/src/mainboard/google/cyan/devicetree.cb b/src/mainboard/google/cyan/devicetree.cb index c36ae3d..c845a8c 100755 --- a/src/mainboard/google/cyan/devicetree.cb +++ b/src/mainboard/google/cyan/devicetree.cb @@ -126,7 +126,7 @@ chip soc/intel/braswell device pci 1e.6 on end # 8086 2290 - SPI 2 device pci 1e.7 on end # 8086 22ac - SPI 3 device pci 1f.0 on # 8086 229c - LPC bridge - chip drivers/pc80/tpm + chip drivers/tpm # Rising edge interrupt register "irq_polarity" = "2" device pnp 0c31.0 on diff --git a/src/mainboard/google/glados/acpi/mainboard.asl b/src/mainboard/google/glados/acpi/mainboard.asl index 53001e4..f3915fb 100644 --- a/src/mainboard/google/glados/acpi/mainboard.asl +++ b/src/mainboard/google/glados/acpi/mainboard.asl @@ -63,7 +63,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Trackpad */ diff --git a/src/mainboard/google/glados/devicetree.cb b/src/mainboard/google/glados/devicetree.cb index b48556f..e466278 100644 --- a/src/mainboard/google/glados/devicetree.cb +++ b/src/mainboard/google/glados/devicetree.cb @@ -93,7 +93,7 @@ chip soc/intel/skylake device pci 1e.4 on end # eMMC device pci 1e.6 on end # SDCard device pci 1f.0 on - chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end chip ec/google/chromeec diff --git a/src/mainboard/google/jecht/acpi/mainboard.asl b/src/mainboard/google/jecht/acpi/mainboard.asl index 236f881..7545cb0 100644 --- a/src/mainboard/google/jecht/acpi/mainboard.asl +++ b/src/mainboard/google/jecht/acpi/mainboard.asl @@ -33,7 +33,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* diff --git a/src/mainboard/google/link/romstage.c b/src/mainboard/google/link/romstage.c index e9b4a09..1837d50 100644 --- a/src/mainboard/google/link/romstage.c +++ b/src/mainboard/google/link/romstage.c @@ -41,7 +41,7 @@ #include <cpu/x86/msr.h> #include <halt.h> #include "gpio.h" -#include <tpm.h> +#include <tpm/tspi.h> #include <cbfs.h>
#include <southbridge/intel/bd82x6x/chip.h> diff --git a/src/mainboard/google/parrot/romstage.c b/src/mainboard/google/parrot/romstage.c index a947c48..209611e 100644 --- a/src/mainboard/google/parrot/romstage.c +++ b/src/mainboard/google/parrot/romstage.c @@ -40,7 +40,7 @@ #include <halt.h> #include "gpio.h" #include <cbfs.h> -#include <tpm.h> +#include <tpm/tspi.h> #include "ec/compal/ene932/ec.h"
static void pch_enable_lpc(void) diff --git a/src/mainboard/google/samus/acpi/mainboard.asl b/src/mainboard/google/samus/acpi/mainboard.asl index 04f98a9..a2a337f 100644 --- a/src/mainboard/google/samus/acpi/mainboard.asl +++ b/src/mainboard/google/samus/acpi/mainboard.asl @@ -62,7 +62,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* diff --git a/src/mainboard/google/samus/devicetree.cb b/src/mainboard/google/samus/devicetree.cb index d12762d..104af07 100644 --- a/src/mainboard/google/samus/devicetree.cb +++ b/src/mainboard/google/samus/devicetree.cb @@ -94,7 +94,7 @@ chip soc/intel/broadwell device pci 1d.0 off end # USB2 EHCI device pci 1e.0 off end # PCI bridge device pci 1f.0 on - chip drivers/pc80/tpm + chip drivers/tpm # Rising edge interrupt register "irq_polarity" = "2" device pnp 0c31.0 on diff --git a/src/mainboard/google/stout/romstage.c b/src/mainboard/google/stout/romstage.c index 31b61e2..9d9f761 100644 --- a/src/mainboard/google/stout/romstage.c +++ b/src/mainboard/google/stout/romstage.c @@ -40,7 +40,7 @@ #include <halt.h> #include "gpio.h" #include <bootmode.h> -#include <tpm.h> +#include <tpm/tspi.h> #include <cbfs.h> #include <ec/quanta/it8518/ec.h> #include "ec.h" diff --git a/src/mainboard/intel/emeraldlake2/romstage.c b/src/mainboard/intel/emeraldlake2/romstage.c index bcf498b..d612d67 100644 --- a/src/mainboard/intel/emeraldlake2/romstage.c +++ b/src/mainboard/intel/emeraldlake2/romstage.c @@ -39,7 +39,7 @@ #include <cpu/x86/bist.h> #include <cpu/x86/msr.h> #include <halt.h> -#include <tpm.h> +#include <tpm/tspi.h> #include "gpio.h"
#define SIO_PORT 0x164e diff --git a/src/mainboard/intel/kunimitsu/acpi/mainboard.asl b/src/mainboard/intel/kunimitsu/acpi/mainboard.asl index a5e7bcf..047e91c 100644 --- a/src/mainboard/intel/kunimitsu/acpi/mainboard.asl +++ b/src/mainboard/intel/kunimitsu/acpi/mainboard.asl @@ -52,7 +52,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> } Scope (_SB.PCI0.I2C0) { diff --git a/src/mainboard/intel/sklrvp/acpi/mainboard.asl b/src/mainboard/intel/sklrvp/acpi/mainboard.asl index d771f62..8737aa6 100644 --- a/src/mainboard/intel/sklrvp/acpi/mainboard.asl +++ b/src/mainboard/intel/sklrvp/acpi/mainboard.asl @@ -28,7 +28,7 @@ */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* diff --git a/src/mainboard/intel/strago/acpi/mainboard.asl b/src/mainboard/intel/strago/acpi/mainboard.asl index eefa005..01287a0 100755 --- a/src/mainboard/intel/strago/acpi/mainboard.asl +++ b/src/mainboard/intel/strago/acpi/mainboard.asl @@ -45,7 +45,7 @@ Scope (_SB) */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> } Scope (_SB.I2C1) { diff --git a/src/mainboard/intel/strago/devicetree.cb b/src/mainboard/intel/strago/devicetree.cb index bcf92f1..15b87a8 100755 --- a/src/mainboard/intel/strago/devicetree.cb +++ b/src/mainboard/intel/strago/devicetree.cb @@ -126,7 +126,7 @@ chip soc/intel/braswell device pci 1e.6 on end # 8086 2290 - SPI 2 device pci 1e.7 on end # 8086 22ac - SPI 3 device pci 1f.0 on # 8086 229c - LPC bridge - chip drivers/pc80/tpm + chip drivers/tpm # Rising edge interrupt register "irq_polarity" = "2" device pnp 0c31.0 on diff --git a/src/mainboard/lenovo/t420s/devicetree.cb b/src/mainboard/lenovo/t420s/devicetree.cb index cd70228..8fb40c1 100644 --- a/src/mainboard/lenovo/t420s/devicetree.cb +++ b/src/mainboard/lenovo/t420s/devicetree.cb @@ -112,7 +112,7 @@ chip northbridge/intel/sandybridge register "dock_event_enable" = "0x01" end
- chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end
diff --git a/src/mainboard/lenovo/t420s/dsdt.asl b/src/mainboard/lenovo/t420s/dsdt.asl index 64e4e9f..6d5c640 100644 --- a/src/mainboard/lenovo/t420s/dsdt.asl +++ b/src/mainboard/lenovo/t420s/dsdt.asl @@ -59,7 +59,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Chipset specific sleep states */ diff --git a/src/mainboard/lenovo/t430s/devicetree.cb b/src/mainboard/lenovo/t430s/devicetree.cb index f3e453e..56ca8cd 100644 --- a/src/mainboard/lenovo/t430s/devicetree.cb +++ b/src/mainboard/lenovo/t430s/devicetree.cb @@ -116,7 +116,7 @@ chip northbridge/intel/sandybridge register "dock_event_enable" = "0x01" end
- chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end
diff --git a/src/mainboard/lenovo/t430s/dsdt.asl b/src/mainboard/lenovo/t430s/dsdt.asl index 64e4e9f..6d5c640 100644 --- a/src/mainboard/lenovo/t430s/dsdt.asl +++ b/src/mainboard/lenovo/t430s/dsdt.asl @@ -59,7 +59,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Chipset specific sleep states */ diff --git a/src/mainboard/lenovo/t520/devicetree.cb b/src/mainboard/lenovo/t520/devicetree.cb index ff9745e..6c1ea89 100644 --- a/src/mainboard/lenovo/t520/devicetree.cb +++ b/src/mainboard/lenovo/t520/devicetree.cb @@ -93,7 +93,7 @@ chip northbridge/intel/sandybridge register "dock_event_enable" = "0x01" end
- chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end
diff --git a/src/mainboard/lenovo/t520/dsdt.asl b/src/mainboard/lenovo/t520/dsdt.asl index f5f3ace..36c1f40 100644 --- a/src/mainboard/lenovo/t520/dsdt.asl +++ b/src/mainboard/lenovo/t520/dsdt.asl @@ -58,7 +58,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Chipset specific sleep states */ diff --git a/src/mainboard/lenovo/t530/devicetree.cb b/src/mainboard/lenovo/t530/devicetree.cb index e1b22fd..830ccdd 100644 --- a/src/mainboard/lenovo/t530/devicetree.cb +++ b/src/mainboard/lenovo/t530/devicetree.cb @@ -98,7 +98,7 @@ chip northbridge/intel/sandybridge register "dock_event_enable" = "0x01" end
- chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end
diff --git a/src/mainboard/lenovo/t530/dsdt.asl b/src/mainboard/lenovo/t530/dsdt.asl index f5f3ace..36c1f40 100644 --- a/src/mainboard/lenovo/t530/dsdt.asl +++ b/src/mainboard/lenovo/t530/dsdt.asl @@ -58,7 +58,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Chipset specific sleep states */ diff --git a/src/mainboard/lenovo/x201/devicetree.cb b/src/mainboard/lenovo/x201/devicetree.cb index 8e9e0a1..9447bfc 100644 --- a/src/mainboard/lenovo/x201/devicetree.cb +++ b/src/mainboard/lenovo/x201/devicetree.cb @@ -156,7 +156,7 @@ chip northbridge/intel/nehalem # DLPC, not connected device pnp 164e.19 off end end - chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end end diff --git a/src/mainboard/lenovo/x201/dsdt.asl b/src/mainboard/lenovo/x201/dsdt.asl index f2f0a89..ec3f1f4 100644 --- a/src/mainboard/lenovo/x201/dsdt.asl +++ b/src/mainboard/lenovo/x201/dsdt.asl @@ -92,7 +92,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Chipset specific sleep states */ diff --git a/src/mainboard/lenovo/x201/romstage.c b/src/mainboard/lenovo/x201/romstage.c index 1e335d3..bb49b49 100644 --- a/src/mainboard/lenovo/x201/romstage.c +++ b/src/mainboard/lenovo/x201/romstage.c @@ -37,7 +37,7 @@ #include <timestamp.h> #include <arch/acpi.h> #include <cbmem.h> -#include <tpm.h> +#include <tpm/tspi.h>
#include "gpio.h" #include "dock.h" diff --git a/src/mainboard/lenovo/x220/devicetree.cb b/src/mainboard/lenovo/x220/devicetree.cb index 9c3aac6..36a6c07 100644 --- a/src/mainboard/lenovo/x220/devicetree.cb +++ b/src/mainboard/lenovo/x220/devicetree.cb @@ -126,7 +126,7 @@ chip northbridge/intel/sandybridge register "dock_event_enable" = "0x01" end
- chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end
diff --git a/src/mainboard/lenovo/x220/dsdt.asl b/src/mainboard/lenovo/x220/dsdt.asl index f5f3ace..36c1f40 100644 --- a/src/mainboard/lenovo/x220/dsdt.asl +++ b/src/mainboard/lenovo/x220/dsdt.asl @@ -58,7 +58,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
/* Chipset specific sleep states */ diff --git a/src/mainboard/lenovo/x230/devicetree.cb b/src/mainboard/lenovo/x230/devicetree.cb index 99db7dd..9e1ed8a 100644 --- a/src/mainboard/lenovo/x230/devicetree.cb +++ b/src/mainboard/lenovo/x230/devicetree.cb @@ -128,7 +128,7 @@ chip northbridge/intel/sandybridge register "dock_event_enable" = "0x01" end
- chip drivers/pc80/tpm + chip drivers/tpm device pnp 0c31.0 on end end
diff --git a/src/mainboard/lenovo/x230/dsdt.asl b/src/mainboard/lenovo/x230/dsdt.asl index 1c71c3c..20f83cc 100644 --- a/src/mainboard/lenovo/x230/dsdt.asl +++ b/src/mainboard/lenovo/x230/dsdt.asl @@ -57,7 +57,7 @@ DefinitionBlock( */ Scope (_SB.PCI0.LPCB) { - #include <drivers/pc80/tpm/acpi/tpm.asl> + #include <drivers/tpm/acpi/tpm.asl> }
diff --git a/src/mainboard/samsung/lumpy/romstage.c b/src/mainboard/samsung/lumpy/romstage.c index 015ae08..cea088d 100644 --- a/src/mainboard/samsung/lumpy/romstage.c +++ b/src/mainboard/samsung/lumpy/romstage.c @@ -32,7 +32,7 @@ #include <cbmem.h> #include <console/console.h> #include <bootmode.h> -#include <tpm.h> +#include <tpm/tspi.h> #include <northbridge/intel/sandybridge/sandybridge.h> #include <northbridge/intel/sandybridge/raminit.h> #include <southbridge/intel/bd82x6x/pch.h> diff --git a/src/mainboard/samsung/stumpy/romstage.c b/src/mainboard/samsung/stumpy/romstage.c index 161c8d1..2906815 100644 --- a/src/mainboard/samsung/stumpy/romstage.c +++ b/src/mainboard/samsung/stumpy/romstage.c @@ -41,7 +41,7 @@ #include <cpu/x86/bist.h> #include <cpu/x86/msr.h> #include <halt.h> -#include <tpm.h> +#include <tpm/tspi.h> #include "gpio.h" #if CONFIG_DRIVERS_UART_8250IO #include <superio/smsc/lpc47n207/lpc47n207.h> diff --git a/src/northbridge/intel/sandybridge/romstage_native.c b/src/northbridge/intel/sandybridge/romstage_native.c index 45f671c..13696bd 100644 --- a/src/northbridge/intel/sandybridge/romstage_native.c +++ b/src/northbridge/intel/sandybridge/romstage_native.c @@ -32,7 +32,7 @@ #include <device/pci_def.h> #include <device/device.h> #include <halt.h> -#include <tpm.h> +#include <tpm/tspi.h> #include "raminit_native.h" #include <northbridge/intel/sandybridge/chip.h> #include "southbridge/intel/bd82x6x/pch.h" diff --git a/src/soc/intel/baytrail/romstage/romstage.c b/src/soc/intel/baytrail/romstage/romstage.c index 1b93eb6..108faf3 100644 --- a/src/soc/intel/baytrail/romstage/romstage.c +++ b/src/soc/intel/baytrail/romstage/romstage.c @@ -33,7 +33,7 @@ #include <romstage_handoff.h> #include <stage_cache.h> #include <timestamp.h> -#include <tpm.h> +#include <tpm/tspi.h> #include <vendorcode/google/chromeos/chromeos.h> #include <soc/gpio.h> #include <soc/iomap.h> diff --git a/src/soc/intel/braswell/romstage/romstage.c b/src/soc/intel/braswell/romstage/romstage.c index 64a3dee..fa9a815 100644 --- a/src/soc/intel/braswell/romstage/romstage.c +++ b/src/soc/intel/braswell/romstage/romstage.c @@ -50,7 +50,7 @@ #include <soc/romstage.h> #include <soc/smm.h> #include <soc/spi.h> -#include <tpm.h> +#include <tpm/tsṕi.h>
void program_base_addresses(void) { diff --git a/src/soc/intel/broadwell/romstage/romstage.c b/src/soc/intel/broadwell/romstage/romstage.c index 27fb0f2..166ee30 100644 --- a/src/soc/intel/broadwell/romstage/romstage.c +++ b/src/soc/intel/broadwell/romstage/romstage.c @@ -29,7 +29,7 @@ #include <cbmem.h> #include <cpu/x86/mtrr.h> #include <elog.h> -#include <tpm.h> +#include <tpm/tspi.h> #include <romstage_handoff.h> #include <stage_cache.h> #include <timestamp.h> diff --git a/src/soc/intel/common/romstage.c b/src/soc/intel/common/romstage.c index 7a05e17..b0f2ff1 100644 --- a/src/soc/intel/common/romstage.c +++ b/src/soc/intel/common/romstage.c @@ -43,7 +43,7 @@ #include <soc/spi.h> #include <stage_cache.h> #include <timestamp.h> -#include <tpm.h> +#include <tpm/tpm.h> #include <vendorcode/google/chromeos/chromeos.h>
/* Entry from cache-as-ram.inc. */ diff --git a/src/vendorcode/google/chromeos/vboot2/antirollback.c b/src/vendorcode/google/chromeos/vboot2/antirollback.c index 407b19c..f947c35 100644 --- a/src/vendorcode/google/chromeos/vboot2/antirollback.c +++ b/src/vendorcode/google/chromeos/vboot2/antirollback.c @@ -9,8 +9,8 @@ #include <antirollback.h> #include <stdlib.h> #include <string.h> -#include <tpm_lite/tlcl.h> -#include <tpm_lite/tss_constants.h> +#include <tpm/tss.h> +#include <tpm/tss_constants.h> #include <vb2_api.h>
#ifndef offsetof