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