blob: a2e84b7eaf6e8b501724d77e29b288b818b0fdc4 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
Antonio Nino Diaz9c9f92c2019-03-13 13:57:39 +00002 * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
Antonio Nino Diaz9c9f92c2019-03-13 13:57:39 +00008#include <arch_features.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02009#include <assert.h>
10#include <debug.h>
Antonio Nino Diaz09a00ef2019-01-11 13:12:58 +000011#include <drivers/arm/arm_gic.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020012#include <irq.h>
13#include <mmio.h>
14#include <nvm.h>
Alexei Fedorov719714f2019-10-03 10:57:53 +010015#include <pauth.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020016#include <plat_topology.h>
17#include <platform.h>
18#include <platform_def.h>
19#include <power_management.h>
20#include <psci.h>
21#include <sgi.h>
Ambroise Vincent602b7f52019-02-11 14:13:43 +000022#include <stdint.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020023#include <string.h>
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +020024#include <tftf.h>
25#include <tftf_lib.h>
26#include <timer.h>
27
28/* version information for TFTF */
29extern const char version_string[];
30
31unsigned int lead_cpu_mpid;
32
33/* Defined in hotplug.c */
34extern volatile test_function_t test_entrypoint[PLATFORM_CORE_COUNT];
35
36/* Per-CPU results for the current test */
37static test_result_t test_results[PLATFORM_CORE_COUNT];
38
39/* Context ID passed to tftf_psci_cpu_on() */
40static u_register_t cpu_on_ctx_id_arr[PLATFORM_CORE_COUNT];
41
42static unsigned int test_is_rebooting;
43
44static inline const test_suite_t *current_testsuite(void)
45{
46 test_ref_t test_to_run;
47 tftf_get_test_to_run(&test_to_run);
48 return &testsuites[test_to_run.testsuite_idx];
49}
50
51static inline const test_case_t *current_testcase(void)
52{
53 test_ref_t test_to_run;
54 tftf_get_test_to_run(&test_to_run);
55 return &testsuites[test_to_run.testsuite_idx].
56 testcases[test_to_run.testcase_idx];
57}
58
59/*
60 * Identify the next test in the tests list and update the NVM data to point to
61 * that test.
62 * If there is no more tests to execute, return NULL.
63 * Otherwise, return the test case.
64 */
65static const test_case_t *advance_to_next_test(void)
66{
67 test_ref_t test_to_run;
68 const test_case_t *testcase;
69 unsigned int testcase_idx;
70 unsigned int testsuite_idx;
71
72#if DEBUG
73 test_progress_t progress;
74 tftf_get_test_progress(&progress);
75 assert(progress == TEST_COMPLETE);
76#endif
77
78 tftf_get_test_to_run(&test_to_run);
79 testcase_idx = test_to_run.testcase_idx;
80 testsuite_idx = test_to_run.testsuite_idx;
81
82 /* Move to the next test case in the current test suite */
83 ++testcase_idx;
84 testcase = &testsuites[testsuite_idx].testcases[testcase_idx];
85
86 if (testcase->name == NULL) {
87 /*
88 * There's no more test cases in the current test suite so move
89 * to the first test case of the next test suite.
90 */
91 const test_suite_t *testsuite;
92 testcase_idx = 0;
93 ++testsuite_idx;
94 testsuite = &testsuites[testsuite_idx];
95 testcase = &testsuite->testcases[0];
96
97 if (testsuite->name == NULL) {
98 /*
99 * This was the last test suite so there's no more tests
100 * at all.
101 */
102 return NULL;
103 }
104 }
105
106 VERBOSE("Moving to test (%u,%u)\n", testsuite_idx, testcase_idx);
107 test_to_run.testsuite_idx = testsuite_idx;
108 test_to_run.testcase_idx = testcase_idx;
109 tftf_set_test_to_run(test_to_run);
110 tftf_set_test_progress(TEST_READY);
111
112 return testcase;
113}
114
115/*
116 * This function is executed only by the lead CPU.
117 * It prepares the environment for the next test to run.
118 */
119static void prepare_next_test(void)
120{
121 unsigned int mpid;
122 unsigned int core_pos;
123 unsigned int cpu_node;
124
125 /* This function should be called by the lead CPU only */
126 assert((read_mpidr_el1() & MPID_MASK) == lead_cpu_mpid);
127
128 /*
129 * Only the lead CPU should be powered on at this stage. All other CPUs
130 * should be powered off or powering off. If some CPUs are not powered
131 * off yet, wait for them to power off.
132 */
133 for_each_cpu(cpu_node) {
134 mpid = tftf_get_mpidr_from_node(cpu_node);
135 if (mpid == lead_cpu_mpid)
136 assert(tftf_is_cpu_online(mpid));
137 else
138 while (tftf_psci_affinity_info(mpid, MPIDR_AFFLVL0)
139 == PSCI_STATE_ON)
140 ;
141 }
142
143 /* No CPU should have entered the test yet */
144 assert(tftf_get_ref_cnt() == 0);
145
146 /* Populate the test entrypoint for the lead CPU */
147 core_pos = platform_get_core_pos(lead_cpu_mpid);
148 test_entrypoint[core_pos] = (test_function_t) current_testcase()->test;
149
150 for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; ++i)
151 test_results[i] = TEST_RESULT_NA;
152
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100153 /* If we're starting a new testsuite, announce it. */
154 test_ref_t test_to_run;
155 tftf_get_test_to_run(&test_to_run);
156 if (test_to_run.testcase_idx == 0) {
157 print_testsuite_start(current_testsuite());
158 }
159
160 print_test_start(current_testcase());
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200161
162 /* Program the watchdog */
163 tftf_platform_watchdog_set();
164
165 /* TODO: Take a 1st timestamp to be able to measure test duration */
166
167 tftf_set_test_progress(TEST_IN_PROGRESS);
168}
169
170/*
171 * Go through individual CPUs' test results and determine the overall
172 * test result from that.
173 */
174static test_result_t get_overall_test_result(void)
175{
176 test_result_t result = TEST_RESULT_NA;
177 unsigned int cpu_mpid;
178 unsigned int cpu_node;
179 unsigned int core_pos;
180
181 for_each_cpu(cpu_node) {
182 cpu_mpid = tftf_get_mpidr_from_node(cpu_node);
183 core_pos = platform_get_core_pos(cpu_mpid);
184
185 switch (test_results[core_pos]) {
186 case TEST_RESULT_NA:
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200187 /* Ignoring */
188 break;
189
190 case TEST_RESULT_SKIPPED:
191 /*
192 * If at least one CPU skipped the test, consider the
193 * whole test as skipped as well.
194 */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200195 return TEST_RESULT_SKIPPED;
196
197 case TEST_RESULT_SUCCESS:
198 result = TEST_RESULT_SUCCESS;
199 break;
200
201 case TEST_RESULT_FAIL:
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200202 return TEST_RESULT_FAIL;
203
204 case TEST_RESULT_CRASHED:
205 /*
206 * Means the CPU never returned from the test whereas it
207 * was supposed to. Either there is a bug in the test's
208 * implementation or some sort of unexpected crash
209 * happened.
210 * If at least one CPU crashed, consider the whole test
211 * as crashed as well.
212 */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200213 return TEST_RESULT_CRASHED;
214
215 default:
216 ERROR("Unknown test result value: %u\n",
217 test_results[core_pos]);
218 panic();
219 }
220 }
221
222 /*
223 * At least one CPU (i.e. the lead CPU) should have participated in the
224 * test.
225 */
226 assert(result != TEST_RESULT_NA);
227 return result;
228}
229
230/*
231 * This function is executed by the last CPU to exit the test only.
232 * It does the necessary bookkeeping and reports the overall test result.
233 * If it was the last test, it will also generate the final test report.
234 * Otherwise, it will reset the platform, provided that the platform
235 * supports reset from non-trusted world. This ensures that the next test
236 * runs in a clean environment
237 *
238 * Return 1 if this was the last test, 0 otherwise.
239 */
240static unsigned int close_test(void)
241{
242 const test_case_t *next_test;
243
244#if DEBUG
245 /*
246 * Check that the test didn't pretend resetting the platform, when in
247 * fact it returned into the framework.
248 *
249 * If that happens, the test implementation should be fixed.
250 * However, it is not a fatal error so just flag the problem in debug
251 * builds.
252 */
253 test_progress_t progress;
254 tftf_get_test_progress(&progress);
255 assert(progress != TEST_REBOOTING);
256#endif /* DEBUG */
257
258 tftf_set_test_progress(TEST_COMPLETE);
259 test_is_rebooting = 0;
260
261 /* TODO: Take a 2nd timestamp and compute test duration */
262
263 /* Reset watchdog */
264 tftf_platform_watchdog_reset();
265
266 /* Ensure no CPU is still executing the test */
267 assert(tftf_get_ref_cnt() == 0);
268
269 /* Save test result in NVM */
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200270 tftf_testcase_set_result(current_testcase(),
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100271 get_overall_test_result(),
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200272 0);
273
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100274 print_test_end(current_testcase());
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200275
276 /* The test is finished, let's move to the next one (if any) */
277 next_test = advance_to_next_test();
278
279 /* If this was the last test then report all results */
280 if (!next_test) {
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100281 print_tests_summary();
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200282 tftf_clean_nvm();
283 return 1;
284 } else {
285#if (PLAT_SUPPORTS_NS_RESET && !NEW_TEST_SESSION && USE_NVM)
286 /*
287 * Reset the platform so that the next test runs in a clean
288 * environment.
289 */
290 INFO("Reset platform before executing next test:%p\n",
291 (void *) &(next_test->test));
292 tftf_plat_reset();
293 bug_unreachable();
294#endif
295 }
296
297 return 0;
298}
299
300/*
301 * Hand over to lead CPU, i.e.:
302 * 1) Power on lead CPU
303 * 2) Power down calling CPU
304 */
305static void __dead2 hand_over_to_lead_cpu(void)
306{
307 int ret;
308 unsigned int mpid = read_mpidr_el1() & MPID_MASK;
309 unsigned int core_pos = platform_get_core_pos(mpid);
310
311 VERBOSE("CPU%u: Hand over to lead CPU%u\n", core_pos,
312 platform_get_core_pos(lead_cpu_mpid));
313
314 /*
315 * Power on lead CPU.
316 * The entry point address passed as the 2nd argument of tftf_cpu_on()
317 * doesn't matter because it will be overwritten by prepare_next_test().
318 * Pass a NULL pointer to easily catch the problem in case something
319 * goes wrong.
320 */
321 ret = tftf_cpu_on(lead_cpu_mpid, 0, 0);
322 if (ret != PSCI_E_SUCCESS) {
323 ERROR("CPU%u: Failed to power on lead CPU%u (%d)\n",
324 core_pos, platform_get_core_pos(lead_cpu_mpid), ret);
325 panic();
326 }
327
328 /* Wait for lead CPU to be actually powered on */
329 while (!tftf_is_cpu_online(lead_cpu_mpid))
330 ;
331
332 /*
333 * Lead CPU has successfully booted, let's now power down the calling
334 * core.
335 */
336 tftf_cpu_off();
337 panic();
338}
339
340void __dead2 run_tests(void)
341{
342 unsigned int mpid = read_mpidr_el1() & MPID_MASK;
343 unsigned int core_pos = platform_get_core_pos(mpid);
344 unsigned int test_session_finished;
345 unsigned int cpus_cnt;
346
347 while (1) {
348 if (mpid == lead_cpu_mpid && (tftf_get_ref_cnt() == 0))
349 prepare_next_test();
350
351 /*
352 * Increment the reference count to indicate that the CPU is
353 * participating in the test.
354 */
355 tftf_inc_ref_cnt();
356
357 /*
358 * Mark the CPU's test result as "crashed". This is meant to be
359 * overwritten by the actual test result when the CPU returns
360 * from the test function into the framework. In case the CPU
361 * crashes in the test (and thus, never returns from it), this
362 * variable will hold the right value.
363 */
364 test_results[core_pos] = TEST_RESULT_CRASHED;
365
366 /*
367 * Jump to the test entrypoint for this core.
368 * - For the lead CPU, it has been populated by
369 * prepare_next_test()
370 * - For other CPUs, it has been populated by tftf_cpu_on() or
371 * tftf_try_cpu_on()
372 */
373 while (test_entrypoint[core_pos] == 0)
374 ;
375
376 test_results[core_pos] = test_entrypoint[core_pos]();
377 test_entrypoint[core_pos] = 0;
378
379 /*
380 * Decrement the reference count to indicate that the CPU is not
381 * participating in the test any longer.
382 */
383 cpus_cnt = tftf_dec_ref_cnt();
384
385 /*
386 * Last CPU to exit the test gets to do the necessary
387 * bookkeeping and to report the overall test result.
388 * Other CPUs shut down.
389 */
390 if (cpus_cnt == 0) {
391 test_session_finished = close_test();
392 if (test_session_finished)
393 break;
394
395 if (mpid != lead_cpu_mpid) {
396 hand_over_to_lead_cpu();
397 bug_unreachable();
398 }
399 } else {
400 tftf_cpu_off();
401 panic();
402 }
403 }
404
405 tftf_exit();
406
407 /* Should never reach this point */
408 bug_unreachable();
409}
410
411u_register_t tftf_get_cpu_on_ctx_id(unsigned int core_pos)
412{
413 assert(core_pos < PLATFORM_CORE_COUNT);
414
415 return cpu_on_ctx_id_arr[core_pos];
416}
417
418void tftf_set_cpu_on_ctx_id(unsigned int core_pos, u_register_t context_id)
419{
420 assert(core_pos < PLATFORM_CORE_COUNT);
421
422 cpu_on_ctx_id_arr[core_pos] = context_id;
423}
424
425unsigned int tftf_is_rebooted(void)
426{
427 return test_is_rebooting;
428}
429
430/*
431 * Return 0 if the test session can be resumed
432 * -1 otherwise.
433 */
434static int resume_test_session(void)
435{
436 test_ref_t test_to_run;
437 test_progress_t test_progress;
438 const test_case_t *next_test;
439
440 /* Get back on our feet. Where did we stop? */
441 tftf_get_test_to_run(&test_to_run);
442 tftf_get_test_progress(&test_progress);
443 assert(TEST_PROGRESS_IS_VALID(test_progress));
444
445 switch (test_progress) {
446 case TEST_READY:
447 /*
448 * The TFTF has reset in the framework code, before the test
449 * actually started.
450 * Nothing to update, just start the test from scratch.
451 */
452 break;
453
454 case TEST_IN_PROGRESS:
455 /*
456 * The test crashed, i.e. it couldn't complete.
457 * Update the test result in NVM then move to the next test.
458 */
459 INFO("Test has crashed, moving to the next one\n");
460 tftf_testcase_set_result(current_testcase(),
461 TEST_RESULT_CRASHED,
462 0);
463 next_test = advance_to_next_test();
464 if (!next_test) {
465 INFO("No more tests\n");
466 return -1;
467 }
468 break;
469
470 case TEST_COMPLETE:
471 /*
472 * The TFTF has reset in the framework code, after the test had
473 * completed but before we finished the framework maintenance
474 * required to move to the next test.
475 *
476 * In this case, we don't know the exact state of the data:
477 * maybe we had the time to update the test result,
478 * maybe we had the time to move to the next test.
479 * We can't be sure so let's stay on the safe side and just
480 * restart the test session from the beginning...
481 */
482 NOTICE("The test framework has been interrupted in the middle "
483 "of critical maintenance operations.\n");
484 NOTICE("Can't recover execution.\n");
485 return -1;
486
487 case TEST_REBOOTING:
488 /*
489 * Nothing to update about the test session, as we want to
490 * re-enter the same test. Just remember that the test is
491 * rebooting in case it queries this information.
492 */
493 test_is_rebooting = 1;
494 break;
495
496 default:
497 bug_unreachable();
498 }
499
500 return 0;
501}
502
503/*
504 * C entry point in the TFTF.
505 * This function is executed by the primary CPU only.
506 */
507void __dead2 tftf_cold_boot_main(void)
508{
509 STATUS status;
510 int rc;
511
512 NOTICE("%s\n", TFTF_WELCOME_STR);
513 NOTICE("%s\n", build_message);
514 NOTICE("%s\n\n", version_string);
515
516#ifndef AARCH32
517 NOTICE("Running at NS-EL%u\n", IS_IN_EL(1) ? 1 : 2);
518#else
519 NOTICE("Running in AArch32 HYP mode\n");
520#endif
521
522 tftf_arch_setup();
Antonio Nino Diaz9c9f92c2019-03-13 13:57:39 +0000523
524 /*
525 * Enable pointer authentication. tftf_cold_boot_main() never returns,
526 * so it is safe to do it here. If this function was to return, the
527 * authentication would fail then.
528 */
529#if ENABLE_PAUTH
530 assert(is_armv8_3_pauth_apa_api_present());
531
Alexei Fedorov719714f2019-10-03 10:57:53 +0100532 /*
533 * Program APIAKey_EL1 key and enable ARMv8.3-PAuth here as this
534 * function doesn't return, and RETAA instuction won't be executed,
535 * what would cause translation fault otherwise.
536 */
537 pauth_init_enable();
Antonio Nino Diaz9c9f92c2019-03-13 13:57:39 +0000538#endif /* ENABLE_PAUTH */
539
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200540 tftf_platform_setup();
541 tftf_init_topology();
542
543 tftf_irq_setup();
544
545 rc = tftf_initialise_timer();
546 if (rc != 0) {
547 ERROR("Failed to initialize the timer subsystem (%d).\n", rc);
548 tftf_exit();
549 }
550
551 /* Enable the SGI used by the timer management framework */
552 tftf_irq_enable(IRQ_WAKE_SGI, GIC_HIGHEST_NS_PRIORITY);
553 enable_irq();
554
555 if (new_test_session()) {
556 NOTICE("Starting a new test session\n");
557 status = tftf_init_nvm();
558 if (status != STATUS_SUCCESS) {
559 /*
560 * TFTF will have an undetermined behavior if its data
561 * structures have not been initialised. There's no
562 * point in continuing execution.
563 */
564 ERROR("FATAL: Failed to initialise internal data structures in NVM.\n");
565 tftf_clean_nvm();
566 tftf_exit();
567 }
568 } else {
569 NOTICE("Resuming interrupted test session\n");
570 rc = resume_test_session();
571 if (rc < 0) {
Sandrine Bailleux125d58c2018-11-07 17:11:59 +0100572 print_tests_summary();
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +0200573 tftf_clean_nvm();
574 tftf_exit();
575 }
576 }
577
578 /* Initialise the CPUs status map */
579 tftf_init_cpus_status_map();
580
581 /*
582 * Detect power state format and get power state information for
583 * a platform.
584 */
585 tftf_init_pstate_framework();
586
587 /* The lead CPU is always the primary core. */
588 lead_cpu_mpid = read_mpidr_el1() & MPID_MASK;
589
590 /*
591 * Hand over to lead CPU if required.
592 * If the primary CPU is not the lead CPU for the first test then:
593 * 1) Power on the lead CPU
594 * 2) Power down the primary CPU
595 */
596 if ((read_mpidr_el1() & MPID_MASK) != lead_cpu_mpid) {
597 hand_over_to_lead_cpu();
598 bug_unreachable();
599 }
600
601 /* Enter the test session */
602 run_tests();
603
604 /* Should never reach this point */
605 bug_unreachable();
606}
607
608void __dead2 tftf_exit(void)
609{
610 NOTICE("Exiting tests.\n");
611
612 /* Let the platform code clean up if required */
613 tftf_platform_end();
614
615 while (1)
616 wfi();
617}