security/tpm: Unify the coreboot TPM software stack

* Remove 2nd software stack in pc80 drivers directory.
* Create TSPI interface for common usage.
* Refactor TSS / TIS code base.
* Add vendor tss (Cr50) directory.
* Change kconfig options for TPM to TPM1.
* Add user / board configuration with:
  * MAINBOARD_HAS_*_TPM # * BUS driver
  * MAINBOARD_HAS_TPM1 or MAINBOARD_HAS_TPM2
  * Add kconfig TPM user selection (e.g. pluggable TPMs)
* Fix existing headers and function calls.
* Fix vboot for interface usage and antirollback mode.

Change-Id: I7ec277e82a3c20c62a0548a1a2b013e6ce8f5b3f
Signed-off-by: Philipp Deppenwiese <zaolin@das-labor.org>
Reviewed-on: https://review.coreboot.org/24903
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
This commit is contained in:
Philipp Deppenwiese
2018-02-27 19:40:52 +01:00
committed by Martin Roth
parent 961d31bdb3
commit c07f8fbe6f
112 changed files with 1126 additions and 1396 deletions

View File

@@ -1,32 +1,28 @@
config I2C_TPM
bool "I2C TPM"
depends on TPM || TPM2
bool
help
I2C TPM driver is enabled!
config MAINBOARD_HAS_I2C_TPM_ATMEL
bool
default n
select I2C_TPM
help
Board has an Atmel I2C TPM support
config MAINBOARD_HAS_I2C_TPM_CR50
bool
default n
select I2C_TPM
help
Board has a Cr50 I2C TPM support
choice
prompt "I2C TPM Driver"
default I2C_TPM_ATMEL if MAINBOARD_HAS_I2C_TPM_ATMEL
default I2C_TPM_CR50 if MAINBOARD_HAS_I2C_TPM_CR50
default I2C_TPM_GENERIC if !MAINBOARD_HAS_I2C_TPM_CR50 && !MAINBOARD_HAS_I2C_TPM_ATMEL
depends on I2C_TPM
config I2C_TPM_GENERIC
bool "Generic I2C TPM Driver"
config I2C_TPM_ATMEL
bool "ATMEL I2C TPM Driver"
config I2C_TPM_CR50
bool "CR50 I2C TPM Driver"
endchoice
config MAINBOARD_HAS_I2C_TPM_GENERIC
bool
default n
select I2C_TPM
help
Board has a generic I2C TPM support
config DRIVER_TIS_DEFAULT
bool

View File

@@ -1,4 +1,3 @@
ramstage-$(CONFIG_DRIVER_TIS_DEFAULT) += tis.c
romstage-$(CONFIG_DRIVER_TIS_DEFAULT) += tis.c
verstage-$(CONFIG_DRIVER_TIS_DEFAULT) += tis.c
@@ -9,14 +8,14 @@ romstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_ATMEL) += tis_atmel.c
verstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_ATMEL) += tis_atmel.c
bootblock-$(CONFIG_MAINBOARD_HAS_I2C_TPM_ATMEL) += tis_atmel.c
ramstage-$(CONFIG_I2C_TPM_GENERIC) += tpm.c
romstage-$(CONFIG_I2C_TPM_GENERIC) += tpm.c
verstage-$(CONFIG_I2C_TPM_GENERIC) += tpm.c
bootblock-$(CONFIG_I2C_TPM_GENERIC) += tpm.c
ramstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_GENERIC) += tpm.c
romstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_GENERIC) += tpm.c
verstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_GENERIC) += tpm.c
bootblock-$(CONFIG_MAINBOARD_HAS_I2C_TPM_GENERIC) += tpm.c
ramstage-$(CONFIG_I2C_TPM_CR50) += cr50.c
romstage-$(CONFIG_I2C_TPM_CR50) += cr50.c
verstage-$(CONFIG_I2C_TPM_CR50) += cr50.c
bootblock-$(CONFIG_I2C_TPM_CR50) += cr50.c
ramstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_CR50) += cr50.c
romstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_CR50) += cr50.c
verstage-$(CONFIG_MAINBOARD_HAS_I2C_TPM_CR50) += cr50.c
bootblock-$(CONFIG_MAINBOARD_HAS_I2C_TPM_CR50) += cr50.c
ramstage-$(CONFIG_DRIVER_I2C_TPM_ACPI) += chip.c

View File

