2020-10-31 16:47:22

by Daniel P. Smith

[permalink] [raw]
Subject: [RFC PATCH 0/4] Secure Launch early PCR extend support

This RFC is a break out of the prerequisite TPM functionality for the larger
Secure Launch capability. This TPM/PCR subset is in a separate smaller patch set
being sent as an RFC to get early feedback before the whole Secure Launch patch
set is resubmitted. This patch RFC, if accepted, will be part of the overall
Secure Launch patch set.

TPMs support numerous operations, the majority of which will never be used by
the Secure Launch feature in the compressed kernel. Given that, this RFC does
not seek to implement a TPM driver but merely enough logic for the PCR extend
operation with a reasonable reuse of the mainline TPM driver.

In this RFC is the early_pcr_extend functionality that is built from shared
headers with the mainline TPM driver for common definitions and TPM buffer
functionality. The early_pcr_extend balances the introduction of new logic to
communicate with the TPM without having to introduce unrelated hardware features
not already available under the compressed kernel. The target usage of
early_pcr_extend is to support DRTM capable hardware under Secure Launch.
Historically the authors have not encountered any DRTM capable hardware that
uses any other interface other than the TPM Interface Specification (TIS) FIFO
software interface. To minimize the impact to code size and avoid unnecessary
functionality in the compressed kernel, the early_pcr_extend provides a very
limited implementation of the FIFO interface necessary to set locality and carry
out the extend operation.

For the sake of completeness, a discussion on the proposed refactoring of the
mainline driver FIFO and TPM command handling for reuse in the compressed kernel
needs to be addressed. After reviewing the mainline TPM driver for a second
time, we have arrived at the conclusion that the driver is too entangled with
the mainline kernel functionality which makes refactoring highly impractical.
The following are a few examples of this entanglement. The mainline TPM driver
is built around the tpm_chip structure which uses definitions not available in
the compressed kernel. It is likely that bringing these definitions into the
compressed kernel purely to make the tpm_chip structure available, would be
found to be unacceptable. Therefore it would be necessary to create a compressed
kernel representation which would end up with a majority of tpm_chip structure
being stubbed out since very little of this abstraction is required for the one
TPM command that will be used. Another concern is that the mainline TPM driver
FIFO interface is heavily reliant on timers implemented with mainline kernel
jiffies for interacting with the TPM. The compressed kernel does not have access
to jiffies. In the compressed kernel, jiffies have not been initialized and
timers have not been started. Therefore the use of jiffies would have to be
abstracted out of the mainline TPM driver resulting in a significant refactoring
or borderline rewrite of the driver.

We believe that the approach we are presenting here should be satisfactory. We
feel it is clear that we are not trying to create a new TPM driver. We have
split up the TPM headers to be able to reuse almost all the needed definitions/
structures. In addition, we switched to using the mainline TPM driver's buffer
functions. The remaining code to do the extend is minimal and appropriate for
the compressed kernel environment.

Thank you,
Daniel P. Smith and Ross Philipson

Daniel P. Smith (4):
tpm: Move TPM TIS definitions out of TIS core header
tpm: Move core definitions and buffer management out of main TPM
header
tpm: Conditionally use static buffer in TPM buffer management
x86: Add early PCR extend support for Secure Launch

arch/x86/boot/compressed/Makefile | 2 +
arch/x86/boot/compressed/early_pcr_extend.c | 311 ++++++++++++++++++++++++++++
arch/x86/boot/compressed/early_pcr_extend.h | 92 ++++++++
drivers/char/tpm/tpm_tis_core.h | 60 +-----
drivers/char/tpm/tpm_tis_defs.h | 81 ++++++++
include/linux/tpm.h | 269 +-----------------------
include/linux/tpm_buffer.h | 135 ++++++++++++
include/linux/tpm_core.h | 185 +++++++++++++++++
8 files changed, 809 insertions(+), 326 deletions(-)
create mode 100644 arch/x86/boot/compressed/early_pcr_extend.c
create mode 100644 arch/x86/boot/compressed/early_pcr_extend.h
create mode 100644 drivers/char/tpm/tpm_tis_defs.h
create mode 100644 include/linux/tpm_buffer.h
create mode 100644 include/linux/tpm_core.h

--
2.11.0


2020-10-31 16:48:02

by Daniel P. Smith

[permalink] [raw]
Subject: [RFC PATCH 1/4] tpm: Move TPM TIS definitions out of TIS core header

Move definitions from drivers/char/tpm/tpm_tis_core.h to new file
drivers/char/tpm/tpm_tis_defs.h. This allows tpm_tis_defs.h to be included
in the Secure Launch early PCR extend module. The rest of tpm_tis_core.h
cannot be included in the compressed kernel environment.

Signed-off-by: Daniel P. Smith <[email protected]>
Signed-off-by: Ross Philipson <[email protected]>
---
drivers/char/tpm/tpm_tis_core.h | 60 +-----------------------------
drivers/char/tpm/tpm_tis_defs.h | 81 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+), 59 deletions(-)
create mode 100644 drivers/char/tpm/tpm_tis_defs.h

diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 7337819f5d7b..daf293dfc570 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -20,65 +20,7 @@
#define __TPM_TIS_CORE_H__

#include "tpm.h"
-
-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,
-};
-
-enum tis_int_flags {
- TPM_GLOBAL_INT_ENABLE = 0x80000000,
- TPM_INTF_BURST_COUNT_STATIC = 0x100,
- TPM_INTF_CMD_READY_INT = 0x080,
- TPM_INTF_INT_EDGE_FALLING = 0x040,
- TPM_INTF_INT_EDGE_RISING = 0x020,
- TPM_INTF_INT_LEVEL_LOW = 0x010,
- TPM_INTF_INT_LEVEL_HIGH = 0x008,
- TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
- TPM_INTF_STS_VALID_INT = 0x002,
- TPM_INTF_DATA_AVAIL_INT = 0x001,
-};
-
-enum tis_defaults {
- TIS_MEM_LEN = 0x5000,
- TIS_SHORT_TIMEOUT = 750, /* ms */
- TIS_LONG_TIMEOUT = 2000, /* 2 sec */
-};
-
-/* Some timeout values are needed before it is known whether the chip is
- * TPM 1.0 or TPM 2.0.
- */
-#define TIS_TIMEOUT_A_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
-#define TIS_TIMEOUT_B_MAX max_t(int, TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
-#define TIS_TIMEOUT_C_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
-#define TIS_TIMEOUT_D_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
-
-#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
-#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
-#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
-#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
-#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
-#define TPM_STS(l) (0x0018 | ((l) << 12))
-#define TPM_STS3(l) (0x001b | ((l) << 12))
-#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
-
-#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
-#define TPM_RID(l) (0x0F04 | ((l) << 12))
-
-#define LPC_CNTRL_OFFSET 0x84
-#define LPC_CLKRUN_EN (1 << 2)
-#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
-#define ILB_REMAP_SIZE 0x100
+#include "tpm_tis_defs.h"

enum tpm_tis_flags {
TPM_TIS_ITPM_WORKAROUND = BIT(0),
diff --git a/drivers/char/tpm/tpm_tis_defs.h b/drivers/char/tpm/tpm_tis_defs.h
new file mode 100644
index 000000000000..9979e3eeb83c
--- /dev/null
+++ b/drivers/char/tpm/tpm_tis_defs.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2005, 2006 IBM Corporation
+ * Copyright (C) 2014, 2015 Intel Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <[email protected]>
+ * Kylene Hall <[email protected]>
+ *
+ * Maintained by: <[email protected]>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at http://www.trustedcomputinggroup.org
+ *
+ * This device driver implements the TPM interface as defined in
+ * the TCG TPM Interface Spec version 1.2, revision 1.0.
+ */
+
+#ifndef __TPM_TIS_DEFS_H__
+#define __TPM_TIS_DEFS_H__
+
+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,
+};
+
+enum tis_int_flags {
+ TPM_GLOBAL_INT_ENABLE = 0x80000000,
+ TPM_INTF_BURST_COUNT_STATIC = 0x100,
+ TPM_INTF_CMD_READY_INT = 0x080,
+ TPM_INTF_INT_EDGE_FALLING = 0x040,
+ TPM_INTF_INT_EDGE_RISING = 0x020,
+ TPM_INTF_INT_LEVEL_LOW = 0x010,
+ TPM_INTF_INT_LEVEL_HIGH = 0x008,
+ TPM_INTF_LOCALITY_CHANGE_INT = 0x004,
+ TPM_INTF_STS_VALID_INT = 0x002,
+ TPM_INTF_DATA_AVAIL_INT = 0x001,
+};
+
+enum tis_defaults {
+ TIS_MEM_LEN = 0x5000,
+ TIS_SHORT_TIMEOUT = 750, /* ms */
+ TIS_LONG_TIMEOUT = 2000, /* 2 sec */
+};
+
+/* Some timeout values are needed before it is known whether the chip is
+ * TPM 1.0 or TPM 2.0.
+ */
+#define TIS_TIMEOUT_A_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
+#define TIS_TIMEOUT_B_MAX max_t(int, TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
+#define TIS_TIMEOUT_C_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
+#define TIS_TIMEOUT_D_MAX max_t(int, TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
+
+#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
+#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
+#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
+#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
+#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
+#define TPM_STS(l) (0x0018 | ((l) << 12))
+#define TPM_STS3(l) (0x001b | ((l) << 12))
+#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
+
+#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
+#define TPM_RID(l) (0x0F04 | ((l) << 12))
+
+#define LPC_CNTRL_OFFSET 0x84
+#define LPC_CLKRUN_EN (1 << 2)
+#define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000
+#define ILB_REMAP_SIZE 0x100
+
+#endif
--
2.11.0

2020-10-31 16:48:14

by Daniel P. Smith

[permalink] [raw]
Subject: [RFC PATCH 2/4] tpm: Move core definitions and buffer management out of main TPM header

Move core definitions from include/linux/tpm.h to new file
include/linux/tpm_core.h. Move buffer management code from
include/linux/tpm.h to new file include/linux/tpm_buffer.h.

This allows tpm_tis_defs.h to be included in the Secure Launch early PCR
extend module. The rest of tpm.h cannot be included in the compressed
kernel environment.

Signed-off-by: Daniel P. Smith <[email protected]>
Signed-off-by: Ross Philipson <[email protected]>
---
include/linux/tpm.h | 269 +--------------------------------------------
include/linux/tpm_buffer.h | 123 +++++++++++++++++++++
include/linux/tpm_core.h | 185 +++++++++++++++++++++++++++++++
3 files changed, 310 insertions(+), 267 deletions(-)
create mode 100644 include/linux/tpm_buffer.h
create mode 100644 include/linux/tpm_core.h

diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 8f4ff39f51e7..a8e3a19caa98 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -23,40 +23,13 @@
#include <linux/fs.h>
#include <linux/highmem.h>
#include <crypto/hash_info.h>
-
-#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
-#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+#include <linux/tpm_buffer.h>
+#include <linux/tpm_core.h>

struct tpm_chip;
struct trusted_key_payload;
struct trusted_key_options;

