[[PATCH v2] tpm: Add wolfTPM library support for TPM 2.0 08/12] cmd: refactor tpm2 command into frontend/backend architecture

David Garske david at wolfssl.com
Mon Mar 16 19:14:37 CET 2026


From: Aidan <aidan at wolfssl.com>

Split the tpm2 command implementation into a shared frontend and
two selectable backends. This allows wolfTPM to provide its own
TPM2 command implementations while keeping the command table,
dispatcher, and help text shared.

Architecture:

cmd/tpm-v2.c (frontend - always compiled):
  Contains the tpm2_commands[] table, get_tpm2_commands(), the
  do_tpm2() dispatcher, and the U_BOOT_CMD help text. References
  backend functions via cmd/tpm2-backend.h. When CONFIG_TPM_WOLF
  is enabled, additional wolfTPM-only commands (caps, pcr_print,
  firmware_update, firmware_cancel) are added to the table.

cmd/tpm2-backend.h (new):
  Declares all backend function prototypes that both backends must
  implement: do_tpm2_device, do_tpm2_info, do_tpm2_init,
  do_tpm2_startup, do_tpm2_selftest, do_tpm2_clear,
  do_tpm2_pcr_extend, do_tpm2_pcr_read, do_tpm2_get_capability,
  do_tpm2_dam_reset, do_tpm2_dam_parameters, do_tpm2_change_auth,
  do_tpm2_pcr_setauthpolicy, do_tpm2_pcr_setauthvalue,
  do_tpm2_pcr_allocate, plus wolfTPM-only functions.

cmd/native_tpm2.c (new - native backend):
  Contains the original tpm2 command implementations that use
  U-Boot's TPM driver model (tpm_api.h, tpm-v2.h). Compiled when
  CONFIG_TPM_WOLF is not set. Common commands delegate to
  tpm-common.c helpers (do_tpm_device, do_tpm_info, etc.).

cmd/wolftpm.c (new - wolfTPM backend):
  Implements all tpm2 commands using wolfTPM library APIs directly
  (wolfTPM2_Init, wolfTPM2_GetCapabilities, wolfTPM2_ExtendPCR,
  etc.). Includes Infineon-specific firmware update and cancel
  commands. Each command initializes its own WOLFTPM2_DEV instance
  rather than going through U-Boot's driver model.

cmd/Kconfig:
  Adds CMD_WOLFTPM option that selects TPM_WOLF and CMD_TPM_V2,
  providing a single menuconfig toggle for wolfTPM support.

cmd/Makefile:
  Conditionally compiles wolftpm.o (when CONFIG_TPM_WOLF=y) or
  native_tpm2.o (otherwise) alongside the shared tpm-v2.o frontend.
  Sets wolfTPM include paths and -DWOLFTPM_USER_SETTINGS.

The reason for separate backend files rather than a callback-based
approach is that wolfTPM uses fundamentally different types and
initialization patterns (WOLFTPM2_DEV vs struct udevice, direct
library calls vs driver model ops), making runtime dispatch
impractical without heavy abstraction.

Signed-off-by: Aidan Garske <aidan at wolfssl.com>
---
 cmd/Kconfig        |   11 +
 cmd/Makefile       |   10 +-
 cmd/native_tpm2.c  |  516 +++++++++++++++++++
 cmd/tpm-v2.c       |  559 +++------------------
 cmd/tpm2-backend.h |   66 +++
 cmd/wolftpm.c      | 1170 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 1840 insertions(+), 492 deletions(-)
 create mode 100644 cmd/native_tpm2.c
 create mode 100644 cmd/tpm2-backend.h
 create mode 100644 cmd/wolftpm.c

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 322ebe600c5..d9360d5237a 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -3202,4 +3202,15 @@ config CMD_SPAWN_NUM_JOBS
 	  When a jobs exits, its identifier is available to be re-used by the next
 	  spawn command.
 
+config CMD_WOLFTPM
+	bool "Use wolfTPM as TPM2 backend"
+	depends on TPM_V2
+	select TPM_WOLF
+	select CMD_TPM_V2
+	help
+	  Use the wolfTPM library as the backend for TPM2 commands instead
+	  of the standard U-Boot TPM2 implementation. wolfTPM offers additional
+	  features including firmware update support for Infineon TPMs and
+	  enhanced capabilities reporting.
+
 endif
diff --git a/cmd/Makefile b/cmd/Makefile
index 4cd13d4fa6e..2b12b26e61f 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -191,9 +191,17 @@ obj-$(CONFIG_CMD_TIMER) += timer.o
 obj-$(CONFIG_CMD_TRACE) += trace.o
 obj-$(CONFIG_HUSH_PARSER) += test.o
 obj-$(CONFIG_CMD_TPM) += tpm-common.o
-obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
 obj-$(CONFIG_CMD_TPM_TEST) += tpm_test.o
+obj-$(CONFIG_CMD_TPM_V1) += tpm-v1.o
 obj-$(CONFIG_CMD_TPM_V2) += tpm-v2.o
+ifeq ($(CONFIG_TPM_WOLF),y)
+ccflags-y += -I$(srctree)/lib/wolftpm \
+             -I$(srctree)/include/configs \
+             -DWOLFTPM_USER_SETTINGS
+obj-$(CONFIG_CMD_TPM_V2) += wolftpm.o
+else
+obj-$(CONFIG_CMD_TPM_V2) += native_tpm2.o
+endif
 obj-$(CONFIG_CMD_CROS_EC) += cros_ec.o
 obj-$(CONFIG_CMD_UBI) += ubi.o
 obj-$(CONFIG_CMD_UBIFS) += ubifs.o
