xref: /rk3399_ARM-atf/drivers/tpm/tpm2_cmds.c (revision 7e848540159ba8fbb0577c76e4dc0c5bbc542489)
1 /*
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 
19 static struct interface_ops *interface;
20 
tpm_xfer(struct tpm_chip_data * chip_data,const tpm_cmd * send,tpm_cmd * receive)21 static 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 
tpm_interface_init(struct tpm_chip_data * chip_data,uint8_t locality)38 int 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 
tpm_interface_close(struct tpm_chip_data * chip_data,uint8_t locality)52 int tpm_interface_close(struct tpm_chip_data *chip_data, uint8_t locality)
53 {
54 	return interface->release_locality(chip_data, locality);
55 }
56 
tpm_update_buffer(tpm_cmd * buf,uint32_t new_data,size_t new_len)57 static 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 
tpm_startup(struct tpm_chip_data * chip_data,uint16_t mode)110 int 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 
tpm_pcr_extend(struct tpm_chip_data * chip_data,uint32_t index,uint16_t algorithm,const uint8_t * digest,uint32_t digest_len)142 int 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 }
223