lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <aW7H_LwhYux0ajtq@kernel.org>
Date: Tue, 20 Jan 2026 02:10:36 +0200
From: Jarkko Sakkinen <jarkko@...nel.org>
To: Ross Philipson <ross.philipson@...cle.com>
Cc: linux-kernel@...r.kernel.org, x86@...nel.org,
	linux-integrity@...r.kernel.org, linux-doc@...r.kernel.org,
	linux-crypto@...r.kernel.org, kexec@...ts.infradead.org,
	linux-efi@...r.kernel.org, iommu@...ts.linux.dev,
	dpsmith@...rtussolutions.com, tglx@...utronix.de, mingo@...hat.com,
	bp@...en8.de, hpa@...or.com, dave.hansen@...ux.intel.com,
	ardb@...nel.org, mjg59@...f.ucam.org,
	James.Bottomley@...senpartnership.com, peterhuewe@....de,
	jgg@...pe.ca, luto@...capital.net, nivedita@...m.mit.edu,
	herbert@...dor.apana.org.au, davem@...emloft.net, corbet@....net,
	ebiederm@...ssion.com, dwmw2@...radead.org,
	baolu.lu@...ux.intel.com, kanth.ghatraju@...cle.com,
	andrew.cooper3@...rix.com, trenchboot-devel@...glegroups.com
Subject: Re: [PATCH v15 19/28] x86/tpm: Early TPM PCR extending driver

On Mon, Dec 15, 2025 at 03:33:07PM -0800, Ross Philipson wrote:
> Introduce an early driver that can interact minimally with the
> TPM. This allows the Secure Launch startup code to extend measurement
> values into the TPM's DRTM PCR banks early in the launch process.
> 
> This driver implementation is very minimal, only supporting basic
> initialization and extend commands. An extend command can be sent to both
> a TPM 2.0 or 1.2 chip but only the TIS/FIFO interface is currently
> supported. The CRB interface is currently not supported. The TCG specs
> for these interface can be found here:
> 
> https://trustedcomputinggroup.org/resource/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/
> https://trustedcomputinggroup.org/resource/tpm-2-0-mobile-command-response-buffer-interface-specification/
> 
> The driver could be extended for further operations if needed. This
> TPM dirver implementation relies as much as possible on existing mainline
> kernel TPM code.
> 
> Signed-off-by: Daniel P. Smith <dpsmith@...rtussolutions.com>
> Signed-off-by: Alec Brown <alec.r.brown@...cle.com>
> Signed-off-by: Ross Philipson <ross.philipson@...cle.com>

Wouldn't it be possible to simply link code from tpm-interface.c and
re-use PCR functions from tpm1-cmd.c and tpm2-cmd.c?

We can even split transmit code from rest of tpm-interface.c if that
is necessary for some reason.

I.e. link the code and define ops re-using code below.

If using tpm_transmit is impossible, less ideally you could also
implement your own tpm_transmit_cmd and link tpm1-cmd.o and tpm2-cmd.o,
which will work out as the symbol is there.