@@ -37,7 +37,7 @@
#include <stage_cache.h>
#include <string.h>
#include <timestamp.h>
#include <security/tpm/tis.h>
#include <security/tpm/tspi.h>
#include <vendorcode/google/chromeos/chromeos.h>
asmlinkage void *romstage_main(FSP_INFO_HEADER *fih)
@@ -172,9 +172,9 @@ void romstage_common(struct romstage_params *params)
* Initialize the TPM, unless the TPM was already initialized
* in verstage and used to verify romstage.
*/
if (IS_ENABLED(CONFIG_LPC_TPM) &&
if ((IS_ENABLED(CONFIG_TPM1) || IS_ENABLED(CONFIG_TPM2)) &&
!IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
init_tpm(params->power_state->prev_sleep_state ==
tpm_setup(params->power_state->prev_sleep_state ==
ACPI_S3);
}

View File

@@ -119,6 +119,8 @@ config DISPLAY_FSP_VERSION_INFO
config FSP2_0_USES_TPM_MRC_HASH
bool
depends on TPM1 || TPM2
depends on VBOOT
default y if HAS_RECOVERY_MRC_CACHE
default n
select VBOOT_HAS_REC_HASH_SPACE

View File

@@ -12,7 +12,7 @@
*/
#include <compiler.h>
#include <security/tpm/antirollback.h>
#include <security/vboot/antirollback.h>
#include <arch/io.h>
#include <arch/cpu.h>
#include <arch/symbols.h>
@@ -31,8 +31,7 @@
#include <string.h>
#include <symbols.h>
#include <timestamp.h>
#include <security/tpm/tis.h>
#include <security/tpm/tss.h>
#include <security/tpm/tspi.h>
#include <security/vboot/vboot_common.h>
#include <vb2_api.h>
@@ -152,9 +151,9 @@ static void do_fsp_post_memory_init(bool s3wake, uint32_t fsp_version)
* Initialize the TPM, unless the TPM was already initialized
* in verstage and used to verify romstage.
*/
if (IS_ENABLED(CONFIG_LPC_TPM) &&
if ((IS_ENABLED(CONFIG_TPM1) || IS_ENABLED(CONFIG_TPM2)) &&
!IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
init_tpm(s3wake);
tpm_setup(s3wake);
}
static int mrc_cache_verify_tpm_hash(const uint8_t *data, size_t size)

View File

@@ -1,11 +1,8 @@
config LPC_TPM
bool "Enable TPM support"
depends on MAINBOARD_HAS_LPC_TPM
bool
default n
help
Enable this option to enable LPC TPM support in coreboot.
If unsure, say N.
LPC TPM driver is enabled!
config TPM_TIS_BASE_ADDRESS
hex
@@ -25,33 +22,9 @@ config TPM_PIRQ
This can be used to specify a PIRQ to use instead of SERIRQ,
which is needed for SPI TPM interrupt support on x86.
config TPM_INIT_FAILURE_IS_FATAL
config MAINBOARD_HAS_LPC_TPM
bool
default n
depends on LPC_TPM
select 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.
config TPM_RDRESP_NEED_DELAY
bool "Enable Delay Workaround for TPM"
default n
depends on LPC_TPM
help
Certain TPMs seem to need some delay when reading response
to work around a race-condition-related issue, possibly
caused by ill-programmed TPM firmware.
Board has LPC TPM support

View File

@@ -1,8 +1,3 @@
ifeq ($(CONFIG_ARCH_X86),y)
verstage-$(CONFIG_LPC_TPM) += tis.c
romstage-$(CONFIG_LPC_TPM) += tis.c
ramstage-$(CONFIG_LPC_TPM) += tis.c
romstage-$(CONFIG_LPC_TPM) += romstage.c
endif

View File

@@ -1,253 +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.
*/
#include <types.h>
#include <console/cbmem_console.h>
#include <console/console.h>
#include <arch/acpi.h>
#include <security/tpm/tis.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 (IS_ENABLED(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");
tis_close();
return;
}
} else {
printk(BIOS_SPEW, "TPM: Startup\n");
result = TlclSendReceive(tpm_startup_cmd.buffer,
response, sizeof(response));
}
tis_close();
if (result == TPM_SUCCESS) {
printk(BIOS_SPEW, "TPM: OK.\n");
return;
}
printk(BIOS_ERR, "TPM: Error code 0x%x.\n", result);
if (IS_ENABLED(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();
}
}

View File

@@ -1,6 +1,7 @@
config SPI_TPM
bool "SPI TPM"
depends on TPM2
bool
help
SPI TPM driver is enabled!
config DRIVER_TPM_SPI_BUS
hex "SPI bus TPM chip is connected to"
@@ -15,3 +16,6 @@ config DRIVER_TPM_SPI_CHIP
config MAINBOARD_HAS_SPI_TPM_CR50
bool
default n
select SPI_TPM
help
Board has SPI TPM support

View File

@@ -1,9 +1,4 @@
bootblock-$(CONFIG_SPI_TPM) += tis.c tpm.c
verstage-$(CONFIG_SPI_TPM) += tis.c tpm.c
romstage-$(CONFIG_SPI_TPM) += tis.c tpm.c
ramstage-$(CONFIG_SPI_TPM) += tis.c tpm.c
ifneq ($(CONFIG_CHROMEOS),y)
bootblock-$(CONFIG_SPI_TPM) += tis.c tpm.c
romstage-$(CONFIG_SPI_TPM) += tis.c tpm.c
ramstage-$(CONFIG_SPI_TPM) += tis.c tpm.c
endif