[PATCH 0/6] Re-configurate TPM when active hash algorithms dismatch

This patch set implements PCR allocate command to handle the algorithm dismatches among TPM device, eventlog from previous boot stage and what U-Boot supports.
It re-configurates TPM device if any active algorithms are not supported by U-Boot or does not exist in the eventlog passed in.
To re-configurate, a PCR allocate command will be sent with new algorithm configurations, followed by a shutdown command and a hardware reset to activate those new configurations.
If any of the algorithms from the eventlog does not supported by U-Boot or TPM device does not support all U-Boot algorithms, exit with error.
This new feature is under control by a new introduced kconfig TPM_PCR_ALLOCATE.
Raymond Mao (6): tpm: add TPM2_Shutdown command tmp: add TPM2_PCR_Allocate command tpm: add wrapper and helper APIs for PCR allocate tpm: add PCR allocate into the eventlog handling tpm: PCR allocate during PCR extend to disable the unsupported algorithms board: qemu-arm: select TPM_PCR_ALLOCATE
cmd/tpm-v2.c | 108 ++++++++++++++- configs/qemu_arm64_defconfig | 1 + include/tpm-v2.h | 52 ++++++- lib/Kconfig | 12 ++ lib/tpm-v2.c | 259 ++++++++++++++++++++++++++++++++++- lib/tpm_api.c | 4 +- lib/tpm_tcg2.c | 52 +++---- 7 files changed, 442 insertions(+), 46 deletions(-)

TPM2_shutdown command is sharing same structure and logics with TPM2_startup, thus this patch extends the existing startup APIs and cmd functions to support shutdown instead of created new ones.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- cmd/tpm-v2.c | 14 +++++++++++--- include/tpm-v2.h | 3 ++- lib/tpm-v2.c | 9 +++++---- lib/tpm_api.c | 4 ++-- 4 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index 8517833f86..a6d57ee7c4 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -18,11 +18,14 @@ static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, enum tpm2_startup_types mode; struct udevice *dev; int ret; + bool bon = true;
ret = get_tpm(&dev); if (ret) return ret; - if (argc != 2) + + /* 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])) { @@ -34,7 +37,10 @@ static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; }
- return report_return_code(tpm2_startup(dev, mode)); + 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, @@ -420,11 +426,13 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " Initialize the software stack. Always the first command to issue.\n" " 'tpm startup' is the only acceptable command after a 'tpm init' has been\n" " issued\n" -"startup <mode>\n" +"startup <mode> [<op>]\n" " Issue a TPM2_Startup command.\n" " <mode> is one of:\n" " * TPM2_SU_CLEAR (reset state)\n" " * TPM2_SU_STATE (preserved state)\n" +" <op>:\n" +" * off - To shutdown the TPM\n" "self_test <type>\n" " Test the TPM capabilities.\n" " <type> is one of:\n" diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 65681464b3..f66a8e1bf4 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -230,6 +230,7 @@ enum tpm2_command_codes { TPM2_CC_PCR_READ = 0x017E, TPM2_CC_PCR_EXTEND = 0x0182, TPM2_CC_PCR_SETAUTHVAL = 0x0183, + TPM2_CC_SHUTDOWN = 0x0145, };
/** @@ -430,7 +431,7 @@ enum { * * Return: code of the operation */ -u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode); +u32 tpm2_startup(struct udevice *dev, bool onoff, enum tpm2_startup_types mode);
/** * Issue a TPM2_SelfTest command. diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index bc750b7ca1..3946ac2dbb 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -44,12 +44,13 @@ static int tpm2_update_active_banks(struct udevice *dev) return 0; }
-u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) +u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode) { + int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN; const u8 command_v2[12] = { tpm_u16(TPM2_ST_NO_SESSIONS), tpm_u32(12), - tpm_u32(TPM2_CC_STARTUP), + tpm_u32(op), tpm_u16(mode), }; int ret; @@ -59,7 +60,7 @@ u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) * but will return RC_INITIALIZE otherwise. */ ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL); - if (ret && ret != TPM2_RC_INITIALIZE) + if ((ret && ret != TPM2_RC_INITIALIZE) || !bon) return ret;
return tpm2_update_active_banks(dev); @@ -84,7 +85,7 @@ u32 tpm2_auto_start(struct udevice *dev) rc = tpm2_self_test(dev, TPMI_YES);
if (rc == TPM2_RC_INITIALIZE) { - rc = tpm2_startup(dev, TPM2_SU_CLEAR); + rc = tpm2_startup(dev, true, TPM2_SU_CLEAR); if (rc) return rc;
diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 39a5121e30..576d601e5f 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -28,7 +28,7 @@ u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode) case TPM_ST_DEACTIVATED: return -EINVAL; } - return tpm2_startup(dev, type); + return tpm2_startup(dev, true, type); } else { return -ENOSYS; } @@ -60,7 +60,7 @@ u32 tpm_resume(struct udevice *dev) if (tpm_is_v1(dev)) return tpm1_startup(dev, TPM_ST_STATE); else if (tpm_is_v2(dev)) - return tpm2_startup(dev, TPM2_SU_STATE); + return tpm2_startup(dev, true, TPM2_SU_STATE); else return -ENOSYS; }

