1 /* SPDX-License-Identifier: GPL-2.0-only */
2
3 #include <bootstate.h>
4 #include <commonlib/console/post_codes.h>
5 #include <console/console.h>
6 #include <ec/google/chromeec/ec.h>
7 #include <elog.h>
8 #include <halt.h>
9 #include <security/tpm/tss.h>
10 #include <vb2_api.h>
11 #include <security/vboot/misc.h>
12 #include <security/vboot/vboot_common.h>
13 #include <vendorcode/google/chromeos/chromeos.h>
14 #include <timestamp.h>
15
16 #define CR50_RESET_DELAY_MS 1000
17
mainboard_prepare_cr50_reset(void)18 void __weak mainboard_prepare_cr50_reset(void) {}
19
20 /**
21 * Check if the Cr50 TPM state requires a chip reset of the Cr50 device.
22 *
23 * Returns 0 if the Cr50 TPM state is good or if the TPM_MODE command is
24 * unsupported. Returns 1 if the Cr50 requires a reset.
25 */
cr50_is_reset_needed(void)26 static int cr50_is_reset_needed(void)
27 {
28 tpm_result_t rc;
29 uint8_t tpm_mode;
30
31 rc = tlcl_cr50_get_tpm_mode(&tpm_mode);
32
33 if (rc == TPM_CB_NO_SUCH_COMMAND) {
34 printk(BIOS_INFO,
35 "Cr50 does not support TPM mode command\n");
36 /* Older Cr50 firmware, assume no Cr50 reset is required */
37 return 0;
38 }
39
40 if (rc == TPM_CB_MUST_REBOOT) {
41 /*
42 * Cr50 indicated a reboot is required to restore TPM
43 * functionality.
44 */
45 return 1;
46 } else if (rc != TPM_SUCCESS) {
47 /* TPM command failed, continue booting. */
48 printk(BIOS_ERR, "Attempt to get CR50 TPM mode failed: %#x\n", rc);
49 return 0;
50 }
51
52 /*
53 * If the TPM mode is not enabled-tentative, then the TPM mode is locked
54 * and cannot be changed. Perform a Cr50 reset because vboot may need
55 * to disable TPM as part of booting an untrusted OS.
56 *
57 * This is not an expected state, as the Cr50 always sets the TPM mode
58 * to TPM_MODE_ENABLED_TENTATIVE during any TPM reset action.
59 */
60 if (tpm_mode != TPM_MODE_ENABLED_TENTATIVE) {
61 printk(BIOS_NOTICE,
62 "NOTICE: Unexpected Cr50 TPM mode (%d). "
63 "A Cr50 reset is required.\n", tpm_mode);
64 return 1;
65 }
66
67 /* If TPM state is okay, no reset needed. */
68 return 0;
69 }
70
enable_update(void * unused)71 static void enable_update(void *unused)
72 {
73 tpm_result_t rc;
74 int cr50_reset_reqd = 0;
75 uint8_t num_restored_headers;
76
77 /**
78 * Never update during manually-triggered recovery to ensure update
79 * cannot interfere. Non-manual VB2_RECOVERY_TRAIN_AND_REBOOT
80 * sometimes used to update in factory.
81 */
82 if (vboot_get_context()->flags & VB2_CONTEXT_FORCE_RECOVERY_MODE)
83 return;
84
85 rc = tlcl_lib_init();
86
87 if (rc != TPM_SUCCESS) {
88 printk(BIOS_ERR, "tlcl_lib_init() failed for CR50 update: %#x\n",
89 rc);
90 return;
91 }
92
93 timestamp_add_now(TS_TPM_ENABLE_UPDATE_START);
94
95 /* Reboot in 1000 ms if necessary. */
96 rc = tlcl_cr50_enable_update(CR50_RESET_DELAY_MS,
97 &num_restored_headers);
98
99 if (rc != TPM_SUCCESS) {
100 printk(BIOS_ERR, "Attempt to enable CR50 update failed: %#x\n",
101 rc);
102 return;
103 }
104
105 if (!num_restored_headers) {
106 /* If no headers were restored there is no reset forthcoming due
107 * to a Cr50 firmware update. Also check if the Cr50 TPM mode
108 * requires a reset.
109 *
110 * TODO: to eliminate a TPM command during every boot, the
111 * TURN_UPDATE_ON command could be enhanced/replaced in the Cr50
112 * firmware to perform the TPM mode/key-ladder check in addition
113 * to the FW version check.
114 */
115
116 /*
117 * If the Cr50 doesn't requires a reset, continue booting.
118 */
119 cr50_reset_reqd = cr50_is_reset_needed();
120 if (!cr50_reset_reqd) {
121 timestamp_add_now(TS_TPM_ENABLE_UPDATE_END);
122 return;
123 }
124
125 printk(BIOS_INFO, "Waiting for CR50 reset to enable TPM.\n");
126 elog_add_event(ELOG_TYPE_CR50_NEED_RESET);
127 } else {
128 printk(BIOS_INFO,
129 "Waiting for CR50 reset to pick up update.\n");
130 elog_add_event(ELOG_TYPE_CR50_UPDATE);
131 }
132
133 /* Give mainboard a chance to take action */
134 mainboard_prepare_cr50_reset();
135
136 /* clear current post code avoid chatty eventlog on subsequent boot*/
137 post_code(POSTCODE_CODE_CLEAR);
138
139 /*
140 * Older Cr50 firmware doesn't support the timeout parameter for the
141 * immediate reset request, so the reset request must be sent after
142 * the mainboard specific code runs.
143 */
144 if (cr50_reset_reqd) {
145 rc = tlcl_cr50_immediate_reset(CR50_RESET_DELAY_MS);
146
147 if (rc != TPM_SUCCESS) {
148 /*
149 * Reset request failed due to TPM error, continue
150 * booting but the current boot will likely end up at
151 * the recovery screen.
152 */
153 printk(BIOS_ERR, "Attempt to reset CR50 failed: %#x\n",
154 rc);
155 return;
156 }
157 }
158
159 if (CONFIG(POWER_OFF_ON_CR50_UPDATE)) {
160 if (CONFIG(CR50_RESET_CLEAR_EC_AP_IDLE_FLAG))
161 google_chromeec_clear_ec_ap_idle();
162 poweroff();
163 }
164 halt();
165 }
166 BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, enable_update, NULL);
167