-enum tpm_algorithms {
- TPM_ALG_ERROR = 0x0000,
- TPM_ALG_SHA1 = 0x0004,
- TPM_ALG_KEYEDHASH = 0x0008,
- TPM_ALG_SHA256 = 0x000B,
- TPM_ALG_SHA384 = 0x000C,
- TPM_ALG_SHA512 = 0x000D,
- TPM_ALG_NULL = 0x0010,
- TPM_ALG_SM3_256 = 0x0012,
-};
-
-struct tpm_digest {
- u16 alg_id;
- u8 digest[TPM_MAX_DIGEST_SIZE];
-} __packed;
-
-struct tpm_bank_info {
- u16 alg_id;
- u16 digest_size;
- u16 crypto_id;
-};
-
-enum TPM_OPS_FLAGS {
- TPM_OPS_AUTO_STARTUP = BIT(0),
-};
-
struct tpm_class_ops {
unsigned int flags;
const u8 req_complete_mask;
@@ -79,26 +52,6 @@ struct tpm_class_ops {

#define TPM_NUM_EVENT_LOG_FILES 3

-/* Indexes the duration array */
-enum tpm_duration {
- TPM_SHORT = 0,
- TPM_MEDIUM = 1,
- TPM_LONG = 2,
- TPM_LONG_LONG = 3,
- TPM_UNDEFINED,
- TPM_NUM_DURATIONS = TPM_UNDEFINED,
-};
-
-#define TPM_PPI_VERSION_LEN 3
-
-struct tpm_space {
- u32 context_tbl[3];
- u8 *context_buf;
- u32 session_tbl[3];
- u8 *session_buf;
- u32 buf_size;
-};
-
struct tpm_bios_log {
void *bios_event_log;
void *bios_event_log_end;
@@ -165,104 +118,6 @@ struct tpm_chip {
int locality;
};

-#define TPM_HEADER_SIZE 10
-
-enum tpm2_const {
- TPM2_PLATFORM_PCR = 24,
- TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
-};
-
-enum tpm2_timeouts {
- TPM2_TIMEOUT_A = 750,
- TPM2_TIMEOUT_B = 2000,
- TPM2_TIMEOUT_C = 200,
- TPM2_TIMEOUT_D = 30,
- TPM2_DURATION_SHORT = 20,
- TPM2_DURATION_MEDIUM = 750,
- TPM2_DURATION_LONG = 2000,
- TPM2_DURATION_LONG_LONG = 300000,
- TPM2_DURATION_DEFAULT = 120000,
-};
-
-enum tpm2_structures {
- TPM2_ST_NO_SESSIONS = 0x8001,
- TPM2_ST_SESSIONS = 0x8002,
-};
-
-/* Indicates from what layer of the software stack the error comes from */
-#define TSS2_RC_LAYER_SHIFT 16
-#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
-
-enum tpm2_return_codes {
- TPM2_RC_SUCCESS = 0x0000,
- TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
- TPM2_RC_HANDLE = 0x008B,
- TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
- TPM2_RC_FAILURE = 0x0101,
- TPM2_RC_DISABLED = 0x0120,
- TPM2_RC_COMMAND_CODE = 0x0143,
- TPM2_RC_TESTING = 0x090A, /* RC_WARN */
- TPM2_RC_REFERENCE_H0 = 0x0910,
- TPM2_RC_RETRY = 0x0922,
-};
-
-enum tpm2_command_codes {
- TPM2_CC_FIRST = 0x011F,
- TPM2_CC_HIERARCHY_CONTROL = 0x0121,
- TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
- TPM2_CC_CREATE_PRIMARY = 0x0131,
- TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
- TPM2_CC_SELF_TEST = 0x0143,
- TPM2_CC_STARTUP = 0x0144,
- TPM2_CC_SHUTDOWN = 0x0145,
- TPM2_CC_NV_READ = 0x014E,
- TPM2_CC_CREATE = 0x0153,
- TPM2_CC_LOAD = 0x0157,
- TPM2_CC_SEQUENCE_UPDATE = 0x015C,
- TPM2_CC_UNSEAL = 0x015E,
- TPM2_CC_CONTEXT_LOAD = 0x0161,
- TPM2_CC_CONTEXT_SAVE = 0x0162,
- TPM2_CC_FLUSH_CONTEXT = 0x0165,
- TPM2_CC_VERIFY_SIGNATURE = 0x0177,
- TPM2_CC_GET_CAPABILITY = 0x017A,
- TPM2_CC_GET_RANDOM = 0x017B,
- TPM2_CC_PCR_READ = 0x017E,
- TPM2_CC_PCR_EXTEND = 0x0182,
- TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
- TPM2_CC_HASH_SEQUENCE_START = 0x0186,
- TPM2_CC_CREATE_LOADED = 0x0191,
- TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
-};
-
-enum tpm2_permanent_handles {
- TPM2_RS_PW = 0x40000009,
-};
-
-enum tpm2_capabilities {
- TPM2_CAP_HANDLES = 1,
- TPM2_CAP_COMMANDS = 2,
- TPM2_CAP_PCRS = 5,
- TPM2_CAP_TPM_PROPERTIES = 6,
-};
-
-enum tpm2_properties {
- TPM_PT_TOTAL_COMMANDS = 0x0129,
-};
-
-enum tpm2_startup_types {
- TPM2_SU_CLEAR = 0x0000,
- TPM2_SU_STATE = 0x0001,
-};
-
-enum tpm2_cc_attrs {
- TPM2_CC_ATTR_CHANDLES = 25,
- TPM2_CC_ATTR_RHANDLE = 28,
-};
-
-#define TPM_VID_INTEL 0x8086
-#define TPM_VID_WINBOND 0x1050
-#define TPM_VID_STM 0x104A
-
enum tpm_chip_flags {
TPM_CHIP_FLAG_TPM2 = BIT(1),
TPM_CHIP_FLAG_IRQ = BIT(2),
@@ -274,126 +129,6 @@ enum tpm_chip_flags {

#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)

-struct tpm_header {
- __be16 tag;
- __be32 length;
- union {
- __be32 ordinal;
- __be32 return_code;
- };
-} __packed;
-
-/* A string buffer type for constructing TPM commands. This is based on the
- * ideas of string buffer code in security/keys/trusted.h but is heap based
- * in order to keep the stack usage minimal.
- */
-
-enum tpm_buf_flags {
- TPM_BUF_OVERFLOW = BIT(0),
-};
-
-struct tpm_buf {
- unsigned int flags;
- u8 *data;
-};
-
-enum tpm2_object_attributes {
- TPM2_OA_USER_WITH_AUTH = BIT(6),
-};
-
-enum tpm2_session_attributes {
- TPM2_SA_CONTINUE_SESSION = BIT(0),
-};
-
-struct tpm2_hash {
- unsigned int crypto_id;
- unsigned int tpm_id;
-};
-
-static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- head->tag = cpu_to_be16(tag);
- head->length = cpu_to_be32(sizeof(*head));
- head->ordinal = cpu_to_be32(ordinal);
-}
-
-static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
-{
- buf->data = (u8 *)__get_free_page(GFP_KERNEL);
- if (!buf->data)
- return -ENOMEM;
-
- buf->flags = 0;
- tpm_buf_reset(buf, tag, ordinal);
- return 0;
-}
-
-static inline void tpm_buf_destroy(struct tpm_buf *buf)
-{
- free_page((unsigned long)buf->data);
-}
-
-static inline u32 tpm_buf_length(struct tpm_buf *buf)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- return be32_to_cpu(head->length);
-}
-
-static inline u16 tpm_buf_tag(struct tpm_buf *buf)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
-
- return be16_to_cpu(head->tag);
-}
-
-static inline void tpm_buf_append(struct tpm_buf *buf,
- const unsigned char *new_data,
- unsigned int new_len)
-{
- struct tpm_header *head = (struct tpm_header *)buf->data;
- u32 len = tpm_buf_length(buf);
-
- /* Return silently if overflow has already happened. */
- if (buf->flags & TPM_BUF_OVERFLOW)
- return;
-
- if ((len + new_len) > PAGE_SIZE) {
- WARN(1, "tpm_buf: overflow\n");
- buf->flags |= TPM_BUF_OVERFLOW;
- return;
- }
-
- memcpy(&buf->data[len], new_data, new_len);
- head->length = cpu_to_be32(len + new_len);
-}
-
-static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
-{
- tpm_buf_append(buf, &value, 1);
-}
-
-static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
-{
- __be16 value2 = cpu_to_be16(value);
-
- tpm_buf_append(buf, (u8 *) &value2, 2);
-}
-
-static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
-{
- __be32 value2 = cpu_to_be32(value);
-
- tpm_buf_append(buf, (u8 *) &value2, 4);
-}
-
-static inline u32 tpm2_rc_value(u32 rc)
-{
- return (rc & BIT(7)) ? rc & 0xff : rc;
-}
-
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)

extern int tpm_is_tpm2(struct tpm_chip *chip);
diff --git a/include/linux/tpm_buffer.h b/include/linux/tpm_buffer.h
new file mode 100644
index 000000000000..8144a52fbc0a
--- /dev/null
+++ b/include/linux/tpm_buffer.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2004,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <[email protected]>
+ * Dave Safford <[email protected]>
+ * Reiner Sailer <[email protected]>
+ * Kylene Hall <[email protected]>
+ * Debora Velarde <[email protected]>
+ *
+ * Maintained by: <[email protected]>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at http://www.trustedcomputinggroup.org
+ */
+
+#ifndef __LINUX_TPM_BUFFER_H__
+#define __LINUX_TPM_BUFFER_H__
+
+struct tpm_header {
+ __be16 tag;
+ __be32 length;
+ union {
+ __be32 ordinal;
+ __be32 return_code;
+ };
+} __packed;
+
+/* A string buffer type for constructing TPM commands. This is based on the
+ * ideas of string buffer code in security/keys/trusted.h but is heap based
+ * in order to keep the stack usage minimal.
+ */
+
+enum tpm_buf_flags {
+ TPM_BUF_OVERFLOW = BIT(0),
+};
+
+struct tpm_buf {
+ unsigned int flags;
+ u8 *data;
+};
+
+static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ head->tag = cpu_to_be16(tag);
+ head->length = cpu_to_be32(sizeof(*head));
+ head->ordinal = cpu_to_be32(ordinal);
+}
+
+static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
+{
+ buf->data = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!buf->data)
+ return -ENOMEM;
+
+ buf->flags = 0;
+ tpm_buf_reset(buf, tag, ordinal);
+ return 0;
+}
+
+static inline void tpm_buf_destroy(struct tpm_buf *buf)
+{
+ free_page((unsigned long)buf->data);
+}
+
+static inline u32 tpm_buf_length(struct tpm_buf *buf)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ return be32_to_cpu(head->length);
+}
+
+static inline u16 tpm_buf_tag(struct tpm_buf *buf)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+
+ return be16_to_cpu(head->tag);
+}
+
+static inline void tpm_buf_append(struct tpm_buf *buf,
+ const unsigned char *new_data,
+ unsigned int new_len)
+{
+ struct tpm_header *head = (struct tpm_header *)buf->data;
+ u32 len = tpm_buf_length(buf);
+
+ /* Return silently if overflow has already happened. */
+ if (buf->flags & TPM_BUF_OVERFLOW)
+ return;
+
+ if ((len + new_len) > PAGE_SIZE) {
+ WARN(1, "tpm_buf: overflow\n");
+ buf->flags |= TPM_BUF_OVERFLOW;
+ return;
+ }
+
+ memcpy(&buf->data[len], new_data, new_len);
+ head->length = cpu_to_be32(len + new_len);
+}
+
+static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
+{
+ tpm_buf_append(buf, &value, 1);
+}
+
+static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
+{
+ __be16 value2 = cpu_to_be16(value);
+
+ tpm_buf_append(buf, (u8 *) &value2, 2);
+}
+
+static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
+{
+ __be32 value2 = cpu_to_be32(value);
+
+ tpm_buf_append(buf, (u8 *) &value2, 4);
+}
+
+#endif
diff --git a/include/linux/tpm_core.h b/include/linux/tpm_core.h
new file mode 100644
index 000000000000..292f96ae2ce4
--- /dev/null
+++ b/include/linux/tpm_core.h
@@ -0,0 +1,185 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2004,2007,2008 IBM Corporation
+ *
+ * Authors:
+ * Leendert van Doorn <[email protected]>
+ * Dave Safford <[email protected]>
+ * Reiner Sailer <[email protected]>
+ * Kylene Hall <[email protected]>
+ * Debora Velarde <[email protected]>
+ *
+ * Maintained by: <[email protected]>
+ *
+ * Device driver for TCG/TCPA TPM (trusted platform module).
+ * Specifications at http://www.trustedcomputinggroup.org
+ */
+#ifndef __LINUX_TPM_CORE_H__
+#define __LINUX_TPM_CORE_H__
+
+#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
+#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+
+enum tpm_algorithms {
+ TPM_ALG_ERROR = 0x0000,
+ TPM_ALG_SHA1 = 0x0004,
+ TPM_ALG_KEYEDHASH = 0x0008,
+ TPM_ALG_SHA256 = 0x000B,
+ TPM_ALG_SHA384 = 0x000C,
+ TPM_ALG_SHA512 = 0x000D,
+ TPM_ALG_NULL = 0x0010,
+ TPM_ALG_SM3_256 = 0x0012,
+};
+
+struct tpm_digest {
+ u16 alg_id;
+ u8 digest[TPM_MAX_DIGEST_SIZE];
+} __packed;
+
+struct tpm_bank_info {
+ u16 alg_id;
+ u16 digest_size;
+ u16 crypto_id;
+};
+
+enum TPM_OPS_FLAGS {
+ TPM_OPS_AUTO_STARTUP = BIT(0),
+};
+
+/* Indexes the duration array */
+enum tpm_duration {
+ TPM_SHORT = 0,
+ TPM_MEDIUM = 1,
+ TPM_LONG = 2,
+ TPM_LONG_LONG = 3,
+ TPM_UNDEFINED,
+ TPM_NUM_DURATIONS = TPM_UNDEFINED,
+};
+
+#define TPM_PPI_VERSION_LEN 3
+
+struct tpm_space {
+ u32 context_tbl[3];
+ u8 *context_buf;
+ u32 session_tbl[3];
+ u8 *session_buf;
+ u32 buf_size;
+};
+
+#define TPM_HEADER_SIZE 10
+
+enum tpm2_const {
+ TPM2_PLATFORM_PCR = 24,
+ TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
+};
+
+enum tpm2_timeouts {
+ TPM2_TIMEOUT_A = 750,
+ TPM2_TIMEOUT_B = 2000,
+ TPM2_TIMEOUT_C = 200,
+ TPM2_TIMEOUT_D = 30,
+ TPM2_DURATION_SHORT = 20,
+ TPM2_DURATION_MEDIUM = 750,
+ TPM2_DURATION_LONG = 2000,
+ TPM2_DURATION_LONG_LONG = 300000,
+ TPM2_DURATION_DEFAULT = 120000,
+};
+
+enum tpm2_structures {
+ TPM2_ST_NO_SESSIONS = 0x8001,
+ TPM2_ST_SESSIONS = 0x8002,
+};
+
+/* Indicates from what layer of the software stack the error comes from */
+#define TSS2_RC_LAYER_SHIFT 16
+#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
+
+enum tpm2_return_codes {
+ TPM2_RC_SUCCESS = 0x0000,
+ TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
+ TPM2_RC_HANDLE = 0x008B,
+ TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
+ TPM2_RC_FAILURE = 0x0101,
+ TPM2_RC_DISABLED = 0x0120,
+ TPM2_RC_COMMAND_CODE = 0x0143,
+ TPM2_RC_TESTING = 0x090A, /* RC_WARN */
+ TPM2_RC_REFERENCE_H0 = 0x0910,
+ TPM2_RC_RETRY = 0x0922,
+};
+
+enum tpm2_command_codes {
+ TPM2_CC_FIRST = 0x011F,
+ TPM2_CC_HIERARCHY_CONTROL = 0x0121,
+ TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
+ TPM2_CC_CREATE_PRIMARY = 0x0131,
+ TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
+ TPM2_CC_SELF_TEST = 0x0143,
+ TPM2_CC_STARTUP = 0x0144,
+ TPM2_CC_SHUTDOWN = 0x0145,
+ TPM2_CC_NV_READ = 0x014E,
+ TPM2_CC_CREATE = 0x0153,
+ TPM2_CC_LOAD = 0x0157,
+ TPM2_CC_SEQUENCE_UPDATE = 0x015C,
+ TPM2_CC_UNSEAL = 0x015E,
+ TPM2_CC_CONTEXT_LOAD = 0x0161,
+ TPM2_CC_CONTEXT_SAVE = 0x0162,
+ TPM2_CC_FLUSH_CONTEXT = 0x0165,
+ TPM2_CC_VERIFY_SIGNATURE = 0x0177,
+ TPM2_CC_GET_CAPABILITY = 0x017A,
+ TPM2_CC_GET_RANDOM = 0x017B,
+ TPM2_CC_PCR_READ = 0x017E,
+ TPM2_CC_PCR_EXTEND = 0x0182,
+ TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
+ TPM2_CC_HASH_SEQUENCE_START = 0x0186,
+ TPM2_CC_CREATE_LOADED = 0x0191,
+ TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
+};
+
+enum tpm2_permanent_handles {
+ TPM2_RS_PW = 0x40000009,
+};
+
+enum tpm2_capabilities {
+ TPM2_CAP_HANDLES = 1,
+ TPM2_CAP_COMMANDS = 2,
+ TPM2_CAP_PCRS = 5,
+ TPM2_CAP_TPM_PROPERTIES = 6,
+};
+
+enum tpm2_properties {
+ TPM_PT_TOTAL_COMMANDS = 0x0129,
+};
+
+enum tpm2_startup_types {
+ TPM2_SU_CLEAR = 0x0000,
+ TPM2_SU_STATE = 0x0001,
+};
+
+enum tpm2_cc_attrs {
+ TPM2_CC_ATTR_CHANDLES = 25,
+ TPM2_CC_ATTR_RHANDLE = 28,
+};
+
+#define TPM_VID_INTEL 0x8086
+#define TPM_VID_WINBOND 0x1050
+#define TPM_VID_STM 0x104A
+
+enum tpm2_object_attributes {
+ TPM2_OA_USER_WITH_AUTH = BIT(6),
+};
+
+enum tpm2_session_attributes {
+ TPM2_SA_CONTINUE_SESSION = BIT(0),
+};
+
+struct tpm2_hash {
+ unsigned int crypto_id;
+ unsigned int tpm_id;
+};
+
+static inline u32 tpm2_rc_value(u32 rc)
+{
+ return (rc & BIT(7)) ? rc & 0xff : rc;
+}
+
+#endif
--
2.11.0