On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_shutdown command is sharing same structure and logics with TPM2_startup, thus this patch extends the existing startup APIs and cmd functions to support shutdown instead of created new ones.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
cmd/tpm-v2.c | 14 +++++++++++--- include/tpm-v2.h | 3 ++- lib/tpm-v2.c | 9 +++++---- lib/tpm_api.c | 4 ++-- 4 files changed, 20 insertions(+), 10 deletions(-)
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index 8517833f86..a6d57ee7c4 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -18,11 +18,14 @@ static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, enum tpm2_startup_types mode; struct udevice *dev; int ret;
bool bon = true; ret = get_tpm(&dev); if (ret) return ret;
if (argc != 2)
/* 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])) {
@@ -34,7 +37,10 @@ static int do_tpm2_startup(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_FAILURE; }
return report_return_code(tpm2_startup(dev, mode));
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, @@ -420,11 +426,13 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " Initialize the software stack. Always the first command to issue.\n" " 'tpm startup' is the only acceptable command after a 'tpm init' has been\n" " issued\n" -"startup <mode>\n" +"startup <mode> [<op>]\n" " Issue a TPM2_Startup command.\n" " <mode> is one of:\n" " * TPM2_SU_CLEAR (reset state)\n" " * TPM2_SU_STATE (preserved state)\n" +" <op>:\n" +" * off - To shutdown the TPM\n" "self_test <type>\n" " Test the TPM capabilities.\n" " <type> is one of:\n" diff --git a/include/tpm-v2.h b/include/tpm-v2.h index 65681464b3..f66a8e1bf4 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -230,6 +230,7 @@ enum tpm2_command_codes { TPM2_CC_PCR_READ = 0x017E, TPM2_CC_PCR_EXTEND = 0x0182, TPM2_CC_PCR_SETAUTHVAL = 0x0183,
TPM2_CC_SHUTDOWN = 0x0145,
};
/** @@ -430,7 +431,7 @@ enum {
- Return: code of the operation
*/ -u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode); +u32 tpm2_startup(struct udevice *dev, bool onoff, enum tpm2_startup_types mode);
/**
- Issue a TPM2_SelfTest command.
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index bc750b7ca1..3946ac2dbb 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -44,12 +44,13 @@ static int tpm2_update_active_banks(struct udevice *dev) return 0; }
-u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) +u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode) {
int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN; const u8 command_v2[12] = { tpm_u16(TPM2_ST_NO_SESSIONS), tpm_u32(12),
tpm_u32(TPM2_CC_STARTUP),
tpm_u32(op), tpm_u16(mode), }; int ret;
@@ -59,7 +60,7 @@ u32 tpm2_startup(struct udevice *dev, enum tpm2_startup_types mode) * but will return RC_INITIALIZE otherwise. */ ret = tpm_sendrecv_command(dev, command_v2, NULL, NULL);
if (ret && ret != TPM2_RC_INITIALIZE)
if ((ret && ret != TPM2_RC_INITIALIZE) || !bon) return ret; return tpm2_update_active_banks(dev);
@@ -84,7 +85,7 @@ u32 tpm2_auto_start(struct udevice *dev) rc = tpm2_self_test(dev, TPMI_YES);
if (rc == TPM2_RC_INITIALIZE) {
rc = tpm2_startup(dev, TPM2_SU_CLEAR);
rc = tpm2_startup(dev, true, TPM2_SU_CLEAR); if (rc) return rc;
diff --git a/lib/tpm_api.c b/lib/tpm_api.c index 39a5121e30..576d601e5f 100644 --- a/lib/tpm_api.c +++ b/lib/tpm_api.c @@ -28,7 +28,7 @@ u32 tpm_startup(struct udevice *dev, enum tpm_startup_type mode) case TPM_ST_DEACTIVATED: return -EINVAL; }
return tpm2_startup(dev, type);
return tpm2_startup(dev, true, type); } else { return -ENOSYS; }
@@ -60,7 +60,7 @@ u32 tpm_resume(struct udevice *dev) if (tpm_is_v1(dev)) return tpm1_startup(dev, TPM_ST_STATE); else if (tpm_is_v2(dev))
return tpm2_startup(dev, TPM2_SU_STATE);
return tpm2_startup(dev, true, TPM2_SU_STATE); else return -ENOSYS;
}
2.25.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

