1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2022, Linaro Limited
4 */
5
6 #include <assert.h>
7 #include <drivers/tpm2_chip.h>
8 #include <io.h>
9 #include <kernel/tcg.h>
10 #include <malloc.h>
11 #include <string.h>
12 #include <tpm2.h>
13 #include <trace.h>
14
15 static struct tpm2_chip *tpm2_device;
16
tpm2_chip_send(uint8_t * buf,uint32_t len)17 enum tpm2_result tpm2_chip_send(uint8_t *buf, uint32_t len)
18 {
19 if (!tpm2_device || !tpm2_device->ops->send)
20 return TPM2_ERR_NODEV;
21
22 return tpm2_device->ops->send(tpm2_device, buf, len);
23 }
24
tpm2_chip_recv(uint8_t * buf,uint32_t * len,uint32_t cmd_duration)25 enum tpm2_result tpm2_chip_recv(uint8_t *buf, uint32_t *len,
26 uint32_t cmd_duration)
27 {
28 if (!tpm2_device || !tpm2_device->ops->recv)
29 return TPM2_ERR_NODEV;
30
31 return tpm2_device->ops->recv(tpm2_device, buf, len, cmd_duration);
32 }
33
tpm2_chip_get_caps(struct tpm2_caps * capability)34 enum tpm2_result tpm2_chip_get_caps(struct tpm2_caps *capability)
35 {
36 if (!tpm2_device)
37 return TPM2_ERR_NODEV;
38
39 memcpy(capability, &tpm2_device->capability, sizeof(struct tpm2_caps));
40
41 return TPM2_OK;
42 }
43
tpm2_chip_is_active_bank(uint16_t alg)44 bool tpm2_chip_is_active_bank(uint16_t alg)
45 {
46 uint32_t alg_mask = tpm2_alg_to_tcg_mask(alg);
47
48 if (!tpm2_device)
49 return false;
50
51 if (alg_mask & tpm2_device->capability.active_mask)
52 return true;
53
54 return false;
55 }
56
57 /* Get value of property (TPM_PT) from capability TPM_CAP_TPM_PROPERTIES */
tpm2_get_tpm_property(uint32_t property,uint32_t * val)58 static enum tpm2_result tpm2_get_tpm_property(uint32_t property, uint32_t *val)
59 {
60 uint8_t *prop = NULL;
61 uint32_t prop_len = sizeof(struct tpml_tagged_tpm_property) +
62 sizeof(struct tpms_tagged_property);
63 uint32_t properties_offset =
64 offsetof(struct tpml_tagged_tpm_property, tpm_property) +
65 offsetof(struct tpms_tagged_property, value);
66 enum tpm2_result ret = TPM2_OK;
67
68 prop = malloc(prop_len);
69 if (!prop)
70 return TPM2_ERR_GENERIC;
71
72 ret = tpm2_get_capability(TPM2_CAP_TPM_PROPERTIES, property, 1, prop,
73 &prop_len);
74 if (ret)
75 goto out;
76
77 *val = get_be32(prop + properties_offset);
78 out:
79 free(prop);
80 return ret;
81 }
82
83 /*
84 * Get the following information from TPM and store it in chip's capability
85 * structure.
86 * Number of banks available in TPM
87 * Number of active banks and the corresponding digest algo
88 */
tpm2_get_bank_info(struct tpm2_chip * chip)89 static enum tpm2_result tpm2_get_bank_info(struct tpm2_chip *chip)
90 {
91 uint32_t i = 0;
92 uint32_t j = 0;
93 uint32_t num_active_banks = 0;
94 uint32_t pcr_cap_len = 0;
95 uint8_t *tpms_pcr_start = NULL;
96 enum tpm2_result ret = TPM2_OK;
97 struct tpm2_caps *caps = &chip->capability;
98 struct tpml_pcr_selection *pcr_cap = NULL;
99 struct tpms_pcr_selection *tmp = NULL;
100
101 /* Calculate maximum size of tpml_pcr_selection structure */
102 pcr_cap_len = sizeof(struct tpml_pcr_selection);
103
104 pcr_cap = malloc(pcr_cap_len);
105 if (!pcr_cap)
106 return TPM2_ERR_GENERIC;
107
108 /*
109 * Capability category TPM2_CAP_PCRS has no property and on querying
110 * TPM returns type TPML_PCR_SELECTION.
111 */
112 ret = tpm2_get_capability(TPM2_CAP_PCRS, 0, 1, pcr_cap, &pcr_cap_len);
113 if (ret)
114 goto out;
115
116 caps->num_banks = get_be32(&pcr_cap->count);
117 if (caps->num_banks > TPM2_NUM_PCR_BANKS) {
118 EMSG("Number of banks more than supported");
119 ret = TPM2_ERR_GENERIC;
120 goto out;
121 }
122
123 tpms_pcr_start = (uint8_t *)&pcr_cap->pcr_selections[0];
124 for (i = 0; i < caps->num_banks; i++) {
125 tmp = (struct tpms_pcr_selection *)tpms_pcr_start;
126
127 if (tmp->size_of_select > TPM2_PCR_SELECT_MAX) {
128 ret = TPM2_ERR_GENERIC;
129 goto out;
130 }
131
132 for (j = 0; j < tmp->size_of_select; j++) {
133 uint16_t alg = get_be16(&tmp->hash);
134 uint32_t alg_mask = tpm2_alg_to_tcg_mask(alg);
135
136 caps->selection_mask |= alg_mask;
137 if (tmp->pcr_select[j]) {
138 caps->active_mask |= alg_mask;
139 num_active_banks++;
140 break;
141 }
142 }
143
144 tpms_pcr_start += tmp->size_of_select * sizeof(uint8_t) +
145 offsetof(struct tpms_pcr_selection, pcr_select);
146 }
147 caps->num_active_banks = num_active_banks;
148
149 ret = TPM2_OK;
150 out:
151 free(pcr_cap);
152 return ret;
153 }
154
tpm2_populate_capability(struct tpm2_chip * chip)155 static enum tpm2_result tpm2_populate_capability(struct tpm2_chip *chip)
156 {
157 uint32_t num_pcrs = 0;
158 uint32_t pcr_select_min = 0;
159 struct tpm2_caps *caps = &chip->capability;
160 enum tpm2_result ret = TPM2_OK;
161
162 /* Get Bank information from TPM */
163 ret = tpm2_get_bank_info(chip);
164 if (ret)
165 return ret;
166
167 /* Get the number of PCR's supported in this TPM */
168 ret = tpm2_get_tpm_property(TPM2_PT_PCR_COUNT, &num_pcrs);
169 if (ret)
170 return ret;
171
172 if (num_pcrs > TPM2_MAX_PCRS)
173 return TPM2_ERR_GENERIC;
174
175 caps->num_pcrs = num_pcrs;
176
177 /* Get the minimum number of PCR Select octets */
178 ret = tpm2_get_tpm_property(TPM2_PT_PCR_SELECT_MIN, &pcr_select_min);
179 if (ret)
180 return ret;
181
182 if (pcr_select_min > TPM2_PCR_SELECT_MAX)
183 return TPM2_ERR_GENERIC;
184
185 caps->pcr_select_min = pcr_select_min;
186
187 return TPM2_OK;
188 }
189
tpm2_dump_capability(struct tpm2_chip * chip)190 static void tpm2_dump_capability(struct tpm2_chip *chip)
191 {
192 struct tpm2_caps *caps __maybe_unused = &chip->capability;
193
194 DMSG("TPM2: No. of banks \t %"PRId32, caps->num_banks);
195 DMSG("TPM2: No. of active banks \t %"PRId32, caps->num_active_banks);
196 DMSG("TPM2: No. of PCRs \t %"PRId32, caps->num_pcrs);
197 DMSG("TPM2: No. of PCR select octets \t %"PRId32, caps->pcr_select_min);
198 }
199
tpm2_chip_register(struct tpm2_chip * chip)200 enum tpm2_result tpm2_chip_register(struct tpm2_chip *chip)
201 {
202 enum tpm2_result ret = TPM2_OK;
203 uint8_t full = 1;
204
205 /* Only 1 tpm2 device is supported */
206 if (tpm2_device)
207 return TPM2_ERR_GENERIC;
208
209 if (!chip || !chip->ops)
210 return TPM2_ERR_NODEV;
211
212 /* Assign timeouts etc based on interface */
213 ret = chip->ops->init(chip);
214 if (ret)
215 return ret;
216
217 tpm2_device = chip;
218
219 /* Now that interface is initialized do basic init of tpm */
220 ret = tpm2_startup(TPM2_SU_CLEAR);
221 if (ret) {
222 EMSG("TPM2 Startup Failed");
223 return ret;
224 }
225
226 /* Self test result is informative */
227 if (tpm2_selftest(full))
228 EMSG("TPM2 Self Test Failed");
229
230 ret = tpm2_populate_capability(chip);
231 if (!ret)
232 tpm2_dump_capability(chip);
233
234 /* Register TPM2 as TCG provider */
235 if (tpm2_tcg_register())
236 return TPM2_ERR_GENERIC;
237
238 return ret;
239 }
240
tpm2_chip_unregister(struct tpm2_chip * chip)241 enum tpm2_result tpm2_chip_unregister(struct tpm2_chip *chip)
242 {
243 enum tpm2_result ret = TPM2_OK;
244
245 ret = chip->ops->end(chip);
246
247 tpm2_device = NULL;
248
249 return ret;
250 }
251