> ---
>  arch/x86/boot/compressed/Makefile           |   1 +
>  arch/x86/boot/compressed/early_tpm_extend.c | 601 ++++++++++++++++++++
>  arch/x86/boot/compressed/tpm.h              |  42 ++
>  3 files changed, 644 insertions(+)
>  create mode 100644 arch/x86/boot/compressed/early_tpm_extend.c
>  create mode 100644 arch/x86/boot/compressed/tpm.h
> 
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index 0ea8a11ec271..b108e0edf367 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -114,6 +114,7 @@ endif
>  
>  slaunch-objs += $(obj)/sha1.o
>  slaunch-objs += $(obj)/sha256.o
> +slaunch-objs += $(obj)/early_tpm_extend.o
>  
>  vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(slaunch-objs)
>  
> diff --git a/arch/x86/boot/compressed/early_tpm_extend.c b/arch/x86/boot/compressed/early_tpm_extend.c
> new file mode 100644
> index 000000000000..7cfdb7969878
> --- /dev/null
> +++ b/arch/x86/boot/compressed/early_tpm_extend.c
> @@ -0,0 +1,601 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2010-2012 United States Government, as represented by
> + * the Secretary of Defense.  All rights reserved.
> + *
> + * based off of the original tools/vtpm_manager code base which is:
> + * Copyright (c) 2005, Intel Corp.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + *
> + *   * Redistributions of source code must retain the above copyright
> + *     notice, this list of conditions and the following disclaimer.
> + *   * Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the following
> + *     disclaimer in the documentation and/or other materials provided
> + *     with the distribution.
> + *   * Neither the name of Intel Corporation nor the names of its
> + *     contributors may be used to endorse or promote products derived
> + *     from this software without specific prior written permission.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
> + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
> + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
> + * OF THE POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <crypto/sha2.h>
> +#include <asm/msr.h>
> +#include <asm/io.h>
> +
> +#include <linux/tpm_common.h>
> +#include <linux/tpm1.h>
> +#include <linux/tpm2.h>
> +#include <linux/tpm_ptp.h>
> +#include <linux/tpm_buf.h>
> +
> +#include "../../../../drivers/char/tpm/tpm1_structs.h"
> +#include "../../../../drivers/char/tpm/tpm2_structs.h"
> +
> +#include "tpm.h"
> +
> +static u8 tpm_buf_page[PAGE_SIZE];
> +
> +/*
> + * Single threaded environment only running on BSP. Use a single shared
> + * page for all TPM extend operations.
> + */
> +static inline struct tpm_buf *tpm_buf_alloc_page(void)
> +{
> +	memset(tpm_buf_page, 0, PAGE_SIZE);
> +	return (struct tpm_buf *)tpm_buf_page;
> +}
> +
> +static inline void tpm_buf_free_page(void)
> +{
> +	memset(tpm_buf_page, 0, PAGE_SIZE);
> +}
> +
> +/* Pull in TPM buffer management support */
> +#undef WARN
> +#define WARN(c, f...)
> +#undef WARN_ON
> +#define WARN_ON(c) (0)
> +
> +#include "../../../../drivers/char/tpm/tpm-buf.c"
> +
> +static u32 tpm_get_alg_size(u16 alg_id)
> +{
> +	switch (alg_id) {
> +	case TPM_ALG_SHA1:
> +		return TPM_DIGEST_SIZE;
> +	case TPM_ALG_SHA256:
> +	case TPM_ALG_SM3_256:
> +		return SHA256_DIGEST_SIZE;
> +	case TPM_ALG_SHA384:
> +		return SHA384_DIGEST_SIZE;
> +	case TPM_ALG_SHA512:
> +	default:
> +		return SHA512_DIGEST_SIZE;
> +	};
> +}
> +
> +static inline u8 tpm_read8(struct tpm_chip *chip, u32 field)
> +{
> +	void *mmio_addr = (void *)(uintptr_t)(chip->baseaddr | field);
> +	return readb(mmio_addr);
> +}
> +
> +static inline void tpm_write8(struct tpm_chip *chip, u32 field, u8 val)
> +{
> +	void *mmio_addr = (void *)(uintptr_t)(chip->baseaddr | field);
> +	writeb(val, mmio_addr);
> +}
> +
> +static inline u32 tpm_read32(struct tpm_chip *chip, u32 field)
> +{
> +	void *mmio_addr = (void *)(uintptr_t)(chip->baseaddr | field);
> +	return readl(mmio_addr);
> +}
> +
> +static inline void tpm_write32(struct tpm_chip *chip, u32 field, u32 val)
> +{
> +	void *mmio_addr = (void *)(uintptr_t)(chip->baseaddr | field);
> +	writel(val, mmio_addr);
> +}
> +
> +static unsigned long ticks_per_ms = (5UL * 1000 * 1000 /* cpu_khz */ / 1000);
> +
> +static inline ktime_t tpm_now_ms(void)
> +{
> +	return rdtsc()/ticks_per_ms;
> +}
> +
> +/*
> + * We're far too early to calibrate time.  Assume a 5GHz processor (the upper
> + * end of the Fam19h range), which causes us to be wrong in the safe direction
> + * on slower systems.
> + */
> +static inline void tpm_mdelay(unsigned int msecs)
> +{
> +	unsigned long ticks = msecs * ticks_per_ms;
> +	unsigned long s, e;
> +
> +	s = rdtsc();
> +	do {
> +		cpu_relax();
> +		e = rdtsc();
> +	} while ((e - s) < ticks);
> +}
> +
> +static inline u8 __tis_status(struct tpm_chip *chip)
> +{
> +	return tpm_read8(chip, TPM_STS(chip->locality));
> +}
> +
> +static inline void __tis_cancel(struct tpm_chip *chip)
> +{
> +	/* This causes the current command to be aborted */
> +	tpm_write8(chip, TPM_STS(chip->locality), TPM_STS_COMMAND_READY);
> +}
> +
> +static int __tis_get_burstcount(struct tpm_chip *chip)
> +{
> +	ktime_t stop;
> +	int burstcnt;
> +
> +	stop = tpm_now_ms() + chip->timeout_d;
> +	do {
> +		burstcnt = tpm_read8(chip, (TPM_STS(chip->locality) + 1));
> +		burstcnt += tpm_read8(chip, TPM_STS(chip->locality) + 2) << 8;
> +
> +		if (burstcnt)
> +			return burstcnt;
> +
> +		tpm_mdelay(TPM_TIMEOUT);
> +	} while (tpm_now_ms() < stop);
> +
> +	return -EBUSY;
> +}
> +
> +static int __tis_wait_for_stat(struct tpm_chip *chip, u8 mask, ktime_t timeout)
> +{
> +	ktime_t stop;
> +	u8 status;
> +
> +	if ((__tis_status(chip) & mask) == mask)
> +		return 0;
> +
> +	stop = tpm_now_ms() + timeout;
> +	do {
> +		tpm_mdelay(TPM_TIMEOUT);
> +
> +		status = __tis_status(chip);
> +		if ((status & mask) == mask)
> +			return 0;
> +	} while (tpm_now_ms() < stop);
> +
> +	return -ETIME;
> +}
> +
> +static int __tis_recv_data(struct tpm_chip *chip, u8 *buf, int count)
> +{
> +	int size = 0;
> +	int burstcnt;
> +
> +	while (size < count && __tis_wait_for_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, chip->timeout_c) == 0) {
> +		burstcnt = __tis_get_burstcount(chip);
> +
> +		for ( ; burstcnt > 0 && size < count; --burstcnt)
> +			buf[size++] = tpm_read8(chip, TPM_DATA_FIFO(chip->locality));
> +	}
> +
> +	return size;
> +}
> +
> +/**
> + * tpm_tis_check_locality - Check if the given locality is the active one
> + * @chip:	The TPM chip instance
> + * @loc:	The locality to check
> + *
> + * Return: true - locality active, false - not active
> + */
> +bool tpm_tis_check_locality(struct tpm_chip *chip, int loc)
> +{
> +	if ((tpm_read8(chip, TPM_ACCESS(loc)) & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
> +		chip->locality = loc;
> +		return true;
> +	}
> +
> +	return false;
> +}
> +
> +/**
> + * tpm_tis_release_locality - Release the active locality
> + * @chip:	The TPM chip instance
> + */
> +void tpm_tis_release_locality(struct tpm_chip *chip)
> +{
> +	if ((tpm_read8(chip, TPM_ACCESS(chip->locality)) & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))
> +		tpm_write8(chip, TPM_ACCESS(chip->locality), TPM_ACCESS_RELINQUISH_LOCALITY);
> +
> +	chip->locality = 0;
> +}
> +
> +/**
> + * tpm_tis_request_locality - Request to make the given locality the active one
> + * @chip:	The TPM chip instance
> + * @loc:	The locality to make active/set as current
> + *
> + * Return:
> + *  >= 0 - Success, new active locality returned or locality already active
> + *  < 0  - Error occurred
> + */
> +int tpm_tis_request_locality(struct tpm_chip *chip, int loc)
> +{
> +	ktime_t stop;
> +
> +	if (tpm_tis_check_locality(chip, loc))
> +		return loc;
> +
> +	/* Set the new locality */
> +	tpm_write8(chip, TPM_ACCESS(loc), TPM_ACCESS_REQUEST_USE);
> +
> +	stop = tpm_now_ms() + chip->timeout_b;
> +	do {
> +		if (tpm_tis_check_locality(chip, loc))
> +			return loc;
> +
> +		tpm_mdelay(TPM_TIMEOUT);
> +	} while (tpm_now_ms() < stop);
> +
> +	return -1;
> +}
> +
> +/**
> + * tpm_tis_disable_interrupts - Disable interrupts for the TPM, use polling mode only
> + * @chip:	The TPM chip instance
> + */
> +void tpm_tis_disable_interrupts(struct tpm_chip *chip)
> +{
> +	u32 intmask;
> +
> +	intmask = tpm_read32(chip, TPM_INT_ENABLE(chip->locality));
> +	/* Disable everything to make sure it is in a consistent state */
> +	intmask &= ~(TPM_GLOBAL_INT_ENABLE | TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | TPM_INTF_DATA_AVAIL_INT);
> +	tpm_write32(chip, TPM_INT_ENABLE(chip->locality), intmask);
> +}
> +
> +/**
> + * tpm_tis_recv - Receive response data from TPM via TIS FIFO
> + * @chip:	The TPM chip instance
> + * @buf:	The response buffer
> + * @count:	Length of the response buffer
> + *
> + * Return:
> + *  = 0 - Success, no response data
> + *  > 0 - Success, value is the response data length
> + *  < 0 - Error occurred
> + */
> +static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, int count)
> +{
> +	int expected, status, size = 0, rc = -EIO;
> +
> +	if (count < TPM_HEADER_SIZE)
> +		goto out;
> +
> +	/* Read first 10 bytes, including tag, paramsize, and result */
> +	size = __tis_recv_data(chip, buf, TPM_HEADER_SIZE);
> +	if (size < TPM_HEADER_SIZE)
> +		goto out;
> +
> +	expected = be32_to_cpu(*((u32 *)(buf + 2)));
> +	if (expected > count)
> +		goto out;
> +
> +	size += __tis_recv_data(chip, &buf[TPM_HEADER_SIZE], expected - TPM_HEADER_SIZE);
> +	if (size < expected) {
> +		rc = -ETIME;
> +		goto out;
> +	}
> +
> +	__tis_wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c);
> +
> +	status = __tis_status(chip);
> +	if (status & TPM_STS_DATA_AVAIL) {
> +		rc = -EIO;
> +		goto out;
> +	}
> +
> +	return size;
> +out:
> +	__tis_cancel(chip);
> +	tpm_tis_release_locality(chip);
> +	return rc;
> +}
> +
> +/**
> + * tpm_tis_send - Send command to TPM via TIS FIFO
> + * @chip:	The TPM chip instance
> + * @buf:	The command buffer
> + * @len:	Length of the command buffer to send
> + *
> + * Return:
> + *  = len - Success, all data sent
> + *  < 0	  - Error occurred
> + */
> +static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, int len)
> +{
> +	int status, burstcnt = 0;
> +	int count = 0;
> +	int rc = 0;
> +
> +	status = __tis_status(chip);
> +	if ((status & TPM_STS_COMMAND_READY) == 0) {
> +		__tis_cancel(chip);
> +		if (__tis_wait_for_stat(chip, TPM_STS_COMMAND_READY, chip->timeout_b) < 0) {
> +			rc = -ETIME;
> +			goto out_err;
> +		}
> +	}
> +
> +	while (count < len - 1) {
> +		burstcnt = __tis_get_burstcount(chip);
> +		for ( ; burstcnt > 0 && count < len - 1; --burstcnt)
> +			tpm_write8(chip, TPM_DATA_FIFO(chip->locality), buf[count++]);
> +
> +		__tis_wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c);
> +		status = __tis_status(chip);
> +		if ((status & TPM_STS_DATA_EXPECT) == 0) {
> +			rc = -EIO;
> +			goto out_err;
> +		}
> +	}
> +
> +	/* Write last byte */
> +	tpm_write8(chip, TPM_DATA_FIFO(chip->locality), buf[count]);
> +	__tis_wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c);
> +	status = __tis_status(chip);
> +	if ((status & TPM_STS_DATA_EXPECT) != 0) {
> +		rc = -EIO;
> +		goto out_err;
> +	}
> +
> +	/* Go and do it */
> +	tpm_write8(chip, TPM_STS(chip->locality), TPM_STS_GO);
> +
> +	return len;
> +
> +out_err:
> +	__tis_cancel(chip);
> +	tpm_tis_release_locality(chip);
> +	return rc;
> +}
> +
> +/**
> + * tpm_tis_transmit - Transmit a TPM FIFO command
> + * @chip:	The TPM chip instance
> + * @buf:	The request and response buffer object
> + * @bufsize:	Entire size available in buffer
> + *
> + * Return:
> + *  = 0 - Success, no returned data
> + *  > 0 - Success, value is the return data length
> + *  < 0 - Error occurred
> + */
> +static int tpm_tis_transmit(struct tpm_chip *chip, u8 *buf, u32 bufsize)
> +{
> +	ktime_t stop;
> +	u32 count;
> +	u8 status;
> +	int rc;
> +
> +	count = be32_to_cpu(*((u32 *) (buf + 2)));
> +	if (count == 0)
> +		return -ENODATA;
> +
> +	if (count > bufsize)
> +		return -E2BIG;
> +
> +	rc = tpm_tis_send(chip, buf, count);
> +	if (rc < 0)
> +		goto out;
> +
> +	stop = tpm_now_ms() + TIS_DURATION;
> +	do {
> +		status = __tis_status(chip);
> +		if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) == (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
> +			goto out_recv;
> +
> +		if (status == TPM_STS_COMMAND_READY) {
> +			rc = -ECANCELED;
> +			goto out;
> +		}
> +
> +		tpm_mdelay(TPM_TIMEOUT);
> +		rmb();
> +	} while (tpm_now_ms() < stop);
> +
> +	/* Cancel the command */
> +	__tis_cancel(chip);
> +	rc = -ETIME;
> +	goto out;
> +
> +out_recv:
> +	rc = tpm_tis_recv(chip, buf, bufsize);
> +	if (rc >= 0) {
> +		if (rc > 0 && rc < TPM_HEADER_SIZE)
> +			return -EFAULT;
> +		return rc;
> +	}
> +	/* Else return was an error, nothing to receive */
> +
> +out:
> +	return rc;
> +}
> +
> +/**
> + * tpm_find_interface_and_family - interface FIFO/CRB, family 2.0 or 1.2
> + * @chip:	The TPM chip instance
> + *
> + * Return: TPM family ID enum
> + */
> +static enum tpm_family tpm_find_interface_and_family(struct tpm_chip *chip)
> +{
> +	struct tpm_intf_capability intf_cap;
> +	struct tpm_interface_id intf_id;
> +
> +	/* Sort out whether it is 1.x */
> +	intf_cap.val = tpm_read32(chip, TPM_INTF_CAPS(0));
> +	if ((intf_cap.interface_version == TPM_TIS_INTF_12) ||
> +	    (intf_cap.interface_version == TPM_TIS_INTF_13))
> +		return TPM_FAMILY_12; /* Always TIS */
> +
> +	/* Assume that it is 2.0 but check if the interface is CRB */
> +	intf_id.val = tpm_read32(chip, TPM_INTF_ID(0));
> +	if (intf_id.interface_type == TPM_CRB_INTF_ACTIVE)
> +		return TPM_FAMILY_INVALID;
> +
> +	/* Else TPM 2.0 with TIS interface */
> +	return TPM_FAMILY_20;
> +}
> +
> +/**
> + * tpm1_pcr_extend - send a TPM1 extend command to the device
> + * @chip:	a TPM chip to use
> + * @pcr_idx:	the PCR index to extend for the current locality
> + * @hash:	the SHA1 hash digest to extend
> + *
> + * Return:
> + * * 0		- OK
> + * * -errno	- A system error
> + * * TPM_RC	- A TPM error
> + */
> +int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash)
> +{
> +	int rc = 0;
> +	struct tpm_buf *buf = tpm_buf_alloc_page();
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	tpm_buf_init(buf, TPM_BUFSIZE);
> +	tpm_buf_reset(buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
> +
> +	tpm_buf_append_u32(buf, pcr_idx);
> +	tpm_buf_append(buf, hash, TPM_DIGEST_SIZE);
> +
> +	rc = tpm_tis_transmit(chip, buf->data, PAGE_SIZE);
> +
> +	/* Ignoring output */
> +	if (rc > 0)
> +		rc = 0;
> +
> +	tpm_buf_free_page();
> +
> +	return rc;
> +}
> +
> +/**
> + * tpm2_pcr_extend() - send a TPM2 extend command to the device
> + *
> + * @chip:		TPM chip to use.
> + * @pcr_idx:		index of the PCR.
> + * @digests:		list of PCR banks and corresponding digest values to extend.
> + * @digest_count:	count of digests to extend
> + *
> + * Return:
> + * * 0		- OK
> + * * -errno	- A system error
> + * * TPM_RC	- A TPM error
> + */
> +int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
> +		    struct tpm_digest *digests, u32 digest_count)
> +{
> +	struct tpm_buf *buf = tpm_buf_alloc_page();
> +	int rc = 0, i;
> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	tpm_buf_init(buf, TPM_BUFSIZE);
> +	tpm_buf_reset(buf, TPM2_ST_SESSIONS, TPM2_CC_PCR_EXTEND);
> +
> +	tpm_buf_append_handle(buf, pcr_idx);
> +
> +	/* Setup a NULL auth session for the command */
> +	tpm_buf_append_u32(buf, 9);
> +	/* auth handle */
> +	tpm_buf_append_u32(buf, TPM2_RS_PW);
> +	/* nonce */
> +	tpm_buf_append_u16(buf, 0);
> +	/* attributes */
> +	tpm_buf_append_u8(buf, 0);
> +	/* passphrase */
> +	tpm_buf_append_u16(buf, 0);
> +
> +	tpm_buf_append_u32(buf, digest_count);
> +
> +	for (i = 0; i < digest_count; i++) {
> +		tpm_buf_append_u16(buf, digests[i].alg_id);
> +		tpm_buf_append(buf, (const unsigned char *)&digests[i].digest,
> +			       tpm_get_alg_size(digests[i].alg_id));
> +	}
> +
> +	rc = tpm_tis_transmit(chip, buf->data, PAGE_SIZE);
> +
> +	/* Ignoring output */
> +	if (rc > 0)
> +		rc = 0;
> +
> +	tpm_buf_free_page();
> +
> +	return rc;
> +}
> +
> +int early_tpm_init(struct tpm_chip *chip, u64 baseaddr)
> +{
> +	u32 didvid;
> +
> +	memset(chip, 0, sizeof(*chip));
> +	chip->baseaddr = baseaddr;
> +
> +	chip->family = tpm_find_interface_and_family(chip);
> +	if (chip->family == TPM_FAMILY_INVALID)
> +		return TPM_ERR_INVALID_FAMILY;
> +
> +	/* Set default timeouts */
> +	chip->timeout_a = TIS_SHORT_TIMEOUT;
> +	chip->timeout_b = TIS_LONG_TIMEOUT;
> +	chip->timeout_c = TIS_SHORT_TIMEOUT;
> +	chip->timeout_d = TIS_SHORT_TIMEOUT;
> +
> +	/* Get the vendor and device ids */
> +	didvid = tpm_read32(chip, TPM_DID_VID(0));
> +	chip->did = didvid >> 16;
> +	chip->vid = didvid & 0xFFFF;
> +
> +	return TPM_SUCCESS;
> +}
> +
> +int early_tpm_fini(struct tpm_chip *chip)
> +{
> +	tpm_tis_release_locality(chip);
> +	memset(chip, 0, sizeof(*chip));
> +
> +	return TPM_SUCCESS;
> +}
> diff --git a/arch/x86/boot/compressed/tpm.h b/arch/x86/boot/compressed/tpm.h
> new file mode 100644
> index 000000000000..6986593e0100
> --- /dev/null
> +++ b/arch/x86/boot/compressed/tpm.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef BOOT_COMPRESSED_TPM_H
> +#define BOOT_COMPRESSED_TPM_H
> +
> +enum early_tis_defaults {
> +	TIS_MEM_X86_LPC_BASE	= 0xFED40000,
> +	TIS_MEM_X86_LEN		= 0x5000,
> +	TPM_TIMEOUT		= 5, /* ms */
> +	TIS_DURATION		= 120000, /* 120 secs in ms */
> +};
> +
> +enum tpm_family {
> +	TPM_FAMILY_INVALID	= 0,
> +	TPM_FAMILY_12		= 1,
> +	TPM_FAMILY_20		= 2
> +};
> +
> +struct tpm_chip {
> +	enum tpm_family family;
> +	u64 baseaddr;
> +	int locality;
> +	int did;
> +	int vid;
> +
> +	/* in ms */
> +	ktime_t timeout_a;
> +	ktime_t timeout_b;
> +	ktime_t timeout_c;
> +	ktime_t timeout_d;
> +};
> +
> +bool tpm_tis_check_locality(struct tpm_chip *chip, int loc);
> +void tpm_tis_release_locality(struct tpm_chip *chip);
> +int tpm_tis_request_locality(struct tpm_chip *chip, int loc);
> +void tpm_tis_disable_interrupts(struct tpm_chip *chip);
> +int tpm1_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, const u8 *hash);
> +int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx,
> +		    struct tpm_digest *digests, u32 digest_count);
> +int early_tpm_init(struct tpm_chip *chip, u64 baseaddr);
> +int early_tpm_fini(struct tpm_chip *chip);
> +
> +#endif /* BOOT_COMPRESSED_TPM_H */
> -- 
> 2.43.7
> 

BR, Jarkko

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