TPM2_PCR_Allocate command is required to re-configurate a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- cmd/tpm-v2.c | 94 +++++++++++++++++++++++++++++++++++ include/tpm-v2.h | 29 +++++++++++ lib/tpm-v2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+)
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index a6d57ee7c4..2302e8e94c 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -232,6 +232,86 @@ unmap_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 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 == -EINVAL) + return CMD_RET_USAGE; + + ret = get_tpm(&dev); + if (ret) + return ret; + + if (!pcr.count) { + /* + * Get current in-use 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]; + + if (!tpm2_is_active_bank(sel)) + continue; + + mask = select_mask(mask, sel->hash, true); + printf("Active bank[%d] with algo[%#x]\n", i, + sel->hash); + } + } + + 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[]) { @@ -401,6 +481,7 @@ static struct cmd_tbl tpm2_commands[] = { do_tpm_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, "", ""), };
struct cmd_tbl *get_tpm2_commands(unsigned int *size) @@ -481,4 +562,17 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command", " <pcr>: index of the PCR\n" " <key>: secret to protect the access of PCR #<pcr>\n" " <password>: optional password of the PLATFORM hierarchy\n" +"pcr_allocate <algorithm> <on/off> [<password>]\n" +" Issue a TPM2_PCR_Allocate Command to reconfig PCR bank algorithm.\n" +" <algorithm> is one of:\n" +" * sha1\n" +" * sha256\n" +" * sha384\n" +" * sha512\n" +" <on|off> is one of:\n" +" * on - Select all available PCRs associated with the specified\n" +" algorithm (bank)\n" +" * off - Clear all available PCRs associated with the specified\n" +" algorithm (bank)\n" +" <password>: optional password\n" ); diff --git a/include/tpm-v2.h b/include/tpm-v2.h index f66a8e1bf4..af3158f6e4 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -230,6 +230,7 @@ enum tpm2_command_codes { TPM2_CC_PCR_READ = 0x017E, TPM2_CC_PCR_EXTEND = 0x0182, TPM2_CC_PCR_SETAUTHVAL = 0x0183, + TPM2_CC_PCR_ALLOCATE = 0x012B, TPM2_CC_SHUTDOWN = 0x0145, };
@@ -702,6 +703,34 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd, u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd);
+/** + * tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot + * + * @dev TPM device + * @algo_mask Mask of the algorithms + * @pcr PCR structure for allocation + * @pcr_len Actual PCR data length + * + * Return: code of the operation + */ +u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask, + struct tpml_pcr_selection *pcr, u32 *pcr_len); + +/** + * tpm2_send_pcr_allocate() - Send PCR allocate command. Requires reboot + * + * @dev TPM device + * @pw Platform password + * @pw_sz Length of the password + * @pcr PCR structure for allocation + * @pcr_len Actual PCR data length + * + * Return: code of the operation + */ +u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, + const ssize_t pw_sz, struct tpml_pcr_selection *pcr, + u32 pcr_len); + /** * tpm2_auto_start() - start up the TPM and perform selftests. * If a testable function has not been tested and is diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 3946ac2dbb..045b5dd9eb 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -400,6 +400,130 @@ u32 tpm2_get_capability(struct udevice *dev, u32 capability, u32 property, return 0; }
+u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask, + struct tpml_pcr_selection *pcr, u32 *pcr_len) +{ + int i; + + if (pcr->count > TPM2_NUM_PCR_BANKS) + return TPM_LIB_ERROR; + + *pcr_len = sizeof(pcr->count); + + for (i = 0; i < pcr->count; i++) { + struct tpms_pcr_selection *sel = &pcr->selection[i]; + u8 pad = 0; + int j; + + if (sel->size_of_select > TPM2_PCR_SELECT_MAX) + return TPM_LIB_ERROR; + + /* + * Found the algorithm (bank) that matches, and enable all PCR + * bits. + * TODO: only select the bits needed + */ + for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) { + if (hash_algo_list[j].hash_alg != sel->hash) + continue; + + if (algo_mask & hash_algo_list[j].hash_mask) + pad = 0xff; + } + + for (j = 0; j < sel->size_of_select; j++) + sel->pcr_select[j] = pad; + + log_info("set bank[%d] %s %s\n", i, + tpm2_algorithm_name(sel->hash), + tpm2_is_active_bank(sel) ? "on" : "off"); + + *pcr_len += sizeof(sel->hash) + sizeof(sel->size_of_select) + + sel->size_of_select; + } + + return 0; +} + +u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, + const ssize_t pw_sz, struct tpml_pcr_selection *pcr, + u32 pcr_len) +{ + /* Length of the message header, up to start of password */ + uint offset = 27; + u8 command_v2[COMMAND_BUFFER_SIZE] = { + tpm_u16(TPM2_ST_SESSIONS), /* TAG */ + tpm_u32(offset + pw_sz + pcr_len), /* Length */ + tpm_u32(TPM2_CC_PCR_ALLOCATE), /* Command code */ + + /* handles 4 bytes */ + tpm_u32(TPM2_RH_PLATFORM), /* Primary platform seed */ + + /* AUTH_SESSION */ + tpm_u32(9 + pw_sz), /* Authorization size */ + tpm_u32(TPM2_RS_PW), /* Session handle */ + tpm_u16(0), /* Size of <nonce> */ + /* <nonce> (if any) */ + 0, /* Attributes: Cont/Excl/Rst */ + tpm_u16(pw_sz), /* Size of <hmac/password> */ + /* STRING(pw) <hmac/password> (if any) */ + + /* TPML_PCR_SELECTION */ + }; + u8 response[COMMAND_BUFFER_SIZE]; + size_t response_len = COMMAND_BUFFER_SIZE; + u32 i; + int ret; + + /* + * Fill the command structure starting from the first buffer: + * the password (if any) + */ + if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, pw, + pw_sz)) + return TPM_LIB_ERROR; + + offset += pw_sz; + + /* Pack the count field */ + if (pack_byte_string(command_v2, sizeof(command_v2), "d", offset, pcr->count)) + return TPM_LIB_ERROR; + + offset += sizeof(pcr->count); + + /* Pack each tpms_pcr_selection */ + for (i = 0; i < pcr->count; i++) { + struct tpms_pcr_selection *sel = &pcr->selection[i]; + + /* Pack hash (16-bit) */ + if (pack_byte_string(command_v2, sizeof(command_v2), "w", offset, + sel->hash)) + return TPM_LIB_ERROR; + + offset += sizeof(sel->hash); + + /* Pack size_of_select (8-bit) */ + if (pack_byte_string(command_v2, sizeof(command_v2), "b", offset, + sel->size_of_select)) + return TPM_LIB_ERROR; + + offset += sizeof(sel->size_of_select); + + /* Pack pcr_select array */ + if (pack_byte_string(command_v2, sizeof(command_v2), "s", offset, + sel->pcr_select, sel->size_of_select)) + return TPM_LIB_ERROR; + + offset += sel->size_of_select; + } + + ret = tpm_sendrecv_command(dev, command_v2, response, &response_len); + if (!ret) + tpm_init(dev); + + return ret; +} + static int tpm2_get_num_pcr(struct udevice *dev, u32 *num_pcr) { u8 response[(sizeof(struct tpms_capability_data) -

Hi Raymond,
On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_PCR_Allocate command is required to re-configurate
reconfigure
a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
cmd/tpm-v2.c | 94 +++++++++++++++++++++++++++++++++++ include/tpm-v2.h | 29 +++++++++++ lib/tpm-v2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+)
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index a6d57ee7c4..2302e8e94c 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -232,6 +232,86 @@ unmap_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 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 == -EINVAL)
return CMD_RET_USAGE;
ret = get_tpm(&dev);
if (ret)
return ret;
if (!pcr.count) {
Ins't this always true?
/*
* Get current in-use algorithms (banks), PCRs and mask via the
* first call
*/
in-use translates to active PCR banks. Isn't that function returning the hardware-supported banks?
ret = tpm2_get_pcr_info(dev, &pcr);
if (ret)
return ret;
So we have the TPM banks the hardware supports here. Does it make sense to check if the requested algorithm is supported and exit early? In theory, it doesn't matter because the hardware will reject the configuration later, but I'd like to have a comment about this.
for (i = 0; i < pcr.count; i++) {
struct tpms_pcr_selection *sel = &pcr.selection[i];
if (!tpm2_is_active_bank(sel))
continue;
mask = select_mask(mask, sel->hash, true);
printf("Active bank[%d] with algo[%#x]\n", i,
sel->hash);
}
}
mask = select_mask(mask, algo, bon);
ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
[...]
Other than that this looks good to me
Thanks /Ilias

Hi Ilias,
On Thu, 16 Jan 2025 at 07:37, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Raymond,
On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_PCR_Allocate command is required to re-configurate
reconfigure
a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
cmd/tpm-v2.c | 94 +++++++++++++++++++++++++++++++++++ include/tpm-v2.h | 29 +++++++++++ lib/tpm-v2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+)
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index a6d57ee7c4..2302e8e94c 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -232,6 +232,86 @@ unmap_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 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 == -EINVAL)
return CMD_RET_USAGE;
ret = get_tpm(&dev);
if (ret)
return ret;
if (!pcr.count) {
Ins't this always true?
Not really, pcr is a static variable to cache the latest configurations.
The command itself is designed to turn on/off one algorithm each time for easy usage, and expects to be called multiple times when the user wants to change more than one algorithm. We just need to get the active bank at the first call when the command is running multiple times. Since tpm2_get_pcr_info() will not return the real actual active banks after one PCR allocate command is sent until a reset occurs.
/*
* Get current in-use algorithms (banks), PCRs and mask
via the
* first call
*/
in-use translates to active PCR banks. Isn't that function returning the hardware-supported banks?
That returns the active ones only but not includes the inactive ones if
any.
ret = tpm2_get_pcr_info(dev, &pcr);
if (ret)
return ret;
So we have the TPM banks the hardware supports here. Does it make sense to check if the requested algorithm is supported and exit early? In theory, it doesn't matter because the hardware will reject the configuration later, but I'd like to have a comment about this.
Ditto. It knows the active algorithms only but not includes the supported
but inactive ones.
Regards, Raymond
for (i = 0; i < pcr.count; i++) {
struct tpms_pcr_selection *sel =
&pcr.selection[i];
if (!tpm2_is_active_bank(sel))
continue;
mask = select_mask(mask, sel->hash, true);
printf("Active bank[%d] with algo[%#x]\n", i,
sel->hash);
}
}
mask = select_mask(mask, algo, bon);
ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
[...]
Other than that this looks good to me
Thanks /Ilias

