]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e76cb927 SG |
2 | /* |
3 | * Copyright (c) 2015 Google, Inc | |
e76cb927 SG |
4 | */ |
5 | ||
6 | #include <common.h> | |
7 | #include <command.h> | |
9a3b4ceb | 8 | #include <cpu_func.h> |
f7ae49fc | 9 | #include <log.h> |
d677bfe2 | 10 | #include <tpm-v1.h> |
abdc7b8a | 11 | #include "tpm-user-utils.h" |
d6a885f0 | 12 | #include <tpm_api.h> |
e76cb927 SG |
13 | |
14 | /* Prints error and returns on failure */ | |
15 | #define TPM_CHECK(tpm_command) do { \ | |
16 | uint32_t result; \ | |
17 | \ | |
18 | result = (tpm_command); \ | |
19 | if (result != TPM_SUCCESS) { \ | |
20 | printf("TEST FAILED: line %d: " #tpm_command ": 0x%x\n", \ | |
21 | __LINE__, result); \ | |
22 | return result; \ | |
23 | } \ | |
24 | } while (0) | |
25 | ||
26 | #define INDEX0 0xda70 | |
27 | #define INDEX1 0xda71 | |
28 | #define INDEX2 0xda72 | |
29 | #define INDEX3 0xda73 | |
30 | #define INDEX_INITIALISED 0xda80 | |
31 | #define PHYS_PRESENCE 4 | |
32 | #define PRESENCE 8 | |
33 | ||
abdc7b8a | 34 | static uint32_t TlclStartupIfNeeded(struct udevice *dev) |
e76cb927 | 35 | { |
abdc7b8a | 36 | uint32_t result = tpm_startup(dev, TPM_ST_CLEAR); |
e76cb927 SG |
37 | |
38 | return result == TPM_INVALID_POSTINIT ? TPM_SUCCESS : result; | |
39 | } | |
40 | ||
abdc7b8a | 41 | static int test_timer(struct udevice *dev) |
e76cb927 SG |
42 | { |
43 | printf("get_timer(0) = %lu\n", get_timer(0)); | |
44 | return 0; | |
45 | } | |
46 | ||
abdc7b8a SG |
47 | static uint32_t tpm_get_flags(struct udevice *dev, uint8_t *disable, |
48 | uint8_t *deactivated, uint8_t *nvlocked) | |
e76cb927 SG |
49 | { |
50 | struct tpm_permanent_flags pflags; | |
51 | uint32_t result; | |
52 | ||
d6a885f0 | 53 | result = tpm1_get_permanent_flags(dev, &pflags); |
e76cb927 SG |
54 | if (result) |
55 | return result; | |
56 | if (disable) | |
57 | *disable = pflags.disable; | |
58 | if (deactivated) | |
59 | *deactivated = pflags.deactivated; | |
60 | if (nvlocked) | |
61 | *nvlocked = pflags.nv_locked; | |
62 | debug("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n", | |
63 | pflags.disable, pflags.deactivated, pflags.nv_locked); | |
64 | ||
65 | return 0; | |
66 | } | |
67 | ||
abdc7b8a | 68 | static uint32_t tpm_nv_write_value_lock(struct udevice *dev, uint32_t index) |
e76cb927 SG |
69 | { |
70 | debug("TPM: Write lock 0x%x\n", index); | |
71 | ||
abdc7b8a | 72 | return tpm_nv_write_value(dev, index, NULL, 0); |
e76cb927 SG |
73 | } |
74 | ||
abdc7b8a | 75 | static int tpm_is_owned(struct udevice *dev) |
e76cb927 SG |
76 | { |
77 | uint8_t response[TPM_PUBEK_SIZE]; | |
78 | uint32_t result; | |
79 | ||
abdc7b8a | 80 | result = tpm_read_pubek(dev, response, sizeof(response)); |
e76cb927 SG |
81 | |
82 | return result != TPM_SUCCESS; | |
83 | } | |
84 | ||
abdc7b8a | 85 | static int test_early_extend(struct udevice *dev) |
e76cb927 SG |
86 | { |
87 | uint8_t value_in[20]; | |
88 | uint8_t value_out[20]; | |
89 | ||
90 | printf("Testing earlyextend ..."); | |
abdc7b8a SG |
91 | tpm_init(dev); |
92 | TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); | |
93 | TPM_CHECK(tpm_continue_self_test(dev)); | |
d6a885f0 | 94 | TPM_CHECK(tpm_pcr_extend(dev, 1, value_in, value_out)); |
e76cb927 SG |
95 | printf("done\n"); |
96 | return 0; | |
97 | } | |
98 | ||
abdc7b8a | 99 | static int test_early_nvram(struct udevice *dev) |
e76cb927 SG |
100 | { |
101 | uint32_t x; | |
102 | ||
103 | printf("Testing earlynvram ..."); | |
abdc7b8a SG |
104 | tpm_init(dev); |
105 | TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); | |
106 | TPM_CHECK(tpm_continue_self_test(dev)); | |
107 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
108 | TPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x))); | |
e76cb927 SG |
109 | printf("done\n"); |
110 | return 0; | |
111 | } | |
112 | ||
abdc7b8a | 113 | static int test_early_nvram2(struct udevice *dev) |
e76cb927 SG |
114 | { |
115 | uint32_t x; | |
116 | ||
117 | printf("Testing earlynvram2 ..."); | |
abdc7b8a SG |
118 | tpm_init(dev); |
119 | TPM_CHECK(tpm_startup(dev, TPM_ST_CLEAR)); | |
120 | TPM_CHECK(tpm_continue_self_test(dev)); | |
121 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
122 | TPM_CHECK(tpm_nv_write_value(dev, INDEX0, (uint8_t *)&x, sizeof(x))); | |
e76cb927 SG |
123 | printf("done\n"); |
124 | return 0; | |
125 | } | |
126 | ||
abdc7b8a | 127 | static int test_enable(struct udevice *dev) |
e76cb927 SG |
128 | { |
129 | uint8_t disable = 0, deactivated = 0; | |
130 | ||
131 | printf("Testing enable ...\n"); | |
abdc7b8a SG |
132 | tpm_init(dev); |
133 | TPM_CHECK(TlclStartupIfNeeded(dev)); | |
134 | TPM_CHECK(tpm_self_test_full(dev)); | |
135 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
136 | TPM_CHECK(tpm_get_flags(dev, &disable, &deactivated, NULL)); | |
e76cb927 | 137 | printf("\tdisable is %d, deactivated is %d\n", disable, deactivated); |
abdc7b8a SG |
138 | TPM_CHECK(tpm_physical_enable(dev)); |
139 | TPM_CHECK(tpm_physical_set_deactivated(dev, 0)); | |
140 | TPM_CHECK(tpm_get_flags(dev, &disable, &deactivated, NULL)); | |
e76cb927 SG |
141 | printf("\tdisable is %d, deactivated is %d\n", disable, deactivated); |
142 | if (disable == 1 || deactivated == 1) | |
143 | printf("\tfailed to enable or activate\n"); | |
144 | printf("\tdone\n"); | |
145 | return 0; | |
146 | } | |
147 | ||
148 | #define reboot() do { \ | |
149 | printf("\trebooting...\n"); \ | |
35b65dd8 | 150 | reset_cpu(); \ |
e76cb927 SG |
151 | } while (0) |
152 | ||
abdc7b8a | 153 | static int test_fast_enable(struct udevice *dev) |
e76cb927 SG |
154 | { |
155 | uint8_t disable = 0, deactivated = 0; | |
156 | int i; | |
157 | ||
158 | printf("Testing fastenable ...\n"); | |
abdc7b8a SG |
159 | tpm_init(dev); |
160 | TPM_CHECK(TlclStartupIfNeeded(dev)); | |
161 | TPM_CHECK(tpm_self_test_full(dev)); | |
162 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
163 | TPM_CHECK(tpm_get_flags(dev, &disable, &deactivated, NULL)); | |
e76cb927 SG |
164 | printf("\tdisable is %d, deactivated is %d\n", disable, deactivated); |
165 | for (i = 0; i < 2; i++) { | |
abdc7b8a SG |
166 | TPM_CHECK(tpm_force_clear(dev)); |
167 | TPM_CHECK(tpm_get_flags(dev, &disable, &deactivated, NULL)); | |
e76cb927 SG |
168 | printf("\tdisable is %d, deactivated is %d\n", disable, |
169 | deactivated); | |
170 | assert(disable == 1 && deactivated == 1); | |
abdc7b8a SG |
171 | TPM_CHECK(tpm_physical_enable(dev)); |
172 | TPM_CHECK(tpm_physical_set_deactivated(dev, 0)); | |
173 | TPM_CHECK(tpm_get_flags(dev, &disable, &deactivated, NULL)); | |
e76cb927 SG |
174 | printf("\tdisable is %d, deactivated is %d\n", disable, |
175 | deactivated); | |
176 | assert(disable == 0 && deactivated == 0); | |
177 | } | |
178 | printf("\tdone\n"); | |
179 | return 0; | |
180 | } | |
181 | ||
abdc7b8a | 182 | static int test_global_lock(struct udevice *dev) |
e76cb927 SG |
183 | { |
184 | uint32_t zero = 0; | |
185 | uint32_t result; | |
186 | uint32_t x; | |
187 | ||
188 | printf("Testing globallock ...\n"); | |
abdc7b8a SG |
189 | tpm_init(dev); |
190 | TPM_CHECK(TlclStartupIfNeeded(dev)); | |
191 | TPM_CHECK(tpm_self_test_full(dev)); | |
192 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
193 | TPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x))); | |
194 | TPM_CHECK(tpm_nv_write_value(dev, INDEX0, (uint8_t *)&zero, | |
e76cb927 | 195 | sizeof(uint32_t))); |
abdc7b8a SG |
196 | TPM_CHECK(tpm_nv_read_value(dev, INDEX1, (uint8_t *)&x, sizeof(x))); |
197 | TPM_CHECK(tpm_nv_write_value(dev, INDEX1, (uint8_t *)&zero, | |
e76cb927 | 198 | sizeof(uint32_t))); |
abdc7b8a | 199 | TPM_CHECK(tpm_set_global_lock(dev)); |
e76cb927 SG |
200 | /* Verifies that write to index0 fails */ |
201 | x = 1; | |
abdc7b8a | 202 | result = tpm_nv_write_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)); |
e76cb927 | 203 | assert(result == TPM_AREA_LOCKED); |
abdc7b8a | 204 | TPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x))); |
e76cb927 SG |
205 | assert(x == 0); |
206 | /* Verifies that write to index1 is still possible */ | |
207 | x = 2; | |
abdc7b8a SG |
208 | TPM_CHECK(tpm_nv_write_value(dev, INDEX1, (uint8_t *)&x, sizeof(x))); |
209 | TPM_CHECK(tpm_nv_read_value(dev, INDEX1, (uint8_t *)&x, sizeof(x))); | |
e76cb927 SG |
210 | assert(x == 2); |
211 | /* Turns off PP */ | |
abdc7b8a | 212 | tpm_tsc_physical_presence(dev, PHYS_PRESENCE); |
e76cb927 SG |
213 | /* Verifies that write to index1 fails */ |
214 | x = 3; | |
abdc7b8a | 215 | result = tpm_nv_write_value(dev, INDEX1, (uint8_t *)&x, sizeof(x)); |
e76cb927 | 216 | assert(result == TPM_BAD_PRESENCE); |
abdc7b8a | 217 | TPM_CHECK(tpm_nv_read_value(dev, INDEX1, (uint8_t *)&x, sizeof(x))); |
e76cb927 SG |
218 | assert(x == 2); |
219 | printf("\tdone\n"); | |
220 | return 0; | |
221 | } | |
222 | ||
abdc7b8a | 223 | static int test_lock(struct udevice *dev) |
e76cb927 SG |
224 | { |
225 | printf("Testing lock ...\n"); | |
abdc7b8a SG |
226 | tpm_init(dev); |
227 | tpm_startup(dev, TPM_ST_CLEAR); | |
228 | tpm_self_test_full(dev); | |
229 | tpm_tsc_physical_presence(dev, PRESENCE); | |
230 | tpm_nv_write_value_lock(dev, INDEX0); | |
e76cb927 SG |
231 | printf("\tLocked 0x%x\n", INDEX0); |
232 | printf("\tdone\n"); | |
233 | return 0; | |
234 | } | |
235 | ||
abdc7b8a | 236 | static void initialise_spaces(struct udevice *dev) |
e76cb927 SG |
237 | { |
238 | uint32_t zero = 0; | |
239 | uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE; | |
240 | ||
241 | printf("\tInitialising spaces\n"); | |
d6a885f0 SG |
242 | tpm1_nv_set_locked(dev); /* useful only the first time */ |
243 | tpm1_nv_define_space(dev, INDEX0, perm, 4); | |
abdc7b8a | 244 | tpm_nv_write_value(dev, INDEX0, (uint8_t *)&zero, 4); |
d6a885f0 | 245 | tpm1_nv_define_space(dev, INDEX1, perm, 4); |
abdc7b8a | 246 | tpm_nv_write_value(dev, INDEX1, (uint8_t *)&zero, 4); |
d6a885f0 | 247 | tpm1_nv_define_space(dev, INDEX2, perm, 4); |
abdc7b8a | 248 | tpm_nv_write_value(dev, INDEX2, (uint8_t *)&zero, 4); |
d6a885f0 | 249 | tpm1_nv_define_space(dev, INDEX3, perm, 4); |
abdc7b8a | 250 | tpm_nv_write_value(dev, INDEX3, (uint8_t *)&zero, 4); |
e76cb927 SG |
251 | perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR | |
252 | TPM_NV_PER_PPWRITE; | |
d6a885f0 | 253 | tpm1_nv_define_space(dev, INDEX_INITIALISED, perm, 1); |
e76cb927 SG |
254 | } |
255 | ||
abdc7b8a | 256 | static int test_readonly(struct udevice *dev) |
e76cb927 SG |
257 | { |
258 | uint8_t c; | |
259 | uint32_t index_0, index_1, index_2, index_3; | |
260 | int read0, read1, read2, read3; | |
261 | ||
262 | printf("Testing readonly ...\n"); | |
abdc7b8a SG |
263 | tpm_init(dev); |
264 | tpm_startup(dev, TPM_ST_CLEAR); | |
265 | tpm_self_test_full(dev); | |
266 | tpm_tsc_physical_presence(dev, PRESENCE); | |
e76cb927 SG |
267 | /* |
268 | * Checks if initialisation has completed by trying to read-lock a | |
269 | * space that's created at the end of initialisation | |
270 | */ | |
abdc7b8a | 271 | if (tpm_nv_read_value(dev, INDEX_INITIALISED, &c, 0) == TPM_BADINDEX) { |
e76cb927 | 272 | /* The initialisation did not complete */ |
abdc7b8a | 273 | initialise_spaces(dev); |
e76cb927 SG |
274 | } |
275 | ||
276 | /* Checks if spaces are OK or messed up */ | |
abdc7b8a SG |
277 | read0 = tpm_nv_read_value(dev, INDEX0, (uint8_t *)&index_0, |
278 | sizeof(index_0)); | |
279 | read1 = tpm_nv_read_value(dev, INDEX1, (uint8_t *)&index_1, | |
280 | sizeof(index_1)); | |
281 | read2 = tpm_nv_read_value(dev, INDEX2, (uint8_t *)&index_2, | |
282 | sizeof(index_2)); | |
283 | read3 = tpm_nv_read_value(dev, INDEX3, (uint8_t *)&index_3, | |
284 | sizeof(index_3)); | |
e76cb927 SG |
285 | if (read0 || read1 || read2 || read3) { |
286 | printf("Invalid contents\n"); | |
287 | return 0; | |
288 | } | |
289 | ||
290 | /* | |
291 | * Writes space, and locks it. Then attempts to write again. | |
292 | * I really wish I could use the imperative. | |
293 | */ | |
294 | index_0 += 1; | |
abdc7b8a SG |
295 | if (tpm_nv_write_value(dev, INDEX0, (uint8_t *)&index_0, |
296 | sizeof(index_0) != | |
e76cb927 | 297 | TPM_SUCCESS)) { |
9b643e31 | 298 | pr_err("\tcould not write index 0\n"); |
e76cb927 | 299 | } |
abdc7b8a SG |
300 | tpm_nv_write_value_lock(dev, INDEX0); |
301 | if (tpm_nv_write_value(dev, INDEX0, (uint8_t *)&index_0, | |
302 | sizeof(index_0)) == | |
e76cb927 | 303 | TPM_SUCCESS) |
9b643e31 | 304 | pr_err("\tindex 0 is not locked\n"); |
e76cb927 SG |
305 | |
306 | printf("\tdone\n"); | |
307 | return 0; | |
308 | } | |
309 | ||
abdc7b8a | 310 | static int test_redefine_unowned(struct udevice *dev) |
e76cb927 SG |
311 | { |
312 | uint32_t perm; | |
313 | uint32_t result; | |
314 | uint32_t x; | |
315 | ||
316 | printf("Testing redefine_unowned ..."); | |
abdc7b8a SG |
317 | tpm_init(dev); |
318 | TPM_CHECK(TlclStartupIfNeeded(dev)); | |
319 | TPM_CHECK(tpm_self_test_full(dev)); | |
320 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
321 | assert(!tpm_is_owned(dev)); | |
e76cb927 SG |
322 | |
323 | /* Ensures spaces exist. */ | |
abdc7b8a SG |
324 | TPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x))); |
325 | TPM_CHECK(tpm_nv_read_value(dev, INDEX1, (uint8_t *)&x, sizeof(x))); | |
e76cb927 SG |
326 | |
327 | /* Redefines spaces a couple of times. */ | |
328 | perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK; | |
d6a885f0 SG |
329 | TPM_CHECK(tpm1_nv_define_space(dev, INDEX0, perm, |
330 | 2 * sizeof(uint32_t))); | |
331 | TPM_CHECK(tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t))); | |
e76cb927 | 332 | perm = TPM_NV_PER_PPWRITE; |
d6a885f0 SG |
333 | TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, |
334 | 2 * sizeof(uint32_t))); | |
335 | TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t))); | |
e76cb927 SG |
336 | |
337 | /* Sets the global lock */ | |
abdc7b8a | 338 | tpm_set_global_lock(dev); |
e76cb927 SG |
339 | |
340 | /* Verifies that index0 cannot be redefined */ | |
d6a885f0 | 341 | result = tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)); |
e76cb927 SG |
342 | assert(result == TPM_AREA_LOCKED); |
343 | ||
344 | /* Checks that index1 can */ | |
d6a885f0 SG |
345 | TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, |
346 | 2 * sizeof(uint32_t))); | |
347 | TPM_CHECK(tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t))); | |
e76cb927 SG |
348 | |
349 | /* Turns off PP */ | |
abdc7b8a | 350 | tpm_tsc_physical_presence(dev, PHYS_PRESENCE); |
e76cb927 SG |
351 | |
352 | /* Verifies that neither index0 nor index1 can be redefined */ | |
d6a885f0 | 353 | result = tpm1_nv_define_space(dev, INDEX0, perm, sizeof(uint32_t)); |
e76cb927 | 354 | assert(result == TPM_BAD_PRESENCE); |
d6a885f0 | 355 | result = tpm1_nv_define_space(dev, INDEX1, perm, sizeof(uint32_t)); |
e76cb927 SG |
356 | assert(result == TPM_BAD_PRESENCE); |
357 | ||
358 | printf("done\n"); | |
359 | return 0; | |
360 | } | |
361 | ||
362 | #define PERMPPGL (TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK) | |
363 | #define PERMPP TPM_NV_PER_PPWRITE | |
364 | ||
abdc7b8a | 365 | static int test_space_perm(struct udevice *dev) |
e76cb927 SG |
366 | { |
367 | uint32_t perm; | |
368 | ||
369 | printf("Testing spaceperm ..."); | |
abdc7b8a SG |
370 | tpm_init(dev); |
371 | TPM_CHECK(TlclStartupIfNeeded(dev)); | |
372 | TPM_CHECK(tpm_continue_self_test(dev)); | |
373 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
374 | TPM_CHECK(tpm_get_permissions(dev, INDEX0, &perm)); | |
e76cb927 | 375 | assert((perm & PERMPPGL) == PERMPPGL); |
abdc7b8a | 376 | TPM_CHECK(tpm_get_permissions(dev, INDEX1, &perm)); |
e76cb927 SG |
377 | assert((perm & PERMPP) == PERMPP); |
378 | printf("done\n"); | |
379 | return 0; | |
380 | } | |
381 | ||
abdc7b8a | 382 | static int test_startup(struct udevice *dev) |
e76cb927 SG |
383 | { |
384 | uint32_t result; | |
abdc7b8a | 385 | |
e76cb927 SG |
386 | printf("Testing startup ...\n"); |
387 | ||
abdc7b8a SG |
388 | tpm_init(dev); |
389 | result = tpm_startup(dev, TPM_ST_CLEAR); | |
e76cb927 SG |
390 | if (result != 0 && result != TPM_INVALID_POSTINIT) |
391 | printf("\ttpm startup failed with 0x%x\n", result); | |
abdc7b8a | 392 | result = tpm_get_flags(dev, NULL, NULL, NULL); |
e76cb927 SG |
393 | if (result != 0) |
394 | printf("\ttpm getflags failed with 0x%x\n", result); | |
395 | printf("\texecuting SelfTestFull\n"); | |
abdc7b8a SG |
396 | tpm_self_test_full(dev); |
397 | result = tpm_get_flags(dev, NULL, NULL, NULL); | |
e76cb927 SG |
398 | if (result != 0) |
399 | printf("\ttpm getflags failed with 0x%x\n", result); | |
400 | printf("\tdone\n"); | |
401 | return 0; | |
402 | } | |
403 | ||
404 | /* | |
405 | * Runs [op] and ensures it returns success and doesn't run longer than | |
406 | * [time_limit] in milliseconds. | |
407 | */ | |
408 | #define TTPM_CHECK(op, time_limit) do { \ | |
409 | ulong start, time; \ | |
410 | uint32_t __result; \ | |
411 | \ | |
412 | start = get_timer(0); \ | |
413 | __result = op; \ | |
414 | if (__result != TPM_SUCCESS) { \ | |
415 | printf("\t" #op ": error 0x%x\n", __result); \ | |
416 | return -1; \ | |
417 | } \ | |
418 | time = get_timer(start); \ | |
419 | printf("\t" #op ": %lu ms\n", time); \ | |
420 | if (time > (ulong)time_limit) { \ | |
421 | printf("\t" #op " exceeded " #time_limit " ms\n"); \ | |
422 | } \ | |
423 | } while (0) | |
424 | ||
425 | ||
abdc7b8a | 426 | static int test_timing(struct udevice *dev) |
e76cb927 | 427 | { |
e76cb927 | 428 | uint8_t in[20], out[20]; |
abdc7b8a | 429 | uint32_t x; |
e76cb927 SG |
430 | |
431 | printf("Testing timing ..."); | |
abdc7b8a SG |
432 | tpm_init(dev); |
433 | TTPM_CHECK(TlclStartupIfNeeded(dev), 50); | |
434 | TTPM_CHECK(tpm_continue_self_test(dev), 100); | |
435 | TTPM_CHECK(tpm_self_test_full(dev), 1000); | |
436 | TTPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE), 100); | |
437 | TTPM_CHECK(tpm_nv_write_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)), | |
438 | 100); | |
439 | TTPM_CHECK(tpm_nv_read_value(dev, INDEX0, (uint8_t *)&x, sizeof(x)), | |
440 | 100); | |
d6a885f0 | 441 | TTPM_CHECK(tpm_pcr_extend(dev, 0, in, out), 200); |
abdc7b8a SG |
442 | TTPM_CHECK(tpm_set_global_lock(dev), 50); |
443 | TTPM_CHECK(tpm_tsc_physical_presence(dev, PHYS_PRESENCE), 100); | |
e76cb927 SG |
444 | printf("done\n"); |
445 | return 0; | |
446 | } | |
447 | ||
448 | #define TPM_MAX_NV_WRITES_NOOWNER 64 | |
449 | ||
abdc7b8a | 450 | static int test_write_limit(struct udevice *dev) |
e76cb927 | 451 | { |
e76cb927 | 452 | uint32_t result; |
abdc7b8a | 453 | int i; |
e76cb927 | 454 | |
abdc7b8a SG |
455 | printf("Testing writelimit ...\n"); |
456 | tpm_init(dev); | |
457 | TPM_CHECK(TlclStartupIfNeeded(dev)); | |
458 | TPM_CHECK(tpm_self_test_full(dev)); | |
459 | TPM_CHECK(tpm_tsc_physical_presence(dev, PRESENCE)); | |
460 | TPM_CHECK(tpm_force_clear(dev)); | |
461 | TPM_CHECK(tpm_physical_enable(dev)); | |
462 | TPM_CHECK(tpm_physical_set_deactivated(dev, 0)); | |
e76cb927 SG |
463 | |
464 | for (i = 0; i < TPM_MAX_NV_WRITES_NOOWNER + 2; i++) { | |
465 | printf("\twriting %d\n", i); | |
abdc7b8a SG |
466 | result = tpm_nv_write_value(dev, INDEX0, (uint8_t *)&i, |
467 | sizeof(i)); | |
e76cb927 SG |
468 | switch (result) { |
469 | case TPM_SUCCESS: | |
470 | break; | |
471 | case TPM_MAXNVWRITES: | |
472 | assert(i >= TPM_MAX_NV_WRITES_NOOWNER); | |
473 | default: | |
9b643e31 | 474 | pr_err("\tunexpected error code %d (0x%x)\n", |
e76cb927 SG |
475 | result, result); |
476 | } | |
477 | } | |
478 | ||
479 | /* Reset write count */ | |
abdc7b8a SG |
480 | TPM_CHECK(tpm_force_clear(dev)); |
481 | TPM_CHECK(tpm_physical_enable(dev)); | |
482 | TPM_CHECK(tpm_physical_set_deactivated(dev, 0)); | |
e76cb927 SG |
483 | |
484 | /* Try writing again. */ | |
abdc7b8a | 485 | TPM_CHECK(tpm_nv_write_value(dev, INDEX0, (uint8_t *)&i, sizeof(i))); |
e76cb927 SG |
486 | printf("\tdone\n"); |
487 | return 0; | |
488 | } | |
489 | ||
490 | #define VOIDTEST(XFUNC) \ | |
09140113 SG |
491 | int do_test_##XFUNC(struct cmd_tbl *cmd_tbl, int flag, int argc, \ |
492 | char *const argv[]) \ | |
e76cb927 | 493 | { \ |
abdc7b8a SG |
494 | struct udevice *dev; \ |
495 | int ret; \ | |
496 | \ | |
497 | ret = get_tpm(&dev); \ | |
498 | if (ret) \ | |
499 | return ret; \ | |
500 | return test_##XFUNC(dev); \ | |
e76cb927 SG |
501 | } |
502 | ||
503 | #define VOIDENT(XNAME) \ | |
504 | U_BOOT_CMD_MKENT(XNAME, 0, 1, do_test_##XNAME, "", ""), | |
505 | ||
506 | VOIDTEST(early_extend) | |
507 | VOIDTEST(early_nvram) | |
508 | VOIDTEST(early_nvram2) | |
509 | VOIDTEST(enable) | |
510 | VOIDTEST(fast_enable) | |
511 | VOIDTEST(global_lock) | |
512 | VOIDTEST(lock) | |
513 | VOIDTEST(readonly) | |
514 | VOIDTEST(redefine_unowned) | |
515 | VOIDTEST(space_perm) | |
516 | VOIDTEST(startup) | |
517 | VOIDTEST(timing) | |
518 | VOIDTEST(write_limit) | |
519 | VOIDTEST(timer) | |
520 | ||
09140113 | 521 | static struct cmd_tbl cmd_cros_tpm_sub[] = { |
e76cb927 SG |
522 | VOIDENT(early_extend) |
523 | VOIDENT(early_nvram) | |
524 | VOIDENT(early_nvram2) | |
525 | VOIDENT(enable) | |
526 | VOIDENT(fast_enable) | |
527 | VOIDENT(global_lock) | |
528 | VOIDENT(lock) | |
529 | VOIDENT(readonly) | |
530 | VOIDENT(redefine_unowned) | |
531 | VOIDENT(space_perm) | |
532 | VOIDENT(startup) | |
533 | VOIDENT(timing) | |
534 | VOIDENT(write_limit) | |
535 | VOIDENT(timer) | |
536 | }; | |
537 | ||
09140113 SG |
538 | static int do_tpmtest(struct cmd_tbl *cmdtp, int flag, int argc, |
539 | char *const argv[]) | |
e76cb927 | 540 | { |
09140113 | 541 | struct cmd_tbl *c; |
0427b9c5 | 542 | int i; |
e76cb927 SG |
543 | |
544 | printf("argc = %d, argv = ", argc); | |
e76cb927 | 545 | |
0427b9c5 SB |
546 | for (i = 0; i < argc; i++) |
547 | printf(" %s", argv[i]); | |
548 | ||
549 | printf("\n------\n"); | |
550 | ||
e76cb927 SG |
551 | argc--; |
552 | argv++; | |
553 | c = find_cmd_tbl(argv[0], cmd_cros_tpm_sub, | |
554 | ARRAY_SIZE(cmd_cros_tpm_sub)); | |
555 | return c ? c->cmd(cmdtp, flag, argc, argv) : cmd_usage(cmdtp); | |
556 | } | |
557 | ||
558 | U_BOOT_CMD(tpmtest, 2, 1, do_tpmtest, "TPM tests", | |
559 | "\n\tearly_extend\n" | |
560 | "\tearly_nvram\n" | |
561 | "\tearly_nvram2\n" | |
562 | "\tenable\n" | |
563 | "\tfast_enable\n" | |
564 | "\tglobal_lock\n" | |
565 | "\tlock\n" | |
566 | "\treadonly\n" | |
567 | "\tredefine_unowned\n" | |
568 | "\tspace_perm\n" | |
569 | "\tstartup\n" | |
570 | "\ttiming\n" | |
571 | "\twrite_limit\n"); |