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