On Thu, 16 Jan 2025 at 20:14, Raymond Mao raymond.mao@linaro.org wrote:
Hi Ilias,
On Thu, 16 Jan 2025 at 07:37, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Raymond,
On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_PCR_Allocate command is required to re-configurate
reconfigure
a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
cmd/tpm-v2.c | 94 +++++++++++++++++++++++++++++++++++ include/tpm-v2.h | 29 +++++++++++ lib/tpm-v2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+)
diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c index a6d57ee7c4..2302e8e94c 100644 --- a/cmd/tpm-v2.c +++ b/cmd/tpm-v2.c @@ -232,6 +232,86 @@ unmap_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 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 == -EINVAL)
return CMD_RET_USAGE;
ret = get_tpm(&dev);
if (ret)
return ret;
if (!pcr.count) {
Ins't this always true?
Not really, pcr is a static variable to cache the latest configurations. The command itself is designed to turn on/off one algorithm each time for easy usage, and expects to be called multiple times when the user wants to change more than one algorithm. We just need to get the active bank at the first call when the command is running multiple times. Since tpm2_get_pcr_info() will not return the real actual active banks after one PCR allocate command is sent until a reset occurs.
I completely ignored the static in that variable.
/*
* Get current in-use algorithms (banks), PCRs and mask via the
* first call
*/
in-use translates to active PCR banks. Isn't that function returning the hardware-supported banks?
That returns the active ones only but not includes the inactive ones if any.
It returns the hardware available PCR banks regardless of them being active or not
/Ilias
ret = tpm2_get_pcr_info(dev, &pcr);
if (ret)
return ret;
So we have the TPM banks the hardware supports here. Does it make sense to check if the requested algorithm is supported and exit early? In theory, it doesn't matter because the hardware will reject the configuration later, but I'd like to have a comment about this.
Ditto. It knows the active algorithms only but not includes the supported but inactive ones.
Regards, Raymond
for (i = 0; i < pcr.count; i++) {
struct tpms_pcr_selection *sel = &pcr.selection[i];
if (!tpm2_is_active_bank(sel))
continue;
mask = select_mask(mask, sel->hash, true);
printf("Active bank[%d] with algo[%#x]\n", i,
sel->hash);
}
}
mask = select_mask(mask, algo, bon);
ret = tpm2_pcr_config_algo(dev, mask, &pcr, &pcr_len);
[...]
Other than that this looks good to me
Thanks /Ilias

Hi Raymond,
On Wed, 15 Jan 2025 at 13:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_PCR_Allocate command is required to re-configurate a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
It would be better to have an automated test.
You could create one using the sandbox TPM, and you could add a pytest which can run on my lab (coral has a TPMv2).
Signed-off-by: Raymond Mao raymond.mao@linaro.org
cmd/tpm-v2.c | 94 +++++++++++++++++++++++++++++++++++ include/tpm-v2.h | 29 +++++++++++ lib/tpm-v2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+)
Regards, Simon

Hi Simon,
On Sat, 18 Jan 2025 at 06:31, Simon Glass sjg@chromium.org wrote:
Hi Raymond,
On Wed, 15 Jan 2025 at 13:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_PCR_Allocate command is required to re-configurate a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
It would be better to have an automated test.
You could create one using the sandbox TPM, and you could add a pytest which can run on my lab (coral has a TPMv2).
The sandbox does not support PCR allocations and I don't personally see the point writing device emulation code. The TPM subsystem definitely needs better testing and I've already discussed this with Raymond. He will start sending tests later on. We can test simple features on the sandbox, but whatever complex features we need to test will take place in QEMU
Thanks /Ilias
Signed-off-by: Raymond Mao raymond.mao@linaro.org
cmd/tpm-v2.c | 94 +++++++++++++++++++++++++++++++++++ include/tpm-v2.h | 29 +++++++++++ lib/tpm-v2.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+)
Regards, Simon

Hi Ilias,
On Wed, 22 Jan 2025 at 23:23, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
Hi Simon,
On Sat, 18 Jan 2025 at 06:31, Simon Glass sjg@chromium.org wrote:
Hi Raymond,
On Wed, 15 Jan 2025 at 13:02, Raymond Mao raymond.mao@linaro.org wrote:
TPM2_PCR_Allocate command is required to re-configurate a TPM device to enable or disable algorithms in run-time, thus this patch introduces the implementation of PCR allocate APIs and adds related cmd functions for testing.
To test the feature, ensure that TPM is started up. Run pcr_allocate command to turn on/off an algorithm, multiple calls are supported and all changes will be cached: `tpm2 pcr_allocate <algorithm_name> <on|off>` Run startup command with argument 'off' to shutdown the TPM. `tpm2 startup TPM2_SU_CLEAR off` Reboot the board via `reset` to activate the changes.
It would be better to have an automated test.
You could create one using the sandbox TPM, and you could add a pytest which can run on my lab (coral has a TPMv2).
The sandbox does not support PCR allocations and I don't personally see the point writing device emulation code.
The point is that we can actually test this code by putting the emulated TPM into a known state before each step and make it easy to debug what is going wrong. The only way to do that on a board is with a cold restart (so the TPM is reset), if that is supported in the lab. I think the QEMU tests are useful; they are somewhere in the middle of the two extremes.
The TPM subsystem definitely needs better testing and I've already discussed this with Raymond.
Well, the TPM tests don't actually work at present, or at least the board I tried.
He will start sending tests later on. We can test simple features on the sandbox, but whatever complex features we need to test will take place in QEMU
Instead, you should spend a little time upgrading the TPM emulation for the tests you need. It will pay dividends in future.
Regards, Simon

