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