This patch adds a menu item for displaying TPM diagnostics such as timeouts and durations, and device, vendor, and revision IDs and the display of some physical presence flags of the TPM.
Signed-off-by: Stefan Berger stefanb@linux.vnet.ibm.com --- src/Kconfig | 8 +++ src/hw/tpm_drivers.c | 11 ++++ src/hw/tpm_drivers.h | 1 + src/tcgbios.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/tcgbios.h | 5 ++ 5 files changed, 198 insertions(+), 1 deletion(-)
diff --git a/src/Kconfig b/src/Kconfig index 9e65449..a6e1096 100644 --- a/src/Kconfig +++ b/src/Kconfig @@ -418,6 +418,14 @@ menu "BIOS interfaces" help Provide TPM support along with TCG BIOS extensions
+ config TPM_DIAGNOSTICS + depends on TCGBIOS + bool "TPM Diagnostics menu item" + default n + help + Add a menu item for displaying of TPM diagnostics in case + of certain issues with the TPM hardware. + endmenu
menu "BIOS Tables" diff --git a/src/hw/tpm_drivers.c b/src/hw/tpm_drivers.c index 1d5a779..f7cb669 100644 --- a/src/hw/tpm_drivers.c +++ b/src/hw/tpm_drivers.c @@ -241,6 +241,16 @@ static u32 tis_waitrespready(enum tpmDurationType to_t) }
+static void tis_version_data(u16 *did, u16 *vid, u16 *rid) +{ + u8 locty = tis_find_active_locality(); + + *did = readw(TIS_REG(locty, TIS_REG_DID_VID + 2)); + *vid = readw(TIS_REG(locty, TIS_REG_DID_VID)); + *rid = readw(TIS_REG(locty, TIS_REG_RID)); +} + + struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { [TIS_DRIVER_IDX] = { @@ -256,6 +266,7 @@ struct tpm_driver tpm_drivers[TPM_NUM_DRIVERS] = { .waitdatavalid = tis_waitdatavalid, .waitrespready = tis_waitrespready, .sha1threshold = 100 * 1024, + .get_vers_data = tis_version_data, }, };
diff --git a/src/hw/tpm_drivers.h b/src/hw/tpm_drivers.h index 34bb12d..f13f198 100644 --- a/src/hw/tpm_drivers.h +++ b/src/hw/tpm_drivers.h @@ -26,6 +26,7 @@ struct tpm_driver { /* the TPM will be used for buffers of sizes below the sha1threshold for calculating the hash */ u32 sha1threshold; + void (*get_vers_data)(u16 *did, u16 *vid, u16 *rid); };
extern struct tpm_driver tpm_drivers[]; diff --git a/src/tcgbios.c b/src/tcgbios.c index 5be9bcd..bdeedb8 100644 --- a/src/tcgbios.c +++ b/src/tcgbios.c @@ -87,6 +87,15 @@ typedef struct { u8 tpm_working:1; u8 if_shutdown:1; u8 tpm_driver_to_use:4; +#ifdef CONFIG_TPM_DIAGNOSTICS + u32 startup_error; + u32 selftest_error; + u32 physpresence_enable_error; + u32 physpresence_lock_error; + u32 get_timeouts_error; + u32 get_durations_error; + u32 sha1_error; +#endif } tcpa_state_t;
@@ -403,6 +412,10 @@ determine_timeouts(void) dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Timeouts)" " = 0x%08x\n", returnCode);
+#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.get_timeouts_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -416,6 +429,10 @@ determine_timeouts(void) dprintf(DEBUG_tcg, "TCGBIOS: Return code from TPM_GetCapability(Durations)" " = 0x%08x\n", returnCode);
+#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.get_durations_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -471,6 +488,10 @@ tcpa_startup(void) dprintf(DEBUG_tcg, "Return code from TPM_Startup = 0x%08x\n", returnCode);
+#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.startup_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -480,6 +501,10 @@ tcpa_startup(void) dprintf(DEBUG_tcg, "Return code from TPM_SelfTestFull = 0x%08x\n", returnCode);
+#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.selftest_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -515,6 +540,11 @@ tcpa_leave_bios(void) PhysicalPresence_CMD_ENABLE, sizeof(PhysicalPresence_CMD_ENABLE), NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + +#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.physpresence_enable_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -522,6 +552,11 @@ tcpa_leave_bios(void) PhysicalPresence_NOT_PRESENT_LOCK, sizeof(PhysicalPresence_NOT_PRESENT_LOCK), NULL, 10, &returnCode, TPM_DURATION_TYPE_SHORT); + +#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.physpresence_lock_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -628,6 +663,10 @@ tpm_sha1_calc(const u8 *data, u32 length, u8 *hash) &returnCode, &data[offset], rest, TPM_DURATION_TYPE_SHORT);
+#ifdef CONFIG_TPM_DIAGNOSTICS + tcpa_state.sha1_error = rc ? rc : returnCode; +#endif + if (rc || returnCode) goto err_exit;
@@ -1929,6 +1968,131 @@ tcpa_process_cfg(const tpm_bios_cfg_t *cfg, int verbose) return rc; }
+#ifdef CONFIG_TPM_DIAGNOSTICS +static void +wait_for_any_key(void) +{ + printf("Press any key to continue.\n"); + while (get_keystroke(1000) < 0) + ; +} + +static void +tcpa_display_timeouts(void) +{ + struct tpm_driver *td; + int i; + + td = &tpm_drivers[tcpa_state.tpm_driver_to_use]; + + printf("\nTIS Timeouts : "); + + if (td->timeouts == NULL) { + printf("not known"); + } else { + for (i = 0; i < 4 ; i++) + printf("%d ", td->timeouts[i]); + } + + printf("\nTPM Durations: "); + + if (td->durations == NULL) { + printf("not known"); + } else { + for (i = 0; i < 3 ; i++) + printf("%d ", td->durations[i]); + } + printf("\n\n"); + + wait_for_any_key(); +} + +static void +tcpa_display_tpm_version(void) +{ + struct tpm_driver *td; + u16 did, vid, rid; + + td = &tpm_drivers[tcpa_state.tpm_driver_to_use]; + + td->get_vers_data(&did, &vid, &rid); + + printf("\nDevice ID : 0x%x\n", did); + printf("Vendor ID : 0x%x\n", vid); + printf("Revision ID : 0x%x\n\n", rid); + wait_for_any_key(); +} + +static void +tcpa_display_errors(void) +{ + printf("\ntpm probed: %d\n", tcpa_state.tpm_probed); + printf("tpm working: %d\n", tcpa_state.tpm_working); + printf("tpm found: %d\n", tcpa_state.tpm_found); + printf("startup error: 0x%x\n", tcpa_state.startup_error); + printf("selftest error: 0x%x\n", tcpa_state.selftest_error); + printf("get timeouts error : 0x%x\n", + tcpa_state.get_timeouts_error); + printf("get durations error: 0x%x\n", + tcpa_state.get_durations_error); + printf("get sha1 error: 0x%x\n", + tcpa_state.sha1_error); + printf("phys. presence enable error: 0x%x\n", + tcpa_state.physpresence_enable_error); + printf("phys. presence lock error : 0x%x\n\n", + tcpa_state.physpresence_lock_error); + wait_for_any_key(); +} + +static void +tcpa_display_perm_flags(void) +{ + struct tpm_permanent_flags pf; + int rc; + + rc = read_permanent_flags((char *)&pf, sizeof(pf)); + if (rc) + return; + + printf("phys. presence lifetime lock: %d\n", + pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK]); + printf("phys. presence hw enable: %d\n", + pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE]); + printf("phys. presence cmd enable: %d\n\n", + pf.flags[PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE]); + wait_for_any_key(); +} + +static void +tcpa_display_stclear_flags(void) +{ + struct tpm_stclear_flags stcf; + int rc; + + rc = read_stclear_flags((char *)&stcf, sizeof(stcf)); + if (rc) + return; + + printf("phys. presence: %d\n", + stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE]); + printf("phys. presence lock: %d\n", + stcf.flags[STCLEAR_FLAG_IDX_PHYSICAL_PRESENCE_LOCK]); + printf("global lock: %d\n\n", + stcf.flags[STCLEAR_FLAG_IDX_GLOBAL_LOCK]); + wait_for_any_key(); +} + +static void +tcpa_display_diagnostics(void) +{ + tcpa_display_tpm_version(); + tcpa_display_errors(); + tcpa_display_timeouts(); + tcpa_display_perm_flags(); + tcpa_display_stclear_flags(); +} +#endif + void tcpa_menu(void) { @@ -1955,9 +2119,12 @@ tcpa_menu(void) "6. Allow installation of owner\n" "7. Prevent installation of owner\n"); } else { - printf("TPM is not working correctly.\n"); + printf("TPM is not working correctly.\n\n"); }
+#ifdef CONFIG_TPM_DIAGNOSTICS + printf("d. TPM Diagnostics\n"); +#endif printf("Escape for previous menu.\n");
if (has_working_tpm()) { @@ -1976,6 +2143,11 @@ tcpa_menu(void) case 2 ... 8: cfg.op = scan_code - 1; break; +#ifdef CONFIG_TPM_DIAGNOSTICS + case 32: + tcpa_display_diagnostics(); + continue; +#endif default: continue; } diff --git a/src/tcgbios.h b/src/tcgbios.h index b01300a..3807b2f 100644 --- a/src/tcgbios.h +++ b/src/tcgbios.h @@ -87,6 +87,10 @@ #define TPM_ST_DEACTIVATED 0x3
+/* TPM command error codes */ +#define TPM_INVALID_POSTINIT 0x26 + + /* interrupt identifiers (al register) */ enum irq_ids { TCG_StatusCheck = 0, @@ -313,6 +317,7 @@ enum permFlagsIndex { PERM_FLAG_IDX_ALLOW_MAINTENANCE, PERM_FLAG_IDX_PHYSICAL_PRESENCE_LIFETIME_LOCK, PERM_FLAG_IDX_PHYSICAL_PRESENCE_HW_ENABLE, + PERM_FLAG_IDX_PHYSICAL_PRESENCE_CMD_ENABLE, };