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