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