Joel Kitching has uploaded this change for review. ( https://review.coreboot.org/29648
Change subject: tss: implement Cr50 vendor-specific VENDOR_CC_TPM_MODE ......................................................................
tss: implement Cr50 vendor-specific VENDOR_CC_TPM_MODE
When an untrusted OS is running, we would like to use the Cr50 vendor-specific VENDOR_CC_TPM_MODE command to disable TPM. This implements the "set" funtionality of this command, and exposes it as tlcl_cr50_set_tpm_mode.
This needs to live in coreboot codebase since on S3 resume path, depthcharge is not reached.
BUG=b:70681930,b:118202153 TEST=hack a call to tlcl_cr50_set_tpm_mode into coreboot on S3 resume verify in AP console that it is called verify that `tpm_version` fails to run
Change-Id: Idd55708797d2b17336fcbe80c0724957f7052e90 Signed-off-by: Joel Kitching kitching@google.com --- M src/security/tpm/tss/tcg-2.0/tss_marshaling.c M src/security/tpm/tss/tcg-2.0/tss_structures.h M src/security/tpm/tss/vendor/cr50/cr50.c M src/security/tpm/tss/vendor/cr50/cr50.h 4 files changed, 73 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/48/29648/1
diff --git a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c index af57248..5f04c6d 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_marshaling.c +++ b/src/security/tpm/tss/tcg-2.0/tss_marshaling.c @@ -273,6 +273,10 @@ rc |= obuf_write_be16(ob, sub_command[0]); rc |= obuf_write_be16(ob, sub_command[1]); break; + case TPM2_CR50_SUB_CMD_TPM_MODE: + rc |= obuf_write_be16(ob, sub_command[0]); + rc |= obuf_write_be8(ob, sub_command[1]); + break; default: /* Unsupported subcommand. */ printk(BIOS_WARNING, "Unsupported cr50 subcommand: 0x%04x\n", @@ -473,6 +477,9 @@ case TPM2_CR50_SUB_CMD_TURN_UPDATE_ON: return ibuf_read_be8(ib, &vcr->num_restored_headers); break; + case TPM2_CR50_SUB_CMD_TPM_MODE: + return ibuf_read_be8(ib, &vcr->tpm_mode); + break; default: printk(BIOS_ERR, "%s:%d - unsupported vendor command %#04x!\n", diff --git a/src/security/tpm/tss/tcg-2.0/tss_structures.h b/src/security/tpm/tss/tcg-2.0/tss_structures.h index 12c84e1..2a49bef 100644 --- a/src/security/tpm/tss/tcg-2.0/tss_structures.h +++ b/src/security/tpm/tss/tcg-2.0/tss_structures.h @@ -293,6 +293,7 @@ uint16_t vc_subcommand; union { uint8_t num_restored_headers; + uint8_t tpm_mode; }; };
diff --git a/src/security/tpm/tss/vendor/cr50/cr50.c b/src/security/tpm/tss/vendor/cr50/cr50.c index 90f7963..bd28a69 100644 --- a/src/security/tpm/tss/vendor/cr50/cr50.c +++ b/src/security/tpm/tss/vendor/cr50/cr50.c @@ -52,3 +52,35 @@ *num_restored_headers = response->vcr.num_restored_headers; return TPM_SUCCESS; } + +uint32_t tlcl_cr50_set_tpm_mode(uint8_t mode) +{ + struct tpm2_response *response; + uint16_t command_body[] = { + TPM2_CR50_SUB_CMD_TPM_MODE, mode + }; + + printk(BIOS_INFO, "Setting cr50 TPM mode\n"); + + response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body); + + if (response == NULL) { + printk(BIOS_ERR, "%s: communications error\n", __func__); + return TPM_E_COMMUNICATION_ERROR; + } + + if (response->hdr.tpm_code) { + printk(BIOS_ERR, "%s: invalid header code: %x\n", __func__, + response->hdr.tpm_code); + return TPM_E_IOERROR; + } + + if (response->vcr.tpm_mode != mode) { + printk(BIOS_ERR, + "%s: invalid TPM mode response: %d (expect %d)\n", + __func__, response->vcr.tpm_mode, mode); + return TPM_E_WRITE_FAILURE; + } + + return TPM_SUCCESS; +} diff --git a/src/security/tpm/tss/vendor/cr50/cr50.h b/src/security/tpm/tss/vendor/cr50/cr50.h index 9bf3bd5..682be70 100644 --- a/src/security/tpm/tss/vendor/cr50/cr50.h +++ b/src/security/tpm/tss/vendor/cr50/cr50.h @@ -25,6 +25,15 @@ #define TPM2_CR50_VENDOR_COMMAND ((TPM_CC)(TPM_CC_VENDOR_BIT_MASK | 0)) #define TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS (21) #define TPM2_CR50_SUB_CMD_TURN_UPDATE_ON (24) +#define TPM2_CR50_SUB_CMD_TPM_MODE (40) + +/* TPM2_CR50_SUB_CMD_TPM_MODE return values (TPM modes) */ +enum { + TpmModeEnabledTentative = 0, /* TPM is enabled, can be changed */ + TpmModeEnabled = 1, /* TPM is enabled, cannot be changed */ + TpmModeDisabled = 2, /* TPM is disabled, cannot be changed */ + TpmModeMax, +};
/** * CR50 specific tpm command to enable nvmem commits before internal timeout @@ -44,4 +53,28 @@ uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms, uint8_t *num_restored_headers);
+/** + * CR50 specific tpm command to get/set the TPM mode. This function sets + * the mode and validates that it was updated successfully. If any of the + * following occur, the function fails: + * - TPM does not understand the instruction (old version) + * - TPM has already left the TpmModeEnabledTentative mode + * - TPM responds with a mode other than the requested mode + * - Some other communication error + * Otherwise, the function call succeeds. + * + * `mode` argument may be any of the following: + * - TpmModeEnabledTentative = 0 TPM is enabled, can be changed + * - TpmModeEnabled = 1 TPM is enabled, cannot be changed + * - TpmModeDisabled = 2 TPM is disabled, cannot be changed + * + * Returns TPM_SUCCESS on success and TPM_E_* on failure. + * + * Note that CR50 also implements a version of this command which simply + * returns the current TPM mode (differentiated by whether or not the 8-bit + * mode argument is attached to the vendor command), but only the "set" + * version is implemented here. + */ +uint32_t tlcl_cr50_set_tpm_mode(uint8_t mode); + #endif /* CR50_TSS_STRUCTURES_H_ */