From 00dbf449c929933d7cdb31140d609269c68d3671 Mon Sep 17 00:00:00 2001 From: Keith Short Date: Fri, 19 Apr 2019 14:02:02 -0600 Subject: coreboot: Run mainboard specific code before Cr50 reset When coreboot checks the TPM and key-ladder state it issues a reboot of the Cr50 with a delay parameter. Older Cr50 code doesn't support the delay parameter and reboots immediately, which prevented coreboot from running the mainboard specific code needed for the AP to come back up. This change calls mainboard_prepare_cr50_reset() prior to sending the VENDOR_CC_IMMEDIATE_RESET command. This change also fixes a false error message from the coreboot log that indicated "Unexpected Cr50 TPM mode 3" when the Cr50 key ladder is disabled. BUG=b:130830178 BRANCH=none TEST=build coreboot on sarien and grunt platforms. TEST=Load Cr50 v3.15, run 'gsctool -a -m disable; reboot'. Verify corebot send the VENDOR_CC_IMMEDIATE_RESET command and that the AP boots normally. Verify event log shows "cr50 Reset Required" TEST=Force Cr50 automatic update. Verify event log shows "cr50 Update Reset". Change-Id: Ib05c9cfde8e87daffd4233114263de5b30822872 Signed-off-by: Keith Short Reviewed-on: https://review.coreboot.org/c/coreboot/+/32365 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh --- .../google/chromeos/cr50_enable_update.c | 59 +++++++++++++--------- 1 file changed, 34 insertions(+), 25 deletions(-) (limited to 'src/vendorcode') diff --git a/src/vendorcode/google/chromeos/cr50_enable_update.c b/src/vendorcode/google/chromeos/cr50_enable_update.c index 91a10cb9aa..f2cdbfd39c 100644 --- a/src/vendorcode/google/chromeos/cr50_enable_update.c +++ b/src/vendorcode/google/chromeos/cr50_enable_update.c @@ -23,7 +23,7 @@ #include #include -#define C50_RESET_DELAY_MS 1000 +#define CR50_RESET_DELAY_MS 1000 void __weak mainboard_prepare_cr50_reset(void) {} @@ -31,12 +31,11 @@ void __weak mainboard_prepare_cr50_reset(void) {} * Check if the Cr50 TPM state requires a chip reset of the Cr50 device. * * Returns 0 if the Cr50 TPM state is good or if the TPM_MODE command is - * unsupported. Returns 1 if the Cr50 was reset. + * unsupported. Returns 1 if the Cr50 requires a reset. */ -static int cr50_reset_if_needed(uint16_t timeout_ms) +static int cr50_is_reset_needed(void) { int ret; - int cr50_must_reset = 0; uint8_t tpm_mode; ret = tlcl_cr50_get_tpm_mode(&tpm_mode); @@ -53,7 +52,7 @@ static int cr50_reset_if_needed(uint16_t timeout_ms) * Cr50 indicated a reboot is required to restore TPM * functionality. */ - cr50_must_reset = 1; + return 1; } else if (ret != TPM_SUCCESS) { /* TPM command failed, continue booting. */ printk(BIOS_ERR, @@ -61,7 +60,8 @@ static int cr50_reset_if_needed(uint16_t timeout_ms) return 0; } - /* If the TPM mode is not enabled-tentative, then the TPM mode is locked + /* + * If the TPM mode is not enabled-tentative, then the TPM mode is locked * and cannot be changed. Perform a Cr50 reset because vboot may need * to disable TPM as part of booting an untrusted OS. * @@ -72,30 +72,17 @@ static int cr50_reset_if_needed(uint16_t timeout_ms) printk(BIOS_NOTICE, "NOTICE: Unexpected Cr50 TPM mode (%d). " "A Cr50 reset is required.\n", tpm_mode); - cr50_must_reset = 1; + return 1; } /* If TPM state is okay, no reset needed. */ - if (!cr50_must_reset) - return 0; - - ret = tlcl_cr50_immediate_reset(timeout_ms); - - if (ret != TPM_SUCCESS) { - /* TPM command failed, continue booting. */ - printk(BIOS_ERR, - "ERROR: Attempt to reset CR50 failed: %x\n", - ret); - return 0; - } - - /* Cr50 is about to be reset, caller needs to prepare */ - return 1; + return 0; } static void enable_update(void *unused) { int ret; + int cr50_reset_reqd = 0; uint8_t num_restored_headers; /* Nothing to do on recovery mode. */ @@ -112,7 +99,7 @@ static void enable_update(void *unused) } /* Reboot in 1000 ms if necessary. */ - ret = tlcl_cr50_enable_update(C50_RESET_DELAY_MS, + ret = tlcl_cr50_enable_update(CR50_RESET_DELAY_MS, &num_restored_headers); if (ret != TPM_SUCCESS) { @@ -134,9 +121,10 @@ static void enable_update(void *unused) */ /* - * If the Cr50 was not reset, continue booting. + * If the Cr50 doesn't requires a reset, continue booting. */ - if (!cr50_reset_if_needed(C50_RESET_DELAY_MS)) + cr50_reset_reqd = cr50_is_reset_needed(); + if (!cr50_reset_reqd) return; printk(BIOS_INFO, "Waiting for CR50 reset to enable TPM.\n"); @@ -153,6 +141,27 @@ static void enable_update(void *unused) /* clear current post code avoid chatty eventlog on subsequent boot*/ post_code(0); + /* + * Older Cr50 firmware doesn't support the timeout parameter for the + * immediate reset request, so the reset request must be sent after + * the mainboard specific code runs. + */ + if (cr50_reset_reqd) { + ret = tlcl_cr50_immediate_reset(CR50_RESET_DELAY_MS); + + if (ret != TPM_SUCCESS) { + /* + * Reset request failed due to TPM error, continue + * booting but the current boot will likely end up at + * the recovery screen. + */ + printk(BIOS_ERR, + "ERROR: Attempt to reset CR50 failed: %x\n", + ret); + return; + } + } + if (CONFIG(POWER_OFF_ON_CR50_UPDATE)) poweroff(); halt(); -- cgit v1.2.3