diff --git a/cmd/native_tpm2.c b/cmd/native_tpm2.c
new file mode 100644
index 00000000000..d8dea956156
--- /dev/null
+++ b/cmd/native_tpm2.c
@@ -0,0 +1,516 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Native TPM2 backend implementation
+ *
+ * Copyright (c) 2018 Bootlin
+ * Author: Miquel Raynal <miquel.raynal at bootlin.com>
+ */
+
+#include <command.h>
+#include <dm.h>
+#include <log.h>
+#include <mapmem.h>
+#include <tpm-common.h>
+#include <tpm-v2.h>
+#include "tpm-user-utils.h"
+
+/* Wrappers for common commands - delegate to tpm-common.c */
+int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, int argc,
+		   char *const argv[])
+{
+	return do_tpm_device(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	return do_tpm_info(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[])
+{
+	return do_tpm_report_state(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[])
+{
+	return do_tpm_init(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[])
+{
+	return do_tpm_autostart(cmdtp, flag, argc, argv);
+}
+
+int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[])
+{
+	enum tpm2_startup_types mode;
+	struct udevice *dev;
+	int ret;
+	bool bon = true;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	/* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */
+	if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2])))
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
+		mode = TPM2_SU_CLEAR;
+	} else if (!strcasecmp("TPM2_SU_STATE", argv[1])) {
+		mode = TPM2_SU_STATE;
+	} else {
+		printf("Couldn't recognize mode string: %s\n", argv[1]);
+		return CMD_RET_FAILURE;
+	}
+
+	if (argv[2])
+		bon = false;
+
+	return report_return_code(tpm2_startup(dev, bon, mode));
+}
+
+int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[])
+{
+	enum tpm2_yes_no full_test;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("full", argv[1])) {
+		full_test = TPMI_YES;
+	} else if (!strcasecmp("continue", argv[1])) {
+		full_test = TPMI_NO;
+	} else {
+		printf("Couldn't recognize test mode: %s\n", argv[1]);
+		return CMD_RET_FAILURE;
+	}
+
+	return report_return_code(tpm2_self_test(dev, full_test));
+}
+
+int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[])
+{
+	u32 handle = 0;
+	const char *pw = (argc < 3) ? NULL : argv[2];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc < 2 || argc > 3)
+		return CMD_RET_USAGE;
+
+	if (pw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
+		handle = TPM2_RH_LOCKOUT;
+	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
+		handle = TPM2_RH_PLATFORM;
+	else
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_clear(dev, handle, pw, pw_sz));
+}
+
+int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[])
+{
+	struct udevice *dev;
+	struct tpm_chip_priv *priv;
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
+	int algo = TPM2_ALG_SHA256;
+	int algo_len;
+	int ret;
+	u32 rc;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+	if (argc == 4) {
+		algo = tpm2_name_to_algorithm(argv[3]);
+		if (algo == TPM2_ALG_INVAL)
+			return CMD_RET_FAILURE;
+	}
+	algo_len = tpm2_algorithm_to_len(algo);
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	priv = dev_get_uclass_priv(dev);
+	if (!priv)
+		return -EINVAL;
+
+	if (index >= priv->pcr_count)
+		return -EINVAL;
+
+	rc = tpm2_pcr_extend(dev, index, algo, digest, algo_len);
+	if (!rc) {
+		printf("PCR #%u extended with %d byte %s digest\n", index,
+		       algo_len, tpm2_algorithm_name(algo));
+		print_byte_string(digest, algo_len);
+	}
+
+	unmap_sysmem(digest);
+
+	return report_return_code(rc);
+}
+
+int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[])
+{
+	enum tpm2_algorithms algo = TPM2_ALG_SHA256;
+	struct udevice *dev;
+	struct tpm_chip_priv *priv;
+	u32 index, rc;
+	int algo_len;
+	unsigned int updates;
+	void *data;
+	int ret;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+	if (argc == 4) {
+		algo = tpm2_name_to_algorithm(argv[3]);
+		if (algo == TPM2_ALG_INVAL)
+			return CMD_RET_FAILURE;
+	}
+	algo_len = tpm2_algorithm_to_len(algo);
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	priv = dev_get_uclass_priv(dev);
+	if (!priv)
+		return -EINVAL;
+
+	index = simple_strtoul(argv[1], NULL, 0);
+	if (index >= priv->pcr_count)
+		return -EINVAL;
+
+	data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
+
+	rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo,
+			   data, algo_len, &updates);
+	if (!rc) {
+		printf("PCR #%u %s %d byte content (%u known updates):\n", index,
+		       tpm2_algorithm_name(algo), algo_len, updates);
+		print_byte_string(data, algo_len);
+	}
+
+	unmap_sysmem(data);
+
+	return report_return_code(rc);
+}
+
+int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	u32 capability, property, rc;
+	u8 *data;
+	size_t count;
+	int i, j;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc != 5)
+		return CMD_RET_USAGE;
+
+	capability = simple_strtoul(argv[1], NULL, 0);
+	property = simple_strtoul(argv[2], NULL, 0);
+	data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
+	count = simple_strtoul(argv[4], NULL, 0);
+
+	rc = tpm2_get_capability(dev, capability, property, data, count);
+	if (rc)
+		goto unmap_data;
+
+	printf("Capabilities read from TPM:\n");
+	for (i = 0; i < count; i++) {
+		printf("Property 0x");
+		for (j = 0; j < 4; j++)
+			printf("%02x", data[(i * 8) + j + sizeof(u32)]);
+		printf(": 0x");
+		for (j = 4; j < 8; j++)
+			printf("%02x", data[(i * 8) + j + sizeof(u32)]);
+		printf("\n");
+	}
+
+unmap_data:
+	unmap_sysmem(data);
+
+	return report_return_code(rc);
+}
+
+static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
+		if (hash_algo_list[i].hash_alg != algo)
+			continue;
+
+		if (select)
+			mask |= hash_algo_list[i].hash_mask;
+		else
+			mask &= ~hash_algo_list[i].hash_mask;
+
+		break;
+	}
+
+	return mask;
+}
+
+static bool
+is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs)
+{
+	size_t i;
+
+	for (i = 0; i < pcrs->count; i++) {
+		if (algo == pcrs->selection[i].hash)
+			return true;
+	}
+
+	return false;
+}
+
+int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	struct udevice *dev;
+	int ret;
+	enum tpm2_algorithms algo;
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	static struct tpml_pcr_selection pcr = { 0 };
+	u32 pcr_len = 0;
+	bool bon = false;
+	static u32 mask;
+	int i;
+
+	/* argv[1]: algorithm (bank), argv[2]: on/off */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("on", argv[2]))
+		bon = true;
+	else if (strcasecmp("off", argv[2]))
+		return CMD_RET_USAGE;
+
+	algo = tpm2_name_to_algorithm(argv[1]);
+	if (algo == TPM2_ALG_INVAL)
+		return CMD_RET_USAGE;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (!pcr.count) {
+		/*
+		 * Get current active algorithms (banks), PCRs and mask via the
+		 * first call
+		 */
+		ret = tpm2_get_pcr_info(dev, &pcr);
+		if (ret)
+			return ret;
+
+		for (i = 0; i < pcr.count; i++) {
+			struct tpms_pcr_selection *sel = &pcr.selection[i];
+			const char *name;
+
+			if (!tpm2_is_active_bank(sel))
+				continue;
+
+			mask = select_mask(mask, sel->hash, true);
+			name = tpm2_algorithm_name(sel->hash);
+			if (name)
+				printf("Active bank[%d]: %s\n", i, name);
+		}
+	}
+
+	if (!is_algo_in_pcrs(algo, &pcr)) {
+		printf("%s is not supported by the tpm device\n", argv[1]);
+		return CMD_RET_USAGE;
+	}
+
+	mask = select_mask(mask, algo, bon);
+	ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
+	if (ret)
+		return ret;
+
+	return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr,
+							 pcr_len));
+}
+
+int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[])
+{
+	const char *pw = (argc < 2) ? NULL : argv[1];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc > 2)
+		return CMD_RET_USAGE;
+
+	if (pw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	return report_return_code(tpm2_dam_reset(dev, pw, pw_sz));
+}
+
+int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[])
+{
+	const char *pw = (argc < 5) ? NULL : argv[4];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	/*
+	 * No Dictionary Attack Mitigation (DAM) means:
+	 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0
+	 */
+	unsigned long int max_tries;
+	unsigned long int recovery_time;
+	unsigned long int lockout_recovery;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc < 4 || argc > 5)
+		return CMD_RET_USAGE;
+
+	if (pw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (strict_strtoul(argv[1], 0, &max_tries))
+		return CMD_RET_USAGE;
+
+	if (strict_strtoul(argv[2], 0, &recovery_time))
+		return CMD_RET_USAGE;
+
+	if (strict_strtoul(argv[3], 0, &lockout_recovery))
+		return CMD_RET_USAGE;
+
+	log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n");
+	log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries);
+	log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time);
+	log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery);
+
+	return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries,
+						      recovery_time,
+						      lockout_recovery));
+}
+
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[])
+{
+	u32 handle;
+	const char *newpw = argv[2];
+	const char *oldpw = (argc == 3) ? NULL : argv[3];
+	const ssize_t newpw_sz = strlen(newpw);
+	const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
+		handle = TPM2_RH_LOCKOUT;
+	else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1]))
+		handle = TPM2_RH_ENDORSEMENT;
+	else if (!strcasecmp("TPM2_RH_OWNER", argv[1]))
+		handle = TPM2_RH_OWNER;
+	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
+		handle = TPM2_RH_PLATFORM;
+	else
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz,
+						   oldpw, oldpw_sz));
+}
+
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
+			      char *const argv[])
+{
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	char *key = argv[2];
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (strlen(key) != TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index,
+							 key));
+}
+
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
+			     int argc, char *const argv[])
+{
+	u32 index = simple_strtoul(argv[1], NULL, 0);
+	char *key = argv[2];
+	const ssize_t key_sz = strlen(key);
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	struct udevice *dev;
+	int ret;
+
+	ret = get_tpm(&dev);
+	if (ret)
+		return ret;
+
+	if (strlen(key) != TPM2_DIGEST_LEN)
+		return -EINVAL;
+
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index,
+							key, key_sz));
+}
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
index 847b2691581..a131a81d1a4 100644
--- a/cmd/tpm-v2.c
+++ b/cmd/tpm-v2.c
@@ -1,507 +1,51 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
+ * TPM2 command frontend - command table, dispatcher, and help text
+ *
+ * The actual command implementations are provided by the backend:
+ *   - native_tpm2.c: U-Boot native TPM2 APIs (driver model)
+ *   - wolftpm.c: wolfTPM library APIs
+ *
  * Copyright (c) 2018 Bootlin
  * Author: Miquel Raynal <miquel.raynal at bootlin.com>
  */
 
 #include <command.h>
-#include <dm.h>
-#include <log.h>
-#include <mapmem.h>
 #include <tpm-common.h>