2020-10-31 16:49:35

by Daniel P. Smith

[permalink] [raw]
Subject: [RFC PATCH 4/4] x86: Add early PCR extend support for Secure Launch

Access to PCR extend functionality is needed early in the compressed
kernel so that Secure Launch can measure items into the DRTM PCRs
before these items are used. The items include the boot parameters and
associated information, the kernel command line, any external initrd
and the OS-MLE TXT heap structure.

NOTE: for the RFC, early_pcr_extend.c is built unconditionally in the
Makefile. In the full Secure Launch patch set it is conditionally built
if CONFIG_SECURE_LAUNCH is defined.

Signed-off-by: Daniel P. Smith <[email protected]>
Signed-off-by: Ross Philipson <[email protected]>
---
arch/x86/boot/compressed/Makefile | 2 +
arch/x86/boot/compressed/early_pcr_extend.c | 311 ++++++++++++++++++++++++++++
arch/x86/boot/compressed/early_pcr_extend.h | 92 ++++++++
3 files changed, 405 insertions(+)
create mode 100644 arch/x86/boot/compressed/early_pcr_extend.c
create mode 100644 arch/x86/boot/compressed/early_pcr_extend.h

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 5a828fde7a42..8f0b29dce9da 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -93,6 +93,8 @@ vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a