Add PCR allocate wrapper APIs for using in tcg2 protocol. The wrapper proceeds a PCR allocate command, followed by a shutdown command. A system boot is required after two commands since TPM device needs a HW reset to activate the new algorithms config. Also, a helper function is included to determine the new bank mask for PCR allocation by combining the status of current active, supported and eventlog bank masks. A new kconfig is created. PCR allocate and system reboot only happens when the kconfig is selected, otherwise just exit with errors.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- include/tpm-v2.h | 20 ++++++++ lib/Kconfig | 12 +++++ lib/tpm-v2.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+)
diff --git a/include/tpm-v2.h b/include/tpm-v2.h index af3158f6e4..79dc4a34e2 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -703,6 +703,17 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd, u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd);
+/** + * tpm2_pcr_allocate_get_mask - Get algorithm bitmask for PCR allocate + * + * @dev TPM device + * @log_active Active algorithm bitmask + * @mask Bitmask for PCR allocate + * + * Return: zero on success, negative errno otherwise + */ +int tpm2_pcr_allocate_get_mask(struct udevice *dev, u32 log_active, u32 *mask); + /** * tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot * @@ -730,6 +741,15 @@ u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask, u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, const ssize_t pw_sz, struct tpml_pcr_selection *pcr, u32 pcr_len); +/** + * tpm2_pcr_allocate() - Allocate the PCRs + * + * @param dev TPM device + * @log_active Bitmask of eventlog algorithms + * + * Return: code of the operation + */ +int tpm2_pcr_allocate(struct udevice *dev, u32 log_active);
/** * tpm2_auto_start() - start up the TPM and perform selftests. diff --git a/lib/Kconfig b/lib/Kconfig index baeb615626..0732333849 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -514,6 +514,18 @@ config VPL_TPM for the low-level TPM interface, but only one TPM is supported at a time by the TPM library.
+config TPM_PCR_ALLOCATE + bool "Re-configurate TPM algorithms in run-time (PCR allocate)" + depends on TPM_V2 && (MEASURED_BOOT || EFI_TCG2_PROTOCOL) + help + This enables a detection for the dismatches of algorithms among TPM + device, eventlog from previous boot stage and U-Boot support. + A PCR allocate command will be sent to reconfigurate the TPM device + in run-time to make sure algorithms in TPM device, eventlog and + U-Boot are aligned with each other. + A system reboot will be proceeded after then to activate the new + algorithms. + endmenu
menu "Android Verified Boot" diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 045b5dd9eb..71abf070de 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -44,6 +44,127 @@ static int tpm2_update_active_banks(struct udevice *dev) return 0; }
+static void tpm2_print_selected_algorithm_name(u32 selected) +{ + size_t i; + const char *str; + + for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { + const struct digest_info *algo = &hash_algo_list[i]; + + if (!(selected & algo->hash_mask)) + continue; + + str = tpm2_algorithm_name(algo->hash_alg); + if (str) + log_info("%s\n", str); + } +} + +int tpm2_pcr_allocate_get_mask(struct udevice *dev, u32 log_active, u32 *mask) +{ + struct tpml_pcr_selection pcrs; + u32 active = 0; + u32 supported = 0; + int rc, i; + + *mask = 0; + + rc = tpm2_get_pcr_info(dev, &pcrs); + if (rc) + return rc; + + for (i = 0; i < pcrs.count; i++) { + struct tpms_pcr_selection *sel = &pcrs.selection[i]; + size_t j; + u32 hash_mask = 0; + + for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) { + if (hash_algo_list[j].hash_alg == sel->hash) + hash_mask = hash_algo_list[j].hash_mask; + } + + if (tpm2_algorithm_supported(sel->hash)) + supported |= hash_mask; + + if (tpm2_is_active_bank(sel)) + active |= hash_mask; + } + + /* All eventlog algorithm(s) must be supported */ + if (log_active & ~supported) { + log_err("EventLog contains U-Boot unsupported algorithm(s)\n"); + tpm2_print_selected_algorithm_name(log_active & ~supported); + rc = -1; + } + if (log_active && active & ~log_active) { + log_warning("TPM active algorithm(s) not exist in eventlog\n"); + tpm2_print_selected_algorithm_name(active & ~log_active); + *mask = log_active; + } + + /* Any active algorithm(s) which are not supported must be removed */ + if (active & ~supported) { + log_warning("TPM active algorithm(s) unsupported by u-boot\n"); + tpm2_print_selected_algorithm_name(active & ~supported); + if (*mask) + *mask = active & supported & *mask; + else + *mask = active & supported; + } + + return rc; +} + +static int tpm2_proceed_pcr_allocate(struct udevice *dev, u32 algo_mask) +{ + struct tpml_pcr_selection pcr = { 0 }; + u32 pcr_len = 0; + int rc; + + rc = tpm2_get_pcr_info(dev, &pcr); + if (rc) + return rc; + + rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len); + if (rc) + return rc; + + /* Assume no password */ + rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len); + if (rc) + return rc; + + /* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */ + return tpm2_startup(dev, false, TPM2_SU_CLEAR); +} + +int tpm2_pcr_allocate(struct udevice *dev, u32 log_active) +{ + u32 algo_mask = 0; + int rc; + + rc = tpm2_pcr_allocate_get_mask(dev, log_active, &algo_mask); + if (rc) + return rc; + + if (algo_mask) { + if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE)) + return -1; + + rc = tpm2_proceed_pcr_allocate(dev, algo_mask); + if (rc) + return rc; + + log_info("PCR allocate done, shutdown TPM and reboot\n"); + do_reset(NULL, 0, 0, NULL); + log_err("reset does not work!\n"); + return -1; + } + + return 0; +} + u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode) { int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN;

On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
Add PCR allocate wrapper APIs for using in tcg2 protocol. The wrapper proceeds a PCR allocate command, followed by a shutdown command.
We have lib/tpm_tcg2.c does any of the functions belong to that file? Unless we expect the non-TCG version to do something similar....
A system boot is required after two commands since TPM device needs a HW reset to activate the new algorithms config. Also, a helper function is included to determine the new bank mask for PCR allocation by combining the status of current active, supported and eventlog bank masks. A new kconfig is created. PCR allocate and system reboot only happens when the kconfig is selected, otherwise just exit with errors.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
include/tpm-v2.h | 20 ++++++++ lib/Kconfig | 12 +++++ lib/tpm-v2.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+)
diff --git a/include/tpm-v2.h b/include/tpm-v2.h index af3158f6e4..79dc4a34e2 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -703,6 +703,17 @@ u32 tpm2_report_state(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd, u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd);
+/**
- tpm2_pcr_allocate_get_mask - Get algorithm bitmask for PCR allocate
Naming nit. This is comparing the EventLog, U-Boot supported, and active algorithms. Can we rename it to tpm2_scan_masks() or something similar and update the description with that?
- @dev TPM device
- @log_active Active algorithm bitmask
- @mask Bitmask for PCR allocate
- Return: zero on success, negative errno otherwise
- */
+int tpm2_pcr_allocate_get_mask(struct udevice *dev, u32 log_active, u32 *mask);
/**
- tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot
@@ -730,6 +741,15 @@ u32 tpm2_pcr_config_algo(struct udevice *dev, u32 algo_mask, u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, const ssize_t pw_sz, struct tpml_pcr_selection *pcr, u32 pcr_len); +/**
- tpm2_pcr_allocate() - Allocate the PCRs
- @param dev TPM device
- @log_active Bitmask of eventlog algorithms
- Return: code of the operation
- */
+int tpm2_pcr_allocate(struct udevice *dev, u32 log_active);
/**
- tpm2_auto_start() - start up the TPM and perform selftests.
diff --git a/lib/Kconfig b/lib/Kconfig index baeb615626..0732333849 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -514,6 +514,18 @@ config VPL_TPM for the low-level TPM interface, but only one TPM is supported at a time by the TPM library.
+config TPM_PCR_ALLOCATE
bool "Re-configurate TPM algorithms in run-time (PCR allocate)"
depends on TPM_V2 && (MEASURED_BOOT || EFI_TCG2_PROTOCOL)
help
This enables a detection for the dismatches of algorithms among TPM
device, eventlog from previous boot stage and U-Boot support.
A PCR allocate command will be sent to reconfigurate the TPM device
in run-time to make sure algorithms in TPM device, eventlog and
U-Boot are aligned with each other.
A system reboot will be proceeded after then to activate the new
algorithms.
endmenu
menu "Android Verified Boot" diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 045b5dd9eb..71abf070de 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -44,6 +44,127 @@ static int tpm2_update_active_banks(struct udevice *dev) return 0; }
+static void tpm2_print_selected_algorithm_name(u32 selected) +{
size_t i;
const char *str;
for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
const struct digest_info *algo = &hash_algo_list[i];
if (!(selected & algo->hash_mask))
continue;
str = tpm2_algorithm_name(algo->hash_alg);
if (str)
log_info("%s\n", str);
}
+}
+int tpm2_pcr_allocate_get_mask(struct udevice *dev, u32 log_active, u32 *mask) +{
struct tpml_pcr_selection pcrs;
u32 active = 0;
u32 supported = 0;
int rc, i;
*mask = 0;
rc = tpm2_get_pcr_info(dev, &pcrs);
if (rc)
return rc;
for (i = 0; i < pcrs.count; i++) {
struct tpms_pcr_selection *sel = &pcrs.selection[i];
size_t j;
u32 hash_mask = 0;
for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
if (hash_algo_list[j].hash_alg == sel->hash)
hash_mask = hash_algo_list[j].hash_mask;
}
if (tpm2_algorithm_supported(sel->hash))
supported |= hash_mask;
if (tpm2_is_active_bank(sel))
active |= hash_mask;
We duplicate this in the tcg functions for getting active pcr banks, but I can live with it now and refactor it later.
}
/* All eventlog algorithm(s) must be supported */
if (log_active & ~supported) {
log_err("EventLog contains U-Boot unsupported algorithm(s)\n");
tpm2_print_selected_algorithm_name(log_active & ~supported);
rc = -1;
}
if (log_active && active & ~log_active) {
log_warning("TPM active algorithm(s) not exist in eventlog\n");
tpm2_print_selected_algorithm_name(active & ~log_active);
*mask = log_active;
}
/* Any active algorithm(s) which are not supported must be removed */
if (active & ~supported) {
log_warning("TPM active algorithm(s) unsupported by u-boot\n");
tpm2_print_selected_algorithm_name(active & ~supported);
if (*mask)
if (rc) is clearer here I think
*mask = active & supported & *mask;
else
*mask = active & supported;
}
return rc;
+}
+static int tpm2_proceed_pcr_allocate(struct udevice *dev, u32 algo_mask)
Naming this tpm2_pcr_allocate() is better
+{
struct tpml_pcr_selection pcr = { 0 };
u32 pcr_len = 0;
int rc;
rc = tpm2_get_pcr_info(dev, &pcr);
if (rc)
return rc;
rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len);
if (rc)
return rc;
/* Assume no password */
rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len);
if (rc)
return rc;
/* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */
return tpm2_startup(dev, false, TPM2_SU_CLEAR);
+}
+int tpm2_pcr_allocate(struct udevice *dev, u32 log_active)
This assumes there's a log involved. So let's find a better name and keep the current one for the function above.
+{
u32 algo_mask = 0;
int rc;
rc = tpm2_pcr_allocate_get_mask(dev, log_active, &algo_mask);
if (rc)
return rc;
if (algo_mask) {
if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE))
return -1;
rc = tpm2_proceed_pcr_allocate(dev, algo_mask);
if (rc)
return rc;
log_info("PCR allocate done, shutdown TPM and reboot\n");
do_reset(NULL, 0, 0, NULL);
log_err("reset does not work!\n");
return -1;
}
return 0;
+}
u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types mode) { int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN; -- 2.25.1
Thanks /Ilias

Hi Ilias,
On Thu, 16 Jan 2025 at 08:01, Ilias Apalodimas ilias.apalodimas@linaro.org wrote:
On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
Add PCR allocate wrapper APIs for using in tcg2 protocol. The wrapper proceeds a PCR allocate command, followed by a shutdown command.
We have lib/tpm_tcg2.c does any of the functions belong to that file? Unless we expect the non-TCG version to do something similar....
Yes. The concept of bitmasks of algorithms is needed for PCR allocation.
Currently I have to implement a few duplicated logics here to avoid moving APIs from tcg2.
A system boot is required after two commands since TPM device needs a HW reset to activate the new algorithms config. Also, a helper function is included to determine the new bank mask for PCR allocation by combining the status of current active, supported and eventlog bank masks. A new kconfig is created. PCR allocate and system reboot only happens when the kconfig is selected, otherwise just exit with errors.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
include/tpm-v2.h | 20 ++++++++ lib/Kconfig | 12 +++++ lib/tpm-v2.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+)
diff --git a/include/tpm-v2.h b/include/tpm-v2.h index af3158f6e4..79dc4a34e2 100644 --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -703,6 +703,17 @@ u32 tpm2_report_state(struct udevice *dev, uint
vendor_cmd, uint vendor_subcmd,
u32 tpm2_enable_nvcommits(struct udevice *dev, uint vendor_cmd, uint vendor_subcmd);
+/**
- tpm2_pcr_allocate_get_mask - Get algorithm bitmask for PCR allocate
Naming nit. This is comparing the EventLog, U-Boot supported, and active algorithms. Can we rename it to tpm2_scan_masks() or something similar and update the description with that?
Will do in V2.
- @dev TPM device
- @log_active Active algorithm bitmask
- @mask Bitmask for PCR allocate
- Return: zero on success, negative errno otherwise
- */
+int tpm2_pcr_allocate_get_mask(struct udevice *dev, u32 log_active, u32
*mask);
/**
- tpm2_pcr_config_algo() - Allocate the active PCRs. Requires reboot
@@ -730,6 +741,15 @@ u32 tpm2_pcr_config_algo(struct udevice *dev, u32
algo_mask,
u32 tpm2_send_pcr_allocate(struct udevice *dev, const char *pw, const ssize_t pw_sz, struct
tpml_pcr_selection *pcr,
u32 pcr_len);
+/**
- tpm2_pcr_allocate() - Allocate the PCRs
- @param dev TPM device
- @log_active Bitmask of eventlog algorithms
- Return: code of the operation
- */
+int tpm2_pcr_allocate(struct udevice *dev, u32 log_active);
/**
- tpm2_auto_start() - start up the TPM and perform selftests.
diff --git a/lib/Kconfig b/lib/Kconfig index baeb615626..0732333849 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -514,6 +514,18 @@ config VPL_TPM for the low-level TPM interface, but only one TPM is supported
at
a time by the TPM library.
+config TPM_PCR_ALLOCATE
bool "Re-configurate TPM algorithms in run-time (PCR allocate)"
depends on TPM_V2 && (MEASURED_BOOT || EFI_TCG2_PROTOCOL)
help
This enables a detection for the dismatches of algorithms
among TPM
device, eventlog from previous boot stage and U-Boot support.
A PCR allocate command will be sent to reconfigurate the TPM
device
in run-time to make sure algorithms in TPM device, eventlog and
U-Boot are aligned with each other.
A system reboot will be proceeded after then to activate the
new
algorithms.
endmenu
menu "Android Verified Boot" diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 045b5dd9eb..71abf070de 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -44,6 +44,127 @@ static int tpm2_update_active_banks(struct udevice
*dev)
return 0;
}
+static void tpm2_print_selected_algorithm_name(u32 selected) +{
size_t i;
const char *str;
for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
const struct digest_info *algo = &hash_algo_list[i];
if (!(selected & algo->hash_mask))
continue;
str = tpm2_algorithm_name(algo->hash_alg);
if (str)
log_info("%s\n", str);
}
+}
+int tpm2_pcr_allocate_get_mask(struct udevice *dev, u32 log_active, u32
*mask)
+{
struct tpml_pcr_selection pcrs;
u32 active = 0;
u32 supported = 0;
int rc, i;
*mask = 0;
rc = tpm2_get_pcr_info(dev, &pcrs);
if (rc)
return rc;
for (i = 0; i < pcrs.count; i++) {
struct tpms_pcr_selection *sel = &pcrs.selection[i];
size_t j;
u32 hash_mask = 0;
for (j = 0; j < ARRAY_SIZE(hash_algo_list); j++) {
if (hash_algo_list[j].hash_alg == sel->hash)
hash_mask = hash_algo_list[j].hash_mask;
}
if (tpm2_algorithm_supported(sel->hash))
supported |= hash_mask;
if (tpm2_is_active_bank(sel))
active |= hash_mask;
We duplicate this in the tcg functions for getting active pcr banks, but I can live with it now and refactor it later.
}
/* All eventlog algorithm(s) must be supported */
if (log_active & ~supported) {
log_err("EventLog contains U-Boot unsupported
algorithm(s)\n");
tpm2_print_selected_algorithm_name(log_active &
~supported);
rc = -1;
}
if (log_active && active & ~log_active) {
log_warning("TPM active algorithm(s) not exist in
eventlog\n");
tpm2_print_selected_algorithm_name(active & ~log_active);
*mask = log_active;
}
/* Any active algorithm(s) which are not supported must be
removed */
if (active & ~supported) {
log_warning("TPM active algorithm(s) unsupported by
u-boot\n");
tpm2_print_selected_algorithm_name(active & ~supported);
if (*mask)
if (rc) is clearer here I think
When *mask is not 0 here, that means the TPM device activated more
algorithm(s) than the ones exist in eventlog.
*mask = active & supported & *mask;
else
*mask = active & supported;
}
return rc;
+}
+static int tpm2_proceed_pcr_allocate(struct udevice *dev, u32 algo_mask)
Naming this tpm2_pcr_allocate() is better
Will do in V2.
+{
struct tpml_pcr_selection pcr = { 0 };
u32 pcr_len = 0;
int rc;
rc = tpm2_get_pcr_info(dev, &pcr);
if (rc)
return rc;
rc = tpm2_pcr_config_algo(dev, algo_mask, &pcr, &pcr_len);
if (rc)
return rc;
/* Assume no password */
rc = tpm2_send_pcr_allocate(dev, NULL, 0, &pcr, pcr_len);
if (rc)
return rc;
/* Send TPM2_Shutdown, assume mode = TPM2_SU_CLEAR */
return tpm2_startup(dev, false, TPM2_SU_CLEAR);
+}
+int tpm2_pcr_allocate(struct udevice *dev, u32 log_active)
This assumes there's a log involved. So let's find a better name and keep the current one for the function above.
Will do in V2.
Regards, Raymond
+{
u32 algo_mask = 0;
int rc;
rc = tpm2_pcr_allocate_get_mask(dev, log_active, &algo_mask);
if (rc)
return rc;
if (algo_mask) {
if (!IS_ENABLED(CONFIG_TPM_PCR_ALLOCATE))
return -1;
rc = tpm2_proceed_pcr_allocate(dev, algo_mask);
if (rc)
return rc;
log_info("PCR allocate done, shutdown TPM and reboot\n");
do_reset(NULL, 0, 0, NULL);
log_err("reset does not work!\n");
return -1;
}
return 0;
+}
u32 tpm2_startup(struct udevice *dev, bool bon, enum tpm2_startup_types
mode)
{ int op = bon ? TPM2_CC_STARTUP : TPM2_CC_SHUTDOWN; -- 2.25.1
Thanks /Ilias

Get eventlog bank mask when parsing the eventlog from previous boot stage and invoke PCR allocate function based on it. PCR allocate will be proceeded if any dismatches observed among the active, supportted and eventlog bank masks to re-configurate the TPM with the proper algorithms and reboot the system.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- lib/tpm_tcg2.c | 52 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 35 deletions(-)
diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c index 2d9076f091..fd84045d8b 100644 --- a/lib/tpm_tcg2.c +++ b/lib/tpm_tcg2.c @@ -360,12 +360,12 @@ static int tcg2_replay_eventlog(struct tcg2_event_log *elog, return 0; }
-static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) +static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog, + u32 *log_active) { struct tpml_digest_values digest_list; struct tcg_efi_spec_id_event *event; struct tcg_pcr_event *log; - u32 log_active; u32 calc_size; u32 active; u32 count; @@ -376,6 +376,8 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) int rc; u32 i;
+ *log_active = 0; + if (elog->log_size <= offsetof(struct tcg_pcr_event, event)) return 0;
@@ -421,7 +423,6 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) * algorithms, so just check the EvenLog against the TPM active ones. */ digest_list.count = 0; - log_active = 0; for (i = 0; i < count; ++i) { algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id); mask = tcg2_algorithm_to_mask(algo); @@ -447,17 +448,15 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) algo); return -1; } - log_active |= mask; + *log_active |= mask; }
rc = tcg2_get_active_pcr_banks(dev, &active); if (rc) return rc; /* If the EventLog and active algorithms don't match exit */ - if (log_active != active) { - log_err("EventLog doesn't contain all active PCR banks\n"); - return -1; - } + if (*log_active != active) + return -ERESTARTSYS;
/* Read PCR0 to check if previous firmware extended the PCRs or not. */ rc = tcg2_pcr_read(dev, 0, &digest_list); @@ -554,43 +553,21 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, bool ignore_existing_log) { struct tcg2_event_log log; - int rc, i; + int rc; + u32 log_active = 0;
elog->log_position = 0; elog->found = false;
- /* - * Make sure U-Boot is compiled with all the active PCRs - * since we are about to create an EventLog and we won't - * measure anything if the PCR banks don't match - */ - if (!tpm2_check_active_banks(dev)) { - log_err("Cannot create EventLog\n"); - log_err("Mismatch between U-Boot and TPM hash algos\n"); - log_info("TPM:\n"); - tpm2_print_active_banks(dev); - log_info("U-Boot:\n"); - for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) { - const struct digest_info *algo = &hash_algo_list[i]; - const char *str; - - if (!algo->supported) - continue; - - str = tpm2_algorithm_name(algo->hash_alg); - if (str) - log_info("%s\n", str); - } - return -EINVAL; - } - rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size); if (!rc) { log.log_position = 0; log.found = false;
if (!ignore_existing_log) { - rc = tcg2_log_parse(dev, &log); + rc = tcg2_log_parse(dev, &log, &log_active); + if (rc == -ERESTARTSYS && log_active) + goto pcr_allocate; if (rc) return rc; } @@ -617,6 +594,11 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, elog->found = log.found; }
+pcr_allocate: + rc = tpm2_pcr_allocate(dev, log_active); + if (rc) + return rc; + if (elog->found) return 0;

