vboot_api_kernel: check TPM mode on normal boot
When booting into Alt OS legacy mode, we plan to disable TPM
before handing off control to the OS. On a warm reboot back
to Chrome OS, we must check the TPM mode. If it is disabled,
a hard reboot should be triggered to restore TPM functionality.
Add this check to VbBootNormal. Only accept the TPM mode
VB2_TPM_MODE_ENABLED_TENTATIVE (0).
BUG=b:119203340
TEST=compile, flash, and boot eve
TEST=run `gsctool -a -m disable`
validate that the following messages show up on boot:
Calling VbSelectAndLoadKernel().
VbCheckTPM: Checking if TPM needs resetting (TPM_MODE)
cr50 TPM 2.0 (i2c 0x50 id 0x28)
tpm_internal_mode: Invalid header code: 1286
VbCheckTPM: TPM encountered some error; reset Cr50
tpm_internal_cr50_reset: Asking Cr50 to reset after 500 ms
VbCheckTPM: Shut down AP and wait for Cr50 reset
VbSelectAndLoadKernel: Returning 65549
Powering off.
Exiting depthcharge with code 2 at timestamp: 6603861
Change-Id: If6097aa67eb135e24c735bd7948ec25091bed3be
Reviewed-on: https://chromium-review.googlesource.com/c/1354140
Tested-by: Joel Kitching <kitching@chromium.org>
Reviewed-by: Namyoon Woo <namyoon@chromium.org>
Commit-Queue: Joel Kitching <kitching@chromium.org>
diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c
index 2647255..48daa6b 100644
--- a/firmware/lib/vboot_api_kernel.c
+++ b/firmware/lib/vboot_api_kernel.c
@@ -520,6 +520,40 @@
return VBERROR_SUCCESS;
}
+
+VbError_t VbCheckTPM(void)
+{
+ const int cr50_reset_delay_msec = 500;
+ enum vb2_tpm_mode tpm_mode;
+ int ret;
+ int need_reset = 0;
+
+ VB2_DEBUG("Checking if TPM needs resetting (TPM_MODE)\n");
+ ret = vb2ex_tpm_get_mode(&tpm_mode);
+ if (ret == VB2_ERROR_EX_TPM_NO_SUCH_COMMAND) {
+ VB2_DEBUG("TPM does not support command, assume good state\n");
+ } else if (ret != VB2_SUCCESS) {
+ VB2_DEBUG("TPM encountered some error; reset Cr50\n");
+ need_reset = 1;
+ } else if (tpm_mode != VB2_TPM_MODE_ENABLED_TENTATIVE) {
+ VB2_DEBUG("Invalid TPM mode (%d, expected: %d); reset Cr50\n",
+ tpm_mode, VB2_TPM_MODE_ENABLED_TENTATIVE);
+ need_reset = 1;
+ } else {
+ VB2_DEBUG("TPM is in good state\n");
+ }
+
+ if (!need_reset)
+ return VBERROR_SUCCESS;
+
+ if (vb2ex_tpm_cr50_reset(cr50_reset_delay_msec)) {
+ VB2_DEBUG("Reset Cr50 failed\n");
+ return VBERROR_UNKNOWN;
+ } else {
+ VB2_DEBUG("Shut down AP and wait for Cr50 reset\n");
+ return VBERROR_SHUTDOWN_REQUESTED;
+ }
+}
#endif /* ALT_OS */
VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
@@ -527,8 +561,19 @@
{
VbSharedDataHeader *shared =
(VbSharedDataHeader *)cparams->shared_data_blob;
+ VbError_t retval;
- VbError_t retval = vb2_kernel_setup(cparams, kparams);
+#ifdef ALT_OS
+ /*
+ * TPM may be disabled from a previous untrusted Alt OS boot.
+ * Check the TPM state and request a Cr50 reset if necessary.
+ */
+ retval = VbCheckTPM();
+ if (retval)
+ goto VbSelectAndLoadKernel_exit;
+#endif /* ALT_OS */
+
+ retval = vb2_kernel_setup(cparams, kparams);
if (retval)
goto VbSelectAndLoadKernel_exit;