blob: b6422a8db5a3de20b46f963ecbf935238bcf484d [file] [log] [blame]
Abhi.Singhc8c5faf2024-08-28 14:17:52 -05001/*
2 * Copyright (c) 2025, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#include <lib/libc/endian.h>
7
8#include <drivers/delay_timer.h>
9#include <drivers/tpm/tpm2.h>
10#include <drivers/tpm/tpm2_chip.h>
11#include <drivers/tpm/tpm2_interface.h>
12
13#define CMD_SIZE_OFFSET 6
14
15#define SINGLE_BYTE 1
16#define TWO_BYTES 2
17#define FOUR_BYTES 4
18
19static struct interface_ops *interface;
20
21static int tpm_xfer(struct tpm_chip_data *chip_data, const tpm_cmd *send, tpm_cmd *receive)
22{
23 int ret;
24
25 ret = interface->send(chip_data, send);
26 if (ret < 0) {
27 return ret;
28 }
29
30 ret = interface->receive(chip_data, receive);
31 if (ret < 0) {
32 return ret;
33 }
34
35 return TPM_SUCCESS;
36}
37
38int tpm_interface_init(struct tpm_chip_data *chip_data, uint8_t locality)
39{
40 int err;
41
42 interface = tpm_interface_getops(chip_data, locality);
43
44 err = interface->request_access(chip_data, locality);
45 if (err != 0) {
46 return err;
47 }
48
49 return interface->get_info(chip_data, locality);
50}
51
52int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality)
53{
54 return interface->release_locality(chip_data, locality);
55}
56
57static int tpm_update_buffer(tpm_cmd *buf, uint32_t new_data, size_t new_len)
58{
59 int i, j, start;
60 uint32_t command_size;
61
62 union {
63 uint8_t var8;
64 uint16_t var16;
65 uint32_t var32;
66 uint8_t array[4];
67 } tpm_new_data;
68
69 command_size = be32toh(buf->header.cmd_size);
70
71 if (command_size + new_len > MAX_SIZE_CMDBUF) {
72 ERROR("%s: buf size exceeded, increase MAX_SIZE_CMDBUF\n",
73 __func__);
74 return TPM_INVALID_PARAM;
75 }
76 /*
77 * Subtract the cmd header size from the current command size
78 * so the data buffer is written to starting at index 0.
79 */
80 start = command_size - TPM_HEADER_SIZE;
81
82 /*
83 * The TPM, according to the TCG spec, processes data in BE byte order,
84 * in the case where the Host is LE, htobe correctly handles the byte order.
85 * When updating the buffer, keep in mind to only pass sizeof(new_data) or
86 * the variable type size for the new_len function parameter. This ensures
87 * there is only the possiblility of writing 1, 2, or 4 bytes to the buffer,
88 * and that the correct number of bytes are written to data[i].
89 */
90 if (new_len == SINGLE_BYTE) {
91 tpm_new_data.var8 = new_data & 0xFF;
92 } else if (new_len == TWO_BYTES) {
93 tpm_new_data.var16 = htobe16(new_data & 0xFFFF);
94 } else if (new_len == FOUR_BYTES) {
95 tpm_new_data.var32 = htobe32(new_data);
96 } else {
97 ERROR("%s: Invalid data length\n", __func__);
98 return TPM_INVALID_PARAM;
99 }
100
101 for (i = start, j = 0; i < start + new_len; i++, j++) {
102 buf->data[i] = tpm_new_data.array[j];
103 }
104 buf->header.cmd_size = htobe32(command_size + new_len);
105
106 return TPM_SUCCESS;
107}
108
109
110int tpm_startup(struct tpm_chip_data *chip_data, uint16_t mode)
111{
112 tpm_cmd startup_cmd, startup_response;
113 uint32_t tpm_rc;
114 int ret;
115
116 memset(&startup_cmd, 0, sizeof(startup_cmd));
117 memset(&startup_response, 0, sizeof(startup_response));
118
119 startup_cmd.header.tag = htobe16(TPM_ST_NO_SESSIONS);
120 startup_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
121 startup_cmd.header.cmd_code = htobe32(TPM_CMD_STARTUP);
122
123 ret = tpm_update_buffer(&startup_cmd, mode, sizeof(mode));
124 if (ret < 0) {
125 return ret;
126 }
127
128 ret = tpm_xfer(chip_data, &startup_cmd, &startup_response);
129 if (ret < 0) {
130 return ret;
131 }
132
133 tpm_rc = be32toh(startup_response.header.cmd_code);
134 if (tpm_rc != TPM_RESPONSE_SUCCESS) {
135 ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
136 return TPM_ERR_RESPONSE;
137 }
138
139 return TPM_SUCCESS;
140}
141
142int tpm_pcr_extend(struct tpm_chip_data *chip_data, uint32_t index,
143 uint16_t algorithm, const uint8_t *digest,
144 uint32_t digest_len)
145{
146 tpm_cmd pcr_extend_cmd, pcr_extend_response;
147 uint32_t tpm_rc;
148 int ret;
149
150 memset(&pcr_extend_cmd, 0, sizeof(pcr_extend_cmd));
151 memset(&pcr_extend_response, 0, sizeof(pcr_extend_response));
152
153 if (digest == NULL) {
154 return TPM_INVALID_PARAM;
155 }
156 pcr_extend_cmd.header.tag = htobe16(TPM_ST_SESSIONS);
157 pcr_extend_cmd.header.cmd_size = htobe32(sizeof(tpm_cmd_hdr));
158 pcr_extend_cmd.header.cmd_code = htobe32(TPM_CMD_PCR_EXTEND);
159
160 /* handle (PCR Index)*/
161 ret = tpm_update_buffer(&pcr_extend_cmd, index, sizeof(index));
162 if (ret < 0) {
163 return ret;
164 }
165
166 /* authorization size , session handle, nonce size, attributes*/
167 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_MIN_AUTH_SIZE, sizeof(uint32_t));
168 if (ret < 0) {
169 return ret;
170 }
171 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_RS_PW, sizeof(uint32_t));
172 if (ret < 0) {
173 return ret;
174 }
175 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_NONCE_SIZE, sizeof(uint16_t));
176 if (ret < 0) {
177 return ret;
178 }
179 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ATTRIBUTES_DISABLE, sizeof(uint8_t));
180 if (ret < 0) {
181 return ret;
182 }
183
184 /* hmac/password size */
185 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_ZERO_HMAC_SIZE, sizeof(uint16_t));
186 if (ret < 0) {
187 return ret;
188 }
189
190 /* hashes count */
191 ret = tpm_update_buffer(&pcr_extend_cmd, TPM_SINGLE_HASH_COUNT, sizeof(uint32_t));
192 if (ret < 0) {
193 return ret;
194 }
195
196 /* hash algorithm */
197 ret = tpm_update_buffer(&pcr_extend_cmd, algorithm, sizeof(algorithm));
198 if (ret < 0) {
199 return ret;
200 }
201
202 /* digest */
203 for (int i = 0; i < digest_len; i++) {
204 ret = tpm_update_buffer(&pcr_extend_cmd, digest[i], sizeof(uint8_t));
205 if (ret < 0) {
206 return ret;
207 }
208 }
209
210 ret = tpm_xfer(chip_data, &pcr_extend_cmd, &pcr_extend_response);
211 if (ret < 0) {
212 return ret;
213 }
214
215 tpm_rc = be32toh(pcr_extend_response.header.cmd_code);
216 if (tpm_rc != TPM_RESPONSE_SUCCESS) {
217 ERROR("%s: response code contains error = %X\n", __func__, tpm_rc);
218 return TPM_ERR_RESPONSE;
219 }
220
221 return TPM_SUCCESS;
222}