arch/x86/gdt: Correct format of multi-line comment
[coreboot.git] / src / lib / tpm2_tlcl.c
blobfde90a002a197b2d0efe174d4842b41ca6d05a52
1 /*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
7 #include <antirollback.h>
8 #include <arch/early_variables.h>
9 #include <console/console.h>
10 #include <endian.h>
11 #include <lib/tpm2_tlcl_structures.h>
12 #include <string.h>
13 #include <tpm.h>
14 #include <vb2_api.h>
16 #include "tpm2_marshaling.h"
19 * This file provides interface between firmware and TPM2 device. The TPM1.2
20 * API was copied as is and relevant functions modified to comply with the
21 * TPM2 specification.
24 static void *tpm_process_command(TPM_CC command, void *command_body)
26 struct obuf ob;
27 struct ibuf ib;
28 size_t out_size;
29 size_t in_size;
30 const uint8_t *sendb;
31 /* Command/response buffer. */
32 static uint8_t cr_buffer[TPM_BUFFER_SIZE] CAR_GLOBAL;
34 uint8_t *cr_buffer_ptr = car_get_var_ptr(cr_buffer);
36 obuf_init(&ob, cr_buffer_ptr, sizeof(cr_buffer));
38 if (tpm_marshal_command(command, command_body, &ob) < 0) {
39 printk(BIOS_ERR, "command %#x\n", command);
40 return NULL;
43 sendb = obuf_contents(&ob, &out_size);
45 in_size = sizeof(cr_buffer);
46 if (tis_sendrecv(sendb, out_size, cr_buffer_ptr, &in_size)) {
47 printk(BIOS_ERR, "tpm transaction failed\n");
48 return NULL;
51 ibuf_init(&ib, cr_buffer_ptr, in_size);
53 return tpm_unmarshal_response(command, &ib);
57 uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
59 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
60 return TPM_SUCCESS;
63 static uint32_t tlcl_send_startup(TPM_SU type)
65 struct tpm2_startup startup;
66 struct tpm2_response *response;
68 startup.startup_type = type;
69 response = tpm_process_command(TPM2_Startup, &startup);
71 if (response && response->hdr.tpm_code &&
72 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
73 printk(BIOS_INFO, "%s: Startup return code is %x\n",
74 __func__, response->hdr.tpm_code);
75 return TPM_E_IOERROR;
77 return TPM_SUCCESS;
81 uint32_t tlcl_resume(void)
83 return tlcl_send_startup(TPM_SU_STATE);
86 uint32_t tlcl_assert_physical_presence(void)
89 * Nothing to do on TPM2 for this, use platform hierarchy availability
90 * instead.
92 return TPM_SUCCESS;
96 * The caller will provide the digest in a 32 byte buffer, let's consider it a
97 * sha256 digest.
99 uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
100 uint8_t *out_digest)
102 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
103 struct tpm2_response *response;
105 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
106 pcr_ext_cmd.digests.count = 1;
107 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
108 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
109 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
111 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
113 printk(BIOS_INFO, "%s: response is %x\n",
114 __func__, response ? response->hdr.tpm_code : -1);
115 if (!response || response->hdr.tpm_code)
116 return TPM_E_IOERROR;
118 return TPM_SUCCESS;
121 uint32_t tlcl_finalize_physical_presence(void)
123 /* Nothing needs to be done with tpm2. */
124 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
125 return TPM_SUCCESS;
128 uint32_t tlcl_force_clear(void)
130 struct tpm2_response *response;
132 response = tpm_process_command(TPM2_Clear, NULL);
133 printk(BIOS_INFO, "%s: response is %x\n",
134 __func__, response ? response->hdr.tpm_code : -1);
136 if (!response || response->hdr.tpm_code)
137 return TPM_E_IOERROR;
139 return TPM_SUCCESS;
142 uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
143 uint8_t *nvlocked)
146 * TPM2 does not map directly into these flags TPM1.2 based firmware
147 * expects to be able to retrieve.
149 * In any case, if any of these conditions are present, the following
150 * firmware flow would be interrupted and will have a chance to report
151 * an error. Let's just hardcode an "All OK" response for now.
154 if (disable)
155 *disable = 0;
157 if (nvlocked)
158 *nvlocked = 1;
160 if (deactivated)
161 *deactivated = 0;
163 return TPM_SUCCESS;
166 static uint8_t tlcl_init_done CAR_GLOBAL;
168 /* This function is called directly by vboot, uses vboot return types. */
169 uint32_t tlcl_lib_init(void)
171 uint8_t done = car_get_var(tlcl_init_done);
172 if (done)
173 return VB2_SUCCESS;
175 if (tis_init())
176 return VB2_ERROR_UNKNOWN;
177 if (tis_open())
178 return VB2_ERROR_UNKNOWN;
180 car_set_var(tlcl_init_done, 1);
182 return VB2_SUCCESS;
185 uint32_t tlcl_physical_presence_cmd_enable(void)
187 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
188 return TPM_SUCCESS;
191 uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
193 struct tpm2_nv_read_cmd nv_readc;
194 struct tpm2_response *response;
196 memset(&nv_readc, 0, sizeof(nv_readc));
198 nv_readc.nvIndex = HR_NV_INDEX + index;
199 nv_readc.size = length;
201 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
203 /* Need to map tpm error codes into internal values. */
204 if (!response)
205 return TPM_E_READ_FAILURE;
207 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
208 __FILE__, __LINE__, index, response->hdr.tpm_code);
209 switch (response->hdr.tpm_code) {
210 case 0:
211 break;
213 /* Uninitialized, returned if the space hasn't been written. */
214 case TPM_RC_NV_UNINITIALIZED:
216 * Bad index, cr50 specific value, returned if the space
217 * hasn't been defined.
219 case TPM_RC_CR50_NV_UNDEFINED:
220 return TPM_E_BADINDEX;
222 default:
223 return TPM_E_READ_FAILURE;
226 if (length > response->nvr.buffer.t.size)
227 return TPM_E_RESPONSE_TOO_LARGE;
229 if (length < response->nvr.buffer.t.size)
230 return TPM_E_READ_EMPTY;
232 memcpy(data, response->nvr.buffer.t.buffer, length);
234 return TPM_SUCCESS;
237 uint32_t tlcl_self_test_full(void)
239 struct tpm2_self_test st;
240 struct tpm2_response *response;
242 st.yes_no = 1;
244 response = tpm_process_command(TPM2_SelfTest, &st);
245 printk(BIOS_INFO, "%s: response is %x\n",
246 __func__, response ? response->hdr.tpm_code : -1);
247 return TPM_SUCCESS;
250 uint32_t tlcl_set_deactivated(uint8_t flag)
252 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
253 return TPM_SUCCESS;
256 uint32_t tlcl_set_enable(void)
258 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
259 return TPM_SUCCESS;
262 uint32_t tlcl_lock_nv_write(uint32_t index)
264 struct tpm2_response *response;
265 /* TPM Wll reject attempts to write at non-defined index. */
266 struct tpm2_nv_write_lock_cmd nv_wl = {
267 .nvIndex = HR_NV_INDEX + index,
270 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
272 printk(BIOS_INFO, "%s: response is %x\n",
273 __func__, response ? response->hdr.tpm_code : -1);
275 if (!response || response->hdr.tpm_code)
276 return TPM_E_IOERROR;
278 return TPM_SUCCESS;
281 uint32_t tlcl_startup(void)
283 return tlcl_send_startup(TPM_SU_CLEAR);
286 uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
288 struct tpm2_nv_write_cmd nv_writec;
289 struct tpm2_response *response;
291 memset(&nv_writec, 0, sizeof(nv_writec));
293 nv_writec.nvIndex = HR_NV_INDEX + index;
294 nv_writec.data.t.size = length;
295 nv_writec.data.t.buffer = data;
297 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
299 printk(BIOS_INFO, "%s: response is %x\n",
300 __func__, response ? response->hdr.tpm_code : -1);
302 /* Need to map tpm error codes into internal values. */
303 if (!response || response->hdr.tpm_code)
304 return TPM_E_WRITE_FAILURE;
306 return TPM_SUCCESS;
309 uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
311 struct tpm2_nv_define_space_cmd nvds_cmd;
312 struct tpm2_response *response;
314 * Different sets of NVRAM space attributes apply to the "ro" spaces,
315 * i.e. those which should not be possible to delete or modify once
316 * the RO exits, and the rest of the NVRAM spaces.
318 const TPMA_NV ro_space_attributes = {
319 .TPMA_NV_PPWRITE = 1,
320 .TPMA_NV_AUTHREAD = 1,
321 .TPMA_NV_PPREAD = 1,
322 .TPMA_NV_PLATFORMCREATE = 1,
323 .TPMA_NV_WRITE_STCLEAR = 1,
324 .TPMA_NV_POLICY_DELETE = 1,
326 const TPMA_NV default_space_attributes = {
327 .TPMA_NV_PPWRITE = 1,
328 .TPMA_NV_AUTHREAD = 1,
329 .TPMA_NV_PPREAD = 1,
330 .TPMA_NV_PLATFORMCREATE = 1,
333 /* Prepare the define space command structure. */
334 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
336 nvds_cmd.publicInfo.dataSize = space_size;
337 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
338 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
340 /* RO only NV spaces should be impossible to destroy. */
341 if ((space_index == FIRMWARE_NV_INDEX) ||
342 (space_index == REC_HASH_NV_INDEX)) {
344 * This policy digest was obtained using TPM2_PolicyPCR
345 * selecting only PCR_0 with a value of all zeros.
347 const uint8_t pcr0_unchanged_policy[] = {
348 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
349 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
350 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
351 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
354 nvds_cmd.publicInfo.attributes = ro_space_attributes;
356 * Use policy digest based on default pcr0 value. This makes
357 * sure that the space can not be deleted as soon as PCR0
358 * value has been extended from default.
360 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
361 nvds_cmd.publicInfo.authPolicy.t.size =
362 sizeof(pcr0_unchanged_policy);
363 } else {
364 nvds_cmd.publicInfo.attributes = default_space_attributes;
367 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
368 printk(BIOS_INFO, "%s: response is %x\n",
369 __func__, response ? response->hdr.tpm_code : -1);
371 if (!response)
372 return TPM_E_NO_DEVICE;
374 /* Map TPM2 retrun codes into common vboot represenation. */
375 switch (response->hdr.tpm_code) {
376 case TPM2_RC_SUCCESS:
377 return TPM_SUCCESS;
378 case TPM2_RC_NV_DEFINED:
379 return TPM_E_NV_DEFINED;
380 default:
381 return TPM_E_INTERNAL_INCONSISTENCY;
385 uint32_t tlcl_disable_platform_hierarchy(void)
387 struct tpm2_response *response;
388 struct tpm2_hierarchy_control_cmd hc = {
389 .enable = TPM_RH_PLATFORM,
390 .state = 0,
393 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
395 if (!response || response->hdr.tpm_code)
396 return TPM_E_INTERNAL_INCONSISTENCY;
398 return TPM_SUCCESS;
401 uint32_t tlcl_cr50_enable_nvcommits(void)
403 uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
404 struct tpm2_response *response;
406 printk(BIOS_INFO, "Enabling cr50 nvmem commmits\n");
408 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
410 if (response == NULL || (response && response->hdr.tpm_code)) {
411 if (response)
412 printk(BIOS_INFO, "%s: failed %x\n", __func__,
413 response->hdr.tpm_code);
414 else
415 printk(BIOS_INFO, "%s: failed\n", __func__);
416 return TPM_E_IOERROR;
418 return TPM_SUCCESS;
421 uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms,
422 uint8_t *num_restored_headers)
424 struct tpm2_response *response;
425 uint16_t command_body[] = {
426 TPM2_CR50_SUB_CMD_TURN_UPDATE_ON, timeout_ms
429 printk(BIOS_INFO, "Checking cr50 for pending updates\n");
431 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body);
433 if (!response || response->hdr.tpm_code)
434 return TPM_E_INTERNAL_INCONSISTENCY;
436 *num_restored_headers = response->vcr.num_restored_headers;
437 return TPM_SUCCESS;