1 /* SPDX-License-Identifier: BSD-3-Clause */
3 #include <console/console.h>
7 #include <security/tpm/tis.h>
8 #include <security/tpm/tss.h>
10 #include "tss_structures.h"
11 #include "tss_marshaling.h"
14 * This file provides interface between firmware and TPM2 device. The TPM1.2
15 * API was copied as is and relevant functions modified to comply with the
19 void *tlcl2_process_command(TPM_CC command
, void *command_body
)
26 /* Command/response buffer. */
27 static uint8_t cr_buffer
[TPM_BUFFER_SIZE
];
29 if (tlcl_tis_sendrecv
== NULL
) {
30 printk(BIOS_ERR
, "Attempted use of uninitialized TSS 2.0 stack\n");
34 obuf_init(&ob
, cr_buffer
, sizeof(cr_buffer
));
36 if (tpm_marshal_command(command
, command_body
, &ob
) < 0) {
37 printk(BIOS_ERR
, "command %#x\n", command
);
41 sendb
= obuf_contents(&ob
, &out_size
);
43 in_size
= sizeof(cr_buffer
);
44 if (tlcl_tis_sendrecv(sendb
, out_size
, cr_buffer
, &in_size
)) {
45 printk(BIOS_ERR
, "tpm transaction failed\n");
49 ibuf_init(&ib
, cr_buffer
, in_size
);
51 return tpm_unmarshal_response(command
, &ib
);
54 static tpm_result_t
tlcl2_send_startup(TPM_SU type
)
56 struct tpm2_startup startup
;
57 struct tpm2_response
*response
;
59 startup
.startup_type
= type
;
60 response
= tlcl2_process_command(TPM2_Startup
, &startup
);
62 /* IO error, tpm2_response pointer is empty. */
64 printk(BIOS_ERR
, "%s: TPM communication error\n", __func__
);
68 printk(BIOS_INFO
, "%s: Startup return code is %#x\n",
69 __func__
, response
->hdr
.tpm_code
);
71 switch (response
->hdr
.tpm_code
) {
72 case TPM_RC_INITIALIZE
:
73 /* TPM already initialized. */
74 return TPM_INVALID_POSTINIT
;
79 /* Collapse any other errors into TPM_IOERROR. */
83 tpm_result_t
tlcl2_resume(void)
85 return tlcl2_send_startup(TPM_SU_STATE
);
88 static tpm_result_t
tlcl2_send_shutdown(TPM_SU type
)
90 struct tpm2_shutdown shutdown
;
91 struct tpm2_response
*response
;
93 shutdown
.shutdown_type
= type
;
94 response
= tlcl2_process_command(TPM2_Shutdown
, &shutdown
);
96 /* IO error, tpm2_response pointer is empty. */
98 printk(BIOS_ERR
, "%s: TPM communication error\n", __func__
);
102 printk(BIOS_INFO
, "%s: Shutdown return code is %#x\n",
103 __func__
, response
->hdr
.tpm_code
);
105 if (response
->hdr
.tpm_code
== TPM2_RC_SUCCESS
)
108 /* Collapse any other errors into TPM_IOERROR. */
112 tpm_result_t
tlcl2_save_state(void)
114 return tlcl2_send_shutdown(TPM_SU_STATE
);
117 tpm_result_t
tlcl2_assert_physical_presence(void)
120 * Nothing to do on TPM2 for this, use platform hierarchy availability
126 static TPM_ALG_ID
tpmalg_from_vb2_hash(enum vb2_hash_algorithm hash_type
)
131 case VB2_HASH_SHA256
:
132 return TPM_ALG_SHA256
;
133 case VB2_HASH_SHA384
:
134 return TPM_ALG_SHA384
;
135 case VB2_HASH_SHA512
:
136 return TPM_ALG_SHA512
;
139 return TPM_ALG_ERROR
;
144 * The caller will provide the digest in a 32 byte buffer, let's consider it a
147 tpm_result_t
tlcl2_extend(int pcr_num
, const uint8_t *digest_data
,
148 enum vb2_hash_algorithm digest_type
)
150 struct tpm2_pcr_extend_cmd pcr_ext_cmd
;
151 struct tpm2_response
*response
;
154 alg
= tpmalg_from_vb2_hash(digest_type
);
155 if (alg
== TPM_ALG_ERROR
)
156 return TPM_CB_HASH_ERROR
;
158 pcr_ext_cmd
.pcrHandle
= HR_PCR
+ pcr_num
;
159 pcr_ext_cmd
.digests
.count
= 1;
160 pcr_ext_cmd
.digests
.digests
[0].hashAlg
= alg
;
161 /* Always copying to sha512 as it's the largest one */
162 memcpy(pcr_ext_cmd
.digests
.digests
[0].digest
.sha512
, digest_data
,
163 vb2_digest_size(digest_type
));
165 response
= tlcl2_process_command(TPM2_PCR_Extend
, &pcr_ext_cmd
);
167 printk(BIOS_INFO
, "%s: response is %#x\n",
168 __func__
, response
? response
->hdr
.tpm_code
: -1);
169 if (!response
|| response
->hdr
.tpm_code
)
175 tpm_result_t
tlcl2_finalize_physical_presence(void)
177 /* Nothing needs to be done with tpm2. */
178 printk(BIOS_INFO
, "%s:%s:%d\n", __FILE__
, __func__
, __LINE__
);
182 tpm_result_t
tlcl2_force_clear(void)
184 struct tpm2_response
*response
;
186 response
= tlcl2_process_command(TPM2_Clear
, NULL
);
187 printk(BIOS_INFO
, "%s: response is %#x\n",
188 __func__
, response
? response
->hdr
.tpm_code
: -1);
190 if (!response
|| response
->hdr
.tpm_code
)
196 tpm_result_t
tlcl2_clear_control(bool disable
)
198 struct tpm2_response
*response
;
199 struct tpm2_clear_control_cmd cc
= {
203 response
= tlcl2_process_command(TPM2_ClearControl
, &cc
);
204 printk(BIOS_INFO
, "%s: response is %#x\n",
205 __func__
, response
? response
->hdr
.tpm_code
: -1);
207 if (!response
|| response
->hdr
.tpm_code
)
213 tpm_result_t
tlcl2_physical_presence_cmd_enable(void)
215 printk(BIOS_INFO
, "%s:%s:%d\n", __FILE__
, __func__
, __LINE__
);
219 tpm_result_t
tlcl2_read(uint32_t index
, void *data
, uint32_t length
)
221 struct tpm2_nv_read_cmd nv_readc
;
222 struct tpm2_response
*response
;
224 memset(&nv_readc
, 0, sizeof(nv_readc
));
226 nv_readc
.nvIndex
= HR_NV_INDEX
+ index
;
227 nv_readc
.size
= length
;
229 response
= tlcl2_process_command(TPM2_NV_Read
, &nv_readc
);
231 /* Need to map tpm error codes into internal values. */
233 return TPM_CB_READ_FAILURE
;
235 printk(BIOS_INFO
, "%s:%d index %#x return code %#x\n",
236 __FILE__
, __LINE__
, index
, response
->hdr
.tpm_code
);
237 switch (response
->hdr
.tpm_code
) {
241 /* Uninitialized, returned if the space hasn't been written. */
242 case TPM_RC_NV_UNINITIALIZED
:
244 * Bad index, cr50 specific value, returned if the space
245 * hasn't been defined.
247 case TPM_RC_CR50_NV_UNDEFINED
:
250 case TPM_RC_NV_RANGE
:
254 return TPM_CB_READ_FAILURE
;
257 if (length
> response
->nvr
.buffer
.t
.size
)
258 return TPM_CB_RESPONSE_TOO_LARGE
;
260 if (length
< response
->nvr
.buffer
.t
.size
)
261 return TPM_CB_READ_EMPTY
;
263 memcpy(data
, response
->nvr
.buffer
.t
.buffer
, length
);
268 tpm_result_t
tlcl2_self_test_full(void)
270 struct tpm2_self_test st
;
271 struct tpm2_response
*response
;
275 response
= tlcl2_process_command(TPM2_SelfTest
, &st
);
276 printk(BIOS_INFO
, "%s: response is %#x\n",
277 __func__
, response
? response
->hdr
.tpm_code
: -1);
281 tpm_result_t
tlcl2_lock_nv_write(uint32_t index
)
283 struct tpm2_response
*response
;
284 /* TPM Will reject attempts to write at non-defined index. */
285 struct tpm2_nv_write_lock_cmd nv_wl
= {
286 .nvIndex
= HR_NV_INDEX
+ index
,
289 response
= tlcl2_process_command(TPM2_NV_WriteLock
, &nv_wl
);
291 printk(BIOS_INFO
, "%s: response is %#x\n",
292 __func__
, response
? response
->hdr
.tpm_code
: -1);
294 if (!response
|| response
->hdr
.tpm_code
)
300 tpm_result_t
tlcl2_startup(void)
302 return tlcl2_send_startup(TPM_SU_CLEAR
);
305 tpm_result_t
tlcl2_write(uint32_t index
, const void *data
, uint32_t length
)
307 struct tpm2_nv_write_cmd nv_writec
;
308 struct tpm2_response
*response
;
310 memset(&nv_writec
, 0, sizeof(nv_writec
));
312 nv_writec
.nvIndex
= HR_NV_INDEX
+ index
;
313 nv_writec
.data
.t
.size
= length
;
314 nv_writec
.data
.t
.buffer
= data
;
316 response
= tlcl2_process_command(TPM2_NV_Write
, &nv_writec
);
318 printk(BIOS_INFO
, "%s: response is %#x\n",
319 __func__
, response
? response
->hdr
.tpm_code
: -1);
321 /* Need to map tpm error codes into internal values. */
322 if (!response
|| response
->hdr
.tpm_code
)
323 return TPM_CB_WRITE_FAILURE
;
328 tpm_result_t
tlcl2_set_bits(uint32_t index
, uint64_t bits
)
330 struct tpm2_nv_setbits_cmd nvsb_cmd
;
331 struct tpm2_response
*response
;
333 /* Prepare the command structure */
334 memset(&nvsb_cmd
, 0, sizeof(nvsb_cmd
));
336 nvsb_cmd
.nvIndex
= HR_NV_INDEX
+ index
;
337 nvsb_cmd
.bits
= bits
;
339 response
= tlcl2_process_command(TPM2_NV_SetBits
, &nvsb_cmd
);
341 printk(BIOS_INFO
, "%s: response is %#x\n",
342 __func__
, response
? response
->hdr
.tpm_code
: -1);
344 /* Need to map tpm error codes into internal values. */
345 if (!response
|| response
->hdr
.tpm_code
)
346 return TPM_CB_WRITE_FAILURE
;
351 tpm_result_t
tlcl2_define_space(uint32_t space_index
, size_t space_size
,
352 const TPMA_NV nv_attributes
,
353 const uint8_t *nv_policy
, size_t nv_policy_size
)
355 struct tpm2_nv_define_space_cmd nvds_cmd
;
356 struct tpm2_response
*response
;
358 /* Prepare the define space command structure. */
359 memset(&nvds_cmd
, 0, sizeof(nvds_cmd
));
361 nvds_cmd
.publicInfo
.dataSize
= space_size
;
362 nvds_cmd
.publicInfo
.nvIndex
= HR_NV_INDEX
+ space_index
;
363 nvds_cmd
.publicInfo
.nameAlg
= TPM_ALG_SHA256
;
364 nvds_cmd
.publicInfo
.attributes
= nv_attributes
;
367 * Use policy digest based on default pcr0 value. This makes
368 * sure that the space can not be deleted as soon as PCR0
369 * value has been extended from default.
371 if (nv_policy
&& nv_policy_size
) {
372 nvds_cmd
.publicInfo
.authPolicy
.t
.buffer
= nv_policy
;
373 nvds_cmd
.publicInfo
.authPolicy
.t
.size
= nv_policy_size
;
376 response
= tlcl2_process_command(TPM2_NV_DefineSpace
, &nvds_cmd
);
377 printk(BIOS_INFO
, "%s: response is %#x\n", __func__
,
378 response
? response
->hdr
.tpm_code
: -1);
381 return TPM_CB_NO_DEVICE
;
383 /* Map TPM2 return codes into common vboot representation. */
384 switch (response
->hdr
.tpm_code
) {
385 case TPM2_RC_SUCCESS
:
387 case TPM2_RC_NV_DEFINED
:
388 return TPM_CB_NV_DEFINED
;
390 return TPM_CB_INTERNAL_INCONSISTENCY
;
394 uint16_t tlcl2_get_hash_size_from_algo(TPMI_ALG_HASH hash_algo
)
403 value
= SHA1_DIGEST_SIZE
;
406 value
= SHA256_DIGEST_SIZE
;
409 value
= SHA384_DIGEST_SIZE
;
412 value
= SHA512_DIGEST_SIZE
;
414 case TPM_ALG_SM3_256
:
415 value
= SM3_256_DIGEST_SIZE
;
418 printk(BIOS_SPEW
, "%s: unknown hash algorithm %d\n", __func__
,
426 tpm_result_t
tlcl2_disable_platform_hierarchy(void)
428 struct tpm2_response
*response
;
429 struct tpm2_hierarchy_control_cmd hc
= {
430 .enable
= TPM_RH_PLATFORM
,
434 response
= tlcl2_process_command(TPM2_Hierarchy_Control
, &hc
);
436 if (!response
|| response
->hdr
.tpm_code
)
437 return TPM_CB_INTERNAL_INCONSISTENCY
;
442 tpm_result_t
tlcl2_get_capability(TPM_CAP capability
, uint32_t property
,
443 uint32_t property_count
,
444 TPMS_CAPABILITY_DATA
*capability_data
)
446 struct tpm2_get_capability cmd
;
447 struct tpm2_response
*response
;
449 cmd
.capability
= capability
;
450 cmd
.property
= property
;
451 cmd
.propertyCount
= property_count
;
453 if (property_count
> 1) {
454 printk(BIOS_ERR
, "%s: property_count more than one not "
455 "supported yet\n", __func__
);
459 response
= tlcl2_process_command(TPM2_GetCapability
, &cmd
);
462 printk(BIOS_ERR
, "%s: Command Failed\n", __func__
);
466 memcpy(capability_data
, &response
->gc
.cd
, sizeof(TPMS_CAPABILITY_DATA
));