-#include <tpm-v2.h>
-#include "tpm-user-utils.h"
-
-static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
-			   char *const argv[])
-{
-	enum tpm2_startup_types mode;
-	struct udevice *dev;
-	int ret;
-	bool bon = true;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	/* argv[2] is optional to perform a TPM2_CC_SHUTDOWN */
-	if (argc > 3 || (argc == 3 && strcasecmp("off", argv[2])))
-		return CMD_RET_USAGE;
-
-	if (!strcasecmp("TPM2_SU_CLEAR", argv[1])) {
-		mode = TPM2_SU_CLEAR;
-	} else if (!strcasecmp("TPM2_SU_STATE", argv[1])) {
-		mode = TPM2_SU_STATE;
-	} else {
-		printf("Couldn't recognize mode string: %s\n", argv[1]);
-		return CMD_RET_FAILURE;
-	}
-
-	if (argv[2])
-		bon = false;
-
-	return report_return_code(tpm2_startup(dev, bon, mode));
-}
-
-static int do_tpm2_self_test(struct cmd_tbl *cmdtp, int flag, int argc,
-			     char *const argv[])
-{
-	enum tpm2_yes_no full_test;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-	if (argc != 2)
-		return CMD_RET_USAGE;
-
-	if (!strcasecmp("full", argv[1])) {
-		full_test = TPMI_YES;
-	} else if (!strcasecmp("continue", argv[1])) {
-		full_test = TPMI_NO;
-	} else {
-		printf("Couldn't recognize test mode: %s\n", argv[1]);
-		return CMD_RET_FAILURE;
-	}
-
-	return report_return_code(tpm2_self_test(dev, full_test));
-}
-
-static int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
-			 char *const argv[])
-{
-	u32 handle = 0;
-	const char *pw = (argc < 3) ? NULL : argv[2];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc < 2 || argc > 3)
-		return CMD_RET_USAGE;
-
-	if (pw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
-		handle = TPM2_RH_LOCKOUT;
-	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
-		handle = TPM2_RH_PLATFORM;
-	else
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_clear(dev, handle, pw, pw_sz));
-}
-
-static int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
-			      char *const argv[])
-{
-	struct udevice *dev;
-	struct tpm_chip_priv *priv;
-	u32 index = simple_strtoul(argv[1], NULL, 0);
-	void *digest = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
-	int algo = TPM2_ALG_SHA256;
-	int algo_len;
-	int ret;
-	u32 rc;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-	if (argc == 4) {
-		algo = tpm2_name_to_algorithm(argv[3]);
-		if (algo == TPM2_ALG_INVAL)
-			return CMD_RET_FAILURE;
-	}
-	algo_len = tpm2_algorithm_to_len(algo);
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	priv = dev_get_uclass_priv(dev);
-	if (!priv)
-		return -EINVAL;
-
-	if (index >= priv->pcr_count)
-		return -EINVAL;
-
-	rc = tpm2_pcr_extend(dev, index, algo, digest, algo_len);
-	if (!rc) {
-		printf("PCR #%u extended with %d byte %s digest\n", index,
-		       algo_len, tpm2_algorithm_name(algo));
-		print_byte_string(digest, algo_len);
-	}
-
-	unmap_sysmem(digest);
-
-	return report_return_code(rc);
-}
-
-static int do_tpm_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
-			   char *const argv[])
-{
-	enum tpm2_algorithms algo = TPM2_ALG_SHA256;
-	struct udevice *dev;
-	struct tpm_chip_priv *priv;
-	u32 index, rc;
-	int algo_len;
-	unsigned int updates;
-	void *data;
-	int ret;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-	if (argc == 4) {
-		algo = tpm2_name_to_algorithm(argv[3]);
-		if (algo == TPM2_ALG_INVAL)
-			return CMD_RET_FAILURE;
-	}
-	algo_len = tpm2_algorithm_to_len(algo);
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	priv = dev_get_uclass_priv(dev);
-	if (!priv)
-		return -EINVAL;
-
-	index = simple_strtoul(argv[1], NULL, 0);
-	if (index >= priv->pcr_count)
-		return -EINVAL;
-
-	data = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
-
-	rc = tpm2_pcr_read(dev, index, priv->pcr_select_min, algo,
-			   data, algo_len, &updates);
-	if (!rc) {
-		printf("PCR #%u %s %d byte content (%u known updates):\n", index,
-		       tpm2_algorithm_name(algo), algo_len, updates);
-		print_byte_string(data, algo_len);
-	}
-
-	unmap_sysmem(data);
-
-	return report_return_code(rc);
-}
-
-static int do_tpm_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
-				 char *const argv[])
-{
-	u32 capability, property, rc;
-	u8 *data;
-	size_t count;
-	int i, j;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc != 5)
-		return CMD_RET_USAGE;
-
-	capability = simple_strtoul(argv[1], NULL, 0);
-	property = simple_strtoul(argv[2], NULL, 0);
-	data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
-	count = simple_strtoul(argv[4], NULL, 0);
-
-	rc = tpm2_get_capability(dev, capability, property, data, count);
-	if (rc)
-		goto unmap_data;
-
-	printf("Capabilities read from TPM:\n");
-	for (i = 0; i < count; i++) {
-		printf("Property 0x");
-		for (j = 0; j < 4; j++)
-			printf("%02x", data[(i * 8) + j + sizeof(u32)]);
-		printf(": 0x");
-		for (j = 4; j < 8; j++)
-			printf("%02x", data[(i * 8) + j + sizeof(u32)]);
-		printf("\n");
-	}
-
-unmap_data:
-	unmap_sysmem(data);
-
-	return report_return_code(rc);
-}
-
-static u32 select_mask(u32 mask, enum tpm2_algorithms algo, bool select)
-{
-	size_t i;
-
-	for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
-		if (hash_algo_list[i].hash_alg != algo)
-			continue;
-
-		if (select)
-			mask |= hash_algo_list[i].hash_mask;
-		else
-			mask &= ~hash_algo_list[i].hash_mask;
-
-		break;
-	}
-
-	return mask;
-}
-
-static bool
-is_algo_in_pcrs(enum tpm2_algorithms algo, struct tpml_pcr_selection *pcrs)
-{
-	size_t i;
-
-	for (i = 0; i < pcrs->count; i++) {
-		if (algo == pcrs->selection[i].hash)
-			return true;
-	}
-
-	return false;
-}
-
-static int do_tpm2_pcrallocate(struct cmd_tbl *cmdtp, int flag, int argc,
-			       char *const argv[])
-{
-	struct udevice *dev;
-	int ret;
-	enum tpm2_algorithms algo;
-	const char *pw = (argc < 4) ? NULL : argv[3];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	static struct tpml_pcr_selection pcr = { 0 };
-	u32 pcr_len = 0;
-	bool bon = false;
-	static u32 mask;
-	int i;
-
-	/* argv[1]: algorithm (bank), argv[2]: on/off */
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	if (!strcasecmp("on", argv[2]))
-		bon = true;
-	else if (strcasecmp("off", argv[2]))
-		return CMD_RET_USAGE;
-
-	algo = tpm2_name_to_algorithm(argv[1]);
-	if (algo == TPM2_ALG_INVAL)
-		return CMD_RET_USAGE;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (!pcr.count) {
-		/*
-		 * Get current active algorithms (banks), PCRs and mask via the
-		 * first call
-		 */
-		ret = tpm2_get_pcr_info(dev, &pcr);
-		if (ret)
-			return ret;
-
-		for (i = 0; i < pcr.count; i++) {
-			struct tpms_pcr_selection *sel = &pcr.selection[i];
-			const char *name;
-
-			if (!tpm2_is_active_bank(sel))
-				continue;
-
-			mask = select_mask(mask, sel->hash, true);
-			name = tpm2_algorithm_name(sel->hash);
-			if (name)
-				printf("Active bank[%d]: %s\n", i, name);
-		}
-	}
-
-	if (!is_algo_in_pcrs(algo, &pcr)) {
-		printf("%s is not supported by the tpm device\n", argv[1]);
-		return CMD_RET_USAGE;
-	}
-
-	mask = select_mask(mask, algo, bon);
-	ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
-	if (ret)
-		return ret;
-
-	return report_return_code(tpm2_send_pcr_allocate(dev, pw, pw_sz, &pcr,
-							 pcr_len));
-}
-
-static int do_tpm_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
-			    char *const argv[])
-{
-	const char *pw = (argc < 2) ? NULL : argv[1];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc > 2)
-		return CMD_RET_USAGE;
-
-	if (pw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	return report_return_code(tpm2_dam_reset(dev, pw, pw_sz));
-}
-
-static int do_tpm_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
-				 char *const argv[])
-{
-	const char *pw = (argc < 5) ? NULL : argv[4];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	/*
-	 * No Dictionary Attack Mitigation (DAM) means:
-	 * maxtries = 0xFFFFFFFF, recovery_time = 1, lockout_recovery = 0
-	 */
-	unsigned long int max_tries;
-	unsigned long int recovery_time;
-	unsigned long int lockout_recovery;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc < 4 || argc > 5)
-		return CMD_RET_USAGE;
-
-	if (pw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (strict_strtoul(argv[1], 0, &max_tries))
-		return CMD_RET_USAGE;
-
-	if (strict_strtoul(argv[2], 0, &recovery_time))
-		return CMD_RET_USAGE;
-
-	if (strict_strtoul(argv[3], 0, &lockout_recovery))
-		return CMD_RET_USAGE;
-
-	log(LOGC_NONE, LOGL_INFO, "Changing dictionary attack parameters:\n");
-	log(LOGC_NONE, LOGL_INFO, "- maxTries: %lu", max_tries);
-	log(LOGC_NONE, LOGL_INFO, "- recoveryTime: %lu\n", recovery_time);
-	log(LOGC_NONE, LOGL_INFO, "- lockoutRecovery: %lu\n", lockout_recovery);
-
-	return report_return_code(tpm2_dam_parameters(dev, pw, pw_sz, max_tries,
-						      recovery_time,
-						      lockout_recovery));
-}
-
-static int do_tpm_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
-			      char *const argv[])
-{
-	u32 handle;
-	const char *newpw = argv[2];
-	const char *oldpw = (argc == 3) ? NULL : argv[3];
-	const ssize_t newpw_sz = strlen(newpw);
-	const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	if (newpw_sz > TPM2_DIGEST_LEN || oldpw_sz > TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
-		handle = TPM2_RH_LOCKOUT;
-	else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1]))
-		handle = TPM2_RH_ENDORSEMENT;
-	else if (!strcasecmp("TPM2_RH_OWNER", argv[1]))
-		handle = TPM2_RH_OWNER;
-	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
-		handle = TPM2_RH_PLATFORM;
-	else
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_change_auth(dev, handle, newpw, newpw_sz,
-						   oldpw, oldpw_sz));
-}
-
-static int do_tpm_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
-				    char *const argv[])
-{
-	u32 index = simple_strtoul(argv[1], NULL, 0);
-	char *key = argv[2];
-	const char *pw = (argc < 4) ? NULL : argv[3];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (strlen(key) != TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_pcr_setauthpolicy(dev, pw, pw_sz, index,
-							 key));
-}
-
-static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
-				   int argc, char *const argv[])
-{
-	u32 index = simple_strtoul(argv[1], NULL, 0);
-	char *key = argv[2];
-	const ssize_t key_sz = strlen(key);
-	const char *pw = (argc < 4) ? NULL : argv[3];
-	const ssize_t pw_sz = pw ? strlen(pw) : 0;
-	struct udevice *dev;
-	int ret;
-
-	ret = get_tpm(&dev);
-	if (ret)
-		return ret;
-
-	if (strlen(key) != TPM2_DIGEST_LEN)
-		return -EINVAL;
-
-	if (argc < 3 || argc > 4)
-		return CMD_RET_USAGE;
-
-	return report_return_code(tpm2_pcr_setauthvalue(dev, pw, pw_sz, index,
-							key, key_sz));
-}
+#include "tpm2-backend.h"
 
 static struct cmd_tbl tpm2_commands[] = {
-	U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
-	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
-	U_BOOT_CMD_MKENT(state, 0, 1, do_tpm_report_state, "", ""),
-	U_BOOT_CMD_MKENT(init, 0, 1, do_tpm_init, "", ""),
+	U_BOOT_CMD_MKENT(device, 0, 1, do_tpm2_device, "", ""),
+	U_BOOT_CMD_MKENT(info, 0, 1, do_tpm2_info, "", ""),
+	U_BOOT_CMD_MKENT(state, 0, 1, do_tpm2_state, "", ""),
+	U_BOOT_CMD_MKENT(init, 0, 1, do_tpm2_init, "", ""),
+	U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm2_autostart, "", ""),
 	U_BOOT_CMD_MKENT(startup, 0, 1, do_tpm2_startup, "", ""),