On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
Get eventlog bank mask when parsing the eventlog from previous boot stage and invoke PCR allocate function based on it. PCR allocate will be proceeded if any dismatches observed among the active, supportted and eventlog bank masks to re-configurate the TPM with the proper algorithms and reboot the system.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
lib/tpm_tcg2.c | 52 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 35 deletions(-)
diff --git a/lib/tpm_tcg2.c b/lib/tpm_tcg2.c index 2d9076f091..fd84045d8b 100644 --- a/lib/tpm_tcg2.c +++ b/lib/tpm_tcg2.c @@ -360,12 +360,12 @@ static int tcg2_replay_eventlog(struct tcg2_event_log *elog, return 0; }
-static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) +static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog,
u32 *log_active)
{ struct tpml_digest_values digest_list; struct tcg_efi_spec_id_event *event; struct tcg_pcr_event *log;
u32 log_active; u32 calc_size; u32 active; u32 count;
@@ -376,6 +376,8 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) int rc; u32 i;
*log_active = 0;
if (elog->log_size <= offsetof(struct tcg_pcr_event, event)) return 0;
@@ -421,7 +423,6 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) * algorithms, so just check the EvenLog against the TPM active ones. */ digest_list.count = 0;
log_active = 0; for (i = 0; i < count; ++i) { algo = get_unaligned_le16(&event->digest_sizes[i].algorithm_id); mask = tcg2_algorithm_to_mask(algo);
@@ -447,17 +448,15 @@ static int tcg2_log_parse(struct udevice *dev, struct tcg2_event_log *elog) algo); return -1; }
log_active |= mask;
*log_active |= mask; } rc = tcg2_get_active_pcr_banks(dev, &active); if (rc) return rc; /* If the EventLog and active algorithms don't match exit */
if (log_active != active) {
log_err("EventLog doesn't contain all active PCR banks\n");
return -1;
}
if (*log_active != active)
return -ERESTARTSYS; /* Read PCR0 to check if previous firmware extended the PCRs or not. */ rc = tcg2_pcr_read(dev, 0, &digest_list);
@@ -554,43 +553,21 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, bool ignore_existing_log) { struct tcg2_event_log log;
int rc, i;
int rc;
u32 log_active = 0; elog->log_position = 0; elog->found = false;
/*
* Make sure U-Boot is compiled with all the active PCRs
* since we are about to create an EventLog and we won't
* measure anything if the PCR banks don't match
*/
if (!tpm2_check_active_banks(dev)) {
log_err("Cannot create EventLog\n");
log_err("Mismatch between U-Boot and TPM hash algos\n");
log_info("TPM:\n");
tpm2_print_active_banks(dev);
log_info("U-Boot:\n");
for (i = 0; i < ARRAY_SIZE(hash_algo_list); i++) {
const struct digest_info *algo = &hash_algo_list[i];
const char *str;
if (!algo->supported)
continue;
str = tpm2_algorithm_name(algo->hash_alg);
if (str)
log_info("%s\n", str);
}
return -EINVAL;
}
rc = tcg2_platform_get_log(dev, (void **)&log.log, &log.log_size); if (!rc) { log.log_position = 0; log.found = false; if (!ignore_existing_log) {
rc = tcg2_log_parse(dev, &log);
rc = tcg2_log_parse(dev, &log, &log_active);
if (rc == -ERESTARTSYS && log_active)
goto pcr_allocate; if (rc) return rc; }
@@ -617,6 +594,11 @@ int tcg2_log_prepare_buffer(struct udevice *dev, struct tcg2_event_log *elog, elog->found = log.found; }
+pcr_allocate:
rc = tpm2_pcr_allocate(dev, log_active);
if (rc)
return rc;
if (elog->found) return 0;
-- 2.25.1
With the naming changes on patch #3
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

During PCR extend process, if any unsupported algorithms are active, try to use PCR allocate to inactivate them.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- lib/tpm-v2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c index 71abf070de..9781c288be 100644 --- a/lib/tpm-v2.c +++ b/lib/tpm-v2.c @@ -344,7 +344,10 @@ u32 tpm2_pcr_extend(struct udevice *dev, u32 index, u32 algorithm,
if (!tpm2_check_active_banks(dev)) { log_err("Cannot extend PCRs if all the TPM enabled algorithms are not supported\n"); - return -EINVAL; + + ret = tpm2_pcr_allocate(dev, 0); + if (ret) + return -EINVAL; } /* * Fill the command structure starting from the first buffer:

Enable PCR allocate and system reboot when algorithms don't match among the values from TPM device, U-Boot support and evenlog.
Signed-off-by: Raymond Mao raymond.mao@linaro.org --- configs/qemu_arm64_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index 0c7107c1f4..6ba3cb1bbd 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -73,3 +73,4 @@ CONFIG_SEMIHOSTING=y CONFIG_MBEDTLS_LIB=y CONFIG_TPM=y CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE=y +CONFIG_TPM_PCR_ALLOCATE=y

On Wed, 15 Jan 2025 at 22:02, Raymond Mao raymond.mao@linaro.org wrote:
Enable PCR allocate and system reboot when algorithms don't match among the values from TPM device, U-Boot support and evenlog.
Signed-off-by: Raymond Mao raymond.mao@linaro.org
configs/qemu_arm64_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig index 0c7107c1f4..6ba3cb1bbd 100644 --- a/configs/qemu_arm64_defconfig +++ b/configs/qemu_arm64_defconfig @@ -73,3 +73,4 @@ CONFIG_SEMIHOSTING=y CONFIG_MBEDTLS_LIB=y CONFIG_TPM=y CONFIG_GENERATE_SMBIOS_TABLE_VERBOSE=y
+CONFIG_TPM_PCR_ALLOCATE=y
2.25.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org
participants (3)
-
Ilias Apalodimas
-
Raymond Mao
-
Simon Glass