diff options
author | Keith Short <keithshort@chromium.org> | 2019-02-05 16:15:10 -0700 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2019-02-13 13:03:33 +0000 |
commit | e0f340054761086e4c329a2f66bb8f5b6e13d7c9 (patch) | |
tree | 977ba95155edd474d6d67c4bf61f58ee869c094f /src/security/tpm/tss/vendor | |
parent | 91be00ef1be29e6670599aa5e9c297854a928d07 (diff) |
coreboot: check Cr50 PM mode on normal boot
Under some scenarios the key ladder on the Cr50 can get disabled. If
this state is detected, trigger a reboot of the Cr50 to restore full
TPM functionality.
BUG=b:121463033
BRANCH=none
TEST=Built coreboot on sarien and grunt platforms.
TEST=Ran 'gsctool -a -m disable' and reboot. Verified coreboot sends
VENDOR_CC_IMMEDIATE_RESET command to Cr50 and that the Cr50 resets and
then the platform boots normally.
TEST=Performed Cr50 rollback to 0.0.22 which does not support the
VENDOR_CC_TPM_MODE command, confirmed that platform boots normally and
the coreboot log captures the unsupported command.
Tested-by: Keith Short <keithshort@chromium.org>
Change-Id: I70e012efaf1079d43890e909bc6b5015bef6835a
Signed-off-by: Keith Short <keithshort@chromium.org>
Reviewed-on: https://review.coreboot.org/c/31260
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'src/security/tpm/tss/vendor')
-rw-r--r-- | src/security/tpm/tss/vendor/cr50/cr50.c | 65 | ||||
-rw-r--r-- | src/security/tpm/tss/vendor/cr50/cr50.h | 48 |
2 files changed, 110 insertions, 3 deletions
diff --git a/src/security/tpm/tss/vendor/cr50/cr50.c b/src/security/tpm/tss/vendor/cr50/cr50.c index 450ad97fe5..1522ce6979 100644 --- a/src/security/tpm/tss/vendor/cr50/cr50.c +++ b/src/security/tpm/tss/vendor/cr50/cr50.c @@ -26,7 +26,7 @@ uint32_t tlcl_cr50_enable_nvcommits(void) if (response == NULL || (response && response->hdr.tpm_code)) { if (response) printk(BIOS_INFO, "%s: failed %x\n", __func__, - response->hdr.tpm_code); + response->hdr.tpm_code); else printk(BIOS_INFO, "%s: failed\n", __func__); return TPM_E_IOERROR; @@ -47,7 +47,7 @@ uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms, response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body); if (!response || response->hdr.tpm_code) - return TPM_E_INTERNAL_INCONSISTENCY; + return TPM_E_IOERROR; *num_restored_headers = response->vcr.num_restored_headers; return TPM_SUCCESS; @@ -63,8 +63,67 @@ uint32_t tlcl_cr50_get_recovery_button(uint8_t *recovery_button_state) response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command); if (!response || response->hdr.tpm_code) - return TPM_E_INTERNAL_INCONSISTENCY; + return TPM_E_IOERROR; *recovery_button_state = response->vcr.recovery_button_state; return TPM_SUCCESS; } + +uint32_t tlcl_cr50_get_tpm_mode(uint8_t *tpm_mode) +{ + struct tpm2_response *response; + uint16_t mode_command = TPM2_CR50_SUB_CMD_TPM_MODE; + *tpm_mode = TPM_MODE_INVALID; + + printk(BIOS_INFO, "Reading cr50 TPM mode\n"); + + response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &mode_command); + + if (!response) + return TPM_E_IOERROR; + + if (response->hdr.tpm_code == VENDOR_RC_INTERNAL_ERROR) { + /* + * The Cr50 returns VENDOR_RC_INTERNAL_ERROR iff the key ladder + * is disabled. The Cr50 requires a reboot to re-enable the key + * ladder. + */ + return TPM_E_MUST_REBOOT; + } + + if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND) { + /* + * Explicitly inform caller when command is not supported + */ + return TPM_E_NO_SUCH_COMMAND; + } + + if (response->hdr.tpm_code) { + /* Unexpected return code from Cr50 */ + return TPM_E_IOERROR; + } + + /* TPM command completed without error */ + *tpm_mode = response->vcr.tpm_mode; + + return TPM_SUCCESS; +} + +uint32_t tlcl_cr50_immediate_reset(uint16_t timeout_ms) +{ + struct tpm2_response *response; + uint16_t reset_command_body[] = { + TPM2_CR50_SUB_CMD_IMMEDIATE_RESET, timeout_ms}; + + /* + * Issue an immediate reset to the Cr50. + */ + printk(BIOS_INFO, "Issuing cr50 reset\n"); + response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, + &reset_command_body); + + if (!response) + return TPM_E_IOERROR; + + return TPM_SUCCESS; +} diff --git a/src/security/tpm/tss/vendor/cr50/cr50.h b/src/security/tpm/tss/vendor/cr50/cr50.h index a1ab539c07..6a160e0a23 100644 --- a/src/security/tpm/tss/vendor/cr50/cr50.h +++ b/src/security/tpm/tss/vendor/cr50/cr50.h @@ -23,9 +23,35 @@ to extending generically because the marshaling code is assuming all knowledge of all commands. */ #define TPM2_CR50_VENDOR_COMMAND ((TPM_CC)(TPM_CC_VENDOR_BIT_MASK | 0)) +#define TPM2_CR50_SUB_CMD_IMMEDIATE_RESET (19) #define TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS (21) #define TPM2_CR50_SUB_CMD_TURN_UPDATE_ON (24) #define TPM2_CR50_SUB_CMD_GET_REC_BTN (29) +#define TPM2_CR50_SUB_CMD_TPM_MODE (40) + +/* Cr50 vendor-specific error codes. */ +#define VENDOR_RC_ERR 0x00000500 +enum cr50_vendor_rc { + VENDOR_RC_INTERNAL_ERROR = (VENDOR_RC_ERR | 6), + VENDOR_RC_NO_SUCH_COMMAND = (VENDOR_RC_ERR | 127), +}; + +enum cr50_tpm_mode { + /* + * Default state: TPM is enabled, and may be set to either + * TPM_MODE_ENABLED or TPM_MODE_DISABLED. + */ + TPM_MODE_ENABLED_TENTATIVE = 0, + + /* TPM is enabled, and mode may not be changed. */ + TPM_MODE_ENABLED = 1, + + /* TPM is disabled, and mode may not be changed. */ + TPM_MODE_DISABLED = 2, + + TPM_MODE_INVALID, +}; + /** * CR50 specific tpm command to enable nvmem commits before internal timeout @@ -53,4 +79,26 @@ uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms, */ uint32_t tlcl_cr50_get_recovery_button(uint8_t *recovery_button_state); +/** + * CR50 specific TPM command sequence to query the current TPM mode. + * + * Returns TPM_SUCCESS if TPM mode command completed, the Cr50 does not need a + * reboot, and the tpm_mode parameter is set to the current TPM mode. + * Returns TPM_E_MUST_REBOOT if TPM mode command completed, but the Cr50 + * requires a reboot. + * Returns TPM_E_NO_SUCH_COMMAND if the Cr50 does not support the command. + * Other returns value indicate a failure accessing the TPM. + */ +uint32_t tlcl_cr50_get_tpm_mode(uint8_t *tpm_mode); + +/** + * CR50 specific TPM command sequence to trigger an immediate reset to the Cr50 + * device after the specified timeout in milliseconds. A timeout of zero means + * "IMMEDIATE REBOOT". + * + * Return value indicates success or failure of accessing the TPM. + */ +uint32_t tlcl_cr50_immediate_reset(uint16_t timeout_ms); + + #endif /* CR50_TSS_STRUCTURES_H_ */ |