-	U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_self_test, "", ""),
+	U_BOOT_CMD_MKENT(self_test, 0, 1, do_tpm2_selftest, "", ""),
 	U_BOOT_CMD_MKENT(clear, 0, 1, do_tpm2_clear, "", ""),
 	U_BOOT_CMD_MKENT(pcr_extend, 0, 1, do_tpm2_pcr_extend, "", ""),
-	U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm_pcr_read, "", ""),
-	U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm_get_capability, "", ""),
-	U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""),
-	U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""),
-	U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""),
-	U_BOOT_CMD_MKENT(autostart, 0, 1, do_tpm_autostart, "", ""),
+	U_BOOT_CMD_MKENT(pcr_read, 0, 1, do_tpm2_pcr_read, "", ""),
+	U_BOOT_CMD_MKENT(get_capability, 0, 1, do_tpm2_get_capability, "", ""),
+	U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm2_dam_reset, "", ""),
+	U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm2_dam_parameters, "", ""),
+	U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm2_change_auth, "", ""),
 	U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1,
-			 do_tpm_pcr_setauthpolicy, "", ""),
+			 do_tpm2_pcr_setauthpolicy, "", ""),
 	U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
-			 do_tpm_pcr_setauthvalue, "", ""),
-	U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcrallocate, "", ""),
+			 do_tpm2_pcr_setauthvalue, "", ""),
+	U_BOOT_CMD_MKENT(pcr_allocate, 0, 1, do_tpm2_pcr_allocate, "", ""),
+#ifdef CONFIG_TPM_WOLF
+	U_BOOT_CMD_MKENT(caps, 0, 1, do_tpm2_caps, "", ""),
+	U_BOOT_CMD_MKENT(pcr_print, 0, 1, do_tpm2_pcr_print, "", ""),
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+	U_BOOT_CMD_MKENT(firmware_update, 0, 1,
+			 do_tpm2_firmware_update, "", ""),
+	U_BOOT_CMD_MKENT(firmware_cancel, 0, 1,
+			 do_tpm2_firmware_cancel, "", ""),
+#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+#endif /* CONFIG_TPM_WOLF */
 };
 
 struct cmd_tbl *get_tpm2_commands(unsigned int *size)
@@ -511,7 +55,22 @@ struct cmd_tbl *get_tpm2_commands(unsigned int *size)
 	return tpm2_commands;
 }
 
-U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
+static int do_tpm2(struct cmd_tbl *cmdtp, int flag, int argc,
+		   char *const argv[])
+{
+	struct cmd_tbl *cmd;
+
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	cmd = find_cmd_tbl(argv[1], tpm2_commands, ARRAY_SIZE(tpm2_commands));
+	if (!cmd)
+		return CMD_RET_USAGE;
+
+	return cmd->cmd(cmdtp, flag, argc - 1, argv + 1);
+}
+
+U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm2, "Issue a TPMv2.x command",
 "<command> [<arguments>]\n"
 "\n"
 "device [num device]\n"
@@ -521,7 +80,7 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "state\n"
 "    Show internal state from the TPM (if available)\n"
 "autostart\n"
-"    Initalize the tpm, perform a Startup(clear) and run a full selftest\n"
+"    Initialize the tpm, perform a Startup(clear) and run a full selftest\n"
 "    sequence\n"
 "init\n"
 "    Initialize the software stack. Always the first command to issue.\n"
@@ -573,6 +132,10 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "    <password>: optional password of the LOCKOUT hierarchy\n"
 "change_auth <hierarchy> <new_pw> [<old_pw>]\n"
 "    <hierarchy>: the hierarchy\n"
+"        * TPM2_RH_LOCKOUT\n"
+"        * TPM2_RH_ENDORSEMENT\n"
+"        * TPM2_RH_OWNER\n"
+"        * TPM2_RH_PLATFORM\n"
 "    <new_pw>: new password for <hierarchy>\n"
 "    <old_pw>: optional previous password of <hierarchy>\n"
 "pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n"
@@ -596,4 +159,18 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "        * off - Clear all available PCRs associated with the specified\n"
 "                algorithm (bank)\n"
 "    <password>: optional password\n"
+#ifdef CONFIG_TPM_WOLF
+"caps\n"
+"    Show TPM capabilities and info\n"
+"pcr_print\n"
+"    Prints the current PCR state\n"
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+"firmware_update <manifest_addr> <manifest_sz> <firmware_addr> <firmware_sz>\n"
+"    Update TPM firmware\n"
+"firmware_cancel\n"
+"    Cancel TPM firmware update\n"
+#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+#endif /* CONFIG_TPM_WOLF */
 );