+vmlinux-objs-y += $(obj)/early_pcr_extend.o
+
# The compressed kernel is built with -fPIC/-fPIE so that a boot loader
# can place it anywhere in memory and it will still run. However, since
# it is executed as-is without any ELF relocation processing performed
diff --git a/arch/x86/boot/compressed/early_pcr_extend.c b/arch/x86/boot/compressed/early_pcr_extend.c
new file mode 100644
index 000000000000..94ee3cc9814e
--- /dev/null
+++ b/arch/x86/boot/compressed/early_pcr_extend.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2020 Apertus Solutions, LLC
+ *
+ * Author(s):
+ * Daniel P. Smith <[email protected]>
+ *
+ * The code in this file is based on the article "Writing a TPM Device Driver"
+ * published on http://ptgmedia.pearsoncmg.com.
+ *
+ * The scope of the TPM functionality here is solely to allow DRTM PCRs to be
+ * extended early in the compressed kernel.
+ */
+
+#include <linux/types.h>
+#include <linux/bits.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#define COMPRESSED_KERNEL
+#include <crypto/sha.h>
+#include <linux/tpm_buffer.h>
+#include <linux/tpm_command.h>
+#include <linux/tpm_core.h>
+#include "../../../../drivers/char/tpm/tpm_tis_defs.h"
+#include "early_pcr_extend.h"
+
+#define tpm_read8(f) readb((void *)(u64)(TPM_MMIO_BASE | f))
+#define tpm_write8(v, f) writeb(v, (void *)(u64)(TPM_MMIO_BASE | f))
+#define tpm_read32(f) readl((void *)(u64)(TPM_MMIO_BASE | f));
+
+static struct tpm tpm;
+static u8 locality = TPM_NO_LOCALITY;
+
+static void tpm_io_delay(void)
+{
+ /* This is the default delay type in native_io_delay */
+ asm volatile ("outb %al, $0x80");
+}
+
+static void tpm_udelay(int loops)
+{
+ while (loops--)
+ tpm_io_delay(); /* Approximately 1 us */
+}
+
+static u32 burst_wait(void)
+{
+ u32 count = 0;
+
+ while (count == 0) {
+ count = tpm_read8(TPM_STS(locality) + 1);
+ count += tpm_read8(TPM_STS(locality) + 2) << 8;
+
+ /* Wait for FIFO to drain */
+ if (count == 0)
+ tpm_udelay(TPM_BURST_MIN_DELAY);
+ }
+
+ return count;
+}
+
+static void tis_relinquish_locality(void)
+{
+ if (locality < TPM_MAX_LOCALITY)
+ tpm_write8(TPM_ACCESS_ACTIVE_LOCALITY, TPM_ACCESS(locality));
+
+ locality = TPM_NO_LOCALITY;
+}
+
+static u8 tis_request_locality(u8 l)
+{
+ if (l > TPM_MAX_LOCALITY)
+ return TPM_NO_LOCALITY;
+
+ if (l == locality)
+ return locality;
+
+ tis_relinquish_locality();
+
+ tpm_write8(TPM_ACCESS_REQUEST_USE, TPM_ACCESS(l));
+
+ /* wait for locality to be granted */
+ if (tpm_read8(TPM_ACCESS(l)) & TPM_ACCESS_ACTIVE_LOCALITY)
+ locality = l;
+
+ return locality;
+}
+
+static size_t tis_send(struct tpm_buf *buf)
+{
+ u8 status, *buf_ptr;
+ u32 length, count = 0, burstcnt = 0;
+
+ if (locality > TPM_MAX_LOCALITY)
+ return 0;
+
+ for (status = 0; (status & TPM_STS_COMMAND_READY) == 0; ) {
+ tpm_write8(TPM_STS_COMMAND_READY, TPM_STS(locality));
+ status = tpm_read8(TPM_STS(locality));
+ }
+
+ buf_ptr = buf->data;
+ length = tpm_buf_length(buf);
+
+ /* send all but the last byte */
+ while (count < (length - 1)) {
+ burstcnt = burst_wait();
+ for (; burstcnt > 0 && count < (length - 1); burstcnt--) {
+ tpm_write8(buf_ptr[count], TPM_DATA_FIFO(locality));
+ count++;
+ }
+
+ /* check for overflow */
+ for (status = 0; (status & TPM_STS_VALID) == 0; )
+ status = tpm_read8(TPM_STS(locality));
+
+ if ((status & TPM_STS_DATA_EXPECT) == 0)
+ return 0;
+ }
+
+ /* write last byte */
+ tpm_write8(buf_ptr[length - 1], TPM_DATA_FIFO(locality));
+ count++;
+
+ /* make sure it stuck */
+ for (status = 0; (status & TPM_STS_VALID) == 0; )
+ status = tpm_read8(TPM_STS(locality));
+
+ if ((status & TPM_STS_DATA_EXPECT) != 0)
+ return 0;
+
+ /* go and do it */
+ tpm_write8(TPM_STS_GO, TPM_STS(locality));
+
+ return (size_t)count;
+}
+
+static u8 tis_init(struct tpm *t)
+{
+ locality = TPM_NO_LOCALITY;
+
+ if (tis_request_locality(0) != 0)
+ return 0;
+
+ t->vendor = tpm_read32(TPM_DID_VID(0));
+ if ((t->vendor & 0xFFFF) == 0xFFFF)
+ return 0;
+
+ return 1;
+}
+
+static u16 tpm_alg_size(u16 alg_id)
+{
+ if (alg_id == TPM_ALG_SHA1)
+ return SHA1_DIGEST_SIZE;
+ else if (alg_id == TPM_ALG_SHA256)
+ return SHA256_DIGEST_SIZE;
+ else if (alg_id == TPM_ALG_SHA512)
+ return SHA512_DIGEST_SIZE;
+
+ return 0;
+}
+
+static int tpm1_pcr_extend(struct tpm *t, u32 pcr, struct tpm_digest *d)
+{
+ struct tpm_buf buf;
+ int ret;
+
+ ret = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
+ if (ret)
+ return ret;
+
+ tpm_buf_append_u32(&buf, pcr);
+ tpm_buf_append(&buf, d->digest, tpm_alg_size(TPM_ALG_SHA1));
+
+ if (tpm_buf_length(&buf) != tis_send(&buf))
+ ret = -EAGAIN;
+
+ return ret;
+}
+
+static int tpm2_extend_pcr(struct tpm *t, u32 pcr, struct tpm_digest *digest)
+{
+ struct tpm_buf buf;
+ u8 auth_area[NULL_AUTH_SIZE] = {0};
+ u32 *handle;
+ int ret;
+
+ ret = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
+ if (ret)
+ return ret;
+
+ tpm_buf_append_u32(&buf, pcr);
+
+ /*
+ * The handle, the first element, is the
+ * only non-zero value in a NULL auth
+ */
+ handle = (u32 *)&auth_area;
+ *handle = cpu_to_be32(TPM2_RS_PW);
+
+ tpm_buf_append_u32(&buf, NULL_AUTH_SIZE);
+ tpm_buf_append(&buf, (const unsigned char *)&auth_area,
+ NULL_AUTH_SIZE);
+
+ tpm_buf_append_u32(&buf, 1);
+
+ tpm_buf_append_u16(&buf, digest->alg_id);
+ tpm_buf_append(&buf, (const unsigned char *)digest->digest,
+ tpm_alg_size(digest->alg_id));
+
+ if (tpm_buf_length(&buf) != tis_send(&buf))
+ ret = -EAGAIN;
+
+ return ret;
+}
+
+static void find_interface_and_family(struct tpm *t)
+{
+ struct tpm_interface_id intf_id;
+ struct tpm_intf_capability intf_cap;
+
+ /* Sort out whether if it is 1.2 */
+ intf_cap.val = tpm_read32(TPM_INTF_CAPABILITY_0);
+ if ((intf_cap.interface_version == TPM12_TIS_INTF_12) ||
+ (intf_cap.interface_version == TPM12_TIS_INTF_13)) {
+ t->family = TPM12;
+ t->intf = TPM_TIS;
+ return;
+ }
+
+ /* Assume that it is 2.0 and TIS */
+ t->family = TPM20;
+ t->intf = TPM_TIS;
+
+ /* Check if the interface is CRB */
+ intf_id.val = tpm_read32(TPM_INTERFACE_ID_0);
+ if (intf_id.interface_type == TPM_CRB_INTF_ACTIVE)
+ t->intf = TPM_CRB;
+}
+
+struct tpm *enable_tpm(void)
+{
+ struct tpm *t = &tpm;
+
+ find_interface_and_family(t);
+
+ switch (t->intf) {
+ case TPM_TIS:
+ if (!tis_init(t))
+ return NULL;
+ break;
+ case TPM_CRB:
+ return NULL;
+ }
+
+ return t;
+}
+
+u8 tpm_request_locality(u8 l)
+{
+ return tis_request_locality(l);
+}
+
+int tpm_extend_pcr(struct tpm *t, u32 pcr, u16 algo,
+ u8 *digest)
+{
+ int ret = -EINVAL;
+
+ if (t->family == TPM12) {
+ struct tpm_digest d;
+
+ if (algo != TPM_ALG_SHA1)
+ return -EINVAL;
+
+ memcpy((void *)d.digest, digest, SHA1_DIGEST_SIZE);
+
+ ret = tpm1_pcr_extend(t, pcr, &d);
+ } else if (t->family == TPM20) {
+ struct tpm_digest *d;
+ u8 buf[MAX_TPM_EXTEND_SIZE];
+
+ d = (struct tpm_digest *) buf;
+ d->alg_id = algo;
+ switch (algo) {
+ case TPM_ALG_SHA1:
+ memcpy(d->digest, digest, SHA1_DIGEST_SIZE);
+ break;
+ case TPM_ALG_SHA256:
+ memcpy(d->digest, digest, SHA256_DIGEST_SIZE);
+ break;
+ case TPM_ALG_SHA512:
+ memcpy(d->digest, digest, SHA512_DIGEST_SIZE);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = tpm2_extend_pcr(t, pcr, d);
+ }
+
+ return ret;
+}
+
+void free_tpm(void)
+{
+ tis_relinquish_locality();
+}
diff --git a/arch/x86/boot/compressed/early_pcr_extend.h b/arch/x86/boot/compressed/early_pcr_extend.h
new file mode 100644
index 000000000000..bcd6d57d8c56
--- /dev/null
+++ b/arch/x86/boot/compressed/early_pcr_extend.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2020 Apertus Solutions, LLC
+ *
+ * Author(s):
+ * Daniel P. Smith <[email protected]>
+ *
+ */
+
+#ifndef BOOT_COMPRESSED_EARLY_PCR_EXTEND_H
+#define BOOT_COMPRESSED_EARLY_PCR_EXTEND_H
+
+#define TPM_MMIO_BASE 0xFED40000
+#define TPM_MAX_LOCALITY 4
+#define TPM_NO_LOCALITY 0xFF
+#define TPM_BURST_MIN_DELAY 100 /* 100us */
+#define TPM_ORD_PCR_EXTEND 20
+#define NULL_AUTH_SIZE 9
+#define MAX_TPM_EXTEND_SIZE 68 /* TPM2 SHA512 is the largest */
+
+#define TPM_INTERFACE_ID_0 0x30
+#define TPM_TIS_INTF_ACTIVE 0x00
+#define TPM_CRB_INTF_ACTIVE 0x01
+
+struct tpm_interface_id {
+ union {
+ u32 val;
+ struct {
+ u32 interface_type:4;
+ u32 interface_version:4;
+ u32 cap_locality:1;
+ u32 reserved1:4;
+ u32 cap_tis:1;
+ u32 cap_crb:1;
+ u32 cap_if_res:2;
+ u32 interface_selector:2;
+ u32 intf_sel_lock:1;
+ u32 reserved2:4;
+ u32 reserved3:8;
+ };
+ };
+} __packed;
+
+#define TPM_INTF_CAPABILITY_0 0x14
+#define TPM12_TIS_INTF_12 0x00
+#define TPM12_TIS_INTF_13 0x02
+#define TPM20_TIS_INTF_13 0x03
+
+struct tpm_intf_capability {
+ union {
+ u32 val;
+ struct {
+ u32 data_avail_int_support:1;
+ u32 sts_valid_int_support:1;
+ u32 locality_change_int_support:1;
+ u32 interrupt_level_high:1;
+ u32 interrupt_level_low:1;
+ u32 interrupt_edge_rising:1;
+ u32 interrupt_edge_falling:1;
+ u32 command_ready_int_support:1;
+ u32 burst_count_static:1;
+ u32 data_transfer_size_support:2;
+ u32 reserved1:17;
+ u32 interface_version:3;
+ u32 reserved2:1;
+ };
+ };
+} __packed;
+
+enum tpm_hw_intf {
+ TPM_TIS,
+ TPM_CRB
+};
+
+enum tpm_family {
+ TPM12,
+ TPM20
+};
+
+struct tpm {
+ u32 vendor;
+ enum tpm_family family;
+ enum tpm_hw_intf intf;
+};
+
+extern struct tpm *enable_tpm(void);
+extern u8 tpm_request_locality(u8 l);
+extern int tpm_extend_pcr(struct tpm *t, u32 pcr, u16 algo,
+ u8 *digest);
+extern void free_tpm(void);
+
+#endif
--
2.11.0

2020-10-31 16:50:59

by Daniel P. Smith

[permalink] [raw]
Subject: [RFC PATCH 3/4] tpm: Conditionally use static buffer in TPM buffer management

Memory management calls cannot be made in the compressed kernel
environment to dynamically allocate TPM buffer space. For the Secure
Launch early PCR extend code, use a static buffer instead.

Signed-off-by: Daniel P. Smith <[email protected]>
Signed-off-by: Ross Philipson <[email protected]>
---
include/linux/tpm_buffer.h | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/include/linux/tpm_buffer.h b/include/linux/tpm_buffer.h
index 8144a52fbc0a..c9482edf6618 100644
--- a/include/linux/tpm_buffer.h
+++ b/include/linux/tpm_buffer.h
@@ -18,6 +18,10 @@
#ifndef __LINUX_TPM_BUFFER_H__
#define __LINUX_TPM_BUFFER_H__

+#ifdef COMPRESSED_KERNEL
+static u8 _tpm_buffer[PAGE_SIZE] = {0};
+#endif
+
struct tpm_header {
__be16 tag;
__be32 length;
@@ -52,7 +56,11 @@ static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)

static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
{
+#ifdef COMPRESSED_KERNEL
+ buf->data = _tpm_buffer;
+#else
buf->data = (u8 *)__get_free_page(GFP_KERNEL);
+#endif
if (!buf->data)
return -ENOMEM;

@@ -63,7 +71,9 @@ static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)

static inline void tpm_buf_destroy(struct tpm_buf *buf)
{
+#ifndef COMPRESSED_KERNEL
free_page((unsigned long)buf->data);
+#endif
}

static inline u32 tpm_buf_length(struct tpm_buf *buf)
@@ -92,7 +102,9 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
return;

if ((len + new_len) > PAGE_SIZE) {
+#ifndef COMPRESSED_KERNEL
WARN(1, "tpm_buf: overflow\n");
+#endif
buf->flags |= TPM_BUF_OVERFLOW;
return;
}
--
2.11.0

2020-11-02 12:11:46

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [RFC PATCH 2/4] tpm: Move core definitions and buffer management out of main TPM header

On Sat, Oct 31, 2020 at 12:51:20PM -0400, Daniel P. Smith wrote:
> Move core definitions from include/linux/tpm.h to new file
> include/linux/tpm_core.h. Move buffer management code from
> include/linux/tpm.h to new file include/linux/tpm_buffer.h.
>
> This allows tpm_tis_defs.h to be included in the Secure Launch early PCR
> extend module. The rest of tpm.h cannot be included in the compressed
> kernel environment.
>
> Signed-off-by: Daniel P. Smith <[email protected]>
> Signed-off-by: Ross Philipson <[email protected]>

Should be split into two patches. I would order them so that definitions
are moved in the first patch and tpm_buf in the second. Then it is
easier to review the changes as other tpm_buf changes follow in the
subsequent patch.

> ---
> include/linux/tpm.h | 269 +--------------------------------------------
> include/linux/tpm_buffer.h | 123 +++++++++++++++++++++

The filename should be tpm_buf.h (aligns with the struct name).

> include/linux/tpm_core.h | 185 +++++++++++++++++++++++++++++++

Dump these into tpm_command.h, which already has constants for TPM 1.2
trusted keys, instead of adding a new file.

> 3 files changed, 310 insertions(+), 267 deletions(-)
> create mode 100644 include/linux/tpm_buffer.h
> create mode 100644 include/linux/tpm_core.h
>
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index 8f4ff39f51e7..a8e3a19caa98 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -23,40 +23,13 @@
> #include <linux/fs.h>
> #include <linux/highmem.h>
> #include <crypto/hash_info.h>
> -
> -#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
> -#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
> +#include <linux/tpm_buffer.h>
> +#include <linux/tpm_core.h>
>
> struct tpm_chip;
> struct trusted_key_payload;
> struct trusted_key_options;
>
> -enum tpm_algorithms {
> - TPM_ALG_ERROR = 0x0000,
> - TPM_ALG_SHA1 = 0x0004,
> - TPM_ALG_KEYEDHASH = 0x0008,
> - TPM_ALG_SHA256 = 0x000B,
> - TPM_ALG_SHA384 = 0x000C,
> - TPM_ALG_SHA512 = 0x000D,
> - TPM_ALG_NULL = 0x0010,
> - TPM_ALG_SM3_256 = 0x0012,
> -};
> -
> -struct tpm_digest {
> - u16 alg_id;
> - u8 digest[TPM_MAX_DIGEST_SIZE];
> -} __packed;
> -
> -struct tpm_bank_info {
> - u16 alg_id;
> - u16 digest_size;
> - u16 crypto_id;
> -};
> -
> -enum TPM_OPS_FLAGS {
> - TPM_OPS_AUTO_STARTUP = BIT(0),
> -};
> -
> struct tpm_class_ops {
> unsigned int flags;
> const u8 req_complete_mask;
> @@ -79,26 +52,6 @@ struct tpm_class_ops {
>
> #define TPM_NUM_EVENT_LOG_FILES 3
>
> -/* Indexes the duration array */
> -enum tpm_duration {
> - TPM_SHORT = 0,
> - TPM_MEDIUM = 1,
> - TPM_LONG = 2,
> - TPM_LONG_LONG = 3,
> - TPM_UNDEFINED,
> - TPM_NUM_DURATIONS = TPM_UNDEFINED,
> -};
> -
> -#define TPM_PPI_VERSION_LEN 3
> -
> -struct tpm_space {
> - u32 context_tbl[3];
> - u8 *context_buf;
> - u32 session_tbl[3];
> - u8 *session_buf;
> - u32 buf_size;
> -};
> -
> struct tpm_bios_log {
> void *bios_event_log;
> void *bios_event_log_end;
> @@ -165,104 +118,6 @@ struct tpm_chip {
> int locality;
> };
>
> -#define TPM_HEADER_SIZE 10
> -
> -enum tpm2_const {
> - TPM2_PLATFORM_PCR = 24,
> - TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
> -};
> -
> -enum tpm2_timeouts {
> - TPM2_TIMEOUT_A = 750,
> - TPM2_TIMEOUT_B = 2000,
> - TPM2_TIMEOUT_C = 200,
> - TPM2_TIMEOUT_D = 30,
> - TPM2_DURATION_SHORT = 20,
> - TPM2_DURATION_MEDIUM = 750,
> - TPM2_DURATION_LONG = 2000,
> - TPM2_DURATION_LONG_LONG = 300000,
> - TPM2_DURATION_DEFAULT = 120000,
> -};
> -
> -enum tpm2_structures {
> - TPM2_ST_NO_SESSIONS = 0x8001,
> - TPM2_ST_SESSIONS = 0x8002,
> -};
> -
> -/* Indicates from what layer of the software stack the error comes from */
> -#define TSS2_RC_LAYER_SHIFT 16
> -#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
> -
> -enum tpm2_return_codes {
> - TPM2_RC_SUCCESS = 0x0000,
> - TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
> - TPM2_RC_HANDLE = 0x008B,
> - TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
> - TPM2_RC_FAILURE = 0x0101,
> - TPM2_RC_DISABLED = 0x0120,
> - TPM2_RC_COMMAND_CODE = 0x0143,
> - TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> - TPM2_RC_REFERENCE_H0 = 0x0910,
> - TPM2_RC_RETRY = 0x0922,
> -};
> -
> -enum tpm2_command_codes {
> - TPM2_CC_FIRST = 0x011F,
> - TPM2_CC_HIERARCHY_CONTROL = 0x0121,
> - TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
> - TPM2_CC_CREATE_PRIMARY = 0x0131,
> - TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
> - TPM2_CC_SELF_TEST = 0x0143,
> - TPM2_CC_STARTUP = 0x0144,
> - TPM2_CC_SHUTDOWN = 0x0145,
> - TPM2_CC_NV_READ = 0x014E,
> - TPM2_CC_CREATE = 0x0153,
> - TPM2_CC_LOAD = 0x0157,
> - TPM2_CC_SEQUENCE_UPDATE = 0x015C,
> - TPM2_CC_UNSEAL = 0x015E,
> - TPM2_CC_CONTEXT_LOAD = 0x0161,
> - TPM2_CC_CONTEXT_SAVE = 0x0162,
> - TPM2_CC_FLUSH_CONTEXT = 0x0165,
> - TPM2_CC_VERIFY_SIGNATURE = 0x0177,
> - TPM2_CC_GET_CAPABILITY = 0x017A,
> - TPM2_CC_GET_RANDOM = 0x017B,
> - TPM2_CC_PCR_READ = 0x017E,
> - TPM2_CC_PCR_EXTEND = 0x0182,
> - TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
> - TPM2_CC_HASH_SEQUENCE_START = 0x0186,
> - TPM2_CC_CREATE_LOADED = 0x0191,
> - TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
> -};
> -
> -enum tpm2_permanent_handles {
> - TPM2_RS_PW = 0x40000009,
> -};
> -
> -enum tpm2_capabilities {
> - TPM2_CAP_HANDLES = 1,
> - TPM2_CAP_COMMANDS = 2,
> - TPM2_CAP_PCRS = 5,
> - TPM2_CAP_TPM_PROPERTIES = 6,
> -};
> -
> -enum tpm2_properties {
> - TPM_PT_TOTAL_COMMANDS = 0x0129,
> -};
> -
> -enum tpm2_startup_types {
> - TPM2_SU_CLEAR = 0x0000,
> - TPM2_SU_STATE = 0x0001,
> -};
> -
> -enum tpm2_cc_attrs {
> - TPM2_CC_ATTR_CHANDLES = 25,
> - TPM2_CC_ATTR_RHANDLE = 28,
> -};
> -
> -#define TPM_VID_INTEL 0x8086
> -#define TPM_VID_WINBOND 0x1050
> -#define TPM_VID_STM 0x104A
> -
> enum tpm_chip_flags {
> TPM_CHIP_FLAG_TPM2 = BIT(1),
> TPM_CHIP_FLAG_IRQ = BIT(2),
> @@ -274,126 +129,6 @@ enum tpm_chip_flags {
>
> #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
>
> -struct tpm_header {
> - __be16 tag;
> - __be32 length;
> - union {
> - __be32 ordinal;
> - __be32 return_code;
> - };
> -} __packed;
> -
> -/* A string buffer type for constructing TPM commands. This is based on the
> - * ideas of string buffer code in security/keys/trusted.h but is heap based
> - * in order to keep the stack usage minimal.
> - */
> -
> -enum tpm_buf_flags {
> - TPM_BUF_OVERFLOW = BIT(0),
> -};
> -
> -struct tpm_buf {
> - unsigned int flags;
> - u8 *data;
> -};
> -
> -enum tpm2_object_attributes {
> - TPM2_OA_USER_WITH_AUTH = BIT(6),
> -};
> -
> -enum tpm2_session_attributes {
> - TPM2_SA_CONTINUE_SESSION = BIT(0),
> -};
> -
> -struct tpm2_hash {
> - unsigned int crypto_id;
> - unsigned int tpm_id;
> -};
> -
> -static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
> -{
> - struct tpm_header *head = (struct tpm_header *)buf->data;
> -
> - head->tag = cpu_to_be16(tag);
> - head->length = cpu_to_be32(sizeof(*head));
> - head->ordinal = cpu_to_be32(ordinal);
> -}
> -
> -static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
> -{
> - buf->data = (u8 *)__get_free_page(GFP_KERNEL);
> - if (!buf->data)
> - return -ENOMEM;
> -
> - buf->flags = 0;
> - tpm_buf_reset(buf, tag, ordinal);
> - return 0;
> -}
> -
> -static inline void tpm_buf_destroy(struct tpm_buf *buf)
> -{
> - free_page((unsigned long)buf->data);
> -}
> -
> -static inline u32 tpm_buf_length(struct tpm_buf *buf)
> -{
> - struct tpm_header *head = (struct tpm_header *)buf->data;
> -
> - return be32_to_cpu(head->length);
> -}
> -
> -static inline u16 tpm_buf_tag(struct tpm_buf *buf)
> -{
> - struct tpm_header *head = (struct tpm_header *)buf->data;
> -
> - return be16_to_cpu(head->tag);
> -}
> -
> -static inline void tpm_buf_append(struct tpm_buf *buf,
> - const unsigned char *new_data,
> - unsigned int new_len)
> -{
> - struct tpm_header *head = (struct tpm_header *)buf->data;
> - u32 len = tpm_buf_length(buf);
> -
> - /* Return silently if overflow has already happened. */
> - if (buf->flags & TPM_BUF_OVERFLOW)
> - return;
> -
> - if ((len + new_len) > PAGE_SIZE) {
> - WARN(1, "tpm_buf: overflow\n");
> - buf->flags |= TPM_BUF_OVERFLOW;
> - return;
> - }
> -
> - memcpy(&buf->data[len], new_data, new_len);
> - head->length = cpu_to_be32(len + new_len);
> -}
> -
> -static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
> -{
> - tpm_buf_append(buf, &value, 1);
> -}
> -
> -static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
> -{
> - __be16 value2 = cpu_to_be16(value);
> -
> - tpm_buf_append(buf, (u8 *) &value2, 2);
> -}
> -
> -static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
> -{
> - __be32 value2 = cpu_to_be32(value);
> -
> - tpm_buf_append(buf, (u8 *) &value2, 4);
> -}
> -
> -static inline u32 tpm2_rc_value(u32 rc)
> -{
> - return (rc & BIT(7)) ? rc & 0xff : rc;
> -}
> -
> #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
>
> extern int tpm_is_tpm2(struct tpm_chip *chip);
> diff --git a/include/linux/tpm_buffer.h b/include/linux/tpm_buffer.h
> new file mode 100644
> index 000000000000..8144a52fbc0a
> --- /dev/null
> +++ b/include/linux/tpm_buffer.h
> @@ -0,0 +1,123 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2004,2007,2008 IBM Corporation
> + *
> + * Authors:
> + * Leendert van Doorn <[email protected]>
> + * Dave Safford <[email protected]>
> + * Reiner Sailer <[email protected]>
> + * Kylene Hall <[email protected]>
> + * Debora Velarde <[email protected]>
> + *
> + * Maintained by: <[email protected]>
> + *
> + * Device driver for TCG/TCPA TPM (trusted platform module).
> + * Specifications at http://www.trustedcomputinggroup.org
> + */
> +
> +#ifndef __LINUX_TPM_BUFFER_H__
> +#define __LINUX_TPM_BUFFER_H__
> +
> +struct tpm_header {
> + __be16 tag;
> + __be32 length;
> + union {
> + __be32 ordinal;
> + __be32 return_code;
> + };
> +} __packed;
> +
> +/* A string buffer type for constructing TPM commands. This is based on the
> + * ideas of string buffer code in security/keys/trusted.h but is heap based
> + * in order to keep the stack usage minimal.
> + */
> +
> +enum tpm_buf_flags {
> + TPM_BUF_OVERFLOW = BIT(0),
> +};
> +
> +struct tpm_buf {
> + unsigned int flags;
> + u8 *data;
> +};
> +
> +static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
> +{
> + struct tpm_header *head = (struct tpm_header *)buf->data;
> +
> + head->tag = cpu_to_be16(tag);
> + head->length = cpu_to_be32(sizeof(*head));
> + head->ordinal = cpu_to_be32(ordinal);
> +}
> +
> +static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
> +{
> + buf->data = (u8 *)__get_free_page(GFP_KERNEL);
> + if (!buf->data)
> + return -ENOMEM;
> +
> + buf->flags = 0;
> + tpm_buf_reset(buf, tag, ordinal);
> + return 0;
> +}
> +
> +static inline void tpm_buf_destroy(struct tpm_buf *buf)
> +{
> + free_page((unsigned long)buf->data);
> +}
> +
> +static inline u32 tpm_buf_length(struct tpm_buf *buf)
> +{
> + struct tpm_header *head = (struct tpm_header *)buf->data;
> +
> + return be32_to_cpu(head->length);
> +}
> +
> +static inline u16 tpm_buf_tag(struct tpm_buf *buf)
> +{
> + struct tpm_header *head = (struct tpm_header *)buf->data;
> +
> + return be16_to_cpu(head->tag);
> +}
> +
> +static inline void tpm_buf_append(struct tpm_buf *buf,
> + const unsigned char *new_data,
> + unsigned int new_len)
> +{
> + struct tpm_header *head = (struct tpm_header *)buf->data;
> + u32 len = tpm_buf_length(buf);
> +
> + /* Return silently if overflow has already happened. */
> + if (buf->flags & TPM_BUF_OVERFLOW)
> + return;
> +
> + if ((len + new_len) > PAGE_SIZE) {
> + WARN(1, "tpm_buf: overflow\n");
> + buf->flags |= TPM_BUF_OVERFLOW;
> + return;
> + }
> +
> + memcpy(&buf->data[len], new_data, new_len);
> + head->length = cpu_to_be32(len + new_len);
> +}
> +
> +static inline void tpm_buf_append_u8(struct tpm_buf *buf, const u8 value)
> +{
> + tpm_buf_append(buf, &value, 1);
> +}
> +
> +static inline void tpm_buf_append_u16(struct tpm_buf *buf, const u16 value)
> +{
> + __be16 value2 = cpu_to_be16(value);
> +
> + tpm_buf_append(buf, (u8 *) &value2, 2);
> +}
> +
> +static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
> +{
> + __be32 value2 = cpu_to_be32(value);
> +
> + tpm_buf_append(buf, (u8 *) &value2, 4);
> +}
> +
> +#endif
> diff --git a/include/linux/tpm_core.h b/include/linux/tpm_core.h
> new file mode 100644
> index 000000000000..292f96ae2ce4
> --- /dev/null
> +++ b/include/linux/tpm_core.h
> @@ -0,0 +1,185 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2004,2007,2008 IBM Corporation
> + *
> + * Authors:
> + * Leendert van Doorn <[email protected]>
> + * Dave Safford <[email protected]>
> + * Reiner Sailer <[email protected]>
> + * Kylene Hall <[email protected]>
> + * Debora Velarde <[email protected]>
> + *
> + * Maintained by: <[email protected]>
> + *
> + * Device driver for TCG/TCPA TPM (trusted platform module).
> + * Specifications at http://www.trustedcomputinggroup.org
> + */
> +#ifndef __LINUX_TPM_CORE_H__
> +#define __LINUX_TPM_CORE_H__
> +
> +#define TPM_DIGEST_SIZE 20 /* Max TPM v1.2 PCR size */
> +#define TPM_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
> +
> +enum tpm_algorithms {
> + TPM_ALG_ERROR = 0x0000,
> + TPM_ALG_SHA1 = 0x0004,
> + TPM_ALG_KEYEDHASH = 0x0008,
> + TPM_ALG_SHA256 = 0x000B,
> + TPM_ALG_SHA384 = 0x000C,
> + TPM_ALG_SHA512 = 0x000D,
> + TPM_ALG_NULL = 0x0010,
> + TPM_ALG_SM3_256 = 0x0012,
> +};
> +
> +struct tpm_digest {
> + u16 alg_id;
> + u8 digest[TPM_MAX_DIGEST_SIZE];
> +} __packed;
> +
> +struct tpm_bank_info {
> + u16 alg_id;
> + u16 digest_size;
> + u16 crypto_id;
> +};
> +
> +enum TPM_OPS_FLAGS {
> + TPM_OPS_AUTO_STARTUP = BIT(0),
> +};
> +
> +/* Indexes the duration array */
> +enum tpm_duration {
> + TPM_SHORT = 0,
> + TPM_MEDIUM = 1,
> + TPM_LONG = 2,
> + TPM_LONG_LONG = 3,
> + TPM_UNDEFINED,
> + TPM_NUM_DURATIONS = TPM_UNDEFINED,
> +};
> +
> +#define TPM_PPI_VERSION_LEN 3
> +
> +struct tpm_space {
> + u32 context_tbl[3];
> + u8 *context_buf;
> + u32 session_tbl[3];
> + u8 *session_buf;
> + u32 buf_size;
> +};
> +
> +#define TPM_HEADER_SIZE 10
> +
> +enum tpm2_const {
> + TPM2_PLATFORM_PCR = 24,
> + TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
> +};
> +
> +enum tpm2_timeouts {
> + TPM2_TIMEOUT_A = 750,
> + TPM2_TIMEOUT_B = 2000,
> + TPM2_TIMEOUT_C = 200,
> + TPM2_TIMEOUT_D = 30,
> + TPM2_DURATION_SHORT = 20,
> + TPM2_DURATION_MEDIUM = 750,
> + TPM2_DURATION_LONG = 2000,
> + TPM2_DURATION_LONG_LONG = 300000,
> + TPM2_DURATION_DEFAULT = 120000,
> +};
> +
> +enum tpm2_structures {
> + TPM2_ST_NO_SESSIONS = 0x8001,
> + TPM2_ST_SESSIONS = 0x8002,
> +};
> +
> +/* Indicates from what layer of the software stack the error comes from */
> +#define TSS2_RC_LAYER_SHIFT 16
> +#define TSS2_RESMGR_TPM_RC_LAYER (11 << TSS2_RC_LAYER_SHIFT)
> +
> +enum tpm2_return_codes {
> + TPM2_RC_SUCCESS = 0x0000,
> + TPM2_RC_HASH = 0x0083, /* RC_FMT1 */
> + TPM2_RC_HANDLE = 0x008B,
> + TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
> + TPM2_RC_FAILURE = 0x0101,
> + TPM2_RC_DISABLED = 0x0120,
> + TPM2_RC_COMMAND_CODE = 0x0143,
> + TPM2_RC_TESTING = 0x090A, /* RC_WARN */
> + TPM2_RC_REFERENCE_H0 = 0x0910,
> + TPM2_RC_RETRY = 0x0922,
> +};
> +
> +enum tpm2_command_codes {
> + TPM2_CC_FIRST = 0x011F,
> + TPM2_CC_HIERARCHY_CONTROL = 0x0121,
> + TPM2_CC_HIERARCHY_CHANGE_AUTH = 0x0129,
> + TPM2_CC_CREATE_PRIMARY = 0x0131,
> + TPM2_CC_SEQUENCE_COMPLETE = 0x013E,
> + TPM2_CC_SELF_TEST = 0x0143,
> + TPM2_CC_STARTUP = 0x0144,
> + TPM2_CC_SHUTDOWN = 0x0145,
> + TPM2_CC_NV_READ = 0x014E,
> + TPM2_CC_CREATE = 0x0153,
> + TPM2_CC_LOAD = 0x0157,
> + TPM2_CC_SEQUENCE_UPDATE = 0x015C,
> + TPM2_CC_UNSEAL = 0x015E,
> + TPM2_CC_CONTEXT_LOAD = 0x0161,
> + TPM2_CC_CONTEXT_SAVE = 0x0162,
> + TPM2_CC_FLUSH_CONTEXT = 0x0165,
> + TPM2_CC_VERIFY_SIGNATURE = 0x0177,
> + TPM2_CC_GET_CAPABILITY = 0x017A,
> + TPM2_CC_GET_RANDOM = 0x017B,
> + TPM2_CC_PCR_READ = 0x017E,
> + TPM2_CC_PCR_EXTEND = 0x0182,
> + TPM2_CC_EVENT_SEQUENCE_COMPLETE = 0x0185,
> + TPM2_CC_HASH_SEQUENCE_START = 0x0186,
> + TPM2_CC_CREATE_LOADED = 0x0191,
> + TPM2_CC_LAST = 0x0193, /* Spec 1.36 */
> +};
> +
> +enum tpm2_permanent_handles {
> + TPM2_RS_PW = 0x40000009,
> +};
> +
> +enum tpm2_capabilities {
> + TPM2_CAP_HANDLES = 1,
> + TPM2_CAP_COMMANDS = 2,
> + TPM2_CAP_PCRS = 5,
> + TPM2_CAP_TPM_PROPERTIES = 6,
> +};
> +
> +enum tpm2_properties {
> + TPM_PT_TOTAL_COMMANDS = 0x0129,
> +};
> +
> +enum tpm2_startup_types {
> + TPM2_SU_CLEAR = 0x0000,
> + TPM2_SU_STATE = 0x0001,
> +};
> +
> +enum tpm2_cc_attrs {
> + TPM2_CC_ATTR_CHANDLES = 25,
> + TPM2_CC_ATTR_RHANDLE = 28,
> +};
> +
> +#define TPM_VID_INTEL 0x8086
> +#define TPM_VID_WINBOND 0x1050
> +#define TPM_VID_STM 0x104A
> +
> +enum tpm2_object_attributes {
> + TPM2_OA_USER_WITH_AUTH = BIT(6),
> +};
> +
> +enum tpm2_session_attributes {
> + TPM2_SA_CONTINUE_SESSION = BIT(0),
> +};
> +
> +struct tpm2_hash {
> + unsigned int crypto_id;
> + unsigned int tpm_id;
> +};
> +
> +static inline u32 tpm2_rc_value(u32 rc)
> +{
> + return (rc & BIT(7)) ? rc & 0xff : rc;
> +}
> +
> +#endif
> --
> 2.11.0
>

/Jarkko

2020-11-02 12:18:57

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [RFC PATCH 3/4] tpm: Conditionally use static buffer in TPM buffer management

On Sat, Oct 31, 2020 at 12:51:21PM -0400, Daniel P. Smith wrote:
> Memory management calls cannot be made in the compressed kernel
> environment to dynamically allocate TPM buffer space. For the Secure
> Launch early PCR extend code, use a static buffer instead.
>
> Signed-off-by: Daniel P. Smith <[email protected]>
> Signed-off-by: Ross Philipson <[email protected]>
> ---

This patch is not necessary.

Just assign tb->data to the static buffer where you use the static
buffer and use tpm_buf_reset().

tpm_buf_init() and tpm_buf_destroy() are optional.

/Jarkko

> include/linux/tpm_buffer.h | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/include/linux/tpm_buffer.h b/include/linux/tpm_buffer.h
> index 8144a52fbc0a..c9482edf6618 100644
> --- a/include/linux/tpm_buffer.h
> +++ b/include/linux/tpm_buffer.h
> @@ -18,6 +18,10 @@
> #ifndef __LINUX_TPM_BUFFER_H__
> #define __LINUX_TPM_BUFFER_H__
>
> +#ifdef COMPRESSED_KERNEL
> +static u8 _tpm_buffer[PAGE_SIZE] = {0};
> +#endif
> +
> struct tpm_header {
> __be16 tag;
> __be32 length;
> @@ -52,7 +56,11 @@ static inline void tpm_buf_reset(struct tpm_buf *buf, u16 tag, u32 ordinal)
>
> static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
> {
> +#ifdef COMPRESSED_KERNEL
> + buf->data = _tpm_buffer;
> +#else
> buf->data = (u8 *)__get_free_page(GFP_KERNEL);
> +#endif
> if (!buf->data)
> return -ENOMEM;
>
> @@ -63,7 +71,9 @@ static inline int tpm_buf_init(struct tpm_buf *buf, u16 tag, u32 ordinal)
>
> static inline void tpm_buf_destroy(struct tpm_buf *buf)
> {
> +#ifndef COMPRESSED_KERNEL
> free_page((unsigned long)buf->data);
> +#endif
> }
>
> static inline u32 tpm_buf_length(struct tpm_buf *buf)
> @@ -92,7 +102,9 @@ static inline void tpm_buf_append(struct tpm_buf *buf,
> return;
>
> if ((len + new_len) > PAGE_SIZE) {
> +#ifndef COMPRESSED_KERNEL
> WARN(1, "tpm_buf: overflow\n");
> +#endif
> buf->flags |= TPM_BUF_OVERFLOW;
> return;
> }
> --
> 2.11.0
>

/Jarkko

2020-11-02 12:21:50

by Jarkko Sakkinen

[permalink] [raw]
Subject: Re: [RFC PATCH 4/4] x86: Add early PCR extend support for Secure Launch

On Sat, Oct 31, 2020 at 12:51:22PM -0400, Daniel P. Smith wrote:
> Access to PCR extend functionality is needed early in the compressed
> kernel so that Secure Launch can measure items into the DRTM PCRs
> before these items are used. The items include the boot parameters and
> associated information, the kernel command line, any external initrd
> and the OS-MLE TXT heap structure.
>
> NOTE: for the RFC, early_pcr_extend.c is built unconditionally in the
> Makefile. In the full Secure Launch patch set it is conditionally built
> if CONFIG_SECURE_LAUNCH is defined.
>
> Signed-off-by: Daniel P. Smith <[email protected]>
> Signed-off-by: Ross Philipson <[email protected]>

We don't want two copies of TIS implementation and TPM helper functions.

This is a problem that the patch set must resolve in order to be
acceptable for the mainline.

/Jarkko

> ---
> arch/x86/boot/compressed/Makefile | 2 +
> arch/x86/boot/compressed/early_pcr_extend.c | 311 ++++++++++++++++++++++++++++
> arch/x86/boot/compressed/early_pcr_extend.h | 92 ++++++++
> 3 files changed, 405 insertions(+)
> create mode 100644 arch/x86/boot/compressed/early_pcr_extend.c
> create mode 100644 arch/x86/boot/compressed/early_pcr_extend.h
>
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index 5a828fde7a42..8f0b29dce9da 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -93,6 +93,8 @@ vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
> efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a
>
> +vmlinux-objs-y += $(obj)/early_pcr_extend.o
> +
> # The compressed kernel is built with -fPIC/-fPIE so that a boot loader
> # can place it anywhere in memory and it will still run. However, since
> # it is executed as-is without any ELF relocation processing performed
> diff --git a/arch/x86/boot/compressed/early_pcr_extend.c b/arch/x86/boot/compressed/early_pcr_extend.c
> new file mode 100644
> index 000000000000..94ee3cc9814e
> --- /dev/null
> +++ b/arch/x86/boot/compressed/early_pcr_extend.c
> @@ -0,0 +1,311 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2020 Apertus Solutions, LLC
> + *
> + * Author(s):
> + * Daniel P. Smith <[email protected]>
> + *
> + * The code in this file is based on the article "Writing a TPM Device Driver"
> + * published on http://ptgmedia.pearsoncmg.com.
> + *
> + * The scope of the TPM functionality here is solely to allow DRTM PCRs to be
> + * extended early in the compressed kernel.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/bits.h>
> +#include <linux/errno.h>
> +#include <linux/string.h>
> +#include <asm/byteorder.h>
> +#include <asm/io.h>
> +
> +#define COMPRESSED_KERNEL
> +#include <crypto/sha.h>
> +#include <linux/tpm_buffer.h>
> +#include <linux/tpm_command.h>
> +#include <linux/tpm_core.h>
> +#include "../../../../drivers/char/tpm/tpm_tis_defs.h"
> +#include "early_pcr_extend.h"
> +
> +#define tpm_read8(f) readb((void *)(u64)(TPM_MMIO_BASE | f))
> +#define tpm_write8(v, f) writeb(v, (void *)(u64)(TPM_MMIO_BASE | f))
> +#define tpm_read32(f) readl((void *)(u64)(TPM_MMIO_BASE | f));
> +
> +static struct tpm tpm;
> +static u8 locality = TPM_NO_LOCALITY;
> +
> +static void tpm_io_delay(void)
> +{
> + /* This is the default delay type in native_io_delay */
> + asm volatile ("outb %al, $0x80");
> +}
> +
> +static void tpm_udelay(int loops)
> +{
> + while (loops--)
> + tpm_io_delay(); /* Approximately 1 us */
> +}
> +
> +static u32 burst_wait(void)
> +{
> + u32 count = 0;
> +
> + while (count == 0) {
> + count = tpm_read8(TPM_STS(locality) + 1);
> + count += tpm_read8(TPM_STS(locality) + 2) << 8;
> +
> + /* Wait for FIFO to drain */
> + if (count == 0)
> + tpm_udelay(TPM_BURST_MIN_DELAY);
> + }
> +
> + return count;
> +}
> +
> +static void tis_relinquish_locality(void)
> +{
> + if (locality < TPM_MAX_LOCALITY)
> + tpm_write8(TPM_ACCESS_ACTIVE_LOCALITY, TPM_ACCESS(locality));
> +
> + locality = TPM_NO_LOCALITY;
> +}
> +
> +static u8 tis_request_locality(u8 l)
> +{
> + if (l > TPM_MAX_LOCALITY)
> + return TPM_NO_LOCALITY;
> +
> + if (l == locality)
> + return locality;
> +
> + tis_relinquish_locality();
> +
> + tpm_write8(TPM_ACCESS_REQUEST_USE, TPM_ACCESS(l));
> +
> + /* wait for locality to be granted */
> + if (tpm_read8(TPM_ACCESS(l)) & TPM_ACCESS_ACTIVE_LOCALITY)
> + locality = l;
> +
> + return locality;
> +}
> +
> +static size_t tis_send(struct tpm_buf *buf)
> +{
> + u8 status, *buf_ptr;
> + u32 length, count = 0, burstcnt = 0;
> +
> + if (locality > TPM_MAX_LOCALITY)
> + return 0;
> +
> + for (status = 0; (status & TPM_STS_COMMAND_READY) == 0; ) {
> + tpm_write8(TPM_STS_COMMAND_READY, TPM_STS(locality));
> + status = tpm_read8(TPM_STS(locality));
> + }
> +
> + buf_ptr = buf->data;
> + length = tpm_buf_length(buf);
> +
> + /* send all but the last byte */
> + while (count < (length - 1)) {
> + burstcnt = burst_wait();
> + for (; burstcnt > 0 && count < (length - 1); burstcnt--) {
> + tpm_write8(buf_ptr[count], TPM_DATA_FIFO(locality));
> + count++;
> + }
> +
> + /* check for overflow */
> + for (status = 0; (status & TPM_STS_VALID) == 0; )
> + status = tpm_read8(TPM_STS(locality));
> +
> + if ((status & TPM_STS_DATA_EXPECT) == 0)
> + return 0;
> + }
> +
> + /* write last byte */
> + tpm_write8(buf_ptr[length - 1], TPM_DATA_FIFO(locality));
> + count++;
> +
> + /* make sure it stuck */
> + for (status = 0; (status & TPM_STS_VALID) == 0; )
> + status = tpm_read8(TPM_STS(locality));
> +
> + if ((status & TPM_STS_DATA_EXPECT) != 0)
> + return 0;
> +
> + /* go and do it */
> + tpm_write8(TPM_STS_GO, TPM_STS(locality));
> +
> + return (size_t)count;
> +}
> +
> +static u8 tis_init(struct tpm *t)
> +{
> + locality = TPM_NO_LOCALITY;
> +
> + if (tis_request_locality(0) != 0)
> + return 0;
> +
> + t->vendor = tpm_read32(TPM_DID_VID(0));
> + if ((t->vendor & 0xFFFF) == 0xFFFF)
> + return 0;
> +
> + return 1;
> +}
> +
> +static u16 tpm_alg_size(u16 alg_id)
> +{
> + if (alg_id == TPM_ALG_SHA1)
> + return SHA1_DIGEST_SIZE;
> + else if (alg_id == TPM_ALG_SHA256)
> + return SHA256_DIGEST_SIZE;
> + else if (alg_id == TPM_ALG_SHA512)
> + return SHA512_DIGEST_SIZE;
> +
> + return 0;
> +}
> +
> +static int tpm1_pcr_extend(struct tpm *t, u32 pcr, struct tpm_digest *d)
> +{
> + struct tpm_buf buf;
> + int ret;
> +
> + ret = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
> + if (ret)
> + return ret;
> +
> + tpm_buf_append_u32(&buf, pcr);
> + tpm_buf_append(&buf, d->digest, tpm_alg_size(TPM_ALG_SHA1));
> +
> + if (tpm_buf_length(&buf) != tis_send(&buf))
> + ret = -EAGAIN;
> +
> + return ret;
> +}
> +
> +static int tpm2_extend_pcr(struct tpm *t, u32 pcr, struct tpm_digest *digest)
> +{
> + struct tpm_buf buf;
> + u8 auth_area[NULL_AUTH_SIZE] = {0};
> + u32 *handle;
> + int ret;
> +
> + ret = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
> + if (ret)
> + return ret;
> +
> + tpm_buf_append_u32(&buf, pcr);
> +
> + /*
> + * The handle, the first element, is the
> + * only non-zero value in a NULL auth
> + */
> + handle = (u32 *)&auth_area;
> + *handle = cpu_to_be32(TPM2_RS_PW);
> +
> + tpm_buf_append_u32(&buf, NULL_AUTH_SIZE);
> + tpm_buf_append(&buf, (const unsigned char *)&auth_area,
> + NULL_AUTH_SIZE);
> +
> + tpm_buf_append_u32(&buf, 1);
> +
> + tpm_buf_append_u16(&buf, digest->alg_id);
> + tpm_buf_append(&buf, (const unsigned char *)digest->digest,
> + tpm_alg_size(digest->alg_id));
> +
> + if (tpm_buf_length(&buf) != tis_send(&buf))
> + ret = -EAGAIN;
> +
> + return ret;
> +}
> +
> +static void find_interface_and_family(struct tpm *t)
> +{
> + struct tpm_interface_id intf_id;
> + struct tpm_intf_capability intf_cap;
> +
> + /* Sort out whether if it is 1.2 */
> + intf_cap.val = tpm_read32(TPM_INTF_CAPABILITY_0);
> + if ((intf_cap.interface_version == TPM12_TIS_INTF_12) ||
> + (intf_cap.interface_version == TPM12_TIS_INTF_13)) {
> + t->family = TPM12;
> + t->intf = TPM_TIS;
> + return;
> + }
> +
> + /* Assume that it is 2.0 and TIS */
> + t->family = TPM20;
> + t->intf = TPM_TIS;
> +
> + /* Check if the interface is CRB */
> + intf_id.val = tpm_read32(TPM_INTERFACE_ID_0);
> + if (intf_id.interface_type == TPM_CRB_INTF_ACTIVE)
> + t->intf = TPM_CRB;
> +}
> +
> +struct tpm *enable_tpm(void)
> +{
> + struct tpm *t = &tpm;
> +
> + find_interface_and_family(t);
> +
> + switch (t->intf) {
> + case TPM_TIS:
> + if (!tis_init(t))
> + return NULL;
> + break;
> + case TPM_CRB:
> + return NULL;
> + }
> +
> + return t;
> +}
> +
> +u8 tpm_request_locality(u8 l)
> +{
> + return tis_request_locality(l);
> +}
> +
> +int tpm_extend_pcr(struct tpm *t, u32 pcr, u16 algo,
> + u8 *digest)
> +{
> + int ret = -EINVAL;
> +
> + if (t->family == TPM12) {
> + struct tpm_digest d;
> +
> + if (algo != TPM_ALG_SHA1)
> + return -EINVAL;
> +
> + memcpy((void *)d.digest, digest, SHA1_DIGEST_SIZE);
> +
> + ret = tpm1_pcr_extend(t, pcr, &d);
> + } else if (t->family == TPM20) {
> + struct tpm_digest *d;
> + u8 buf[MAX_TPM_EXTEND_SIZE];
> +
> + d = (struct tpm_digest *) buf;
> + d->alg_id = algo;
> + switch (algo) {
> + case TPM_ALG_SHA1:
> + memcpy(d->digest, digest, SHA1_DIGEST_SIZE);
> + break;
> + case TPM_ALG_SHA256:
> + memcpy(d->digest, digest, SHA256_DIGEST_SIZE);
> + break;
> + case TPM_ALG_SHA512:
> + memcpy(d->digest, digest, SHA512_DIGEST_SIZE);
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + ret = tpm2_extend_pcr(t, pcr, d);
> + }
> +
> + return ret;
> +}
> +
> +void free_tpm(void)
> +{
> + tis_relinquish_locality();
> +}
> diff --git a/arch/x86/boot/compressed/early_pcr_extend.h b/arch/x86/boot/compressed/early_pcr_extend.h
> new file mode 100644
> index 000000000000..bcd6d57d8c56
> --- /dev/null
> +++ b/arch/x86/boot/compressed/early_pcr_extend.h
> @@ -0,0 +1,92 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 Apertus Solutions, LLC
> + *
> + * Author(s):
> + * Daniel P. Smith <[email protected]>
> + *
> + */
> +
> +#ifndef BOOT_COMPRESSED_EARLY_PCR_EXTEND_H
> +#define BOOT_COMPRESSED_EARLY_PCR_EXTEND_H
> +
> +#define TPM_MMIO_BASE 0xFED40000
> +#define TPM_MAX_LOCALITY 4
> +#define TPM_NO_LOCALITY 0xFF
> +#define TPM_BURST_MIN_DELAY 100 /* 100us */
> +#define TPM_ORD_PCR_EXTEND 20
> +#define NULL_AUTH_SIZE 9
> +#define MAX_TPM_EXTEND_SIZE 68 /* TPM2 SHA512 is the largest */
> +
> +#define TPM_INTERFACE_ID_0 0x30
> +#define TPM_TIS_INTF_ACTIVE 0x00
> +#define TPM_CRB_INTF_ACTIVE 0x01
> +
> +struct tpm_interface_id {
> + union {
> + u32 val;
> + struct {
> + u32 interface_type:4;
> + u32 interface_version:4;
> + u32 cap_locality:1;
> + u32 reserved1:4;
> + u32 cap_tis:1;
> + u32 cap_crb:1;
> + u32 cap_if_res:2;
> + u32 interface_selector:2;
> + u32 intf_sel_lock:1;
> + u32 reserved2:4;
> + u32 reserved3:8;
> + };
> + };
> +} __packed;
> +
> +#define TPM_INTF_CAPABILITY_0 0x14
> +#define TPM12_TIS_INTF_12 0x00
> +#define TPM12_TIS_INTF_13 0x02
> +#define TPM20_TIS_INTF_13 0x03
> +
> +struct tpm_intf_capability {
> + union {
> + u32 val;
> + struct {
> + u32 data_avail_int_support:1;
> + u32 sts_valid_int_support:1;
> + u32 locality_change_int_support:1;
> + u32 interrupt_level_high:1;
> + u32 interrupt_level_low:1;
> + u32 interrupt_edge_rising:1;
> + u32 interrupt_edge_falling:1;
> + u32 command_ready_int_support:1;
> + u32 burst_count_static:1;
> + u32 data_transfer_size_support:2;
> + u32 reserved1:17;
> + u32 interface_version:3;
> + u32 reserved2:1;
> + };
> + };
> +} __packed;
> +
> +enum tpm_hw_intf {
> + TPM_TIS,
> + TPM_CRB
> +};
> +
> +enum tpm_family {
> + TPM12,
> + TPM20
> +};
> +
> +struct tpm {
> + u32 vendor;
> + enum tpm_family family;
> + enum tpm_hw_intf intf;
> +};
> +
> +extern struct tpm *enable_tpm(void);
> +extern u8 tpm_request_locality(u8 l);
> +extern int tpm_extend_pcr(struct tpm *t, u32 pcr, u16 algo,
> + u8 *digest);
> +extern void free_tpm(void);
> +
> +#endif
> --
> 2.11.0
>