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