diff --git a/cmd/tpm2-backend.h b/cmd/tpm2-backend.h
new file mode 100644
index 00000000000..39e9a3a6b7b
--- /dev/null
+++ b/cmd/tpm2-backend.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * TPM2 backend function declarations
+ *
+ * Each backend (native_tpm2.c or wolftpm.c) implements these functions.
+ * The frontend (tpm-v2.c) references them in the command table.
+ */
+
+#ifndef __TPM2_BACKEND_H
+#define __TPM2_BACKEND_H
+
+#include <command.h>
+
+/* Common TPM2 command handlers - both backends must implement these */
+int do_tpm2_device(struct cmd_tbl *cmdtp, int flag, int argc,
+		   char *const argv[]);
+int do_tpm2_info(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+int do_tpm2_state(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[]);
+int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[]);
+int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc,
+		    char *const argv[]);
+int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[]);
+int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag, int argc,
+		  char *const argv[]);
+int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag, int argc,
+		       char *const argv[]);
+int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag, int argc,
+		     char *const argv[]);
+int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[]);
+int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[]);
+int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag, int argc,
+			   char *const argv[]);
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag, int argc,
+			char *const argv[]);
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag, int argc,
+			      char *const argv[]);
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag, int argc,
+			     char *const argv[]);
+int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag, int argc,
+			 char *const argv[]);
+
+/* wolfTPM-only command handlers */
+#ifdef CONFIG_TPM_WOLF
+int do_tpm2_caps(struct cmd_tbl *cmdtp, int flag, int argc,
+		 char *const argv[]);
+int do_tpm2_pcr_print(struct cmd_tbl *cmdtp, int flag, int argc,
+		      char *const argv[]);
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag, int argc,
+			    char *const argv[]);
+int do_tpm2_firmware_cancel(struct cmd_tbl *cmdtp, int flag, int argc,
+			    char *const argv[]);
+#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+#endif /* CONFIG_TPM_WOLF */
+
+#endif /* __TPM2_BACKEND_H */
diff --git a/cmd/wolftpm.c b/cmd/wolftpm.c
new file mode 100644
index 00000000000..06ea8d47c8a
--- /dev/null
+++ b/cmd/wolftpm.c
@@ -0,0 +1,1170 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TPM2 command implementation using wolfTPM library
+ *
+ * Copyright (C) 2025 wolfSSL Inc.
+ * Author: Aidan Garske <aidan at wolfssl.com>
+ */
+
+#define LOG_CATEGORY UCLASS_BOOTSTD
+
+#include <wolftpm/tpm2.h>
+#include <wolftpm/tpm2_wrap.h>
+#include <wolftpm/tpm2_packet.h>
+#include <wolftpm.h>
+
+#include <stdio.h>
+#include <hash.h>
+#ifndef WOLFTPM2_NO_WRAPPER
+
+#include <hal/tpm_io.h>
+#include <examples/wrap/wrap_test.h>
+
+/* U-boot specific includes */
+#include <command.h>
+#include <tpm-common.h>
+#include <vsprintf.h>
+#include <mapmem.h>
+#include <errno.h>
+#include <log.h>
+#include <string.h>
+
+/* Firmware update info structure for Infineon TPM */
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+struct fw_info {
+	byte *manifest_buf;
+	byte *firmware_buf;
+	size_t manifest_bufSz;
+	size_t firmware_bufSz;
+};
+#endif
+#endif
+
+/******************************************************************************/
+/* --- BEGIN Common Commands -- */
+/******************************************************************************/
+
+int do_tpm2_device(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_CAPS caps;
+	int rc;
+
+	/* Expected 1 arg only in native SPI mode (no device switching) */
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Try to initialize and get device info */
+	rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
+	if (!rc) {
+		rc = wolfTPM2_GetCapabilities(&dev, &caps);
+		if (!rc) {
+			printf("TPM Device 0: %s (%s) FW=%d.%d\n",
+				   caps.mfgStr, caps.vendorStr,
+				   caps.fwVerMajor, caps.fwVerMinor);
+		}
+		wolfTPM2_Cleanup(&dev);
+	}
+
+	if (rc != 0) {
+		printf("No TPM device found (rc=%d: %s)\n", rc, TPM2_GetRCString(rc));
+		return CMD_RET_FAILURE;
+	}
+
+	return 0;
+}
+
+int do_tpm2_info(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_CAPS caps;
+	int rc;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
+	if (!rc) {
+		rc = wolfTPM2_GetCapabilities(&dev, &caps);
+		if (!rc) {
+			printf("TPM 2.0: %s (%s)\n", caps.mfgStr, caps.vendorStr);
+			printf("  Firmware: %d.%d (0x%08X)\n",
+				   caps.fwVerMajor, caps.fwVerMinor, caps.fwVerVendor);
+			printf("  Type: 0x%08X\n", caps.tpmType);
+		}
+		wolfTPM2_Cleanup(&dev);
+	}
+
+	if (rc != 0) {
+		printf("Couldn't get TPM info (rc=%d: %s)\n", rc, TPM2_GetRCString(rc));
+		return CMD_RET_FAILURE;
+	}
+
+	log_debug("tpm2 info: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+	return 0;
+}
+
+int do_tpm2_state(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_CAPS caps;
+	int rc;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
+	if (!rc) {
+		rc = wolfTPM2_GetCapabilities(&dev, &caps);
+		if (!rc) {
+			printf("TPM State:\n");
+			printf("  Manufacturer: %s\n", caps.mfgStr);
+			printf("  Vendor: %s\n", caps.vendorStr);
+			printf("  Firmware: %d.%d\n", caps.fwVerMajor, caps.fwVerMinor);
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+			printf("  Mode: Infineon SLB967x (Native SPI)\n");
+			printf("  OpMode: %d\n", caps.opMode);
+#else
+			printf("  Mode: Native wolfTPM SPI\n");
+#endif
+		}
+		wolfTPM2_Cleanup(&dev);
+	}
+
+	if (rc != 0) {
+		printf("Couldn't get TPM state (rc=%d: %s)\n", rc, TPM2_GetRCString(rc));
+		return CMD_RET_FAILURE;
+	}
+
+	log_debug("tpm2 state: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+	return 0;
+}
+
+int do_tpm2_init(struct cmd_tbl *cmdtp, int flag, int argc,
+	char *const argv[])
+{
+	WOLFTPM2_DEV dev;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	return TPM2_Init_Device(&dev, NULL);
+}
+
+int do_tpm2_autostart(struct cmd_tbl *cmdtp, int flag, int argc,
+	char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		return rc;
+
+	/* Perform a startup clear - doStartup=1: Just starts up the TPM */
+	rc = wolfTPM2_Reset(&dev, 0, 1);
+	/* TPM_RC_INITIALIZE means already started - treat as success */
+	if (rc == TPM_RC_INITIALIZE)
+		rc = TPM_RC_SUCCESS;
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("wolfTPM2_Reset failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+		return rc;
+	}
+
+	/* Perform a full self test */
+	rc = wolfTPM2_SelfTest(&dev);
+	if (rc != TPM_RC_SUCCESS)
+		log_debug("wolfTPM2_SelfTest failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+
+	log_debug("tpm2 autostart: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+/******************************************************************************/
+/* --- END Common Commands -- */
+/******************************************************************************/
+
+/******************************************************************************/
+/* --- START TPM 2.0 Commands -- */
+/******************************************************************************/
+
+int do_tpm2_get_capability(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	GetCapability_In  in;
+	GetCapability_Out out;
+	u32 capability, property, rc;
+	u8 *data;
+	size_t count;
+	int i, j;
+
+	if (argc != 5)
+		return CMD_RET_USAGE;
+
+	capability = simple_strtoul(argv[1], NULL, 0);
+	property = simple_strtoul(argv[2], NULL, 0);
+	data = map_sysmem(simple_strtoul(argv[3], NULL, 0), 0);
+	count = simple_strtoul(argv[4], NULL, 0);
+
+	memset(&in, 0, sizeof(in));
+	memset(&out, 0, sizeof(out));
+	in.capability = capability;
+	in.property = property;
+	in.propertyCount = count;
+	rc = TPM2_GetCapability(&in, &out);
+	if (!rc) {
+		memcpy(data, &out.capabilityData.data, sizeof(out.capabilityData.data));
+
+		printf("Capabilities read from TPM:\n");
+		for (i = 0; i < count; i++) {
+			printf("Property 0x");
+			for (j = 0; j < 4; j++)
+				printf("%02x", data[(i * 8) + j + sizeof(u32)]);
+			printf(": 0x");
+			for (j = 4; j < 8; j++)
+				printf("%02x", data[(i * 8) + j + sizeof(u32)]);
+			printf("\n");
+		}
+	}
+
+	unmap_sysmem(data);
+
+	log_debug("tpm2 get_capability: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_caps(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_CAPS caps;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		return rc;
+
+	rc = wolfTPM2_GetCapabilities(&dev, &caps);
+	if (rc != TPM_RC_SUCCESS)
+		goto cleanup;
+
+	log_debug("Mfg %s (%d), Vendor %s, Fw %u.%u (0x%x), "
+		"FIPS 140-2 %d, CC-EAL4 %d\n",
+		caps.mfgStr, caps.mfg, caps.vendorStr, caps.fwVerMajor,
+		caps.fwVerMinor, caps.fwVerVendor, caps.fips140_2, caps.cc_eal4);
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+	log_debug("Operational mode: %s (0x%x)\n",
+		TPM2_IFX_GetOpModeStr(caps.opMode), caps.opMode);
+	log_debug("KeyGroupId 0x%x, FwCounter %d (%d same)\n",
+		caps.keyGroupId, caps.fwCounter, caps.fwCounterSame);
+#endif
+
+	/* List the active persistent handles */
+	rc = wolfTPM2_GetHandles(PERSISTENT_FIRST, NULL);
+	if (rc >= TPM_RC_SUCCESS)
+		log_debug("Found %d persistent handles\n", rc);
+
+	/* Print the available PCR's */
+	rc = TPM2_PCRs_Print();
+
+cleanup:
+	/* Only doShutdown=1: Just shut down the TPM */
+	wolfTPM2_Reset(&dev, 1, 0);
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 caps: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+#ifdef WOLFTPM_FIRMWARE_UPGRADE
+#if defined(WOLFTPM_SLB9672) || defined(WOLFTPM_SLB9673)
+int do_tpm2_firmware_update(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_CAPS caps;
+	struct fw_info fwinfo;
+	ulong manifest_addr, firmware_addr;
+	size_t manifest_sz, firmware_sz;
+	uint8_t manifest_hash[TPM_SHA384_DIGEST_SIZE];
+	int recovery = 0;
+
+	memset(&fwinfo, 0, sizeof(fwinfo));
+
+	/* Need 5 args: command + 4 arguments */
+	if (argc != 5) {
+		log_debug("Error: Expected 5 arguments but got %d\n", argc);
+		return CMD_RET_USAGE;
+	}
+	printf("TPM2 Firmware Update\n");
+
+	/* Convert all arguments from strings to numbers */
+	manifest_addr = simple_strtoul(argv[1], NULL, 0);
+	manifest_sz = simple_strtoul(argv[2], NULL, 0);
+	firmware_addr = simple_strtoul(argv[3], NULL, 0);
+	firmware_sz = simple_strtoul(argv[4], NULL, 0);
+
+	/* Map the memory addresses */
+	fwinfo.manifest_buf = map_sysmem(manifest_addr, manifest_sz);
+	fwinfo.firmware_buf = map_sysmem(firmware_addr, firmware_sz);
+	fwinfo.manifest_bufSz = manifest_sz;
+	fwinfo.firmware_bufSz = firmware_sz;
+
+	if (fwinfo.manifest_buf == NULL || fwinfo.firmware_buf == NULL) {
+		log_debug("Error: Invalid memory addresses\n");
+		return CMD_RET_FAILURE;
+	}
+
+	printf("Infineon Firmware Update Tool\n");
+	printf("\tManifest Address: 0x%lx (size: %zu)\n",
+		manifest_addr, manifest_sz);
+	printf("\tFirmware Address: 0x%lx (size: %zu)\n",
+		firmware_addr, firmware_sz);
+
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		goto fw_cleanup;
+
+	rc = wolfTPM2_GetCapabilities(&dev, &caps);
+	if (rc != TPM_RC_SUCCESS)
+		goto fw_cleanup;
+
+	TPM2_IFX_PrintInfo(&caps);
+	if (caps.keyGroupId == 0)
+		log_debug("Error getting key group id from TPM!\n");
+	if (caps.opMode == 0x02 || (caps.opMode & 0x80))
+		recovery = 1;
+
+	if (recovery) {
+		printf("Firmware Update (recovery mode):\n");
+		rc = wolfTPM2_FirmwareUpgradeRecover(&dev,
+			fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz,
+			TPM2_IFX_FwData_Cb, &fwinfo);
+	} else {
+		/* Normal mode - hash with wc_Sha384Hash */
+		printf("Firmware Update (normal mode):\n");
+		rc = wc_Sha384Hash(fwinfo.manifest_buf,
+			(uint32_t)fwinfo.manifest_bufSz, manifest_hash);
+		if (rc != TPM_RC_SUCCESS)
+			goto fw_cleanup;
+		rc = wolfTPM2_FirmwareUpgradeHash(&dev, TPM_ALG_SHA384,
+			manifest_hash, (uint32_t)sizeof(manifest_hash),
+			fwinfo.manifest_buf, (uint32_t)fwinfo.manifest_bufSz,
+			TPM2_IFX_FwData_Cb, &fwinfo);
+	}
+
+	if (!rc)
+		TPM2_IFX_PrintInfo(&caps);
+
+fw_cleanup:
+	if (fwinfo.manifest_buf)
+		unmap_sysmem(fwinfo.manifest_buf);
+	if (fwinfo.firmware_buf)
+		unmap_sysmem(fwinfo.firmware_buf);
+
+	if (rc != TPM_RC_SUCCESS)
+		log_debug("Infineon firmware update failed 0x%x: %s\n",
+			rc, TPM2_GetRCString(rc));
+
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 firmware_update: rc=%d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_firmware_cancel(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	uint8_t cmd[TPM2_HEADER_SIZE + 2];
+	uint16_t val16;
+
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc == TPM_RC_SUCCESS) {
+		/* Setup command size in header */
+		val16 = TPM2_HEADER_SIZE + 2;
+		memcpy(cmd, &val16, sizeof(val16));
+		val16 = 0;
+		memcpy(&cmd[TPM2_HEADER_SIZE], &val16, sizeof(val16));
+
+		rc = TPM2_IFX_FieldUpgradeCommand(TPM_CC_FieldUpgradeAbandonVendor,
+			cmd, sizeof(cmd));
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("Firmware abandon failed 0x%x: %s\n",
+				rc, TPM2_GetRCString(rc));
+		}
+	}
+
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 firmware_cancel: rc=%d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+#endif /* WOLFTPM_SLB9672 || WOLFTPM_SLB9673 */
+#endif /* WOLFTPM_FIRMWARE_UPGRADE */
+
+int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	Startup_In startupIn;
+	Shutdown_In shutdownIn;
+	int doStartup = YES;
+
+	/* startup TPM2_SU_CLEAR|TPM2_SU_STATE [off] */
+	if (argc < 2 || argc > 3)
+		return CMD_RET_USAGE;
+	/* Check if shutdown requested */
+	if (argc == 3) {
+		if (strcmp(argv[2], "off") != 0)
+			return CMD_RET_USAGE;
+		doStartup = NO; /* shutdown */
+	}
+	printf("TPM2 Startup\n");
+
+	memset(&startupIn, 0, sizeof(startupIn));
+	memset(&shutdownIn, 0, sizeof(shutdownIn));
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		return rc;
+
+	if (!strcmp(argv[1], "TPM2_SU_CLEAR")) {
+		if (doStartup == YES)
+			startupIn.startupType = TPM_SU_CLEAR;
+		else
+			shutdownIn.shutdownType = TPM_SU_CLEAR;
+	} else if (!strcmp(argv[1], "TPM2_SU_STATE")) {
+		if (doStartup == YES)
+			startupIn.startupType = TPM_SU_STATE;
+		else
+			shutdownIn.shutdownType = TPM_SU_STATE;
+	} else {
+		log_debug("Couldn't recognize mode string: %s\n", argv[1]);
+		wolfTPM2_Cleanup(&dev);
+		return CMD_RET_FAILURE;
+	}
+
+	/* startup */
+	if (doStartup == YES) {
+		rc = TPM2_Startup(&startupIn);
+		/* TPM_RC_INITIALIZE = Already started */
+		if (rc != TPM_RC_SUCCESS && rc != TPM_RC_INITIALIZE) {
+			log_debug("TPM2 Startup: Result = 0x%x (%s)\n", rc,
+				TPM2_GetRCString(rc));
+		}
+	/* shutdown */
+	} else {
+		rc = TPM2_Shutdown(&shutdownIn);
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("TPM2 Shutdown: Result = 0x%x (%s)\n", rc,
+				TPM2_GetRCString(rc));
+		}
+	}
+
+	wolfTPM2_Cleanup(&dev);
+
+	if (rc >= 0)
+		rc = 0;
+
+	log_debug("tpm2 startup (%s): rc = %d (%s)\n",
+		doStartup ? "startup" : "shutdown", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_selftest(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	TPMI_YES_NO fullTest = YES;
+
+	/* Need 2 arg: command + type */
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc == TPM_RC_SUCCESS) {
+		if (!strcmp(argv[1], "full")) {
+			fullTest = YES;
+		} else if (!strcmp(argv[1], "continue")) {
+			fullTest = NO;
+		} else {
+			log_debug("Couldn't recognize test mode: %s\n", argv[1]);
+			wolfTPM2_Cleanup(&dev);
+			return CMD_RET_FAILURE;
+		}
+
+		/* full test */
+		if (fullTest == YES) {
+			rc = wolfTPM2_SelfTest(&dev);
+			if (rc != TPM_RC_SUCCESS) {
+				log_debug("TPM2 Self Test: Result = 0x%x (%s)\n", rc,
+					TPM2_GetRCString(rc));
+			}
+		/* continue test */
+		} else {
+			rc = wolfTPM2_SelfTest(&dev);
+			if (rc != TPM_RC_SUCCESS) {
+				log_debug("TPM2 Self Test: Result = 0x%x (%s)\n", rc,
+					TPM2_GetRCString(rc));
+			}
+		}
+	}
+
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 selftest (%s): rc = %d (%s)\n",
+		fullTest ? "full" : "continue", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_clear(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	Clear_In clearIn;
+	TPMI_RH_CLEAR handle;
+
+	/* Need 2 arg: command + type */
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
+		handle = TPM_RH_LOCKOUT;
+	else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
+		handle = TPM_RH_PLATFORM;
+	else
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc == TPM_RC_SUCCESS) {
+		/* Set up clear */
+		memset(&clearIn, 0, sizeof(clearIn));
+		clearIn.authHandle = handle;
+
+		rc = TPM2_Clear(&clearIn);
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("TPM2 Clear: Result = 0x%x (%s)\n", rc,
+				TPM2_GetRCString(rc));
+		}
+	}
+
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 clear (%s): rc = %d (%s)\n",
+		handle == TPM_RH_LOCKOUT ? "TPM2_RH_LOCKOUT" : "TPM2_RH_PLATFORM",
+		rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_pcr_extend(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	uint32_t pcrIndex;
+	int algo = TPM_ALG_SHA256;
+	int digestLen;
+	void *digest;
+	ulong digest_addr;
+
+	/* Need 3-4 args: command + pcr + digest_addr + [algo] */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+	printf("TPM2 PCR Extend\n");
+
+	pcrIndex = simple_strtoul(argv[1], NULL, 0);
+	digest_addr = simple_strtoul(argv[2], NULL, 0);
+
+	/* Optional algorithm */
+	if (argc == 4) {
+		algo = TPM2_GetAlgId(argv[3]);
+		if (algo < 0) {
+			log_debug("Couldn't recognize algorithm: %s\n", argv[3]);
+			return CMD_RET_FAILURE;
+		}
+		log_debug("Using algorithm: %s\n", TPM2_GetAlgName(algo));
+	}
+
+	/* Get digest length based on algorithm */
+	digestLen = TPM2_GetHashDigestSize(algo);
+	if (digestLen <= 0) {
+		log_debug("Invalid algorithm digest length\n");
+		return CMD_RET_FAILURE;
+	}
+
+	/* Map digest from memory address */
+	digest = map_sysmem(digest_addr, digestLen);
+	if (digest == NULL) {
+		log_debug("Error: Invalid digest memory address\n");
+		return CMD_RET_FAILURE;
+	}
+
+	log_debug("TPM2 PCR Extend: PCR %u with %s digest\n",
+		(unsigned int)pcrIndex, TPM2_GetAlgName(algo));
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS) {
+		unmap_sysmem(digest);
+		return rc;
+	}
+
+	/* Extend the PCR */
+	rc = wolfTPM2_ExtendPCR(&dev, pcrIndex, algo, digest, digestLen);
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("TPM2_PCR_Extend failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+	}
+
+	unmap_sysmem(digest);
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 pcr_extend: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_pcr_read(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	uint32_t pcrIndex;
+	int algo = TPM_ALG_SHA256;
+	void *digest;
+	ulong digest_addr;
+	int digestLen;
+
+	/* Need 3-4 args: command + pcr + digest_addr + [algo] */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	pcrIndex = simple_strtoul(argv[1], NULL, 0);
+	digest_addr = simple_strtoul(argv[2], NULL, 0);
+
+	/* Optional algorithm */
+	if (argc == 4) {
+		algo = TPM2_GetAlgId(argv[3]);
+		if (algo < 0) {
+			log_debug("Couldn't recognize algorithm: %s\n", argv[3]);
+			return CMD_RET_FAILURE;
+		}
+		log_debug("Using algorithm: %s\n", TPM2_GetAlgName(algo));
+	}
+
+	/* Get digest length based on algorithm */
+	digestLen = TPM2_GetHashDigestSize(algo);
+	if (digestLen <= 0) {
+		log_debug("Invalid algorithm digest length\n");
+		return CMD_RET_FAILURE;
+	}
+
+	/* Map digest from memory address */
+	digest = map_sysmem(digest_addr, digestLen);
+	if (digest == NULL) {
+		log_debug("Error: Invalid digest memory address\n");
+		return CMD_RET_FAILURE;
+	}
+
+	log_debug("TPM2 PCR Read: PCR %u to %s digest\n",
+		(unsigned int)pcrIndex, TPM2_GetAlgName(algo));
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS) {
+		unmap_sysmem(digest);
+		return rc;
+	}
+
+	/* Read the PCR */
+	rc = wolfTPM2_ReadPCR(&dev, pcrIndex, algo, digest, &digestLen);
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("TPM2_PCR_Read failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+	}
+
+	unmap_sysmem(digest);
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 pcr_read: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_pcr_allocate(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	PCR_Allocate_In in;
+	PCR_Allocate_Out out;
+	TPM2B_AUTH auth;
+
+	/* Need 3-4 args: command + algorithm + on/off + [password] */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		return rc;
+
+	/* Setup PCR Allocation command */
+	memset(&in, 0, sizeof(in));
+	in.authHandle = TPM_RH_PLATFORM;
+
+	/* Single PCR bank allocation */
+	in.pcrAllocation.count = 1; /* Change only one bank */
+	in.pcrAllocation.pcrSelections[0].hash = TPM2_GetAlgId(argv[1]);
+	in.pcrAllocation.pcrSelections[0].sizeofSelect = PCR_SELECT_MAX;
+
+	/* Set all PCRs for this algorithm */
+	if (!strcmp(argv[2], "on")) {
+		memset(in.pcrAllocation.pcrSelections[0].pcrSelect, 0xFF,
+			PCR_SELECT_MAX);
+	} else if (!strcmp(argv[2], "off")) {
+		/* Clear all PCRs for this algorithm */
+		memset(in.pcrAllocation.pcrSelections[0].pcrSelect, 0x00,
+			PCR_SELECT_MAX);
+	} else {
+		log_debug("Couldn't recognize allocate mode: %s\n", argv[2]);
+		wolfTPM2_Cleanup(&dev);
+		return CMD_RET_USAGE;
+	}
+	log_debug("Attempting to set %s bank to %s\n",
+		TPM2_GetAlgName(in.pcrAllocation.pcrSelections[0].hash),
+		argv[2]);
+
+	/* Set auth password if provided */
+	if (argc == 4) {
+		memset(&auth, 0, sizeof(auth));
+		auth.size = strlen(argv[3]);
+		memcpy(auth.buffer, argv[3], auth.size);
+		rc = wolfTPM2_SetAuth(&dev, 0, TPM_RH_PLATFORM, &auth, 0, NULL);
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("wolfTPM2_SetAuth failed 0x%x: %s\n", rc,
+				TPM2_GetRCString(rc));
+			wolfTPM2_Cleanup(&dev);
+			return rc;
+		}
+	}
+
+	/* Allocate the PCR */
+	rc = TPM2_PCR_Allocate(&in, &out);
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("TPM2_PCR_Allocate failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+	}
+
+	/* Print current PCR state */
+	printf("\n\tNOTE: A TPM restart is required for changes to take effect\n");
+	printf("\nCurrent PCR state:\n");
+	TPM2_PCRs_Print();
+
+	wolfTPM2_Cleanup(&dev);
+
+	printf("Allocation Success: %s\n",
+		out.allocationSuccess ? "YES" : "NO");
+	log_debug("tpm2 pcr_allocate %s (%s): rc = %d (%s)\n",
+		TPM2_GetAlgName(in.pcrAllocation.pcrSelections[0].hash),
+		argv[2], rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+/*
+ * Without wolfCrypt, parameter encryption is not available.
+ * A session is required to protect the new platform auth.
+ */
+#ifndef WOLFTPM2_NO_WOLFCRYPT
+static int TPM2_PCR_SetAuth(int argc, char *const argv[],
+	int isPolicy)
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_SESSION session;
+	TPM2B_AUTH auth;
+	const char *pw = (argc < 4) ? NULL : argv[3];
+	const char *key = argv[2];
+	const ssize_t key_sz = strlen(key);
+	u32 pcrIndex = simple_strtoul(argv[1], NULL, 0);
+
+	/* Need 3-4 args: command + pcr + auth + [platform_auth] */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device for value/policy */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		return rc;
+
+	/* Start the session */
+	rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL,
+		isPolicy ? TPM_SE_POLICY : TPM_SE_HMAC, TPM_ALG_NULL);
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("wolfTPM2_StartSession failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+		wolfTPM2_Cleanup(&dev);
+		return rc;
+	}
+
+	/* Set the platform auth if provided */
+	if (pw) {
+		TPM2B_AUTH platformAuth;
+
+		memset(&platformAuth, 0, sizeof(platformAuth));
+		platformAuth.size = strlen(pw);
+		memcpy(platformAuth.buffer, pw, platformAuth.size);
+		rc = wolfTPM2_SetAuth(&dev, 0, TPM_RH_PLATFORM,
+			&platformAuth, 0, NULL);
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("wolfTPM2_SetAuth failed 0x%x: %s\n", rc,
+				TPM2_GetRCString(rc));
+			wolfTPM2_UnloadHandle(&dev, &session.handle);
+			wolfTPM2_Cleanup(&dev);
+			return rc;
+		}
+	}
+
+	printf("Setting %s auth for PCR %u\n",
+		isPolicy ? "policy" : "value", pcrIndex);
+
+	/* Set up the auth value/policy */
+	memset(&auth, 0, sizeof(auth));
+	auth.size = key_sz;
+	memcpy(auth.buffer, key, key_sz);
+
+	if (isPolicy) {
+		/* Use TPM2_PCR_SetAuthPolicy command */
+		PCR_SetAuthPolicy_In in;
+
+		memset(&in, 0, sizeof(in));
+		in.authHandle = TPM_RH_PLATFORM;
+		in.authPolicy = auth;
+		in.hashAlg = TPM_ALG_SHA256; /* Default to SHA256 */
+		in.pcrNum = pcrIndex;
+		rc = TPM2_PCR_SetAuthPolicy(&in);
+	} else {
+		/* Use TPM2_PCR_SetAuthValue command */
+		PCR_SetAuthValue_In in;
+
+		memset(&in, 0, sizeof(in));
+		in.pcrHandle = pcrIndex;
+		in.auth = auth;
+		rc = TPM2_PCR_SetAuthValue(&in);
+	}
+
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("TPM2_PCR_SetAuth%s failed 0x%x: %s\n",
+			isPolicy ? "Policy" : "Value",
+			rc, TPM2_GetRCString(rc));
+	}
+
+	wolfTPM2_UnloadHandle(&dev, &session.handle);
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 set_auth %s: rc = %d (%s)\n",
+		isPolicy ? "Policy" : "Value", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	return TPM2_PCR_SetAuth(argc, argv, YES);
+}
+
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	return TPM2_PCR_SetAuth(argc, argv, NO);
+}
+
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	WOLFTPM2_SESSION session;
+	const char *newpw = argv[2];
+	const char *oldpw = (argc == 4) ? argv[3] : NULL;
+	const ssize_t newpw_sz = strlen(newpw);
+	const ssize_t oldpw_sz = oldpw ? strlen(oldpw) : 0;
+	HierarchyChangeAuth_In in;
+	TPM2B_AUTH newAuth;
+
+	/* Need 3-4 args: command + hierarchy + new_pw + [old_pw] */
+	if (argc < 3 || argc > 4)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc != TPM_RC_SUCCESS)
+		return rc;
+
+	memset(&in, 0, sizeof(in));
+
+	/* Set the handle */
+	if (!strcmp(argv[1], "TPM2_RH_LOCKOUT"))
+		in.authHandle = TPM_RH_LOCKOUT;
+	else if (!strcmp(argv[1], "TPM2_RH_ENDORSEMENT"))
+		in.authHandle = TPM_RH_ENDORSEMENT;
+	else if (!strcmp(argv[1], "TPM2_RH_OWNER"))
+		in.authHandle = TPM_RH_OWNER;
+	else if (!strcmp(argv[1], "TPM2_RH_PLATFORM"))
+		in.authHandle = TPM_RH_PLATFORM;
+	else {
+		wolfTPM2_Cleanup(&dev);
+		return CMD_RET_USAGE;
+	}
+
+	/* Validate password length if provided */
+	if (newpw_sz > TPM_SHA256_DIGEST_SIZE ||
+		oldpw_sz > TPM_SHA256_DIGEST_SIZE) {
+		wolfTPM2_Cleanup(&dev);
+		return -EINVAL;
+	}
+
+	/* Start auth session */
+	rc = wolfTPM2_StartSession(&dev, &session, NULL, NULL,
+		TPM_SE_HMAC, TPM_ALG_CFB);
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("wolfTPM2_StartSession failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+		wolfTPM2_Cleanup(&dev);
+		return rc;
+	}
+
+	/* If old password exists then set it as the current auth */
+	if (oldpw) {
+		TPM2B_AUTH oldAuth;
+
+		memset(&oldAuth, 0, sizeof(oldAuth));
+		oldAuth.size = oldpw_sz;
+		memcpy(oldAuth.buffer, oldpw, oldpw_sz);
+		rc = wolfTPM2_SetAuthPassword(&dev, 0, &oldAuth);
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("wolfTPM2_SetAuthPassword failed 0x%x: %s\n", rc,
+				TPM2_GetRCString(rc));
+			wolfTPM2_UnloadHandle(&dev, &session.handle);
+			wolfTPM2_Cleanup(&dev);
+			return rc;
+		}
+	}
+
+	memset(&newAuth, 0, sizeof(newAuth));
+	newAuth.size = newpw_sz;
+	memcpy(newAuth.buffer, newpw, newpw_sz);
+	in.newAuth = newAuth;
+
+	/* Change the auth based on the hierarchy */
+	rc = wolfTPM2_ChangeHierarchyAuth(&dev, &session, in.authHandle);
+	if (rc != TPM_RC_SUCCESS) {
+		log_debug("wolfTPM2_ChangeHierarchyAuth failed 0x%x: %s\n", rc,
+			TPM2_GetRCString(rc));
+	} else {
+		log_debug("Successfully changed auth for %s\n", argv[1]);
+	}
+
+	wolfTPM2_UnloadHandle(&dev, &session.handle);
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 change_auth: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+#else /* WOLFTPM2_NO_WOLFCRYPT */
+int do_tpm2_change_auth(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	printf("wolfCrypt support required for change_auth\n");
+	return CMD_RET_FAILURE;
+}
+
+int do_tpm2_pcr_setauthpolicy(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	printf("wolfCrypt support required for pcr_setauthpolicy\n");
+	return CMD_RET_FAILURE;
+}
+
+int do_tpm2_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	printf("wolfCrypt support required for pcr_setauthvalue\n");
+	return CMD_RET_FAILURE;
+}
+#endif /* !WOLFTPM2_NO_WOLFCRYPT */
+
+int do_tpm2_pcr_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+
+	/* Need 1 arg: command */
+	if (argc != 1)
+		return CMD_RET_USAGE;
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc == TPM_RC_SUCCESS) {
+		/* Print the current PCR state */
+		TPM2_PCRs_Print();
+	}
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 pcr_print: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_dam_reset(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	const char *pw = (argc < 2) ? NULL : argv[1];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	DictionaryAttackLockReset_In in;
+	TPM2_AUTH_SESSION session[MAX_SESSION_NUM];
+
+	/* Need 1-2 args: command + [password] */
+	if (argc > 2)
+		return CMD_RET_USAGE;
+
+	/* Validate password length if provided */
+	if (pw && pw_sz > TPM_SHA256_DIGEST_SIZE) {
+		log_debug("Error: Password too long\n");
+		return -EINVAL;
+	}
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc == TPM_RC_SUCCESS) {
+		/* set lock handle */
+		memset(&in, 0, sizeof(in));
+		in.lockHandle = TPM_RH_LOCKOUT;
+
+		/* Setup auth session only if password provided */
+		memset(session, 0, sizeof(session));
+		session[0].sessionHandle = TPM_RS_PW;
+		if (pw) {
+			session[0].auth.size = pw_sz;
+			memcpy(session[0].auth.buffer, pw, pw_sz);
+		}
+		TPM2_SetSessionAuth(session);
+
+		rc = TPM2_DictionaryAttackLockReset(&in);
+		log_debug("TPM2_Dam_Reset: Result = 0x%x (%s)\n", rc,
+			TPM2_GetRCString(rc));
+	}
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 dam_reset: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+int do_tpm2_dam_parameters(struct cmd_tbl *cmdtp, int flag,
+	int argc, char *const argv[])
+{
+	int rc;
+	WOLFTPM2_DEV dev;
+	const char *pw = (argc < 5) ? NULL : argv[4];
+	const ssize_t pw_sz = pw ? strlen(pw) : 0;
+	DictionaryAttackParameters_In in;
+	TPM2_AUTH_SESSION session[MAX_SESSION_NUM];
+
+	/*
+	 * Need 4-5 args: command + max_tries + recovery_time +
+	 * lockout_recovery + [password]
+	 */
+	if (argc < 4 || argc > 5)
+		return CMD_RET_USAGE;
+
+	/* Validate password length if provided */
+	if (pw && pw_sz > TPM_SHA256_DIGEST_SIZE) {
+		log_debug("Error: Password too long\n");
+		return -EINVAL;
+	}
+
+	/* Init the TPM2 device */
+	rc = TPM2_Init_Device(&dev, NULL);
+	if (rc == TPM_RC_SUCCESS) {
+		/* Set parameters */
+		memset(&in, 0, sizeof(in));
+		in.newMaxTries = simple_strtoul(argv[1], NULL, 0);
+		in.newRecoveryTime = simple_strtoul(argv[2], NULL, 0);
+		in.lockoutRecovery = simple_strtoul(argv[3], NULL, 0);
+
+		/* set lock handle */
+		in.lockHandle = TPM_RH_LOCKOUT;
+
+		/* Setup auth session only if password provided */
+		memset(session, 0, sizeof(session));
+		session[0].sessionHandle = TPM_RS_PW;
+		if (pw) {
+			session[0].auth.size = pw_sz;
+			memcpy(session[0].auth.buffer, pw, pw_sz);
+		}
+		TPM2_SetSessionAuth(session);
+
+		/* Set DAM parameters */
+		rc = TPM2_DictionaryAttackParameters(&in);
+		if (rc != TPM_RC_SUCCESS) {
+			log_debug("TPM2_DictionaryAttackParameters failed 0x%x: %s\n", rc,
+				TPM2_GetRCString(rc));
+		}
+
+		printf("Changing dictionary attack parameters:\n");
+		printf("  maxTries: %u\n", in.newMaxTries);
+		printf("  recoveryTime: %u\n", in.newRecoveryTime);
+		printf("  lockoutRecovery: %u\n", in.lockoutRecovery);
+	}
+	wolfTPM2_Cleanup(&dev);
+
+	log_debug("tpm2 dam_parameters: rc = %d (%s)\n", rc, TPM2_GetRCString(rc));
+
+	return rc;
+}
+
+#endif /* !WOLFTPM2_NO_WRAPPER */
-- 
2.43.0



More information about the U-Boot mailing list