From: Aidan <[email protected]>

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 <[email protected]>
---
 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 b71ac554c0b..fe9b3819eaa 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -3194,4 +3194,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 <[email protected]>
+ */
+
+#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 <[email protected]>
  */
 
 #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 <[email protected]>
+ */
+
+#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.49.0

Reply via email to