1 /* SPDX-License-Identifier: BSD-3-Clause */
2
3 #include <console/console.h>
4 #include <endian.h>
5 #include <halt.h>
6 #include <vb2_api.h>
7 #include <security/tpm/tis.h>
8 #include <security/tpm/tss.h>
9
10 #include "../../tcg-2.0/tss_marshaling.h"
11
tlcl_cr50_enable_nvcommits(void)12 tpm_result_t tlcl_cr50_enable_nvcommits(void)
13 {
14 uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
15 struct tpm2_response *response;
16
17 printk(BIOS_INFO, "Enabling GSC nvmem commits\n");
18
19 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
20
21 if (!response || (response && response->hdr.tpm_code)) {
22 if (response)
23 printk(BIOS_INFO, "%s: failed %#x\n", __func__,
24 response->hdr.tpm_code);
25 else
26 printk(BIOS_INFO, "%s: failed\n", __func__);
27 return TPM_IOERROR;
28 }
29 return TPM_SUCCESS;
30 }
31
tlcl_cr50_enable_update(uint16_t timeout_ms,uint8_t * num_restored_headers)32 tpm_result_t tlcl_cr50_enable_update(uint16_t timeout_ms,
33 uint8_t *num_restored_headers)
34 {
35 struct tpm2_response *response;
36 uint16_t command_body[] = {
37 TPM2_CR50_SUB_CMD_TURN_UPDATE_ON, timeout_ms
38 };
39
40 printk(BIOS_INFO, "Checking GSC for pending updates\n");
41
42 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, command_body);
43
44 if (!response || response->hdr.tpm_code)
45 return TPM_IOERROR;
46
47 *num_restored_headers = response->vcr.num_restored_headers;
48 return TPM_SUCCESS;
49 }
50
tlcl_cr50_get_recovery_button(uint8_t * recovery_button_state)51 tpm_result_t tlcl_cr50_get_recovery_button(uint8_t *recovery_button_state)
52 {
53 struct tpm2_response *response;
54 uint16_t sub_command = TPM2_CR50_SUB_CMD_GET_REC_BTN;
55
56 printk(BIOS_INFO, "Checking GSC for recovery request\n");
57
58 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
59
60 if (!response || response->hdr.tpm_code)
61 return TPM_IOERROR;
62
63 *recovery_button_state = response->vcr.recovery_button_state;
64 return TPM_SUCCESS;
65 }
66
tlcl_cr50_get_tpm_mode(uint8_t * tpm_mode)67 tpm_result_t tlcl_cr50_get_tpm_mode(uint8_t *tpm_mode)
68 {
69 struct tpm2_response *response;
70 uint16_t mode_command = TPM2_CR50_SUB_CMD_TPM_MODE;
71 *tpm_mode = TPM_MODE_INVALID;
72
73 printk(BIOS_INFO, "Reading GSC TPM mode\n");
74
75 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &mode_command);
76
77 if (!response)
78 return TPM_IOERROR;
79
80 if (response->hdr.tpm_code == VENDOR_RC_INTERNAL_ERROR) {
81 /*
82 * The Cr50 returns VENDOR_RC_INTERNAL_ERROR iff the key ladder
83 * is disabled. The Cr50 requires a reboot to re-enable the key
84 * ladder.
85 */
86 return TPM_CB_MUST_REBOOT;
87 }
88
89 if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
90 response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND) {
91 /*
92 * Explicitly inform caller when command is not supported
93 */
94 return TPM_CB_NO_SUCH_COMMAND;
95 }
96
97 if (response->hdr.tpm_code) {
98 /* Unexpected return code from Cr50 */
99 return TPM_IOERROR;
100 }
101
102 /* TPM command completed without error */
103 *tpm_mode = response->vcr.tpm_mode;
104
105 return TPM_SUCCESS;
106 }
107
tlcl_cr50_get_boot_mode(uint8_t * boot_mode)108 tpm_result_t tlcl_cr50_get_boot_mode(uint8_t *boot_mode)
109 {
110 struct tpm2_response *response;
111 uint16_t mode_command = TPM2_CR50_SUB_CMD_GET_BOOT_MODE;
112
113 printk(BIOS_DEBUG, "Reading GSC boot mode\n");
114
115 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &mode_command);
116
117 if (!response)
118 return TPM_IOERROR;
119
120 if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
121 response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND)
122 /* Explicitly inform caller when command is not supported */
123 return TPM_CB_NO_SUCH_COMMAND;
124
125 if (response->hdr.tpm_code)
126 /* Unexpected return code from Cr50 */
127 return TPM_IOERROR;
128
129 *boot_mode = response->vcr.boot_mode;
130
131 return TPM_SUCCESS;
132 }
133
tlcl_cr50_immediate_reset(uint16_t timeout_ms)134 tpm_result_t tlcl_cr50_immediate_reset(uint16_t timeout_ms)
135 {
136 struct tpm2_response *response;
137 uint16_t reset_command_body[] = {
138 TPM2_CR50_SUB_CMD_IMMEDIATE_RESET, timeout_ms};
139
140 /*
141 * Issue an immediate reset to the Cr50.
142 */
143 printk(BIOS_INFO, "Issuing GSC reset\n");
144 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &reset_command_body);
145
146 if (!response)
147 return TPM_IOERROR;
148
149 return TPM_SUCCESS;
150 }
151
tlcl_cr50_reset_ec(void)152 tpm_result_t tlcl_cr50_reset_ec(void)
153 {
154 struct tpm2_response *response;
155 uint16_t reset_cmd = TPM2_CR50_SUB_CMD_RESET_EC;
156
157 printk(BIOS_DEBUG, "Issuing EC reset\n");
158
159 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &reset_cmd);
160
161 if (!response)
162 return TPM_IOERROR;
163
164 if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
165 response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND)
166 /* Explicitly inform caller when command is not supported */
167 return TPM_CB_NO_SUCH_COMMAND;
168
169 if (response->hdr.tpm_code)
170 /* Unexpected return code from Cr50 */
171 return TPM_IOERROR;
172
173 printk(BIOS_DEBUG, "EC reset coming up...\n");
174 halt();
175
176 return TPM_SUCCESS;
177 }
178
tlcl_cr50_get_factory_config(uint64_t * factory_config)179 tpm_result_t tlcl_cr50_get_factory_config(uint64_t *factory_config)
180 {
181 struct tpm2_response *response;
182 uint16_t factory_config_command = TPM2_CR50_SUB_CMD_GET_FACTORY_CONFIG;
183 *factory_config = 0;
184
185 response = tlcl2_process_command(TPM2_CR50_VENDOR_COMMAND, &factory_config_command);
186
187 if (!response)
188 return TPM_IOERROR;
189
190 /* Explicitly inform caller when command is not supported */
191 if (response->hdr.tpm_code == VENDOR_RC_NO_SUCH_COMMAND ||
192 response->hdr.tpm_code == VENDOR_RC_NO_SUCH_SUBCOMMAND)
193 return TPM_CB_NO_SUCH_COMMAND;
194
195 /* Unexpected return code from TPM */
196 if (response->hdr.tpm_code)
197 return TPM_IOERROR;
198
199 /* TPM command completed without error */
200 *factory_config = response->vcr.factory_config;
201
202 printk(BIOS_INFO, "Reading factory config = %016" PRIX64 "\n", *factory_config);
203
204 return TPM_SUCCESS;
205 }
206